diff --git a/src/86box.h b/src/86box.h index 4c60598bc..b3956ea10 100644 --- a/src/86box.h +++ b/src/86box.h @@ -8,7 +8,7 @@ * * Main include file for the application. * - * Version: @(#)86box.h 1.0.25 2018/10/02 + * Version: @(#)86box.h 1.0.27 2019/01/13 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -98,7 +98,7 @@ extern int serial_enabled[], /* (C) enable serial ports */ isartc_type; /* (C) enable ISA RTC card */ extern int sound_is_float, /* (C) sound uses FP values */ GAMEBLASTER, /* (C) sound option */ - GUS, /* (C) sound option */ + GUS, GUSMAX, /* (C) sound option */ SSI2001, /* (C) sound option */ voodoo_enabled; /* (C) video option */ extern uint32_t mem_size; /* (C) memory size */ @@ -109,8 +109,8 @@ extern int cpu_manufacturer, /* (C) cpu manufacturer */ extern int time_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 */ - +extern char network_host[522]; /* (C) host network intf */ +extern int hdd_format_type; /* (C) hard disk file format */ extern int is_pentium; /* TODO: Move back to cpu/cpu.h when it's figured out, how to remove that hack from the ET4000/W32p. */ diff --git a/src/Makefile.local b/src/Makefile.local index 862dcc032..93cb032a0 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -10,7 +10,7 @@ # settings, so we can avoid changing the main one for all of # our local setups. # -# Version: @(#)Makefile.local 1.0.19 2018/10/22 +# Version: @(#)Makefile.local 1.0.20 2018/11/18 # # Author: Fred N. van Kempen, # @@ -133,6 +133,7 @@ STUFF := # -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_SETTINGS_LOG=N sets logging level at N. # -DENABLE_WIN_LOG=N sets logging level at N. EXTRAS := diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.cc index 9513943a7..94394a01b 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.cc @@ -8,7 +8,7 @@ * * CD-ROM image support. * - * Version: @(#)cdrom_image.cc 1.0.7 2018/10/28 + * Version: @(#)cdrom_image.cc 1.0.9 2019/02/01 * * Author: RichardG867, * Miran Grca, @@ -292,6 +292,6 @@ cdrom_image_close(cdrom_t *dev) { cdrom_image_log("CDROM: image_close(%ls)\n", dev->image_path); - if (dev->ops->exit) + if (dev && dev->ops && dev->ops->exit) dev->ops->exit(dev); } diff --git a/src/config.c b/src/config.c index 805415ba7..b4dae66e2 100644 --- a/src/config.c +++ b/src/config.c @@ -8,7 +8,7 @@ * * Configuration file handler. * - * Version: @(#)config.c 1.0.58 2018/10/17 + * Version: @(#)config.c 1.0.60 2019/01/13 * * Authors: Sarah Walker, * Miran Grca, @@ -208,7 +208,7 @@ create_section(char *name) section_t *ns = malloc(sizeof(section_t)); memset(ns, 0x00, sizeof(section_t)); - strncpy(ns->name, name, sizeof(ns->name)); + memcpy(ns->name, name, strlen(name) + 1); list_add(&ns->list, &config_head); return(ns); @@ -221,7 +221,7 @@ 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)); + memcpy(ne->name, name, strlen(name) + 1); list_add(&ne->list, §ion->entry_head); return(ne); @@ -652,7 +652,7 @@ load_sound(void) SSI2001 = !!config_get_int(cat, "ssi2001", 0); GAMEBLASTER = !!config_get_int(cat, "gameblaster", 0); GUS = !!config_get_int(cat, "gus", 0); - + memset(temp, '\0', sizeof(temp)); p = config_get_string(cat, "opl_type", "dbopl"); strcpy(temp, p); @@ -766,29 +766,17 @@ load_other_peripherals(void) else scsi_card_current = 0; - if (hdc_name) { - free(hdc_name); - hdc_name = NULL; - } p = config_get_string(cat, "hdc", NULL); - if (p == NULL) { - p = config_get_string(cat, "hdd_controller", NULL); - if (p != NULL) - config_delete_var(cat, "hdd_controller"); - } if (p == NULL) { if (machines[machine].flags & MACHINE_HDC) { - hdc_name = (char *) malloc((strlen("internal") + 1) * sizeof(char)); - strcpy(hdc_name, "internal"); + p = (char *)malloc((strlen("internal")+1)*sizeof(char)); + strcpy(p, "internal"); } else { - hdc_name = (char *) malloc((strlen("none") + 1) * sizeof(char)); - strcpy(hdc_name, "none"); + p = (char *)malloc((strlen("none")+1)*sizeof(char)); + strcpy(p, "none"); } - } else { - hdc_name = (char *) malloc((strlen(p) + 1) * sizeof(char)); - strcpy(hdc_name, p); } - config_set_string(cat, "hdc", hdc_name); + hdc_current = hdc_get_from_internal_name(p); ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); @@ -1249,12 +1237,7 @@ config_load(void) 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"); + hdc_current = hdc_get_from_internal_name("none"); serial_enabled[0] = 1; serial_enabled[1] = 1; lpt_enabled = 1; @@ -1652,7 +1635,8 @@ save_other_peripherals(void) config_set_string(cat, "scsicard", scsi_card_get_internal_name(scsi_card_current)); - config_set_string(cat, "hdc", hdc_name); + config_set_string(cat, "hdc", + hdc_get_internal_name(hdc_current)); if (ide_ter_enabled == 0) config_delete_var(cat, "ide_ter"); @@ -2170,7 +2154,7 @@ config_set_string(char *head, char *name, char *val) if (ent == NULL) ent = create_entry(section, name); - strncpy(ent->data, val, sizeof(ent->data)); + memcpy(ent->data, val, sizeof(ent->data)); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } diff --git a/src/cpu/386.c b/src/cpu/386.c index b71c779cc..988b5e987 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -27,53 +27,33 @@ extern int codegen_flags_changed; -extern int nmi_enable; +int cpl_override = 0, fpucount = 0; +int tempc, oldcpl, optype, inttype, oddeven = 0; +int use32, stack32; -int inscounts[256]; -uint32_t oldpc2; +uint16_t flags, eflags; +uint16_t rds, ea_rseg; +uint16_t oldcs; -int trap; - -uint16_t flags,eflags; -uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +uint32_t oldds, oldss, olddslimit, oldsslimit, + olddslimitw, oldsslimitw; +uint32_t *eal_r, *eal_w; +uint32_t oxpc, cr2, cr3, cr4; +uint32_t dr[8]; +uint32_t rmdat32; +uint32_t backupregs[16]; 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++ @@ -149,11 +129,6 @@ void exec386(int cycs) 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; diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 54ea6832c..b14e192f5 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -34,43 +34,10 @@ uint32_t cpu_cur_status = 0; int cpu_reps, cpu_reps_latched; int cpu_notreps, cpu_notreps_latched; -int inrecomp = 0; +int inrecomp = 0, cpu_block_end = 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 diff --git a/src/cpu/808x.c b/src/cpu/808x.c index c75cbeaad..859a98acf 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1,49 +1,25 @@ /* - * 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. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * - * 808x CPU emulation. + * 808x CPU emulation, mostly ported from reenigne's XTCE, which + * is cycle-accurate. * - * SHR AX,1 + * Version: @(#)808x.c 1.0.8 2018/11/14 * - * 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.7 2018/10/17 - * - * Authors: Sarah Walker, + * Authors: Andrew Jenner, * Miran Grca, + * Authors: Sarah Walker, * - * Copyright 2008-2018 Sarah Walker. + * Copyright 2015-2018 Andrew Jenner. * 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. + * Copyright 2008-2018 Sarah Walker. */ +#include #include #include #include @@ -60,32 +36,78 @@ #include "../nmi.h" #include "../pic.h" #include "../timer.h" -#include "../plat.h" +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The tables to speed up the setting of the Z, N, and P flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +int rmdat; + +/* XT CPU multiplier. */ int xt_cpu_multi; -int nmi = 0; -int nmi_auto_clear = 0; -int nextcyc=0; -int cycdiff; -int is8086=0; +/* Is the CPU 8088 or 8086. */ +int is8086 = 0; -int memcycs; -int nopageerrors=0; +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; +int nmi_enable = 1; -void FETCHCOMPLETE(); +/* Was the CPU ever reset? */ +int x86_was_reset = 0; -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); +/* Amount of instructions executed - used to calculate the % shown in the title bar. */ +int ins = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; + + +/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ +static uint8_t pfq[6]; + +/* Variables to aid with the prefetch queue operation. */ +static int fetchcycles = 0; +static int fetchclocks, pfq_pos = 0; + +/* The IP equivalent of the current prefetch queue position. */ +static uint16_t pfq_ip; + +/* Where is this even used?! */ +static int nextcyc = 0; + +/* Pointer tables needed for segment overrides. */ +static uint32_t *opseg[4]; +static x86seg *_opseg[4]; + +static int takeint = 0, noint = 0; +static int in_lock = 0, halt = 0; +static int cpu_alu_op, pfq_size; + +static uint16_t cpu_src = 0, cpu_dest = 0; +static uint16_t cpu_data = 0; + +static uint32_t *ovr_seg = NULL; #ifdef ENABLE_808X_LOG +void dumpregs(int); + int x808x_do_log = ENABLE_808X_LOG; +int indump = 0; static void @@ -99,367 +121,473 @@ x808x_log(const char *fmt, ...) va_end(ap); } } + + +void +dumpregs(int force) +{ + int c; + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, flags); + x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); + for (c = 0; c < 4; c++) { + x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->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("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); + x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + 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("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + 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("Entries in readlookup : %i writelookup : %i\n", readlnum, writelnum); + x87_dumpregs(); + indump = 0; +} #else #define x808x_log(fmt, ...) #endif +static void pfq_add(int c); +static void set_pzs(int bits); + + +static int +irq_pending(void) +{ + if ((nmi && nmi_enable && nmi_mask) || ((flags & I_FLAG) && (pic.pend & ~pic.mask) && !noint)) + return 1; + + return 0; +} + + +static void +wait(int c, int bus) +{ + cycles -= c; + if (!bus) + pfq_add(c); +} + + #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) +/* Reads a byte from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static uint8_t +readmemb(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)); -} + uint8_t ret; -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); -} + wait(4, 1); -void refreshread() { FETCHCOMPLETE(); memcycs+=4; } + if (readlookup2 == NULL) + ret = readmembl(a); + else { + if (readlookup2[(a) >> 12] == -1) + ret = readmembl(a); + else + ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + } -#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; + return ret; } -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() +/* Reads a byte from the memory but does not accounts for memory transfer + cycles to subtract from the cycles to use for adding to the prefetch + queue. */ +static uint8_t +readmembf(uint32_t a) { - uint8_t temp; + uint8_t ret; - 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]; - if (is8086) { - prefetchqueue[3]=prefetchqueue[4]; - prefetchqueue[4]=prefetchqueue[5]; - } - prefetchw--; - fetchcycles-=4; - cpu_state.pc++; - } - return temp; -} + a = cs + (a & 0xffff); -static __inline void FETCHADD(int c) -{ - int d; - if (c<0) return; - if (prefetchw>((is8086)?5: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<((is8086)?6:4)) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - } - fetchcycles+=c; - if (fetchcycles>16) fetchcycles=16; -} + if (readlookup2 == NULL) + ret = readmembl(a); + else { + if (readlookup2[(a) >> 12] == -1) + ret = readmembl(a); + else + ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + } -void FETCHCOMPLETE() -{ - if (!(fetchcycles&3)) return; - if (prefetchw>((is8086)?5: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<((is8086)?6:4)) - { - 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); + return ret; } -/*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() +/* Reads a word from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static uint16_t +readmemw(uint32_t s, uint16_t a) { - 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; + uint16_t ret; + + if (!is8086 || (a & 1)) { + ret = readmemb(s + a); + ret |= readmemb(s + ((a + 1) & 0xffff)) << 8; + } else { + wait(4, 1); + + if (readlookup2 == NULL) + ret = readmemwl(s, a); + else { + if ((readlookup2[((s) + (a)) >> 12] == -1 || (s) == 0xFFFFFFFF)) + ret = readmemwl(s, a); + else + ret = *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); + } + } + + return ret; } -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; +/* Writes a byte from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static void +writememb(uint32_t a, uint8_t v) +{ + wait(4, 1); + + if (writelookup2 == NULL) + writemembl(a, v); + else { + if (writelookup2[(a) >> 12] == -1) + writemembl(a, v); + else + *(uint8_t *)(writelookup2[a >> 12] + a) = v; + } } -static __inline uint8_t geteab() + +/* Writes a word from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static void +writememw(uint32_t s, uint32_t a, uint16_t v) { - 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); + if (!is8086 || (a & 1)) { + writememb(s + a, v & 0xff); + writememb(s + ((a + 1) & 0xffff), v >> 8); + } else { + wait(4, 1); + + if (writelookup2 == NULL) + writememwl(s, a, v); + else { + if ((writelookup2[((s) + (a)) >> 12]== -1) || ((s) == 0xFFFFFFFF)) + writememwl(s, a, v); + else + *(uint16_t *) (writelookup2[(s + a) >> 12] + s + a) = v; + } + } } -static __inline uint16_t geteaw() + +/* Fetches a byte from the prefetch queue, or from memory if the queue has + been drained. */ +static uint8_t +pfq_fetchb(void) { - if (cpu_mod == 3) - return cpu_state.regs[cpu_rm].w; - return readmemw(easeg,cpu_state.eaaddr); + uint8_t temp, i; + + if (pfq_pos == 0) { + cycles -= (4 - (fetchcycles & 3)); + fetchclocks += (4 - (fetchcycles & 3)); + fetchcycles = 4; + temp = readmembf(cpu_state.pc); + pfq_ip = cpu_state.pc = cpu_state.pc + 1; + if (is8086 && (cpu_state.pc & 1)) { + pfq[0] = readmembf(cpu_state.pc); + pfq_ip++; + pfq_pos++; + } + } else { + temp = pfq[0]; + for (i = 0; i < (pfq_size - 1); i++) + pfq[i] = pfq[i + 1]; + pfq_pos--; + fetchcycles -= 4; + cpu_state.pc++; + } + wait(1, 0); + return temp; } -#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) +/* Fetches a word from the prefetch queue, or from memory if the queue has + been drained. */ +static uint16_t +pfq_fetchw(void) { - 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); - } + uint8_t temp = pfq_fetchb(); + return temp | (pfq_fetchb() << 8); } -static __inline void seteaw(uint16_t val) + +/* Adds bytes to the prefetch queue based on the instruction's cycle count. */ +static void +pfq_add(int c) { - if (cpu_mod == 3) - cpu_state.regs[cpu_rm].w = val; - else - { - writememw(easeg,cpu_state.eaaddr,val); - } + int d; + if (c < 0) + return; + if (pfq_pos >= pfq_size) + return; + d = c + (fetchcycles & 3); + while ((d > 3) && (pfq_pos < pfq_size)) { + d -= 4; + if (is8086 && !(pfq_ip & 1)) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + if (pfq_pos < pfq_size) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + } + fetchcycles += c; + if (fetchcycles > 16) + fetchcycles = 16; +} + + +/* Completes a fetch (called by refreshread()). */ +static void +pfq_complete(void) +{ + if (!(fetchcycles & 3)) + return; + if (pfq_pos >= pfq_size) + return; + if (!pfq_pos) + nextcyc = (4 - (fetchcycles & 3)); + cycles -= (4 - (fetchcycles & 3)); + fetchclocks += (4 - (fetchcycles & 3)); + if (is8086 && !(pfq_ip & 1)) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + if (pfq_pos < pfq_size) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + fetchcycles += (4 - (fetchcycles & 3)); +} + + +/* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ +static void +pfq_clear() +{ + pfq_ip = cpu_state.pc; + pfq_pos = 0; + fetchclocks = 0; +} + + +/* Memory refresh read - called by reads and writes on DMA channel 0. */ +void +refreshread(void) { + pfq_complete(); +} + + +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) +{ + 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; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; + opseg[0] = &es; + opseg[1] = &cs; + opseg[2] = &ss; + opseg[3] = &ds; + _opseg[0] = &_es; + _opseg[1] = &_cs; + _opseg[2] = &_ss; + _opseg[3] = &_ds; +} + + +/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ +static void +do_mod_rm(void) +{ + rmdat = pfq_fetchb(); + cpu_reg = (rmdat >> 3) & 7; + cpu_mod = (rmdat >> 6) & 3; + cpu_rm = rmdat & 7; + + if (cpu_mod == 3) + return; + + wait(3, 0); + + if (!cpu_mod && (cpu_rm == 6)) { + wait(2, 0); + cpu_state.eaaddr = pfq_fetchw(); + easeg = ds; + wait(1, 0); + } else { + switch (cpu_rm) { + case 0: + case 3: + wait(2, 0); + break; + case 1: + case 2: + wait(3, 0); + break; + } + + cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = *mod1seg[cpu_rm]; + + switch (cpu_mod) { + case 1: + wait(4, 0); + cpu_state.eaaddr += (uint16_t) (int8_t) pfq_fetchb(); + break; + case 2: + wait(4, 0); + cpu_state.eaaddr += pfq_fetchw(); + break; + } + wait(2, 0); + } + + cpu_state.eaaddr &= 0xffff; + cpu_state.last_ea = cpu_state.eaaddr; + + if (ovr_seg) + easeg = *ovr_seg; +} + + +/* Reads a byte from the effective address. */ +static uint8_t +geteab(void) +{ + 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); +} + + +/* Reads a word from the effective address. */ +static uint16_t +geteaw(void) +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg, cpu_state.eaaddr); +} + + +static void +read_ea(int memory_only, int bits) +{ + if (cpu_mod != 3) { + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); + return; + } + if (!memory_only) { + if (bits == 8) + cpu_data = (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +static void +read_ea2(int bits) +{ + if (bits == 16) + cpu_data = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xffff); + else + cpu_data = readmemb(easeg + ((cpu_state.eaaddr + 2) & 0xffff)); +} + + +/* Writes a byte to the effective address. */ +static 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); +} + + +/* Writes a word to the effective address. */ +static 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 @@ -470,2843 +598,2094 @@ static __inline void seteaw(uint16_t val) else cpu_state.regs[r & 3].b.l = v; -/*Flags*/ -uint8_t znptable8[256]; -uint16_t znptable16[65536]; - -void makeznptable() +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P flags. */ +static void +makeznptable(void) { - 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 + 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; + } -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; + 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; + } } -int resets = 0; -int x86_was_reset = 0; -void resetx86() + +/* Common reset function. */ +static void +reset_common(int hard) { - 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(); + if (hard) { + x808x_log("x86 reset\n"); + 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; + trap = 0; + ovr_seg = NULL; + in_lock = halt = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + pfq_clear(); + cpu_set_edx(); EAX = 0; - ESP=0; - mmu_perm=4; - memset(inscounts, 0, sizeof(inscounts)); - x86seg_reset(); + ESP = 0; + mmu_perm = 4; + pfq_size = (is8086) ? 6 : 4; + } + + x86seg_reset(); #ifdef USE_DYNAREC - codegen_reset(); + if (hard) + 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; + x86_was_reset = 1; + port_92_clear_reset(); } -int inhlt=0; -uint16_t lastpc,lastcs; -int firstrepcycle; -int skipnextprint=0; - -int instime=0; -void execx86(int cycs) +/* Hard reset. */ +void +resetx86(void) { - 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; + reset_common(1); +} - 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; +/* Soft reset. */ +void +softresetx86(void) +{ + reset_common(0); +} - 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; +/* Pushes a word to the stack. */ +static void +push(uint16_t val) +{ + writememw(ss, ((SP - 2) & 0xFFFF), val); + SP -= 2; + cpu_state.last_ea = SP; +} - 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; +/* Pops a word from the stack. */ +static uint16_t +pop(void) +{ + uint16_t tempw; - 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; + tempw = readmemw(ss, SP); + SP += 2; + cpu_state.last_ea = SP; + return tempw; +} - 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; +static void +access(int num, int bits) +{ + switch (num) { + case 0: case 61: case 63: case 64: + case 67: case 69: case 71: case 72: + default: + break; + case 1: case 6: case 8: case 9: + case 17: case 20: case 21: case 24: + case 28: case 55: case 56: + wait(1 + (cycles % 3), 0); + break; + case 2: case 15: case 22: case 23: + case 25: case 26: case 46: case 53: + wait(2 + (cycles % 3), 0); + break; + case 3: case 44: case 45: case 52: + case 54: + wait(2 + (cycles & 1), 0); + break; + case 4: + wait(5 + (cycles & 1), 0); + break; + case 5: + if (opcode == 0xcc) + wait(7 + (cycles % 3), 0); + else + wait(4 + (cycles & 1), 0); + break; + case 7: case 47: case 48: case 49: + case 50: case 51: + wait(1 + (cycles % 4), 0); + break; + case 10: case 11: case 18: case 19: + case 43: + wait(3 + (cycles % 3), 0); + break; + case 12: case 13: case 14: case 29: + case 30: case 33: + wait(4 + (cycles % 3), 0); + break; + case 16: + if (!(opcode & 1) && (cycles & 1)) + wait(1, 0); + /* Fall through. */ + case 42: + wait(3 + (cycles & 1), 0); + break; + case 27: case 32: case 37: + wait(3, 0); + break; + case 31: + wait(6 + (cycles % 3), 0); + break; + case 34: case 39: case 41: case 60: + wait(4, 0); + break; + case 35: + wait(2, 0); + break; + case 36: + wait(5 + (cycles & 1), 0); + if (cpu_mod != 3) + wait(1, 0); + break; + case 38: + wait(5 + (cycles % 3), 0); + break; + case 40: + wait(6, 0); + break; + case 57: + if (cpu_mod != 3) + wait(2, 0); + wait(4 + (cycles & 1), 0); + break; + case 58: + if (cpu_mod != 3) + wait(1, 0); + wait(4 + (cycles & 1), 0); + break; + case 59: + if (cpu_mod != 3) + wait(1, 0); + wait(5 + (cycles & 1), 0); + break; + case 62: + wait(1, 0); + break; + case 65: + wait(3 + (cycles & 1), 0); + if (cpu_mod != 3) + wait(1, 0); + break; + case 70: + wait(5, 0); + 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; +/* Calls an interrupt. */ +static void +interrupt(uint16_t addr, int cli) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; - case 0x90: /*NOP*/ - cycles-=3; - break; + addr <<= 2; + old_cs = CS; + access(5, 16); + new_ip = readmemw(0, addr); + wait(1, 0); + access(6, 16); + new_cs = readmemw(0, (addr + 2) & 0xffff); + access(39, 16); + push(flags & 0x0fd7); + if (cli) + flags &= ~I_FLAG; + flags &= ~T_FLAG; + access(40, 16); + push(old_cs); + old_ip = cpu_state.pc; + loadcs(new_cs); + access(68, 16); + cpu_state.pc = new_ip; + access(41, 16); + push(old_ip); + pfq_clear(); +} - 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; +static int +rep_action(int *completed, int *repeating, int in_rep, int bits) +{ + uint16_t t; - 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; + if (in_rep == 0) + return 0; + wait(2, 0); + t = CX; + if (irq_pending()) { + access(71, bits); + pfq_clear(); + cpu_state.pc = cpu_state.pc - 2; + t = 0; + } + if (t == 0) { + wait(1, 0); + *completed = 1; + *repeating = 0; + return 1; + } + --CX; + *completed = 0; + wait(2, 0); + if (!*repeating) + wait(2, 0); + return 0; +} - 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; +static uint16_t +jump(uint16_t delta) +{ + uint16_t old_ip; + access(67, 8); + wait(5, 0); + old_ip = cpu_state.pc; + cpu_state.pc = (cpu_state.pc + delta) & 0xffff; + pfq_clear(); + return old_ip; +} - 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(); +static uint16_t +sign_extend(uint8_t data) +{ + return data + (data < 0x80 ? 0 : 0xff00); +} - 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(); +static void +jump_short(void) +{ + jump(sign_extend((uint8_t) cpu_data)); +} - 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; +static uint16_t +jump_near(void) +{ + return jump(pfq_fetchw()); +} - 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; +/* Performs a conditional jump. */ +static void +jcc(uint8_t opcode, int cond) +{ + /* int8_t offset; */ + + wait(1, 0); + cpu_data = pfq_fetchb(); + wait(1, 0); + if ((!cond) == (opcode & 0x01)) + jump_short(); +} + + +static void +set_cf(int cond) +{ + flags = (flags & ~C_FLAG) | (cond ? C_FLAG : 0); +} + + +static void +set_if(int cond) +{ + flags = (flags & ~I_FLAG) | (cond ? I_FLAG : 0); +} + + +static void +set_df(int cond) +{ + flags = (flags & ~D_FLAG) | (cond ? D_FLAG : 0); +} + + +static void +bitwise(int bits, uint16_t data) +{ + cpu_data = data; + flags &= ~(C_FLAG | A_FLAG | V_FLAG); + set_pzs(bits); +} + + +static void +test(int bits, uint16_t dest, uint16_t src) +{ + cpu_dest = dest; + cpu_src = src; + bitwise(bits, (cpu_dest & cpu_src)); +} + + +static void +set_of(int of) +{ + flags = (flags & ~0x800) | (of ? 0x800 : 0); +} + + +static int +top_bit(uint16_t w, int bits) +{ + if (bits == 16) + return ((w & 0x8000) != 0); + else + return ((w & 0x80) != 0); +} + + +static void +set_of_add(int bits) +{ + set_of(top_bit((cpu_data ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_of_sub(int bits) +{ + set_of(top_bit((cpu_dest ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_af(int af) +{ + flags = (flags & ~0x10) | (af ? 0x10 : 0); +} + + +static void +do_af(void) +{ + set_af(((cpu_data ^ cpu_src ^ cpu_dest) & 0x10) != 0); +} + + +static void +set_apzs(int bits) +{ + set_pzs(bits); + do_af(); +} + + +static void +add(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest + cpu_src; + set_apzs(bits); + set_of_add(bits); + + /* Anything - FF with carry on is basically anything + 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (flags & C_FLAG)) + flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_data & size_mask)); +} + + +static void +sub(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest - cpu_src; + set_apzs(bits); + set_of_sub(bits); + + /* Anything - FF with carry on is basically anything - 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (flags & C_FLAG)) + flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_dest & size_mask)); +} + + +static void +alu_op(int bits) +{ + switch(cpu_alu_op) { + case 1: + bitwise(bits, (cpu_dest | cpu_src)); + break; + case 2: + if (flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 0: + add(bits); + break; + case 3: + if (flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 5: case 7: + sub(bits); + break; + case 4: + test(bits, cpu_dest, cpu_src); + break; + case 6: + bitwise(bits, (cpu_dest ^ cpu_src)); + break; + } +} + + +static void +set_sf(int bits) +{ + flags = (flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); +} + + +static void +set_pf(void) +{ + static uint8_t table[0x100] = { + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4}; + + flags = (flags & ~4) | table[cpu_data & 0xff]; +} + + +static void +mul(uint16_t a, uint16_t b) +{ + int negate = 0; + int bit_count = 8; + int carry, i; + uint16_t high_bit = 0x80; + uint16_t size_mask; + uint16_t c, r; + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd5) { + if (opcode & 1) { + bit_count = 16; + high_bit = 0x8000; + } else + wait(8, 0); + + size_mask = (1 << bit_count) - 1; + + if ((rmdat & 0x38) == 0x28) { + if (!top_bit(a, bit_count)) { + if (top_bit(b, bit_count)) { + wait(1, 0); + if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) + wait(1, 0); + b = ~b + 1; + negate = 1; + } + } else { + wait(1, 0); + a = ~a + 1; + negate = 1; + if (top_bit(b, bit_count)) { + b = ~b + 1; + negate = 0; + } else + wait(4, 0); + } + wait(10, 0); + } + wait(3, 0); + } + + c = 0; + a &= size_mask; + carry = (a & 1) != 0; + a >>= 1; + for (i = 0; i < bit_count; ++i) { + wait(7, 0); + if (carry) { + cpu_src = c; + cpu_dest = b; + add(bit_count); + c = cpu_data & size_mask; + wait(1, 0); + carry = !!(flags & C_FLAG); + } + r = (c >> 1) + (carry ? high_bit : 0); + carry = (c & 1) != 0; + c = r; + r = (a >> 1) + (carry ? high_bit : 0); + carry = (a & 1) != 0; + a = r; + } + if (negate) { + c = ~c; + a = (~a + 1) & size_mask; + if (a == 0) + ++c; + wait(9, 0); + } + cpu_data = a; + cpu_dest = c; + + set_sf(bit_count); + set_pf(); +} + + +static void +set_of_rotate(int bits) +{ + set_of(top_bit(cpu_data ^ cpu_dest, bits)); +} + + +static void +set_zf(int bits) +{ + int size_mask = (1 << bits) - 1; + + flags = (flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); +} + + +static void +set_pzs(int bits) +{ + set_pf(); + set_zf(bits); + set_sf(bits); +} + + +static void +set_co_mul(int carry) +{ + set_cf(carry); + set_of(carry); + if (!carry) + wait(1, 0); +} + + +static int +div(uint16_t l, uint16_t h) +{ + int b, bit_count = 8; + int negative = 0; + int dividend_negative = 0; + int size_mask, carry; + uint16_t r; + + if (opcode & 1) { + l = AX; + h = DX; + bit_count = 16; + } + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd4) { + if ((rmdat & 0x38) == 0x38) { + if (top_bit(h, bit_count)) { + h = ~h; + l = (~l + 1) & size_mask; + if (l == 0) + ++h; + h &= size_mask; + negative = 1; + dividend_negative = 1; + wait(4, 0); + } + if (top_bit(cpu_src, bit_count)) { + cpu_src = ~cpu_src + 1; + negative = !negative; + } else + wait(1, 0); + wait(9, 0); + } + wait(3, 0); + } + cycles -= 8; + cpu_src &= size_mask; + if (h >= cpu_src) { + if (opcode != 0xd4) + wait(1, 0); + interrupt(0, 1); + return 0; + } + if (opcode != 0xd4) + wait(1, 0); + wait(2, 0); + carry = 1; + for (b = 0; b < bit_count; ++b) { + r = (l << 1) + (carry ? 1 : 0); + carry = top_bit(l, bit_count); + l = r; + r = (h << 1) + (carry ? 1 : 0); + carry = top_bit(h, bit_count); + h = r; + wait(8, 0); + if (carry) { + carry = 0; + h -= cpu_src; + if (b == bit_count - 1) + wait(2, 0); + } else { + carry = cpu_src > h; + if (!carry) { + h -= cpu_src; + wait(1, 0); + if (b == bit_count - 1) + wait(2, 0); + } + } + } + l = ~((l << 1) + (carry ? 1 : 0)); + if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { + wait(4, 0); + if (top_bit(l, bit_count)) { + if (cpu_mod == 3) + wait(1, 0); + interrupt(0, 1); + return 0; + } + wait(7, 0); + if (negative) + l = ~l + 1; + if (dividend_negative) + h = ~h + 1; + } + if (opcode == 0xd4) { + AL = h & 0xff; + AH = l & 0xff; + } else { + AH = h & 0xff; + AL = l & 0xff; + if (opcode & 1) { + DX = h; + AX = l; + } + } + return 1; +} + + +static void +lods(int bits) +{ + if (bits == 16) + cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), SI); + else + cpu_data = readmemb((ovr_seg ? *ovr_seg : ds) + SI); + if (flags & D_FLAG) + SI -= (bits >> 3); + else + SI += (bits >> 3); +} + + +static void +stos(int bits) +{ + if (bits == 16) + writememw(es, DI, cpu_data); + else + writememb(es + DI, cpu_data); + if (flags & D_FLAG) + DI -= (bits >> 3); + else + DI += (bits >> 3); +} + + +static void +da(void) +{ + set_pzs(8); + wait(2, 0); +} + + +static void +aa(void) +{ + set_of(0); + AL &= 0x0f; + wait(6, 0); +} + + +static void +set_ca(void) +{ + set_cf(1); + set_af(1); +} + + +static void +clear_ca(void) +{ + set_cf(0); + set_af(0); +} + + +/* Executes instructions up to the specified number of cycles. */ +void +execx86(int cycs) +{ + uint8_t temp = 0, temp2; + uint16_t addr, tempw; + uint16_t new_cs, new_ip; + int bits, completed; + int in_rep, repeating; + int oldc; + + cycles += cycs; + + while (cycles > 0) { + timer_start_period(cycles * xt_cpu_multi); + wait(nextcyc, 0); + nextcyc = 0; + fetchclocks = 0; + cpu_state.oldpc = cpu_state.pc; + in_rep = repeating = 0; + completed = 0; + +opcodestart: + if (halt) { + wait(2, 0); + goto on_halt; + } + + if (!repeating) { + opcode = pfq_fetchb(); + oldc = flags & C_FLAG; + trap = flags & T_FLAG; + wait(1, 0); + } + + /* if ((CS >= 0xc800) && (CS <= 0xcfff)) + pclog("%04X:%04X %02X (%04X)\n", CS, cpu_state.pc, opcode, flags); */ + + switch (opcode) { + case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ + access(29, 16); + push(_opseg[(opcode >> 3) & 0x03]->seg); + break; + case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ + access(22, 16); + if (opcode == 0x0F) { + loadcs(pop()); + pfq_clear(); + } else + loadseg(pop(), _opseg[(opcode >> 3) & 0x03]); + wait(1, 0); + noint = 1; + break; + + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + wait(1, 0); + ovr_seg = opseg[(opcode >> 3) & 0x03]; + goto opcodestart; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x38: case 0x39: case 0x3a: case 0x3b: + /* alu rm, r / r, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(46, bits); + if (opcode & 1) + tempw = geteaw(); + else + tempw = geteab(); + cpu_alu_op = (opcode >> 3) & 7; + if ((opcode & 2) == 0) { + cpu_dest = tempw; + cpu_src = (opcode & 1) ? cpu_state.regs[cpu_reg].w : getr8(cpu_reg); + } else { + cpu_dest = (opcode & 1) ? cpu_state.regs[cpu_reg].w : getr8(cpu_reg); + cpu_src = tempw; + } + if (cpu_mod != 3) + wait(2, 0); + wait(1, 0); + alu_op(bits); + if (cpu_alu_op != 7) { + if ((opcode & 2) == 0) { + access(10, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + if (cpu_mod == 3) + wait(1, 0); + } else { + if (opcode & 1) + cpu_state.regs[cpu_reg].w = cpu_data; + else + setr8(cpu_reg, cpu_data); + wait(1, 0); } - 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); + } else + wait(1, 0); + break; + + case 0x04: case 0x05: case 0x0c: case 0x0d: + case 0x14: case 0x15: case 0x1c: case 0x1d: + case 0x24: case 0x25: case 0x2c: case 0x2d: + case 0x34: case 0x35: case 0x3c: case 0x3d: + /* alu A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + if (opcode & 1) { + cpu_data = pfq_fetchw(); + cpu_dest = AX; + } else { + cpu_data = pfq_fetchb(); + cpu_dest = AL; + } + cpu_src = cpu_data; + cpu_alu_op = (opcode >> 3) & 7; + alu_op(bits); + if (cpu_alu_op != 7) { + if (opcode & 1) + AX = cpu_data; + else + AL = cpu_data & 0xff; + } + wait(1, 0); + break; + + case 0x27: /*DAA*/ + wait(1, 0); + if ((flags & A_FLAG) || (AL & 0x0f) > 9) { + cpu_data = AL + 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((flags & C_FLAG) || AL > 0x9f) { + AL += 0x60; + set_cf(1); + } + da(); + break; + case 0x2F: /*DAS*/ + wait(1, 0); + temp = AL; + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_data = AL - 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((flags & C_FLAG) || temp > 0x9f) { + AL -= 0x60; + set_cf(1); + } + da(); + break; + case 0x37: /*AAA*/ + wait(1, 0); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL += 6; + ++AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + case 0x3F: /*AAS*/ + wait(1, 0); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL -= 6; + --AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + + 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: + /* INCDEC rw */ + wait(1, 0); + cpu_dest = cpu_state.regs[opcode & 7].w; + cpu_src = 1; + bits = 16; + if ((opcode & 8) == 0) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(16); + cpu_state.regs[opcode & 7].w = cpu_data; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + access(30, 16); + push(cpu_state.regs[opcode & 0x07].w); + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + access(23, 16); + cpu_state.regs[opcode & 0x07].w = pop(); + wait(1, 0); + break; + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + jcc(opcode, flags & V_FLAG); + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + jcc(opcode, flags & C_FLAG); + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + jcc(opcode, flags & Z_FLAG); + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + jcc(opcode, flags & (C_FLAG | Z_FLAG)); + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + jcc(opcode, flags & N_FLAG); + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + jcc(opcode, flags & P_FLAG); + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + temp = (flags & N_FLAG) ? 1 : 0; + temp2 = (flags & V_FLAG) ? 1 : 0; + jcc(opcode, temp ^ temp2); + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + temp = (flags & N_FLAG) ? 1 : 0; + temp2 = (flags & V_FLAG) ? 1 : 0; + jcc(opcode, (flags & Z_FLAG) || (temp != temp2)); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + /* alu rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(47, bits); + if (opcode & 1) + cpu_data = geteaw(); + else + cpu_data = geteab(); + cpu_dest = cpu_data; + if (cpu_mod != 3) + wait(3, 0); + if (opcode == 0x81) { + if (cpu_mod == 3) + wait(1, 0); + cpu_src = pfq_fetchw(); + } else { + if (cpu_mod == 3) + wait(1, 0); + if (opcode == 0x83) + cpu_src = sign_extend(pfq_fetchb()); + else + cpu_src = pfq_fetchb() | 0xff00; + } + wait(1, 0); + cpu_alu_op = (rmdat & 0x38) >> 3; + alu_op(bits); + if (cpu_alu_op != 7) { + access(11, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + } else { + if (cpu_mod != 3) + wait(1, 0); + } + break; + + case 0x84: case 0x85: + /* TEST rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(48, bits); + if (opcode & 1) { + cpu_data = geteaw(); + test(bits, cpu_data, cpu_state.regs[cpu_reg].w); + } else { + cpu_data = geteab(); + test(bits, cpu_data, getr8(cpu_reg)); + } + if (cpu_mod == 3) + wait(2, 0); + wait(2, 0); + break; + case 0x86: case 0x87: + /* XCHG rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(49, bits); + if (opcode & 1) { + cpu_data = geteaw(); + cpu_src = cpu_state.regs[cpu_reg].w; + cpu_state.regs[cpu_reg].w = cpu_data; + } else { + cpu_data = geteab(); + cpu_src = getr8(cpu_reg); + setr8(cpu_reg, cpu_data); + } + wait(3, 0); + access(12, bits); + if (opcode & 1) + seteaw(cpu_src); + else + seteab(cpu_src); + break; + + case 0x88: case 0x89: + /* MOV rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + access(13, bits); + if (opcode & 1) + seteaw(cpu_state.regs[cpu_reg].w); + else + seteab(getr8(cpu_reg)); + break; + case 0x8A: case 0x8B: + /* MOV reg, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(50, bits); + if (opcode & 1) + cpu_state.regs[cpu_reg].w = geteaw(); + else + setr8(cpu_reg, geteab()); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8C: /*MOV w,sreg*/ + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(14, 16); + switch (rmdat & 0x38) { + case 0x00: /*ES*/ + seteaw(ES); 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); + case 0x08: /*CS*/ + seteaw(CS); break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + } + break; + + case 0x8D: /*LEA*/ + do_mod_rm(); + cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8E: /*MOV sreg,w*/ + do_mod_rm(); + access(51, 16); + tempw = geteaw(); + switch (rmdat & 0x38) { + case 0x00: /*ES*/ + loadseg(tempw, &_es); + break; + case 0x08: /*CS - 8088/8086 only*/ + loadcs(tempw); + pfq_clear(); + break; + case 0x18: /*DS*/ + loadseg(tempw, &_ds); + break; + case 0x10: /*SS*/ + loadseg(tempw, &_ss); + break; + } + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + noint = 1; + break; + + case 0x8F: /*POPW*/ + do_mod_rm(); + wait(1, 0); + cpu_src = cpu_state.eaaddr; + access(24, 16); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pop(); + cpu_state.eaaddr = cpu_src; + wait(2, 0); + access(15, 16); + seteaw(cpu_data); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + /* XCHG AX, rw */ + wait(1, 0); + cpu_data = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = AX; + AX = cpu_data; + wait(1, 0); + break; + + case 0x98: /*CBW*/ + wait(1, 0); + AX = sign_extend(AL); + break; + case 0x99: /*CWD*/ + wait(4, 0); + if (!top_bit(AX, 16)) + DX = 0; + else { + wait(1, 0); + DX = 0xffff; + } + break; + case 0x9A: /*CALL FAR*/ + wait(1, 0); + new_ip = pfq_fetchw(); + wait(1, 0); + new_cs = pfq_fetchw(); + access(31, 16); + push(CS); + access(60, 16); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + cpu_state.pc = new_ip; + access(32, 16); + push(cpu_state.oldpc); + pfq_clear(); + break; + case 0x9B: /*WAIT*/ + pclog("PCem: %02X\n", opcode); + cycles -= 4; + break; + case 0x9C: /*PUSHF*/ + access(33, 16); + push((flags & 0x0fd7) | 0xf000); + break; + case 0x9D: /*POPF*/ + access(25, 16); + flags = pop() | 2; + wait(1, 0); + break; + case 0x9E: /*SAHF*/ + wait(1, 0); + flags = (flags & 0xff02) | AH; + wait(2, 0); + break; + case 0x9F: /*LAHF*/ + wait(1, 0); + AH = flags & 0xd7; + break; + + case 0xA0: case 0xA1: + /* MOV A, [iw] */ + bits = 8 << (opcode & 1); + wait(1, 0); + addr = pfq_fetchw(); + access(1, bits); + if (opcode & 1) + AX = readmemw((ovr_seg ? *ovr_seg : ds), addr); + else + AL = readmemb((ovr_seg ? *ovr_seg : ds) + addr); + wait(1, 0); + break; + case 0xA2: case 0xA3: + /* MOV [iw], A */ + bits = 8 << (opcode & 1); + wait(1, 0); + addr = pfq_fetchw(); + access(7, bits); + if (opcode & 1) + writememw((ovr_seg ? *ovr_seg : ds), addr, AX); + else + writememb((ovr_seg ? *ovr_seg : ds) + addr, AL); + break; + + case 0xA4: case 0xA5: /* MOVS */ + case 0xAC: case 0xAD: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1 /*2*/, 0); + if ((opcode & 8) == 0 && in_rep != 0) + wait(1, 0); + } + if (rep_action(&completed, &repeating, in_rep, bits)) { + wait(1, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + if (in_rep != 0 && (opcode & 8) != 0) + wait(1, 0); + access(20, bits); + lods(bits); + if ((opcode & 8) == 0) { + access(27, bits); + stos(bits); + } else { + if (opcode & 1) + AX = cpu_data; + else + AL = cpu_data; + if (in_rep != 0) + wait(2, 0); + } + if (in_rep == 0) { + wait(3, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + repeating = 1; + timer_end_period(cycles * xt_cpu_multi); + goto opcodestart; + + case 0xA6: case 0xA7: /* CMPS */ + case 0xAE: case 0xAF: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) + wait(1, 0); + if (rep_action(&completed, &repeating, in_rep, bits)) { + wait(2, 0); + break; + } + if (in_rep != 0) + wait(1, 0); + if (opcode & 1) + cpu_dest = AX; + else + cpu_dest = AL; + if ((opcode & 8) == 0) { + access(21, bits); + lods(bits); + wait(1, 0); + cpu_dest = cpu_data; + } + access(2, bits); + if (opcode & 1) + cpu_data = readmemw(es, DI); + else + cpu_data = readmemb(es + DI); + if (flags & D_FLAG) + DI -= (bits >> 3); + else + DI += (bits >> 3); + cpu_src = cpu_data; + sub(bits); + wait(2, 0); + if (in_rep == 0) { + wait(3, 0); + break; + } + if ((!!(flags & Z_FLAG)) == (in_rep == 1)) { + wait(4, 0); + break; + } + repeating = 1; + timer_end_period(cycles * xt_cpu_multi); + goto opcodestart; + + case 0xA8: case 0xA9: + /* TEST A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + if (opcode & 1) { + cpu_data = pfq_fetchw(); + test(bits, AX, cpu_data); + } else { + cpu_data = pfq_fetchb(); + test(bits, AL, cpu_data); + } + wait(1, 0); + break; + + case 0xAA: case 0xAB: /* STOS */ + bits = 8 << (opcode & 1); + if (!repeating) { + if (opcode & 1) + wait(1, 0); + if (in_rep != 0) + wait(1, 0); + } + if (rep_action(&completed, &repeating, in_rep, bits)) { + wait(1, 0); + break; + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait(3, 0); + break; + } + repeating = 1; + timer_end_period(cycles * xt_cpu_multi); + goto opcodestart; + + case 0xB0: case 0xB1: case 0xB2: case 0xB3: /*MOV cpu_reg,#8*/ + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + wait(1, 0); + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + wait(1, 0); + break; + + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + wait(1, 0); + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + wait(1, 0); + break; + + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + /* RET */ + bits = 8 + (opcode & 0x08); + if ((opcode & 9) != 1) + wait(1, 0); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); + wait(1, 0); + } + if ((opcode & 9) == 9) + wait(1, 0); + access(26, bits); + new_ip = pop(); + wait(2, 0); + if ((opcode & 8) == 0) + new_cs = CS; + else { + access(42, bits); + new_cs = pop(); + if (opcode & 1) + wait(1, 0); + } + if (!(opcode & 1)) { + SP += cpu_src; + wait(1, 0); + } + loadcs(new_cs); + access(72, bits); + cpu_state.pc = new_ip; + pfq_clear(); + break; + + case 0xC4: case 0xC5: + /* LsS rw, rmd */ + do_mod_rm(); + bits = 16; + access(52, bits); + cpu_state.regs[cpu_reg].w = readmemw(easeg, cpu_state.eaaddr); + tempw = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xFFFF); + loadseg(tempw, (opcode & 0x01) ? &_ds : &_es); + wait(1, 0); + noint = 1; + break; + + case 0xC6: case 0xC7: + /* MOV rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + if (opcode & 1) + cpu_data = pfq_fetchw(); + else + cpu_data = pfq_fetchb(); + if (cpu_mod == 3) + wait(1, 0); + access(16, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + break; + + case 0xCC: /*INT 3*/ + interrupt(3, 1); + break; + case 0xCD: /*INT*/ + wait(1, 0); + interrupt(pfq_fetchb(), 1); + break; + case 0xCE: /*INTO*/ + wait(3, 0); + if (flags & V_FLAG) { + wait(2, 0); + interrupt(4, 1); + } + break; + + case 0xCF: /*IRET*/ + access(43, 8); + new_ip = pop(); + wait(3, 0); + access(44, 8); + new_cs = pop(); + loadcs(new_cs); + access(62, 8); + cpu_state.pc = new_ip; + access(45, 8); + flags = pop() | 2; + wait(5, 0); + noint = 1; + nmi_enable = 1; + pfq_clear(); + break; + + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(53, bits); + if (opcode & 1) + cpu_data = geteaw(); + else + cpu_data = geteab(); + if ((opcode & 2) == 0) { + cpu_src = 1; + wait((cpu_mod != 3) ? 4 : 0, 0); + } else { + cpu_src = CL; + wait((cpu_mod != 3) ? 9 : 6, 0); + } + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = flags & C_FLAG; + switch (rmdat & 0x38) { + case 0x00: /* ROL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + cpu_data |= ((flags & C_FLAG) ? 1 : 0); + set_of_rotate(bits); + break; + case 0x08: /* ROR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (flags & C_FLAG) + cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); + set_of_rotate(bits); + break; + case 0x10: /* RCL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); + set_of_rotate(bits); + break; + case 0x18: /* RCR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (oldc) + cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); + set_cf((cpu_dest & 1) != 0); + set_of_rotate(bits); + break; + case 0x20: /* SHL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + set_of_rotate(bits); + set_pzs(bits); + break; + case 0x28: /* SHR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + case 0x30: /* SETMO - undocumented? */ + bitwise(bits, 0xffff); + set_cf(0); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x38: /* SAR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (!(opcode & 1)) + cpu_data |= (cpu_dest & 0x80); + else + cpu_data |= (cpu_dest & 0x8000); + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + 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; + if ((opcode & 2) != 0) + wait(4, 0); + --cpu_src; + } + access(17, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + 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; + case 0xD4: /*AAM*/ + wait(1, 0); + cpu_src = pfq_fetchb(); + if (div(AL, 0)) + set_pzs(16); + break; + case 0xD5: /*AAD*/ + wait(1, 0); + mul(pfq_fetchb(), AH); + AL += cpu_data; + AH = 0x00; + set_pzs(16); + break; + case 0xD6: /*SALC*/ + wait(1, 0); + AL = (flags & C_FLAG) ? 0xff : 0x00; + wait(1, 0); + break; + case 0xD7: /*XLATB*/ + 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; + access(4, 8); + AL = readmemb((ovr_seg ? *ovr_seg : ds) + addr); + wait(1, 0); + 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 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDD: case 0xDC: case 0xDE: case 0xDF: + /* esc i, r, rm */ + do_mod_rm(); + access(54, 16); + geteaw(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + 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 0xE0: case 0xE1: case 0xE2: case 0xE3: + /* LOOP */ + wait(3, 0); + cpu_data = pfq_fetchb(); + if (opcode != 0xe2) + wait(1, 0); + if (opcode != 0xe3) { + --CX; + oldc = (CX != 0); + switch (opcode) { + case 0xE0: + if (flags & Z_FLAG) + oldc = 0; + break; + case 0xE1: + if (!(flags & Z_FLAG)) + oldc = 0; + break; + } + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + 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 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) + wait(1, 0); + if ((opcode & 8) == 0) + cpu_data = pfq_fetchb(); + else + cpu_data = DX; + if ((opcode & 2) == 0) { + access(3, bits); + if ((opcode & 1) && is8086) { + AX = inw(cpu_data); + wait(4, 1); /* I/O access and wait state. */ + } else { + AL = inb(cpu_data); + if (opcode & 1) + AH = inb(temp + 1); + wait(bits >> 1, 1); /* I/O access. */ + } + wait(1, 0); + } else { + if ((opcode & 8) == 0) + access(8, bits); + else + access(9, bits); + if ((opcode & 1) && is8086) { + outw(cpu_data, AX); + wait(4, 1); + } else { + outb(cpu_data, AL); + if (opcode & 1) + outb(cpu_data + 1, AH); + wait(bits >> 1, 1); /* I/O access. */ + } + } + break; - case 0xF0: /*LOCK*/ - case 0xF1: /*LOCK alias*/ - cycles-=4; - break; + case 0xE8: /*CALL rel 16*/ + wait(1, 0); + cpu_state.oldpc = jump_near(); + access(34, 8); + push(cpu_state.oldpc); + pfq_clear(); + break; + case 0xE9: /*JMP rel 16*/ + wait(1, 0); + jump_near(); + break; + case 0xEA: /*JMP far*/ + wait(1, 0); + addr = pfq_fetchw(); + wait(1, 0); + tempw = pfq_fetchw(); + loadcs(tempw); + access(70, 8); + cpu_state.pc = addr; + pfq_clear(); + break; + case 0xEB: /*JMP rel*/ + wait(1, 0); + cpu_data = (int8_t) pfq_fetchb(); + jump_short(); + wait(1, 0); + pfq_clear(); + break; - case 0xF2: /*REPNE*/ - rep(0); - break; - case 0xF3: /*REPE*/ - rep(1); - break; + case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait(1, 0); + goto opcodestart; - case 0xF4: /*HLT*/ - inhlt=1; - cpu_state.pc--; - FETCHCLEAR(); - cycles-=2; - break; - case 0xF5: /*CMC*/ - flags^=C_FLAG; - cycles-=2; - break; + case 0xF2: /*REPNE*/ + case 0xF3: /*REPE*/ + wait(1, 0); + in_rep = (opcode == 0xf2 ? 1 : 2); + repeating = 0; + completed = 0; + goto opcodestart; - 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 0xF4: /*HLT*/ + halt = 1; + pfq_clear(); + wait(2, 0); + break; + case 0xF5: /*CMC*/ + wait(1, 0); + flags ^= C_FLAG; + 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 0xF6: case 0xF7: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(55, bits); + if (opcode & 1) + cpu_data = geteaw(); + else + cpu_data = geteab(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: + /* TEST */ + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + if (opcode & 1) + cpu_src = pfq_fetchw(); + else + cpu_src = pfq_fetchb(); + wait(1, 0); + test(bits, cpu_data, cpu_src); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x10: /* NOT */ + case 0x18: /* NEG */ + wait(2, 0); + if ((rmdat & 0x38) == 0x10) + cpu_data = ~cpu_data; + else { + cpu_src = cpu_data; + cpu_dest = 0; + sub(bits); + } + access(18, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + break; + case 0x20: /* MUL */ + case 0x28: /* IMUL */ + wait(1, 0); + if (opcode & 1) { + mul(AX, cpu_data); + AX = cpu_data; + DX = cpu_dest; + cpu_data |= DX; + set_co_mul((DX != ((AX & 0x8000) == 0) || ((rmdat & 0x38) == 0x20) ? 0 : 0xffff)); + } else { + mul(AL, cpu_data); + AL = (uint8_t) cpu_data; + AH = (uint8_t) cpu_dest; + set_co_mul(AH != (((AL & 0x80) == 0) || ((rmdat & 0x38) == 0x20) ? 0 : 0xff)); + } + set_zf(bits); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x30: /* DIV */ + case 0x38: /* IDIV */ + if (cpu_mod != 3) + wait(1, 0); + cpu_src = cpu_data; + if (div(AL, AH)) + wait(1, 0); + 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 0xF8: case 0xF9: + /* CLCSTC */ + wait(1, 0); + set_cf(opcode & 1); + break; + case 0xFA: case 0xFB: + /* CLISTI */ + wait(1, 0); + set_if(opcode & 1); + break; + case 0xFC: case 0xFD: + /* CLDSTD */ + wait(1, 0); + set_df(opcode & 1); + 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 0xFE: case 0xFF: + /* misc */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(56, bits); + read_ea((rmdat & 0x38) == 0x18 || (rmdat & 0x38) == 0x28, bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + cpu_dest = cpu_data; + cpu_src = 1; + if ((rmdat & 0x38) == 0x00) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(bits); + wait(2, 0); + access(19, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + break; + case 0x10: /* CALL rm */ + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } + access(63, bits); + wait(5, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(1, 0); /* Wait. */ + cpu_state.oldpc = cpu_state.pc; + cpu_state.pc = cpu_data; + wait(2, 0); + access(35, bits); + push(cpu_state.oldpc); + pfq_clear(); + break; + case 0x18: /* CALL rmd */ + new_ip = cpu_data; + access(58, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + access(36, bits); + push(CS); + access(64, bits); + wait(4, 0); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + cpu_state.pc = new_ip; + access(37, bits); + push(cpu_state.oldpc); + pfq_clear(); + break; + case 0x20: /* JMP rm */ + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } + access(65, bits); + cpu_state.pc = cpu_data; + pfq_clear(); + break; + case 0x28: /* JMP rmd */ + new_ip = cpu_data; + access(59, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + loadcs(new_cs); + access(66, bits); + cpu_state.pc = new_ip; + pfq_clear(); + break; + case 0x30: /* PUSH rm */ + case 0x38: + if (cpu_mod != 3) + wait(1, 0); + access(38, bits); + push(cpu_data); + break; + } + 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: + x808x_log("Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait(8, 0); + break; + } - default: - FETCH(); - cycles-=8; - break; - } - cpu_state.pc&=0xFFFF; + cpu_state.pc &= 0xFFFF; - if (cpu_state.ssegs) - { - ds=oldds; - ss=oldss; - cpu_state.ssegs=0; - } - - FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); - if ((cycdiff-cycles) * leilei, @@ -442,7 +442,6 @@ 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); @@ -463,8 +462,12 @@ 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); + +#ifdef ENABLE_808X_LOG +extern void dumpregs(int __force); extern void x87_dumpregs(void); extern void x87_reset(void); +#endif extern int cpu_effective; extern void cpu_dynamic_switch(int new_cpu); diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 51b28bea0..a1050bd33 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -53,7 +53,7 @@ CPU cpus_8088[] = { /*8088 standard*/ {"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/7.16", CPU_8088, 1, 7159092, 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}, {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} }; @@ -67,16 +67,16 @@ CPU cpus_pcjr[] = { 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}, + {"8088/7.16", CPU_8088, 1, 7159092, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/9.54", CPU_8088, 1, 9545456, 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/7.16", CPU_8086, 1, 7159092, 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/9.54", CPU_8086, 1, 9545456, 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}, {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} }; diff --git a/src/cpu/x86.h b/src/cpu/x86.h index a49ea9769..86a6aa14d 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -1,23 +1,28 @@ -uint16_t oldcs; -extern uint32_t rmdat32; -int oldcpl; +extern uint8_t opcode, opcode2; +extern uint8_t flags_p; +extern uint8_t znptable8[256]; -extern int nmi_enable; +extern uint16_t zero, oldcs; +extern uint16_t lastcs, lastpc; +extern uint16_t rds, ea_rseg; +extern uint16_t znptable16[65536]; +extern uint16_t *mod1add[2][8]; -int tempc; -int output; -int firstrepcycle; +extern int x86_was_reset, codegen_flat_ds; +extern int codegen_flat_ss, nmi_enable; +extern int timetolive, keyboardtimer, trap; +extern int tempc, optype, use32, stack32; +extern int oldcpl, cgate32, cpl_override, fpucount; +extern int gpf, nmi_enable; +extern int oddeven, inttype; -uint32_t easeg,ealimit,ealimitw; +extern uint32_t rmdat32, easeg; +extern uint32_t oxpc, flags_zn; +extern uint32_t abrt_error; +extern uint32_t backupregs[16]; +extern uint32_t *mod1seg[8]; +extern uint32_t *eal_r, *eal_w; -int skipnextprint; -int inhlt; - -uint8_t opcode; -int noint; - -uint16_t lastcs,lastpc; -extern int timetolive,keyboardtimer; #define setznp168 setznp16 @@ -30,47 +35,25 @@ extern int timetolive,keyboardtimer; #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]; +#define fetchea() { \ + rmdat = readmemb(cs + pc); \ + pc++; \ + reg = (rmdat >> 3) & 7; \ + mod = (rmdat >> 6) & 3; \ + rm = rmdat & 7; \ + if (mod!=3) \ + fetcheal(); \ + } -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 { @@ -83,25 +66,8 @@ enum 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; +extern void x86_doabrt(int x86_abrt); +extern void x86illegal(); +extern void x86seg_reset(); +extern void x86gpf(char *s, uint16_t error); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index 6a5ea0478..c4e8229f1 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -8,7 +8,7 @@ * * x86 CPU segment emulation. * - * Version: @(#)x86seg.c 1.0.8 2018/10/17 + * Version: @(#)x86seg.c 1.0.9 2018/11/14 * * Authors: Sarah Walker, * Miran Grca, @@ -46,7 +46,7 @@ int dtimes = 0; int btimes = 0; uint32_t abrt_error; -int cgate16,cgate32; +int cgate16, cgate32; #define breaknullsegs 0 @@ -55,7 +55,6 @@ 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*/ @@ -89,7 +88,9 @@ void x86abort(const char *format, ...) va_end(ap); fflush(stdlog); nvr_save(); +#ifdef ENABLE_808X_LOG dumpregs(1); +#endif fflush(stdlog); exit(-1); } diff --git a/src/cpu/x87.c b/src/cpu/x87.c index 72d8142a0..ed1c16828 100644 --- a/src/cpu/x87.c +++ b/src/cpu/x87.c @@ -65,6 +65,7 @@ void x87_settag(uint16_t new_tag) cpu_state.tag[7] = (new_tag >> 14) & 3; } +#ifdef ENABLE_808X_LOG void x87_dumpregs() { if (cpu_state.ismmx) @@ -79,21 +80,4 @@ void x87_dumpregs() } fpu_log("Status = %04X Control = %04X Tag = %04X\n", cpu_state.npxs, cpu_state.npxc, x87_gettag()); } - -void x87_print() -{ - if (cpu_state.ismmx) - { - fpu_log("\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); - fpu_log("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 - { - fpu_log("\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]); - fpu_log("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() -{ -} +#endif diff --git a/src/device.h b/src/device.h index 896108e49..3b103f11b 100644 --- a/src/device.h +++ b/src/device.h @@ -8,7 +8,7 @@ * * Definitions for the device handler. * - * Version: @(#)device.h 1.0.10 2018/10/23 + * Version: @(#)device.h 1.0.11 2018/11/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -54,15 +54,16 @@ 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 */ + DEVICE_PCJR = 2, /* requires an IBM PCjr */ + DEVICE_AT = 4, /* requires an AT-compatible system */ + DEVICE_PS2 = 8, /* requires a PS/1 or PS/2 system */ + DEVICE_ISA = 0x10, /* requires the ISA bus */ + DEVICE_CBUS = 0x20, /* requires the C-BUS bus */ + DEVICE_MCA = 0x40, /* requires the MCA bus */ + DEVICE_EISA = 0x80, /* requires the EISA bus */ + DEVICE_VLB = 0x100, /* requires the PCI bus */ + DEVICE_PCI = 0x200, /* requires the VLB bus */ + DEVICE_AGP = 0x400 /* requires the AGP bus */ }; diff --git a/src/disk/hdc.c b/src/disk/hdc.c index e409778a7..84c71e765 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -8,7 +8,7 @@ * * Common code to handle all sorts of disk controllers. * - * Version: @(#)hdc.c 1.0.16 2018/10/17 + * Version: @(#)hdc.c 1.0.17 2018/11/18 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -30,7 +30,6 @@ #include "hdd.h" -char *hdc_name; /* configured HDC name */ int hdc_current; @@ -160,19 +159,10 @@ static const struct { /* Initialize the 'hdc_current' value based on configured HDC name. */ void -hdc_init(char *name) +hdc_init(void) { - 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(); } @@ -211,6 +201,22 @@ hdc_get_internal_name(int hdc) } +int +hdc_get_id(char *s) +{ + int c = 0; + + while (strlen((char *) controllers[c].name)) + { + if (!strcmp((char *) controllers[c].name, s)) + return c; + c++; + } + + return 0; +} + + int hdc_get_from_internal_name(char *s) { diff --git a/src/disk/hdc.h b/src/disk/hdc.h index 3f8e0f8e3..37b4af09f 100644 --- a/src/disk/hdc.h +++ b/src/disk/hdc.h @@ -8,7 +8,7 @@ * * Definitions for the common disk controller handler. * - * Version: @(#)hdc.h 1.0.9 2018/09/24 + * Version: @(#)hdc.h 1.0.10 2018/11/18 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -28,7 +28,6 @@ * least 7 devices, with each device being * able to support 8 units, but hey... */ -extern char *hdc_name; extern int hdc_current; @@ -59,11 +58,12 @@ 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_init(void); extern void hdc_reset(void); extern char *hdc_get_name(int hdc); extern char *hdc_get_internal_name(int hdc); +extern int hdc_get_id(char *s); 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); diff --git a/src/dma.c b/src/dma.c index ef07c6137..a9a4389f4 100644 --- a/src/dma.c +++ b/src/dma.c @@ -8,7 +8,7 @@ * * Implementation of the Intel DMA controllers. * - * Version: @(#)dma.c 1.0.3 2018/03/13 + * Version: @(#)dma.c 1.0.4 2018/11/18 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -625,7 +625,7 @@ ps2_dma_init(void) uint8_t _dma_read(uint32_t addr) { - uint8_t temp = mem_readb_phys_dma(addr); + uint8_t temp = mem_readb_phys(addr); return(temp); } @@ -634,7 +634,7 @@ _dma_read(uint32_t addr) void _dma_write(uint32_t addr, uint8_t val) { - mem_writeb_phys_dma(addr, val); + mem_writeb_phys(addr, val); mem_invalidate_range(addr, addr); } @@ -654,14 +654,14 @@ dma_channel_read(int channel) return(DMA_NODATA); } - if (! AT) - refreshread(); - if (dma_m & (1 << channel)) return(DMA_NODATA); if ((dma_c->mode & 0xC) != 8) return(DMA_NODATA); + if ((!AT) && !channel) + refreshread(); + if (! dma_c->size) { temp = _dma_read(dma_c->ac); @@ -725,14 +725,14 @@ dma_channel_write(int channel, uint16_t val) return(DMA_NODATA); } - if (! AT) - refreshread(); - if (dma_m & (1 << channel)) return(DMA_NODATA); if ((dma_c->mode & 0xC) != 4) return(DMA_NODATA); + if ((!AT) && !channel) + refreshread(); + if (! dma_c->size) { _dma_write(dma_c->ac, val & 0xff); @@ -895,7 +895,7 @@ DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) memcpy(DataRead, &ram[PhysAddress], TotalSize); #else for (i = 0; i < TotalSize; i++) - DataRead[i] = mem_readb_phys_dma(PhysAddress + i); + DataRead[i] = mem_readb_phys(PhysAddress + i); #endif } @@ -910,7 +910,7 @@ DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) memcpy(&ram[PhysAddress], DataWrite, TotalSize); #else for (i = 0; i < TotalSize; i++) - mem_writeb_phys_dma(PhysAddress + i, DataWrite[i]); + mem_writeb_phys(PhysAddress + i, DataWrite[i]); mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); #endif diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 32b0eda7b..8eac08f4d 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -9,7 +9,7 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.c 1.0.12 2018/10/18 + * Version: @(#)fdc.c 1.0.15 2019/01/26 * * Authors: Miran Grca, * Sarah Walker, @@ -156,7 +156,7 @@ fdc_ctrl_reset(void *p) fdc->head = 0; fdc->abort = 0; fdc->step = 0; - if (!(fdc->flags & FDC_FLAG_AT)) + if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PS1)) fdc->rate = 2; } @@ -383,20 +383,6 @@ fdc_update_rates(fdc_t *fdc) } -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) { @@ -613,7 +599,7 @@ void fdc_seek(fdc_t *fdc, int drive, int params) { fdd_seek(real_drive(fdc, drive), params); - fdc->time = 5000LL * (1 << TIMER_SHIFT); + fdc->time = 2048LL * (1 << TIMER_SHIFT); fdc->stat |= (1 << fdc->drive); } @@ -636,7 +622,7 @@ fdc_bad_command(fdc_t *fdc) { fdc->stat = 0x10; fdc->interrupt = 0xfc; - timer_clock(); + timer_process(); fdc->time = 200LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); } @@ -713,6 +699,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Write FDC %04X %02X\n", addr, val); cycles -= ISA_CYCLES(8); + // pclog("fdc_write(): cycles -= ISA_CYCLES(8);\n"); switch (addr&7) { case 0: @@ -727,7 +714,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) picintc(1 << fdc->irq); } if ((val & 0x80) && !(fdc->dor & 0x80)) { - timer_clock(); + timer_process(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; @@ -758,7 +745,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pnum = fdc->ptot = 0; } if ((val&4) && !(fdc->dor&4)) { - timer_clock(); + timer_process(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; @@ -769,7 +756,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_ctrl_reset(fdc); } - timer_clock(); + timer_process(); timer_update_outstanding(); /* We can now simplify this since each motor now spins separately. */ for (i = 0; i < FDD_NUM; i++) { @@ -795,15 +782,13 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) return; case 4: if (val & 0x80) { - timer_clock(); + timer_process(); 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) { @@ -981,7 +966,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if (fdc->pnum==fdc->ptot) { fdc_log("Got all params %02X\n", fdc->command); fdc->interrupt = fdc->command & 0x1F; - timer_clock(); + timer_process(); fdc->time = 1024LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->reset_stat = 0; @@ -1073,7 +1058,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->st0 = 0x20 | (fdc->params[0] & 3); fdc->pcn[fdc->params[0] & 3] = 0; fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1081,8 +1066,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) 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; + fdc->time = 2048LL * (1 << TIMER_SHIFT); + fdc->seek_dir = fdc->step = 1; break; case 0x0d: /*Format*/ fdc_rate(fdc, fdc->drive); @@ -1117,7 +1102,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } else fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1135,12 +1120,12 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_seek(fdc, fdc->drive, -fdc->params[1]); fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; } - fdc->time = 5000LL * (1 << TIMER_SHIFT); + fdc->time = 2048LL * (1 << TIMER_SHIFT); fdc->step = 1; } else { fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1151,7 +1136,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Failed seek\n"); fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1162,7 +1147,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) 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->time = 2048LL * (1 << TIMER_SHIFT); fdc->step = 1; fdc_log("fdc->time = %i\n", fdc->time); } @@ -1206,8 +1191,9 @@ fdc_read(uint16_t addr, void *priv) int drive; cycles -= ISA_CYCLES(8); + // pclog("fdc_read(): cycles -= ISA_CYCLES(8);\n"); - switch (addr&7) { + switch (addr & 7) { case 0: /* STA */ if (fdc->flags & FDC_FLAG_PS1) { drive = real_drive(fdc, fdc->dor & 3); @@ -1216,9 +1202,9 @@ fdc_read(uint16_t addr, void *priv) 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 |= 0x01; + if (writeprot[drive]) /* WRITEPROT */ ret |= 0x02; if (!fdd_get_head(drive)) /* nHDSEL */ ret |= 0x08; @@ -1239,10 +1225,20 @@ fdc_read(uint16_t addr, void *priv) if (!fdd_get_type(1)) ret |= 80; /* -Drive Select 1,0 */ - if (drive) - ret |= 0x20; - else - ret |= 0x40; + switch (drive) { + case 0: + ret |= 0x43; + break; + case 1: + ret |= 0x23; + break; + case 2: + ret |= 0x62; + break; + case 3: + ret |= 0x61; + break; + } } else { if (is486) return 0xff; @@ -1326,6 +1322,7 @@ fdc_read(uint16_t addr, void *priv) drive = real_drive(fdc, fdc->dor & 3); if (fdc->flags & FDC_FLAG_PS1) { + fdc->step = 0; if (fdc->dor & (0x10 << drive)) { ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x00 : 0x80; ret |= (fdc->dor & 0x08); @@ -1613,7 +1610,7 @@ fdc_callback(void *priv) if (!fdd_track0(drive_num)) fdc->st0 |= 0x50; fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->stat = 0x80 | (1 << fdc->drive); @@ -1621,7 +1618,7 @@ fdc_callback(void *priv) case 0x0d: /*Format track*/ if (fdc->format_state == 1) { fdc->format_state = 2; - timer_clock(); + timer_process(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); } else if (fdc->format_state == 2) { @@ -1664,7 +1661,7 @@ fdc_callback(void *priv) drive_num = real_drive(fdc, fdc->rw_drive); fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - /* timer_clock(); + /* timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); */ fdc->stat = 0x80 | (1 << fdc->drive); @@ -2083,13 +2080,15 @@ fdc_reset(void *priv) 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); + if (fdc->flags & FDC_FLAG_NSC) + fdc_update_densel_force(fdc, 3); + else + 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); @@ -2099,6 +2098,7 @@ fdc_reset(void *priv) fdc_update_drvrate(fdc, 2, 0); fdc_update_drvrate(fdc, 3, 0); fdc_update_drv2en(fdc, 1); + fdc_update_rates(fdc); fdc->fifo = 0; fdc->tfifo = 1; @@ -2172,6 +2172,7 @@ fdc_init(const device_t *info) fdd_set_fdc(fdc); imd_set_fdc(fdc); img_set_fdc(fdc); + mfm_set_fdc(fdc); fdc_reset(fdc); diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 70305494b..64558ad7e 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -8,7 +8,7 @@ * * Implementation of the floppy drive emulation. * - * Version: @(#)fdd.c 1.0.12 2018/10/18 + * Version: @(#)fdd.c 1.0.13 2018/11/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -52,6 +52,7 @@ #include "fdd_imd.h" #include "fdd_img.h" #include "fdd_json.h" +#include "fdd_mfm.h" #include "fdd_td0.h" #include "fdc.h" @@ -122,6 +123,7 @@ static const struct {L"IMD", imd_load, imd_close, -1}, {L"IMG", img_load, img_close, -1}, {L"JSON", json_load, json_close, -1}, + {L"MFM", mfm_load, mfm_close, -1}, {L"TD0", td0_load, td0_close, -1}, {L"VFD", img_load, img_close, -1}, {L"XDF", img_load, img_close, -1}, @@ -464,14 +466,7 @@ int fdd_get_check_bpb(int drive) 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; - } + return fdd[drive].densel; } void fdd_load(int drive, wchar_t *fn) diff --git a/src/floppy/fdd.h b/src/floppy/fdd.h index 70414804f..31a7786ef 100644 --- a/src/floppy/fdd.h +++ b/src/floppy/fdd.h @@ -8,7 +8,7 @@ * * Definitions for the floppy drive emulation. * - * Version: @(#)fdd.h 1.0.4 2018/04/12 + * Version: @(#)fdd.h 1.0.5 2018/11/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -254,6 +254,7 @@ void fdi_set_fdc(void *fdc); void fdd_set_fdc(void *fdc); void imd_set_fdc(void *fdc); void img_set_fdc(void *fdc); +void mfm_set_fdc(void *fdc); #ifdef __cplusplus diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 2c2295443..16de640b6 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -10,7 +10,7 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)fdd_86f.c 1.0.16 2018/10/17 + * Version: @(#)fdd_86f.c 1.0.17 2018/11/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -190,6 +190,10 @@ typedef struct { * 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 + * Bit 12 If bits 6, 5 are not 0, they specify % of speedup instead + * of slowdown; + * If bits 6, 5 are 0, and bit 7 is 1, the extra bitcell count + * specifies the entire bitcell count */ typedef struct { FILE *f; @@ -360,6 +364,14 @@ d86f_get_rpm_mode(int drive) return (d86f_handler[drive].disk_flags(drive) & 0x60) >> 5; } + +int +d86f_get_speed_shift_dir(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x1000) >> 12; +} + + int d86f_reverse_bytes(int drive) { @@ -521,12 +533,15 @@ common_get_raw_size(int drive, int side) double rpm, rpm_diff; double size = 100000.0; int mfm; + int rm, ssd; mfm = d86f_is_mfm(drive); rpm = ((d86f_track_flags(drive) & 0xE0) == 0x20) ? 360.0 : 300.0; rpm_diff = 1.0; + rm = d86f_get_rpm_mode(drive); + ssd = d86f_get_speed_shift_dir(drive); - switch (d86f_get_rpm_mode(drive)) { + switch (rm) { case 1: rpm_diff = 1.01; break; @@ -544,6 +559,9 @@ common_get_raw_size(int drive, int side) break; } + if (ssd) + rpm_diff = 1.0 / rpm_diff; + switch (d86f_track_flags(drive) & 7) { case 0: rate = 500.0; @@ -572,9 +590,13 @@ common_get_raw_size(int drive, int side) if (! mfm) rate /= 2.0; - size = (size / 250.0) * rate; - size = (size * 300.0) / rpm; - size *= rpm_diff; + if (!rm && ssd) + size = 0.0; + else { + 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, @@ -640,25 +662,30 @@ d86f_get_array_size(int drive, int side) { int array_size; int hole, rm; + int ssd; rm = d86f_get_rpm_mode(drive); + ssd = d86f_get_speed_shift_dir(drive); hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; - switch (hole) { + + if (!rm && ssd) /* Special case - extra bit cells size specifies entire array size. */ + array_size = 0; + else switch (hole) { case 0: case 1: default: array_size = 12500; switch (rm) { case 1: - array_size = 12625; + array_size = ssd ? 12376 : 12625; break; case 2: - array_size = 12687; + array_size = ssd ? 12315 : 12687; break; case 3: - array_size = 12750; + array_size = ssd ? 12254 : 12750; break; default: @@ -670,15 +697,15 @@ d86f_get_array_size(int drive, int side) array_size = 25000; switch (rm) { case 1: - array_size = 25250; + array_size = ssd ? 24752 : 25250; break; case 2: - array_size = 25375; + array_size = ssd ? 24630 : 25375; break; case 3: - array_size = 25500; + array_size = ssd ? 24509 : 25500; break; default: @@ -690,15 +717,15 @@ d86f_get_array_size(int drive, int side) array_size = 50000; switch (rm) { case 1: - array_size = 50500; + array_size = ssd ? 49504 : 50500; break; case 2: - array_size = 50750; + array_size = ssd ? 49261 : 50750; break; case 3: - array_size = 51000; + array_size = ssd ? 49019 : 51000; break; default: @@ -1099,23 +1126,16 @@ d86f_get_bit(int drive, int side) if (d86f_has_surface_desc(drive) && dev->track_surface_data && dev->track_surface_data[side]) { 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 (! surface_bit) + dev->last_word[side] |= current_bit; + else { if (current_bit) { /* Bit is 1 and is set to fuzzy, we randomly generate it. */ dev->last_word[side] |= (random_generate() & 1); } } - } else { + } else dev->last_word[side] |= current_bit; - } } @@ -1267,7 +1287,7 @@ d86f_word_is_aligned(int drive, int side, uint32_t base_pos) /* 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_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1283,6 +1303,15 @@ d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, ui return; } + if ((wrong_am) && (dev->last_word[side] == wrong_am)) { + 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_nodataam(d86f_fdc); + 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)); @@ -1329,7 +1358,7 @@ d86f_write_find_address_mark_fm(int drive, int side, find_t *find) 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_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1341,6 +1370,15 @@ d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, u return; } + if ((wrong_am) && (dev->last_word[side] == wrong_am) && (find->sync_marks >= 3)) { + 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_nodataam(d86f_fdc); + 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; @@ -1430,7 +1468,7 @@ d86f_read_sector_id(int drive, int side, int match) if (dev->id_find.bytes_obtained == 6) { /* We've got the ID. */ - if (dev->calc_crc.word != dev->track_crc.word) { + if ((dev->calc_crc.word != dev->track_crc.word) && (dev->last_sector.dword == dev->req_sector.dword)) { 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)) { @@ -2401,9 +2439,9 @@ d86f_poll(int drive) 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); + d86f_find_address_mark_mfm(drive, side, &(dev->id_find), 0x5554, 0, 0, 0); else - d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0); + d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0, 0); break; case STATE_0A_READ_ID: @@ -2422,18 +2460,18 @@ d86f_poll(int drive) case STATE_02_FIND_DATA: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 2); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, 2); else - d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 2); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, 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); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, 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); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, fdc_is_sk(d86f_fdc) | 2); break; case STATE_05_FIND_DATA: @@ -2446,9 +2484,9 @@ d86f_poll(int drive) 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); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x554A, 0x5545, 0x5554, 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); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56A, 0xF56F, 0xF57E, fdc_is_sk(d86f_fdc) | 2); break; case STATE_02_READ_DATA: @@ -2808,6 +2846,7 @@ d86f_decompose_encoded_buffer(int drive, int 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]; + dst = d86f_handler[drive].encoded_data(drive, side); len = d86f_get_array_size(drive, side); for (i = 0; i < len; i++) { @@ -2857,17 +2896,19 @@ d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, ui 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 { + /* If RPM shift is 0% and direction is 1, do not adjust extra bit cells, + as that is the whole track length. */ + if (d86f_get_rpm_mode(drive) || !d86f_get_speed_shift_dir(drive)) { + 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 { + } 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); @@ -3009,11 +3050,14 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *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); + d86f_decompose_encoded_buffer(drive, 0); + if (sides == 2) + d86f_decompose_encoded_buffer(drive, 1); + + for (thin_track = 0; thin_track < 2; thin_track++) { + for (side = 0; side < sides; side++) { + fdd_set_head(drive, side); - for (thin_track = 0; thin_track < 2; thin_track++) { if (sides == 2) logical_track = ((dev->cur_track + thin_track) << 1) + side; else @@ -3021,8 +3065,9 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) if (track_table && !tbl[logical_track]) { fseek(*f, 0, SEEK_END); - track_table[logical_track] = ftell(*f); + tbl[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]); @@ -3039,12 +3084,12 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) if (track_table && !tbl[logical_track]) { fseek(*f, 0, SEEK_END); - track_table[logical_track] = ftell(*f); + tbl[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]); + d86f_write_track(drive, f, side, d86f_handler[drive].encoded_data(drive, side), dev->track_surface_data[side]); } } } @@ -3376,7 +3421,7 @@ d86f_export(int drive, wchar_t *fn) int i; int inc = 1; uint32_t magic = 0x46423638; - uint16_t version = 0x020B; + uint16_t version = 0x020C; uint16_t disk_flags = d86f_handler[drive].disk_flags(drive); memset(tt, 0, 512 * sizeof(uint32_t)); diff --git a/src/floppy/fdd_86f.h b/src/floppy/fdd_86f.h index 8242f5bb7..394918580 100644 --- a/src/floppy/fdd_86f.h +++ b/src/floppy/fdd_86f.h @@ -8,7 +8,7 @@ * * Definitions for the 86F floppy image format. * - * Version: @(#)floppy_86f.h 1.0.4 2018/03/17 + * Version: @(#)floppy_86f.h 1.0.5 2018/11/14 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -38,7 +38,7 @@ # define EMU_FLOPPY_86F_H -#define D86FVER 0x020B +#define D86FVER 0x020C extern void d86f_init(void); diff --git a/src/floppy/fdd_mfm.c b/src/floppy/fdd_mfm.c new file mode 100644 index 000000000..45aca2469 --- /dev/null +++ b/src/floppy/fdd_mfm.c @@ -0,0 +1,469 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * 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 HxC MFM image format. + * + * Version: @(#)fdd_mfm.c 1.0.0 2018/11/12 + * + * Authors: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ +#include +#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_mfm.h" +#include "fdc.h" + + +#pragma pack(push,1) +typedef struct { + uint8_t hdr_name[7]; + + uint16_t tracks_no; + uint8_t sides_no; + + uint16_t rpm; + uint16_t bit_rate; + uint8_t if_type; + + uint32_t track_list_offset; +} mfm_header_t; + +typedef struct { + uint16_t track_no; + uint8_t side_no; + uint32_t track_size; + uint32_t track_offset; +} mfm_track_t; + +typedef struct { + uint16_t track_no; + uint8_t side_no; + uint16_t rpm; + uint16_t bit_rate; + uint32_t track_size; + uint32_t track_offset; +} mfm_adv_track_t; +#pragma pack(pop) + +typedef struct { + FILE *f; + + mfm_header_t hdr; + mfm_track_t *tracks; + mfm_adv_track_t *adv_tracks; + + int br_rounded, rpm_rounded, + total_tracks, cur_track; + + uint8_t track_data[2][256*1024]; +} mfm_t; + + +static mfm_t *mfm[FDD_NUM]; +static fdc_t *mfm_fdc; + + +#ifdef ENABLE_MFM_LOG +int mfm_do_log = ENABLE_MFM_LOG; + + +static void +mfm_log(const char *fmt, ...) +{ + va_list ap; + + if (mfm_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define mfm_log(fmt, ...) +#endif + + +static uint16_t +disk_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + uint16_t temp_disk_flags = 0x1080; /* We ALWAYS claim to have extra bit cells, even if the actual amount is 0; + Bit 12 = 1, bits 6, 5 = 0 - extra bit cells field specifies the entire + amount of bit cells per track. */ + + switch (dev->br_rounded) { + case 500: + temp_disk_flags |= 2; + break; + + case 300: + case 250: + default: + temp_disk_flags |= 0; + break; + + case 1000: + temp_disk_flags |= 4; + break; + } + + if (dev->hdr.sides_no == 2) + temp_disk_flags |= 8; + + return(temp_disk_flags); +} + + +static int +get_track_index(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->tracks[i].track_no == dev->cur_track) && + (dev->tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static int +get_adv_track_index(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->adv_tracks[i].track_no == dev->cur_track) && + (dev->adv_tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static void +get_adv_track_bitrate(int drive, int side, int *br, int *rpm) +{ + mfm_t *dev = mfm[drive]; + int track_index; + double dbr; + + track_index = get_adv_track_index(drive, side); + + if (track_index == -1) { + *br = 250; + *rpm = 300; + } else { + dbr = round(((double) dev->adv_tracks[track_index].bit_rate) / 50.0) * 50.0; + *br = ((int) dbr); + dbr = round(((double) dev->adv_tracks[track_index].rpm) / 60.0) * 60.0; + *rpm = ((int) dbr); + } +} + + +static uint16_t +side_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + uint16_t temp_side_flags = 0; + int side, br = 250, rpm = 300; + + if (dev->hdr.if_type & 0x80) { + side = fdd_get_head(drive); + get_adv_track_bitrate(drive, side, &br, &rpm); + } else { + br = dev->br_rounded; + rpm = dev->rpm_rounded; + } + + /* 300 kbps @ 360 rpm = 250 kbps @ 200 rpm */ + if ((rpm >= 352) && (rpm <= 367) && (br == 300)) { + br = 250; + rpm = 300; + } + + switch (br) { + case 500: + temp_side_flags = 0; + break; + + case 300: + temp_side_flags = 1; + break; + + case 250: + default: + temp_side_flags = 2; + break; + + case 1000: + temp_side_flags = 3; + break; + } + + if ((rpm >= 352) && (rpm <= 367)) + 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 uint32_t +get_raw_size(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int track_index, is_300_rpm; + + if (dev->hdr.if_type & 0x80) + track_index = get_adv_track_index(drive, side); + else + track_index = get_track_index(drive, side); + + is_300_rpm = (dev->hdr.rpm < 352); + + if (track_index == -1) { + mfm_log("MFM: Unable to find track (%i, %i)\n", dev->cur_track, side); + return is_300_rpm ? 100000 : 83333; + } + + /* Bit 7 on - my extension of the HxC MFM format to output exact bitcell counts + for each track instead of rounded byte counts. */ + if (dev->hdr.if_type & 0x80) + return dev->adv_tracks[track_index].track_size; + else + return dev->tracks[track_index].track_size * 8; +} + + +static int32_t +extra_bit_cells(int drive, int side) +{ + return (int32_t) get_raw_size(drive, side); +} + + +static uint16_t * +encoded_data(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + + return((uint16_t *)dev->track_data[side]); +} + + +void +mfm_read_side(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int track_index, track_size; + int track_bytes; + + if (dev->hdr.if_type & 0x80) + track_index = get_adv_track_index(drive, side); + else + track_index = get_track_index(drive, side); + + track_size = get_raw_size(drive, side); + track_bytes = track_size >> 3; + if (track_size & 0x07) + track_bytes++; + + if (track_index == -1) + memset(dev->track_data[side], 0x00, track_bytes); + else { + if (dev->hdr.if_type & 0x80) + fseek(dev->f, dev->adv_tracks[track_index].track_offset, SEEK_SET); + else + fseek(dev->f, dev->tracks[track_index].track_offset, SEEK_SET); + fread(dev->track_data[side], 1, track_size, dev->f); + } + + mfm_log("drive = %i, side = %i, dev->cur_track = %i, track_index = %i, track_size = %i\n", + drive, side, dev->cur_track, track_index, track_size); +} + + +void +mfm_seek(int drive, int track) +{ + mfm_t *dev = mfm[drive]; + + mfm_log("mfm_seek(%i, %i)\n", drive, track); + + if (fdd_doublestep_40(drive)) { + if (dev->hdr.tracks_no <= 43) + track /= 2; + } + + dev->cur_track = track; + d86f_set_cur_track(drive, track); + + if (dev->f == NULL) + return; + + if (track < 0) + track = 0; + + mfm_read_side(drive, 0); + mfm_read_side(drive, 1); +} + + +void +mfm_load(int drive, wchar_t *fn) +{ + mfm_t *dev; + double dbr; + int i; + + writeprot[drive] = fwriteprot[drive] = 1; + + /* Allocate a drive block. */ + dev = (mfm_t *)malloc(sizeof(mfm_t)); + memset(dev, 0x00, sizeof(mfm_t)); + + dev->f = plat_fopen(fn, L"rb"); + if (dev->f == NULL) { + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + + d86f_unregister(drive); + + /* Read the header. */ + fread(&dev->hdr, 1, sizeof(mfm_header_t), dev->f); + + /* Calculate tracks * sides, allocate the tracks array, and read it. */ + dev->total_tracks = dev->hdr.tracks_no * dev->hdr.sides_no; + if (dev->hdr.if_type & 0x80) { + dev->adv_tracks = (mfm_adv_track_t *) malloc(dev->total_tracks * sizeof(mfm_adv_track_t)); + fread(dev->adv_tracks, 1, dev->total_tracks * sizeof(mfm_adv_track_t), dev->f); + } else { + dev->tracks = (mfm_track_t *) malloc(dev->total_tracks * sizeof(mfm_track_t)); + fread(dev->tracks, 1, dev->total_tracks * sizeof(mfm_track_t), dev->f); + } + + /* The chances of finding a HxC MFM image of a single-sided thin track + disk are much smaller than the chances of finding a HxC MFM image + incorrectly converted from a SCP image, erroneously indicating 1 + side and 80+ tracks instead of 2 sides and <= 43 tracks, so if we + have detected such an image, convert the track numbers. */ + if ((dev->hdr.tracks_no > 43) && (dev->hdr.sides_no == 1)) { + dev->hdr.tracks_no >>= 1; + dev->hdr.sides_no <<= 1; + + for (i = 0; i < dev->total_tracks; i++) { + if (dev->hdr.if_type & 0x80) { + dev->adv_tracks[i].side_no <<= 1; + dev->adv_tracks[i].side_no |= (dev->adv_tracks[i].track_no & 1); + dev->adv_tracks[i].track_no >>= 1; + } else { + dev->tracks[i].side_no <<= 1; + dev->tracks[i].side_no |= (dev->tracks[i].track_no & 1); + dev->tracks[i].track_no >>= 1; + } + } + } + + if (!(dev->hdr.if_type & 0x80)) { + dbr = round(((double) dev->hdr.bit_rate) / 50.0) * 50.0; + dev->br_rounded = (int) dbr; + mfm_log("Round bit rate: %i kbps\n", dev->br_rounded); + + dbr = round(((double) dev->hdr.rpm) / 60.0) * 60.0; + dev->rpm_rounded = (int) dbr; + mfm_log("Round RPM: %i kbps\n", dev->rpm_rounded); + } + + /* Set up the drive unit. */ + mfm[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 = 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 = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_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 = mfm_seek; + + mfm_log("Loaded as MFM\n"); +} + + +void +mfm_close(int drive) +{ + mfm_t *dev = mfm[drive]; + + if (dev == NULL) return; + + d86f_unregister(drive); + + drives[drive].seek = NULL; + + if (dev->tracks) + free(dev->tracks); + + if (dev->adv_tracks) + free(dev->adv_tracks); + + if (dev->f) + fclose(dev->f); + + /* Release the memory. */ + free(dev); + mfm[drive] = NULL; +} + + +void +mfm_set_fdc(void *fdc) +{ + mfm_fdc = (fdc_t *)fdc; +} diff --git a/src/floppy/fdd_mfm.h b/src/floppy/fdd_mfm.h new file mode 100644 index 000000000..2aba3fb47 --- /dev/null +++ b/src/floppy/fdd_mfm.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. + * + * This file is part of the 86Box distribution. + * + * Implementation of the HxC MFM image format. + * + * Version: @(#)fdd_mfm.h 1.0.0 2018/11/12 + * + * Authors: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ +#ifndef EMU_FLOPPY_MFM_H +# define EMU_FLOPPY_MFM_H + + +extern void mfm_seek(int drive, int track); +extern void mfm_load(int drive, wchar_t *fn); +extern void mfm_close(int drive); + + +#endif /*EMU_FLOPPY_MFM_H*/ diff --git a/src/game/gameport.h b/src/game/gameport.h index 3db999646..e1fec8fb8 100644 --- a/src/game/gameport.h +++ b/src/game/gameport.h @@ -10,7 +10,7 @@ * * NOTE: This module needs a good cleanup someday. * - * Version: @(#)gameport.h 1.0.3 2018/03/15 + * Version: @(#)gameport.h 1.0.4 2018/11/11 * * Authors: Miran Grca, * Sarah Walker, @@ -52,24 +52,24 @@ typedef struct { - char name[64]; + char name[260]; int a[8]; int b[32]; int p[4]; struct { - char name[32]; + char name[260]; int id; } axis[8]; struct { - char name[32]; + char name[260]; int id; } button[32]; struct { - char name[32]; + char name[260]; int id; } pov[4]; diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c index 8604b0fa4..b1fb90c1d 100644 --- a/src/keyboard_xt.c +++ b/src/keyboard_xt.c @@ -8,7 +8,7 @@ * * Implementation of the XT-style keyboard. * - * Version: @(#)keyboard_xt.c 1.0.14 2018/11/02 + * Version: @(#)keyboard_xt.c 1.0.15 2019/01/24 * * Authors: Sarah Walker, * Miran Grca, @@ -50,13 +50,14 @@ typedef struct { + int want_irq; int blocked; + int tandy; uint8_t pa; uint8_t pb; - - int tandy; - int type; + uint8_t key_waiting; + uint8_t type; } xtkbd_t; @@ -333,15 +334,24 @@ kbd_poll(void *priv) keyboard_delay += (1000LL * TIMER_USEC); - if (key_queue_start != key_queue_end && !kbd->blocked) { - kbd->pa = key_queue[key_queue_start]; + if (!(kbd->pb & 0x40) && (romset != ROM_TANDY)) + return; + + if (kbd->want_irq) { + kbd->want_irq = 0; + kbd->pa = kbd->key_waiting; + kbd->blocked = 1; picint(2); + } + + if (key_queue_start != key_queue_end && !kbd->blocked) { + kbd->key_waiting = key_queue[key_queue_start]; #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; + kbd->want_irq = 1; } } @@ -423,33 +433,34 @@ kbd_write(uint16_t port, uint8_t val, void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; - if (port != 0x61) return; + switch (port) { + case 0x61: + if (!(kbd->pb & 0x40) && (val & 0x40)) { + key_queue_start = key_queue_end = 0; + kbd->want_irq = 0; + kbd->blocked = 0; + kbd_adddata(0xaa); + } + kbd->pb = val; + ppi.pb = val; - 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); + 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 (val & 0x80) { + kbd->pa = 0; + kbd->blocked = 0; + picintc(2); + } + break; } - - 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); } @@ -468,7 +479,9 @@ kbd_read(uint16_t port, void *priv) ret = 0x7d; else ret = 0x6d; - } else + } else if ((kbd->type == 1) && (kbd->pb & 0x80)) + ret = 0xff; /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ + else ret = kbd->pa; break; @@ -521,10 +534,13 @@ kbd_reset(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; + kbd->want_irq = 0; kbd->blocked = 0; kbd->pa = 0x00; kbd->pb = 0x00; + keyboard_scan = 1; + key_queue_start = 0, key_queue_end = 0; } @@ -538,17 +554,16 @@ kbd_init(const device_t *info) kbd = (xtkbd_t *)malloc(sizeof(xtkbd_t)); memset(kbd, 0x00, sizeof(xtkbd_t)); - keyboard_set_table(scancode_xt); - - kbd->type = info->local; - - keyboard_scan = 1; - io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); keyboard_send = kbd_adddata_ex; + kbd_reset(kbd); + kbd->type = info->local; + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + keyboard_set_table(scancode_xt); + return(kbd); } diff --git a/src/lang/language.h b/src/lang/language.h index 6f2f4dcae..8f8bee8ce 100644 --- a/src/lang/language.h +++ b/src/lang/language.h @@ -10,7 +10,7 @@ * * NOTE: FIXME: Strings 2176 and 2193 are same. * - * Version: @(#)language.h 1.0.9 2018/09/06 + * Version: @(#)language.h 1.0.10 2018/11/19 * * Author: Fred N. van Kempen, * @@ -93,6 +93,8 @@ #define IDS_2117 2117 // "Floppy %i (%s): %ls" #define IDS_2118 2118 // "All floppy images (*.0??;*.." #define IDS_2119 2119 // "You must save the settings.." +#define IDS_2120 2120 // "Unable to initialize Free.." +#define IDS_2121 2121 // "Unable to initialize SDL..." #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -171,7 +173,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 72 +#define STR_NUM_2048 74 #define STR_NUM_3072 11 #define STR_NUM_4096 18 #define STR_NUM_4352 7 diff --git a/src/lpt.c b/src/lpt.c index f7e25513e..d37211844 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -12,6 +12,7 @@ #include "sound/snd_lpt_dss.h" #include "printer/prt_devs.h" + char lpt_device_names[3][16]; @@ -64,7 +65,7 @@ void lpt_devices_init() { 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(); + lpt_device_ps[i] = lpt_device_ts[i]->init(lpt_device_ts[i]); } } } @@ -87,12 +88,16 @@ void lpt_write(int i, uint16_t port, uint8_t val, void *priv) switch (port & 3) { case 0: - if (lpt_device_ts[i]) + if (lpt_device_ts[i] && lpt_device_ts[i]->write_data) lpt_device_ts[i]->write_data(val, lpt_device_ps[i]); lpt_dats[i] = val; break; + + case 1: + break; + case 2: - if (lpt_device_ts[i]) + if (lpt_device_ts[i] && lpt_device_ts[i]->write_ctrl) lpt_device_ts[i]->write_ctrl(val, lpt_device_ps[i]); lpt_ctrls[i] = val; break; @@ -100,18 +105,35 @@ void lpt_write(int i, uint16_t port, uint8_t val, void *priv) } uint8_t lpt_read(int i, uint16_t port, void *priv) { + uint8_t retval = 0xff; + switch (port & 3) { case 0: - return lpt_dats[i]; + if (lpt_device_ts[i] && lpt_device_ts[i]->read_data) { + retval = lpt_device_ts[i]->read_data(lpt_device_ps[i]); + break; + } + retval = lpt_dats[i]; + break; + case 1: - if (lpt_device_ts[i]) - return lpt_device_ts[i]->read_status(lpt_device_ps[i]); - return 0; + if (lpt_device_ts[i] && lpt_device_ts[i]->read_status) { + retval = lpt_device_ts[i]->read_status(lpt_device_ps[i]); + break; + } + retval = 0xdf; + break; + case 2: - return lpt_ctrls[i]; + if (lpt_device_ts[i] && lpt_device_ts[i]->read_ctrl) { + retval = lpt_device_ts[i]->read_ctrl(lpt_device_ps[i]); + break; + } + retval = 0xe0 | lpt_ctrls[i]; + break; } - return 0xff; + return retval; } void lpt1_write(uint16_t port, uint8_t val, void *priv) @@ -124,6 +146,7 @@ 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); diff --git a/src/lpt.h b/src/lpt.h index 7db61930b..f5edae8ba 100644 --- a/src/lpt.h +++ b/src/lpt.h @@ -17,10 +17,12 @@ extern char lpt_device_names[3][16]; typedef struct { - char name[80]; + const char *name; 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_data)(void *p); uint8_t (*read_status)(void *p); + uint8_t (*read_ctrl)(void *p); } lpt_device_t; diff --git a/src/machine/m_at_commodore.c b/src/machine/m_at_commodore.c index 8f0eb849b..294e6a12e 100644 --- a/src/machine/m_at_commodore.c +++ b/src/machine/m_at_commodore.c @@ -8,7 +8,7 @@ * * Implementation of the Commodore PC3 system. * - * Version: @(#)m_at_commodore.c 1.0.1 2018/11/06 + * Version: @(#)m_at_commodore.c 1.0.2 2018/11/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -51,49 +51,54 @@ #include "machine.h" -static void cbm_io_write(uint16_t port, uint8_t val, void *p) -{ - serial_t *uart = machine_get_serial(0); +static serial_t *cmd_uart; - 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(uart, 0x2f8, 3); - break; - case 0x8: - serial_setup(uart, 0x3f8, 4); - break; - } + +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(cmd_uart, 0x2f8, 3); + break; + case 0x8: + serial_setup(cmd_uart, 0x3f8, 4); + break; + } } -static void cbm_io_init() + +static void +cbm_io_init() { - io_sethandler(0x0230, 0x0001, NULL,NULL,NULL, cbm_io_write,NULL,NULL, NULL); + 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_init(model); - - mem_remap_top(384); - - device_add(&fdc_at_device); + machine_at_ide_init(model); - cbm_io_init(); + mem_remap_top(384); + + device_add(&fdc_at_device); + cmd_uart = device_add(&i8250_device); + + cbm_io_init(); } diff --git a/src/machine/m_at_sis_85c471.c b/src/machine/m_at_sis_85c471.c index 8082ad27c..6f408b5ea 100644 --- a/src/machine/m_at_sis_85c471.c +++ b/src/machine/m_at_sis_85c471.c @@ -9,7 +9,7 @@ * SiS sis85c471 Super I/O Chip * Used by DTK PKM-0038S E-2 * - * Version: @(#)m_at_sis85c471.c 1.0.12 2018/11/09 + * Version: @(#)m_at_sis85c471.c 1.0.13 2018/11/12 * * Author: Miran Grca, * @@ -36,6 +36,7 @@ typedef struct { uint8_t cur_reg, regs[39]; + serial_t *uart[2]; } sis_85c471_t; @@ -45,7 +46,6 @@ sis_85c471_write(uint16_t port, uint8_t val, void *priv) sis_85c471_t *dev = (sis_85c471_t *) priv; uint8_t index = (port & 1) ? 0 : 1; uint8_t valxor; - serial_t *uart[2]; if (index) { if ((val >= 0x50) && (val <= 0x76)) @@ -68,13 +68,11 @@ sis_85c471_write(uint16_t port, uint8_t val, void *priv) ide_pri_enable(); } if (valxor & 0x20) { - uart[0] = machine_get_serial(0); - uart[1] = machine_get_serial(1); - serial_remove(uart[0]); - serial_remove(uart[1]); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); if (val & 0x20) { - serial_setup(uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(uart[0], SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(dev->uart[0], SERIAL2_ADDR, SERIAL2_IRQ); } } if (valxor & 0x10) { @@ -204,6 +202,9 @@ sis_85c471_init(const device_t *info) dev->regs[0x23] = 0xF0; dev->regs[0x26] = 1; + dev->uart[0] = device_add_inst(&i8250_device, 1); + dev->uart[1] = device_add_inst(&i8250_device, 2); + io_sethandler(0x0022, 0x0002, sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); diff --git a/src/machine/m_at_wd76c10.c b/src/machine/m_at_wd76c10.c index bb45adc9e..646f9cf02 100644 --- a/src/machine/m_at_wd76c10.c +++ b/src/machine/m_at_wd76c10.c @@ -22,6 +22,8 @@ static uint16_t wd76c10_2072; static uint16_t wd76c10_2872; static uint16_t wd76c10_5872; +static serial_t *wd76c10_uart[2]; + static fdc_t *wd76c10_fdc; @@ -50,11 +52,6 @@ wd76c10_read(uint16_t port, void *priv) static void wd76c10_write(uint16_t port, uint16_t val, void *priv) { - serial_t *uart[2]; - - uart[0] = machine_get_serial(0); - uart[1] = machine_get_serial(1); - switch (port) { case 0x0092: @@ -67,27 +64,27 @@ wd76c10_write(uint16_t port, uint16_t val, void *priv) case 0x2072: wd76c10_2072 = val; - serial_remove(uart[0]); + serial_remove(wd76c10_uart[0]); if (!(val & 0x10)) { switch ((val >> 5) & 7) { - case 1: serial_setup(uart[0], 0x3f8, 4); break; - case 2: serial_setup(uart[0], 0x2f8, 4); break; - case 3: serial_setup(uart[0], 0x3e8, 4); break; - case 4: serial_setup(uart[0], 0x2e8, 4); break; + case 1: serial_setup(wd76c10_uart[0], 0x3f8, 4); break; + case 2: serial_setup(wd76c10_uart[0], 0x2f8, 4); break; + case 3: serial_setup(wd76c10_uart[0], 0x3e8, 4); break; + case 4: serial_setup(wd76c10_uart[0], 0x2e8, 4); break; default: break; } } - serial_remove(uart[1]); + serial_remove(wd76c10_uart[1]); if (!(val & 0x01)) { switch ((val >> 1) & 7) { - case 1: serial_setup(uart[1], 0x3f8, 3); break; - case 2: serial_setup(uart[1], 0x2f8, 3); break; - case 3: serial_setup(uart[1], 0x3e8, 3); break; - case 4: serial_setup(uart[1], 0x2e8, 3); break; + case 1: serial_setup(wd76c10_uart[1], 0x3f8, 3); break; + case 2: serial_setup(wd76c10_uart[1], 0x2f8, 3); break; + case 3: serial_setup(wd76c10_uart[1], 0x3e8, 3); break; + case 4: serial_setup(wd76c10_uart[1], 0x2e8, 3); break; default: break; } } @@ -152,6 +149,8 @@ machine_at_wd76c10_init(const machine_t *model) device_add(&keyboard_ps2_quadtel_device); wd76c10_fdc = device_add(&fdc_at_device); + wd76c10_uart[0] = device_add_inst(&i8250_device, 1); + wd76c10_uart[1] = device_add_inst(&i8250_device, 2); wd76c10_init(); diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index a5e7a0600..4eef6f095 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -8,7 +8,7 @@ * * Emulation of the IBM PCjr. * - * Version: @(#)m_pcjr.c 1.0.11 2018/11/06 + * Version: @(#)m_pcjr.c 1.0.12 2018/11/12 * * Authors: Sarah Walker, * Miran Grca, @@ -756,9 +756,6 @@ machine_pcjr_init(const machine_t *model) else setrtcconst(14318184.0); - if (serial_enabled[0]) - serial_setup(machine_get_serial(0), 0x2f8, 3); - /* Initialize the video controller. */ mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, vid_read, NULL, NULL, diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 2ea9bd3cb..3012b8725 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -28,7 +28,7 @@ * boot. Sometimes, they do, and then it shows an "Incorrect * DOS" error message?? --FvK * - * Version: @(#)m_ps1.c 1.0.13 2018/11/06 + * Version: @(#)m_ps1.c 1.0.14 2018/11/12 * * Authors: Sarah Walker, * Miran Grca, @@ -98,6 +98,8 @@ typedef struct { ps1_190; int ps1_e0_addr; uint8_t ps1_e0_regs[256]; + + serial_t *uart; } ps1_t; @@ -292,7 +294,6 @@ static void ps1_write(uint16_t port, uint8_t val, void *priv) { ps1_t *ps = (ps1_t *)priv; - serial_t *uart; switch (port) { case 0x0092: @@ -328,11 +329,10 @@ ps1_write(uint16_t port, uint8_t val, void *priv) case 0x0102: lpt1_remove(); - uart = machine_get_serial(0); if (val & 0x04) - serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps->uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_remove(uart); + serial_remove(ps->uart); if (val & 0x10) { switch ((val >> 5) & 3) { case 0: @@ -449,6 +449,8 @@ ps1_setup(int model) io_sethandler(0x0190, 1, ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + ps->uart = device_add_inst(&i8250_device, 1); + lpt1_remove(); lpt1_init(0x3bc); @@ -459,9 +461,6 @@ ps1_setup(int model) lpt2_remove(); - serial_remove(machine_get_serial(0)); - serial_remove(machine_get_serial(1)); - /* Enable the PS/1 VGA controller. */ if (model == 2011) device_add(&ps1vga_device); diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 63c498edc..9dea86ee8 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -22,6 +22,7 @@ static uint8_t ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; +static serial_t *ps2_uart; static struct @@ -70,8 +71,6 @@ static uint8_t ps2_read(uint16_t port, void *p) static void ps2_write(uint16_t port, uint8_t val, void *p) { - serial_t *uart = machine_get_serial(0); - switch (port) { case 0x94: @@ -80,9 +79,9 @@ static void ps2_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2_uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_remove(uart); + serial_remove(ps2_uart); if (val & 0x10) { switch ((val >> 5) & 3) @@ -143,6 +142,8 @@ static void ps2board_init(void) ps2_190 = 0; + ps2_uart = device_add_inst(&i8250_device, 1); + lpt1_init(0x3bc); memset(&ps2_hd, 0, sizeof(ps2_hd)); diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 30fc3a564..7a69901e4 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -8,7 +8,7 @@ * * Implementation of MCA-based PS/2 machines. * - * Version: @(#)m_ps2_mca.c 1.0.4 2018/11/06 + * Version: @(#)m_ps2_mca.c 1.0.5 2018/11/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -97,6 +97,8 @@ static struct uint8_t mem_2mb_pos_regs[8]; int pending_cache_miss; + + serial_t *uart; } ps2; /*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any @@ -372,8 +374,6 @@ static uint8_t model_80_read(uint16_t port) static void model_50_write(uint16_t port, uint8_t val) { - serial_t *uart = machine_get_serial(0); - switch (port) { case 0x100: @@ -383,13 +383,13 @@ static void model_50_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(uart); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } if (val & 0x10) { @@ -428,8 +428,6 @@ static void model_50_write(uint16_t port, uint8_t val) static void model_55sx_write(uint16_t port, uint8_t val) { - serial_t *uart = machine_get_serial(0); - switch (port) { case 0x100: @@ -439,13 +437,13 @@ static void model_55sx_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(uart); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } if (val & 0x10) { @@ -505,8 +503,6 @@ static void model_55sx_write(uint16_t port, uint8_t val) static void model_70_type3_write(uint16_t port, uint8_t val) { - serial_t *uart = machine_get_serial(0); - switch (port) { case 0x100: @@ -515,13 +511,13 @@ static void model_70_type3_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(uart); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } if (val & 0x10) { @@ -555,8 +551,6 @@ static void model_70_type3_write(uint16_t port, uint8_t val) static void model_80_write(uint16_t port, uint8_t val) { - serial_t *uart = machine_get_serial(0); - switch (port) { case 0x100: @@ -565,13 +559,13 @@ static void model_80_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(uart); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } if (val & 0x10) { @@ -1246,6 +1240,8 @@ machine_ps2_common_init(const machine_t *model) pit_ps2_init(); nmi_mask = 0x80; + + ps2.uart = device_add_inst(&i8250_device, 1); } diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index 7de664ed6..56a6d6ae6 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -115,7 +115,7 @@ static uint8_t mem_read_laserxtems(uint32_t addr, void *priv) } -static void laserxt_init(is_lxt3) +static void laserxt_init(int is_lxt3) { int i; diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c new file mode 100644 index 000000000..f818ddf81 --- /dev/null +++ b/src/machine/m_xt_zenith.c @@ -0,0 +1,113 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * 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 Zenith PC compatible machines. + * Currently only the Zenith Data Systems Supersport is emulated. + * + * Version: @(#)m_xt_compaq.c 1.0.0 2019/01/13 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#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" + +typedef struct { + mem_mapping_t scratchpad_mapping; + uint8_t *scratchpad_ram; +} zenith_t; + +static uint8_t zenith_scratchpad_read(uint32_t addr, void *p) +{ + zenith_t *dev = (zenith_t *)p; + return dev->scratchpad_ram[addr & 0x3fff]; +} +static void zenith_scratchpad_write(uint32_t addr, uint8_t val, void *p) +{ + zenith_t *dev = (zenith_t *)p; + dev->scratchpad_ram[addr & 0x3fff] = val; +} + +static void * +zenith_scratchpad_init(const device_t *info) +{ + zenith_t *dev; + + dev = (zenith_t *)malloc(sizeof(zenith_t)); + memset(dev, 0x00, sizeof(zenith_t)); + + dev->scratchpad_ram = malloc(0x4000); + + mem_mapping_disable(&bios_mapping[4]); + mem_mapping_disable(&bios_mapping[5]); + + mem_mapping_add(&dev->scratchpad_mapping, 0xf0000, 0x4000, + zenith_scratchpad_read, NULL, NULL, + zenith_scratchpad_write, NULL, NULL, + dev->scratchpad_ram, MEM_MAPPING_EXTERNAL, dev); + + return dev; +} + +static void +zenith_scratchpad_close(void *p) +{ + zenith_t *dev = (zenith_t *)p; + + free(dev->scratchpad_ram); + free(dev); +} + + +static const device_t zenith_scratchpad_device = { + "Zenith scratchpad RAM", + 0, 0, + zenith_scratchpad_init, zenith_scratchpad_close, NULL, + NULL, + NULL, + NULL +}; + +void +machine_xt_zenith_init(const machine_t *model) +{ + machine_common_init(model); + + lpt2_remove(); /* only one parallel port */ + + device_add(&zenith_scratchpad_device); + + 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); +} \ No newline at end of file diff --git a/src/machine/machine.c b/src/machine/machine.c index a186631bd..da5d59615 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.c 1.0.36 2018/11/05 + * Version: @(#)machine.c 1.0.37 2018/11/12 * * Authors: Sarah Walker, * Miran Grca, @@ -42,8 +42,6 @@ int machine; int AT, PCI; int romset; -static serial_t *uart[2]; - #ifdef ENABLE_MACHINE_LOG int machine_do_log = ENABLE_MACHINE_LOG; @@ -92,12 +90,6 @@ machine_init(void) /* All good, boot the machine! */ machines[machine].init(&machines[machine]); - /* For non-PCI machines, add two regular 8250 UART's. */ - if (!PCI) { - uart[0] = device_add_inst(&i8250_device, 1); - uart[1] = device_add_inst(&i8250_device, 2); - } - /* If it's a PCI or MCA machine, reset the video card after initializing the machine, so the slots work correctly. */ if (PCI || MCA) @@ -105,13 +97,6 @@ machine_init(void) } -serial_t * -machine_get_serial(int port) -{ - return uart[port]; -} - - void machine_common_init(const machine_t *model) { diff --git a/src/machine/machine.h b/src/machine/machine.h index ca87e3fe9..5d6c0a017 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.30 2018/09/15 + * Version: @(#)machine.h 1.0.32 2019/01/13 * * Authors: Sarah Walker, * Miran Grca, @@ -82,9 +82,6 @@ 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); -#ifdef EMU_SERIAL_H -extern serial_t *machine_get_serial(int port); -#endif extern void machine_init(void); #ifdef EMU_DEVICE_H extern const device_t *machine_getdevice(int machine); @@ -199,6 +196,7 @@ 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 *); +extern void machine_xt_zenith_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t *xi8088_get_device(void); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e5e7daa93..f19b9bd67 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.44 2018/11/03 + * Version: @(#)machine_table.c 1.0.45 2019/01/13 * * Authors: Sarah Walker, * Miran Grca, @@ -51,7 +51,8 @@ const machine_t machines[] = { { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL }, #endif { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL }, - + { "[8088] Zenith Data SupersPort", ROM_ZD_SUPERS, "zdsupers", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 128, 640, 128, 0, machine_xt_zenith_init, NULL }, + { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"Intel", 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", {{"Intel", 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", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, diff --git a/src/mem.c b/src/mem.c index 2312641f6..03bb9e13b 100644 --- a/src/mem.c +++ b/src/mem.c @@ -12,7 +12,7 @@ * the DYNAMIC_TABLES=1 enables this. Will eventually go * away, either way... * - * Version: @(#)mem.c 1.0.18 2018/10/17 + * Version: @(#)mem.c 1.0.19 2018/11/18 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -494,10 +494,12 @@ getpccache(uint32_t a) 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; + if (is286) { + 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)]; } @@ -996,26 +998,6 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) 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]) @@ -1028,36 +1010,24 @@ mem_readb_phys_dma(uint32_t addr) uint16_t mem_readw_phys(uint32_t addr) { - mem_logical_addr = 0xffffffff; + uint16_t temp; - if (_mem_read_w[addr >> 14]) - return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + if (_mem_exec[addr >> 14]) + return ((uint16_t *) _mem_exec[addr >> 14])[(addr >> 1) & 0x1fff]; + else if (_mem_read_w[addr >> 14]) + return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + else { + temp = mem_readb_phys(addr + 1) << 8; + temp |= mem_readb_phys(addr); + } - return 0xff; + return temp; } 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]) @@ -1065,16 +1035,6 @@ mem_writeb_phys_dma(uint32_t addr, uint8_t val) } -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) { diff --git a/src/mem.h b/src/mem.h index afbe52bb4..e07383c71 100644 --- a/src/mem.h +++ b/src/mem.h @@ -8,7 +8,7 @@ * * Definitions for the memory interface. * - * Version: @(#)mem.h 1.0.6 2018/09/15 + * Version: @(#)mem.h 1.0.8 2018/11/18 * * Authors: Fred N. van Kempen, * Sarah Walker, @@ -139,7 +139,6 @@ extern int shadowbios, extern int readlnum, writelnum; -extern int nopageerrors; extern int memspeed[11]; extern int mmu_perm; @@ -209,11 +208,8 @@ 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 uint32_t mem_readl_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 void mem_writel_phys(uint32_t addr, uint32_t val); extern uint8_t mem_read_ram(uint32_t addr, void *priv); extern uint16_t mem_read_ramw(uint32_t addr, void *priv); diff --git a/src/mouse_serial.c b/src/mouse_serial.c index dff7ba0f3..d2b088e62 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -10,7 +10,7 @@ * * TODO: Add the Genius Serial Mouse. * - * Version: @(#)mouse_serial.c 1.0.26 2018/11/05 + * Version: @(#)mouse_serial.c 1.0.27 2018/11/11 * * Author: Fred N. van Kempen, */ @@ -30,12 +30,21 @@ #define SERMOUSE_PORT 0 /* attach to Serial0 */ -#define PHASE_IDLE 0 -#define PHASE_ID 1 -#define PHASE_DATA 2 -#define PHASE_STATUS 3 -#define PHASE_DIAGNOSTIC 4 -#define PHASE_FORMAT_AND_REVISION 5 +enum { + PHASE_IDLE, + PHASE_ID, + PHASE_DATA, + PHASE_STATUS, + PHASE_DIAGNOSTIC, + PHASE_FORMAT_AND_REVISION, + PHASE_COPYRIGHT_STRING, + PHASE_BUTTONS +}; + +enum { + REPORT_PHASE_PREPARE, + REPORT_PHASE_TRANSMIT +}; typedef struct { @@ -45,16 +54,18 @@ typedef struct { uint8_t flags, but, /* device flags */ want_data, status, format, - prompt, continuous, + prompt, on_change, id_len, id[255], data_len, data[5]; - int abs_x, abs_y; + int abs_x, abs_y, + rel_x, rel_y, + rel_z, + oldb, lastb; - int pos; - int64_t delay; - int64_t period; - int oldb; - int phase; + int command_pos, command_phase, + report_pos, report_phase; + int64_t command_delay, transmit_period, + report_delay, report_period; serial_t *serial; } mouse_t; @@ -93,9 +104,9 @@ sermouse_callback(struct serial_s *serial, void *priv) mouse_t *dev = (mouse_t *)priv; /* Start a timer to wake us up in a little while. */ - dev->pos = 0; - dev->phase = PHASE_ID; - dev->delay = dev->period; + dev->command_pos = 0; + dev->command_phase = PHASE_ID; + dev->command_delay = dev->transmit_period; } @@ -234,114 +245,256 @@ sermouse_report(int x, int y, int z, int b, mouse_t *dev) memset(dev->data, 0, 5); - switch(dev->type) { - case MOUSE_TYPE_MSYSTEMS: + switch (dev->format) { + case 0: len = sermouse_data_msystems(dev, x, y, b); break; - - case MOUSE_TYPE_MICROSOFT: - case MOUSE_TYPE_MS3BUTTON: - case MOUSE_TYPE_MSWHEEL: - len = sermouse_data_ms(dev, x, y, z, b); + case 1: + len = sermouse_data_3bp(dev, x, y, b); break; - - case MOUSE_TYPE_LOGITECH: - case MOUSE_TYPE_LT3BUTTON: - switch (dev->format) { - case 0: - len = sermouse_data_msystems(dev, x, y, b); - break; - case 1: - len = sermouse_data_3bp(dev, x, y, b); - break; - case 2: - len = sermouse_data_hex(dev, x, y, b); - break; - case 3: /* Relative */ - len = sermouse_data_bp1(dev, x, y, b); - break; - case 5: - len = sermouse_data_mmseries(dev, x, y, b); - break; - case 6: /* Absolute */ - len = sermouse_data_bp1(dev, dev->abs_x, dev->abs_y, b); - break; - case 7: - len = sermouse_data_ms(dev, x, y, z, b); - break; - } + case 2: + len = sermouse_data_hex(dev, x, y, b); + break; + case 3: /* Relative */ + len = sermouse_data_bp1(dev, x, y, b); + break; + case 5: + len = sermouse_data_mmseries(dev, x, y, b); + break; + case 6: /* Absolute */ + len = sermouse_data_bp1(dev, dev->abs_x, dev->abs_y, b); + break; + case 7: + len = sermouse_data_ms(dev, x, y, z, b); break; } - dev->oldb = b; dev->data_len = len; +} - dev->pos = 0; - if (dev->phase != PHASE_DATA) - dev->phase = PHASE_DATA; +static void +sermouse_command_phase_idle(mouse_t *dev) +{ + dev->command_delay = 0LL; + dev->command_pos = 0; + dev->command_phase = PHASE_IDLE; +} - if (!dev->delay) - dev->delay = dev->period; + +static void +sermouse_command_pos_check(mouse_t *dev, int len) +{ + if (++dev->command_pos == len) + sermouse_command_phase_idle(dev); + else + dev->command_delay += dev->transmit_period; +} + + +static uint8_t +sermouse_last_button_status(mouse_t *dev) +{ + uint8_t ret = 0x00; + + if (dev->oldb & 0x01) + ret |= 0x04; + if (dev->oldb & 0x02) + ret |= 0x02; + if (dev->oldb & 0x04) + ret |= 0x01; + + return ret; +} + + +static int64_t +sermouse_transmit_period(mouse_t *dev, int bps, int rps) +{ + double dbps = (double) bps; + double dusec = (double) TIMER_USEC; + double temp = 0.0; + int word_len; + + switch (dev->format) { + case 0: + case 1: /* Mouse Systems and Three Byte Packed formats: 8 data, no parity, 2 stop, 1 start */ + word_len = 11; + break; + case 2: /* Hexadecimal format - 8 data, no parity, 1 stop, 1 start - number of stop bits is a guess because + it is not documented anywhere. */ + word_len = 10; + break; + case 3: + case 6: /* Bit Pad One formats: 7 data, even parity, 2 stop, 1 start */ + word_len = 11; + break; + case 5: /* MM Series format: 8 data, odd parity, 1 stop, 1 start */ + word_len = 11; + break; + default: + case 7: /* Microsoft-compatible format: 7 data, no parity, 1 stop, 1 start */ + word_len = 9; + break; + } + + if (rps == -1) + temp = (double) word_len; + else { + temp = (double) rps; + temp = (9600.0 - (temp * 33.0)); + temp /= rps; + } + temp = (1000000.0 / dbps) * temp; + temp *= dusec; + + return (int64_t) temp; +} + + +static void +sermouse_update_delta(mouse_t *dev, int *local, int *global) +{ + int min, max; + + if (dev->format == 3) { + min = -2048; + max = 2047; + } else { + min = -128; + max = 127; + } + + if (*global > max) { + *local = max; + *global -= max; + } else if (*global < min) { + *local = min; + *global += -min; + } else { + *local = *global; + *global = 0; + } +} + + +static uint8_t +sermouse_update_data(mouse_t *dev) +{ + uint8_t ret = 0; + int delta_x, delta_y, delta_z; + + /* Update the deltas and the delays. */ + sermouse_update_delta(dev, &delta_x, &dev->rel_x); + sermouse_update_delta(dev, &delta_y, &dev->rel_y); + sermouse_update_delta(dev, &delta_z, &dev->rel_z); + + sermouse_report(delta_x, delta_y, delta_z, dev->oldb, dev); + + mouse_serial_log("delta_x = %i, delta_y = %i, delta_z = %i, dev->oldb = %02X\n", + delta_x, delta_y, delta_z, dev->oldb); + + if (delta_x || delta_y || delta_z || (dev->oldb != dev->lastb) || !dev->on_change) + ret = 1; + + dev->lastb = dev->oldb; + + return ret; +} + + +static void +sermouse_report_prepare(mouse_t *dev) +{ + if (sermouse_update_data(dev)) { + /* Start sending data. */ + dev->report_phase = REPORT_PHASE_TRANSMIT; + dev->report_pos = 0; + dev->report_delay += dev->transmit_period; + } else { + dev->report_phase = REPORT_PHASE_PREPARE; + if (dev->report_period == 0LL) + dev->report_delay += dev->transmit_period; + else + dev->report_delay += dev->report_period; + } +} + + +static void +sermouse_report_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->report_phase == REPORT_PHASE_PREPARE) + sermouse_report_prepare(dev); + else { + /* If using the Mouse Systems format, update data because + the last two bytes are the X and Y delta since bytes 1 + and 2 were transmitted. */ + if (!dev->format && (dev->report_pos == 3)) + sermouse_update_data(dev); + serial_write_fifo(dev->serial, dev->data[dev->report_pos]); + if (++dev->report_pos == dev->data_len) { + if (dev->report_delay == 0LL) + sermouse_report_prepare(dev); + else { + if (dev->report_period == 0LL) + dev->report_delay += dev->transmit_period; + else + dev->report_delay += dev->report_period; + dev->report_phase = REPORT_PHASE_PREPARE; + } + } else + dev->report_delay += dev->transmit_period; + } } /* Callback timer expired, now send our "mouse ID" to the serial port. */ static void -sermouse_timer(void *priv) +sermouse_command_timer(void *priv) { mouse_t *dev = (mouse_t *)priv; - switch (dev->phase) { + switch (dev->command_phase) { case PHASE_ID: - serial_write_fifo(dev->serial, dev->id[dev->pos]); - dev->pos++; - if (dev->pos == dev->id_len) { - dev->delay = 0LL; - dev->pos = 0; - dev->phase = PHASE_IDLE; - } else - dev->delay += dev->period; + serial_write_fifo(dev->serial, dev->id[dev->command_pos]); + sermouse_command_pos_check(dev, dev->id_len); + if ((dev->command_phase == PHASE_IDLE) && (dev->type != MOUSE_TYPE_MSYSTEMS)) { + /* This resets back to Microsoft-compatible mode. */ + dev->report_delay = 0LL; + dev->report_phase = REPORT_PHASE_PREPARE; + dev->format = 7; + dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); + sermouse_report_timer((void *) dev); + } break; case PHASE_DATA: - serial_write_fifo(dev->serial, dev->data[dev->pos]); - dev->pos++; - if (dev->pos == dev->data_len) { - dev->delay = 0LL; - dev->pos = 0; - dev->phase = PHASE_IDLE; - } else - dev->delay += dev->period; + serial_write_fifo(dev->serial, dev->data[dev->command_pos]); + sermouse_command_pos_check(dev, dev->data_len); break; case PHASE_STATUS: serial_write_fifo(dev->serial, dev->status); - dev->delay = 0LL; - dev->pos = 0; - dev->phase = PHASE_IDLE; + sermouse_command_phase_idle(dev); break; case PHASE_DIAGNOSTIC: - if (dev->pos) + if (dev->command_pos) serial_write_fifo(dev->serial, 0x00); - else /* This should return the last button status, bits 2,1,0 = L,M,R. */ - serial_write_fifo(dev->serial, 0x00); - dev->pos++; - if (dev->pos == 3) { - dev->delay = 0LL; - dev->pos = 0; - dev->phase = PHASE_IDLE; - } else - dev->delay += dev->period; + else + serial_write_fifo(dev->serial, sermouse_last_button_status(dev)); + sermouse_command_pos_check(dev, 3); break; case PHASE_FORMAT_AND_REVISION: serial_write_fifo(dev->serial, 0x10 | (dev->format << 1)); - dev->delay = 0LL; - dev->pos = 0; - dev->phase = PHASE_IDLE; + sermouse_command_phase_idle(dev); + break; + case PHASE_BUTTONS: + serial_write_fifo(dev->serial, dev->but); + sermouse_command_phase_idle(dev); break; default: - dev->delay = 0LL; - dev->pos = 0; - dev->phase = PHASE_IDLE; + sermouse_command_phase_idle(dev); break; } } @@ -352,8 +505,10 @@ sermouse_poll(int x, int y, int z, int b, void *priv) { mouse_t *dev = (mouse_t *)priv; - if (!x && !y && (b == dev->oldb) && dev->continuous) + if (!x && !y && !z && (b == dev->oldb)) { + dev->oldb = b; return(1); + } dev->oldb = b; dev->abs_x += x; @@ -379,51 +534,71 @@ sermouse_poll(int x, int y, int z, int b, void *priv) if (y <- 128) y = -128; } - /* No report if we're either in prompt mode, - or the mouse wants data. */ - if (!dev->prompt && !dev->want_data) - sermouse_report(x, y, z, b, dev); + dev->rel_x += x; + dev->rel_y += y; + dev->rel_z += z; return(0); } +static void +ltsermouse_prompt_mode(mouse_t *dev, int prompt) +{ + dev->prompt = prompt; + dev->status &= 0xBF; + if (prompt) + dev->status |= 0x40; +} + + +static void +ltsermouse_command_phase(mouse_t *dev, int phase) +{ + dev->command_pos = 0; + dev->command_phase = phase; + dev->command_delay = dev->transmit_period; +} + + +static void +ltsermouse_set_report_period(mouse_t *dev, int rps) +{ + dev->report_delay = dev->report_period = sermouse_transmit_period(dev, 9600, rps); + ltsermouse_prompt_mode(dev, 0); + dev->report_phase = REPORT_PHASE_PREPARE; +} + + static void ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) { mouse_t *dev = (mouse_t *)priv; -#if 0 - /* Make sure to stop any transmission when we receive a byte. */ - if (dev->phase != PHASE_IDLE) { - dev->delay = 0LL; - dev->phase = PHASE_IDLE; - } -#endif + /* Stop reporting when we're processing a command. */ + dev->report_phase = REPORT_PHASE_PREPARE; + dev->report_delay = 0LL; if (dev->want_data) switch (dev->want_data) { case 0x2A: dev->data_len--; dev->want_data = 0; - dev->delay = 0LL; - dev->phase = PHASE_IDLE; switch (data) { default: mouse_serial_log("Serial mouse: Invalid period %02X, using 1200 bps\n", data); case 0x6E: - dev->period = 7500LL; /* 1200 bps */ + dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); break; case 0x6F: - dev->period = 3750LL; /* 2400 bps */ + dev->transmit_period = sermouse_transmit_period(dev, 2400, -1); break; case 0x70: - dev->period = 1875LL; /* 4800 bps */ + dev->transmit_period = sermouse_transmit_period(dev, 4800, -1); break; case 0x71: - dev->period = 938LL; /* 9600 bps */ + dev->transmit_period = sermouse_transmit_period(dev, 9600, -1); break; } - dev->period *= TIMER_USEC; break; } else switch (data) { case 0x2A: @@ -431,33 +606,43 @@ ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) dev->data_len = 1; break; case 0x44: /* Set prompt mode */ - dev->prompt = 1; - dev->status |= 0x40; + ltsermouse_prompt_mode(dev, 1); break; case 0x50: - if (!dev->prompt) { - dev->prompt = 1; - dev->status |= 0x40; - } - /* TODO: Here we should send the current position. */ + if (!dev->prompt) + ltsermouse_prompt_mode(dev, 1); + sermouse_update_data(dev); + ltsermouse_command_phase(dev, PHASE_DATA); break; case 0x73: /* Status */ - dev->pos = 0; - dev->phase = PHASE_STATUS; - if (!dev->delay) - dev->delay = dev->period; + ltsermouse_command_phase(dev, PHASE_STATUS); break; case 0x4A: /* Report Rate Selection commands */ + ltsermouse_set_report_period(dev, 10); + break; case 0x4B: + ltsermouse_set_report_period(dev, 20); + break; case 0x4C: + ltsermouse_set_report_period(dev, 35); + break; case 0x52: + ltsermouse_set_report_period(dev, 50); + break; case 0x4D: + ltsermouse_set_report_period(dev, 70); + break; case 0x51: + ltsermouse_set_report_period(dev, 100); + break; case 0x4E: + ltsermouse_set_report_period(dev, 150); + break; case 0x4F: - dev->prompt = 0; - dev->status &= 0xBF; - // dev->continuous = (data == 0x4F); + ltsermouse_prompt_mode(dev, 0); + dev->report_delay = dev->report_period = 0LL; + dev->report_phase = REPORT_PHASE_PREPARE; + sermouse_report_timer((void *) dev); break; case 0x41: dev->format = 6; /* Aboslute Bit Pad One Format */ @@ -482,16 +667,13 @@ ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) dev->format = 2; /* Hexadecimal Format */ break; case 0x05: - dev->pos = 0; - dev->phase = PHASE_DIAGNOSTIC; - if (!dev->delay) - dev->delay = dev->period; + ltsermouse_command_phase(dev, PHASE_DIAGNOSTIC); break; case 0x66: - dev->pos = 0; - dev->phase = PHASE_FORMAT_AND_REVISION; - if (!dev->delay) - dev->delay = dev->period; + ltsermouse_command_phase(dev, PHASE_FORMAT_AND_REVISION); + break; + case 0x6B: + ltsermouse_command_phase(dev, PHASE_BUTTONS); break; } } @@ -520,19 +702,19 @@ sermouse_init(const device_t *info) memset(dev, 0x00, sizeof(mouse_t)); dev->name = info->name; dev->but = device_get_config_int("buttons"); - dev->continuous = 1; if (dev->but > 2) dev->flags |= FLAG_3BTN; if (info->local == MOUSE_TYPE_MSYSTEMS) { - dev->period = 8333LL * TIMER_USEC; /* 1200 bps, 8 data bits, 1 start bit, 1 stop bit, no parity bit */ + dev->on_change = 1; + dev->format = 0; dev->type = info->local; dev->id_len = 1; dev->id[0] = 'H'; } else { + dev->on_change = !info->local; dev->format = 7; dev->status = 0x0f; - dev->period = 7500LL * TIMER_USEC; /* 1200 bps, 7 data bits, 1 start bit, 1 stop bit, no parity bit */ dev->id_len = 1; dev->id[0] = 'M'; switch(dev->but) { @@ -554,6 +736,21 @@ sermouse_init(const device_t *info) } } + dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); + + /* Default: Continuous reporting = no delay between reports. */ + dev->report_phase = REPORT_PHASE_PREPARE; + dev->report_period = 0LL; + + if (info->local == MOUSE_TYPE_MSYSTEMS) + dev->report_delay = dev->transmit_period; + else + dev->report_delay = 0LL; + + /* Default: Doing nothing - command transmit timer deactivated. */ + dev->command_phase = PHASE_IDLE; + dev->command_delay = 0LL; + dev->port = device_get_config_int("port"); /* Attach a serial port to the mouse. */ @@ -564,7 +761,8 @@ sermouse_init(const device_t *info) mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port + 1); - timer_add(sermouse_timer, &dev->delay, &dev->delay, dev); + timer_add(sermouse_report_timer, &dev->report_delay, &dev->report_delay, dev); + timer_add(sermouse_command_timer, &dev->command_delay, &dev->command_delay, dev); /* Tell them how many buttons we have. */ mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); diff --git a/src/network/network.c b/src/network/network.c index c9856f607..0db312a39 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -12,7 +12,7 @@ * it should be malloc'ed and then linked to the NETCARD def. * Will be done later. * - * Version: @(#)network.c 1.0.9 2018/10/22 + * Version: @(#)network.c 1.0.10 2018/11/18 * * Author: Fred N. van Kempen, * @@ -99,7 +99,7 @@ static netcard_t net_cards[] = { int network_type; int network_ndev; int network_card; -char network_host[512]; +char network_host[522]; netdev_t network_devs[32]; #ifdef ENABLE_NIC_LOG int nic_do_log = ENABLE_NIC_LOG; diff --git a/src/network/slirp/slirp.c b/src/network/slirp/slirp.c index 7457f1340..5ade8ae30 100644 --- a/src/network/slirp/slirp.c +++ b/src/network/slirp/slirp.c @@ -389,172 +389,127 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) 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(); + /* Update time */ + updtime(); - /* 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. + /* + * 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; + } + } + + ret = 0; + + /* + * 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; + } + 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, (char *)&ret, 0, 0); + 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; + } + + /* + * Continue tcp_input + */ + tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip), so); + } else + ret = sowrite(so); + } + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; + 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 @@ -701,10 +656,3 @@ int slirp_redir(int is_udp, int host_port, } 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/pc.c b/src/pc.c index f56cce0a5..baa1a97df 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.89 2018/11/05 + * Version: @(#)pc.c 1.0.91 2018/11/14 * * Authors: Sarah Walker, * Miran Grca, @@ -256,7 +256,9 @@ fatal(const char *fmt, ...) config_save(); dumppic(); +#ifdef ENABLE_808X_LOG dumpregs(1); +#endif /* Make sure the message does not have a trailing newline. */ if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; @@ -658,7 +660,7 @@ again2: sound_init(); - hdc_init(hdc_name); + hdc_init(); return(1); } @@ -758,6 +760,9 @@ pc_reset_hard_init(void) /* Initialize the actual machine and its basic modules. */ machine_init(); + /* Reset and reconfigure the serial ports. */ + serial_standalone_init(); + /* Reset and reconfigure the Sound Card layer. */ sound_card_reset(); @@ -895,7 +900,9 @@ pc_close(thread_t *ptr) if (dump_on_exit) dumppic(); +#ifdef ENABLE_808X_LOG dumpregs(0); +#endif video_close(); diff --git a/src/pic.c b/src/pic.c index e1cc04290..1a07fe01c 100644 --- a/src/pic.c +++ b/src/pic.c @@ -8,7 +8,7 @@ * * Implementation of the Intel PIC chip emulation. * - * Version: @(#)pic.c 1.0.2 2018/10/17 + * Version: @(#)pic.c 1.0.4 2019/01/21 * * Author: Miran Grca, * @@ -61,7 +61,7 @@ pic_updatepending() { uint16_t temp_pending = 0; if (AT) { - if ((pic2.pend&~pic2.mask)&~pic2.mask2) + if ((pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; else pic.pend &= ~pic.icw3; @@ -135,7 +135,7 @@ pic_autoeoi() pic_update_mask(&pic.mask2, pic.ins); if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; } @@ -180,9 +180,9 @@ pic_write(uint16_t addr, uint8_t val, void *priv) } else { if (val & 16) { /*ICW1*/ pic.mask = 0; - pic.mask2=0; - pic.icw=1; - pic.icw1=val; + pic.mask2 = 0; + pic.icw = 1; + pic.icw1 = val; pic.ins = 0; pic_updatepending(); } @@ -208,7 +208,7 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic_update_mask(&pic.mask2, pic.ins); if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; } @@ -217,8 +217,8 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic.pend |= 1 << c; } - if (c==1 && keywaiting) - intclear&=~1; + if ((c == 1) && keywaiting) + intclear &= ~1; pic_updatepending(); return; } @@ -241,7 +241,10 @@ pic_read(uint16_t addr, void *priv) } if (pic.read) { pic_log("Read PIC ins %02X\n", pic.ins); - return pic.ins | (pic2.ins ? 4 : 0); + if (AT) + return pic.ins | (pic2.ins ? 4 : 0); + else + return pic.ins; } return pic.pend; } @@ -481,12 +484,27 @@ pic_process_interrupt(PIC* target_pic, int c) int pic_int = c & 7; int pic_int_num = 1 << pic_int; - if (pending & pic_int_num) { + int in_service = 0; +#if 0 + if (AT) { + in_service = (target_pic->ins & (pic_int_num - 1)); + if (c >= 8) + in_service |= (pic.ins & 0x03); + } + if (!AT) + in_service = (target_pic->ins & (pic_int_num - 1)); +#else + in_service = (target_pic->ins & (pic_int_num - 1)); + if (AT && (c >= 8)) + in_service |= (pic.ins & 0x03); +#endif + + if ((pending & pic_int_num) && !in_service) { target_pic->pend &= ~pic_int_num; target_pic->ins |= pic_int_num; pic_update_mask(&target_pic->mask2, target_pic->ins); - if (c >= 8) { + if (AT && (c >= 8)) { pic.ins |= (1 << pic2.icw3); /*Cascade IRQ*/ pic_update_mask(&pic.mask2, pic.ins); } @@ -494,7 +512,7 @@ pic_process_interrupt(PIC* target_pic, int c) pic_updatepending(); if (target_pic->icw4 & 0x02) - (c >= 8) ? pic2_autoeoi() : pic_autoeoi(); + (AT && (c >= 8)) ? pic2_autoeoi() : pic_autoeoi(); if (!c) pit_set_gate(&pit2, 0, 0); diff --git a/src/pit.c b/src/pit.c index 3ba096154..65c435cf1 100644 --- a/src/pit.c +++ b/src/pit.c @@ -48,19 +48,43 @@ void setrtcconst(float clock) void setpitclock(float clock) { + /* Some calculations are done differently 4.77 MHz, 7.16 MHz, and 9.54 MHz CPU's, so that + loss of precision is avoided and the various component kept in better synchronization. */ + cpuclock=clock; - PITCONST=clock/(1193181.0 + (2.0 / 3.0)); - CGACONST=(clock/(19687503.0/11.0)); + if (clock == 4772728.0) { + PITCONST=4.0; + CGACONST=(8.0 / 3.0); + } else if (clock == 7159092.0) { + /* 7.16 MHz CPU - simplify the calculation to avoid + loss of precision. */ + PITCONST=6.0; + CGACONST=4.0; + } else if (clock == 9545456.0) { + /* 9.54 MHz CPU - simplify the calculation to avoid + loss of precision. */ + PITCONST=8.0; + CGACONST=(8.0 / 1.5); + } else { + PITCONST=clock/1193182.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)); */ + + if (clock == 4772728.0) + xt_cpu_multi = 3 * (1 << TIMER_SHIFT); + else if (clock == 7159092.0) + xt_cpu_multi = 2 * (1 << TIMER_SHIFT); + else if (clock == 9545456.0) + xt_cpu_multi = (int64_t)(1.5*(double)(1 << TIMER_SHIFT)); + else + xt_cpu_multi = (int64_t)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + device_speed_changed(); } @@ -91,14 +115,6 @@ 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]); @@ -306,7 +322,7 @@ static void pit_over(PIT *pit, int t) int pit_get_timer_0() { - int read = (int)((int64_t)((pit.c[0] + ((1LL << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT); + int read = (int)((pit.c[0] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; if (pit.m[0] == 2) read++; if (read < 0) @@ -323,7 +339,7 @@ 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); + int read = (int)((pit->c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; if (pit->m[t] == 2) read++; if (read < 0) @@ -343,6 +359,7 @@ void pit_write(uint16_t addr, uint8_t val, void *p) { PIT *pit = (PIT *)p; int t; + double sv = 0.0; switch (addr&3) { @@ -439,7 +456,9 @@ void pit_write(uint16_t addr, uint8_t val, void *p) pit->wm[t]=0; break; } - speakval=(((float)pit->l[2]/(float)pit->l[0])*0x4000)-0x2000; + /* PIT latches are in fractions of 60 ms, so convert to sample using the formula below. */ + sv = (((double) pit->l[2]) / 60.0) * 16384.0; + speakval = ((int) sv) - 0x2000; if (speakval>0x2000) speakval=0x2000; break; } @@ -527,7 +546,7 @@ void pit_set_using_timer(PIT *pit, int t, int using_timer) 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->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(); diff --git a/src/printer/png.c b/src/printer/png.c index fbe3b39a0..752df0080 100644 --- a/src/printer/png.c +++ b/src/printer/png.c @@ -8,7 +8,7 @@ * * Provide centralized access to the PNG image handler. * - * Version: @(#)png.c 1.0.4 2018/10/07 + * Version: @(#)png.c 1.0.5 2018/11/19 * * Author: Fred N. van Kempen, * @@ -66,100 +66,40 @@ #endif -static void *png_handle = NULL; /* handle to DLL */ -# define PNGFUNC(x) PNG_ ## x +# define PNGFUNC(x) png_ ## x -/* Pointers to the real functions. */ -static png_structp (*PNG_create_write_struct)(png_const_charp user_png_ver, - png_voidp error_ptr, - png_error_ptr error_fn, - png_error_ptr warn_fn); -static void (*PNG_destroy_write_struct)(png_structpp png_ptr_ptr, - png_infopp info_ptr_ptr); -static png_infop (*PNG_create_info_struct)(png_const_structrp png_ptr); -static void (*PNG_init_io)(png_structrp png_ptr, png_FILE_p fp); -static void (*PNG_set_IHDR)(png_const_structrp png_ptr, - png_inforp info_ptr, png_uint_32 width, - png_uint_32 height, int bit_depth, - int color_type, int interlace_method, - int compression_method, - int filter_method); -static png_size_t (*PNG_get_rowbytes)(png_const_structrp png_ptr, - png_const_inforp info_ptr); -static void (*PNG_write_info)(png_structrp png_ptr, - png_const_inforp info_ptr); -static void (*PNG_write_image)(png_structrp png_ptr, - png_bytepp image); -static void (*PNG_write_row)(png_structrp png_ptr, - png_bytep row); -static void (*PNG_write_rows)(png_structrp png_ptr, - png_bytepp rows, int num); -static void (*PNG_write_end)(png_structrp png_ptr, - png_inforp info_ptr); +#ifdef ENABLE_ESCP_LOG +int png_do_log = ENABLE_ESCP_LOG; -static dllimp_t png_imports[] = { - { "png_create_write_struct", &PNG_create_write_struct }, - { "png_destroy_write_struct", &PNG_destroy_write_struct }, - { "png_create_info_struct", &PNG_create_info_struct }, - { "png_init_io", &PNG_init_io }, - { "png_set_IHDR", &PNG_set_IHDR }, - { "png_get_rowbytes", &PNG_get_rowbytes }, - { "png_write_info", &PNG_write_info }, - { "png_write_row", &PNG_write_row }, - { "png_write_rows", &PNG_write_rows }, - { "png_write_image", &PNG_write_image }, - { "png_write_end", &PNG_write_end }, - { NULL, NULL } -}; +static void +png_log(const char *fmt, ...) +{ + va_list ap; + + if (escp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define png_log(fmt, ...) +#endif static void error_handler(png_structp arg, const char *str) { - pclog("PNG: stream 0x%08lx error '%s'\n", arg, str); + png_log("PNG: stream 0x%08lx error '%s'\n", arg, str); } static void warning_handler(png_structp arg, const char *str) { - pclog("PNG: stream 0x%08lx warning '%s'\n", arg, str); -} - - -/* Prepare the PNG library for use, load DLL if needed. */ -int -png_load(void) -{ - const char *fn = PATH_PNG_DLL; - - /* If already loaded, good! */ - if (png_handle != NULL) return(1); - - /* Try loading the DLL. */ - png_handle = dynld_module(fn, png_imports); - if (png_handle == NULL) { - ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081); - pclog("PNG: unable to load '%s'; format disabled!\n", fn); - return(0); - } else - pclog("PNG: module '%s' loaded.\n", fn); - - return(1); -} - - -/* PNG library no longer needed, unload DLL if needed. */ -void -png_unload(void) -{ - /* Unload the DLL if possible. */ - if (png_handle != NULL) - dynld_close(png_handle); - - png_handle = NULL; + png_log("PNG: stream 0x%08lx warning '%s'\n", arg, str); } @@ -173,18 +113,15 @@ png_write_gray(wchar_t *fn, int inv, uint8_t *pix, int16_t w, int16_t h) int16_t x, y; FILE *fp; - /* Load the DLL if needed, give up if that fails. */ - if (! png_load()) return(0); - /* Create the image file. */ fp = plat_fopen(fn, L"wb"); if (fp == NULL) { /* Yes, this looks weird. */ if (fp == NULL) - pclog("PNG: file %ls could not be opened for writing!\n", fn); + png_log("PNG: file %ls could not be opened for writing!\n", fn); else error: - pclog("PNG: fatal error, bailing out, error = %i\n", errno); + png_log("PNG: fatal error, bailing out, error = %i\n", errno); if (png != NULL) PNGFUNC(destroy_write_struct)(&png, &info); if (fp != NULL) @@ -196,13 +133,13 @@ error: png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL, error_handler, warning_handler); if (png == NULL) { - pclog("PNG: create_write_struct failed!\n"); + png_log("PNG: create_write_struct failed!\n"); goto error; } info = PNGFUNC(create_info_struct)(png); if (info == NULL) { - pclog("PNG: create_info_struct failed!\n"); + png_log("PNG: create_info_struct failed!\n"); goto error; } @@ -247,103 +184,81 @@ error: /* Write the given BITMAP-format image as an 8-bit RGBA PNG image file. */ -int -png_write_rgb(wchar_t *fn, uint8_t *pix, int16_t w, int16_t h) +void +png_write_rgb(wchar_t *fn, uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE palcol) { png_structp png = NULL; png_infop info = NULL; - png_bytepp rows; - uint8_t *r, *b; - uint32_t *rgb; + png_bytep* rows; + png_color palette[256]; FILE *fp; - int y, x; - - /* Load the DLL if needed, give up if that fails. */ - if (! png_load()) return(0); + int i; /* Create the image file. */ fp = plat_fopen(fn, L"wb"); if (fp == NULL) { - pclog("PNG: File %ls could not be opened for writing!\n", fn); + png_log("PNG: File %ls could not be opened for writing!\n", fn); error: if (png != NULL) PNGFUNC(destroy_write_struct)(&png, &info); if (fp != NULL) (void)fclose(fp); - return(0); + return; } /* Initialize PNG stuff. */ png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL, error_handler, warning_handler); if (png == NULL) { - pclog("PNG: create_write_struct failed!\n"); + png_log("PNG: create_write_struct failed!\n"); goto error; } info = PNGFUNC(create_info_struct)(png); if (info == NULL) { - pclog("PNG: create_info_struct failed!\n"); + png_log("PNG: create_info_struct failed!\n"); goto error; } + /* Finalize the initing of png library */ PNGFUNC(init_io)(png, fp); + PNGFUNC(set_compression_level)(png, 9); - PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_RGB, + /* set other zlib parameters */ + PNGFUNC(set_compression_mem_level)(png, 8); + PNGFUNC(set_compression_strategy)(png, PNG_Z_DEFAULT_STRATEGY); + PNGFUNC(set_compression_window_bits)(png, 15); + PNGFUNC(set_compression_method)(png, 8); + PNGFUNC(set_compression_buffer_size)(png, 8192); + + PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - PNGFUNC(write_info)(png, info); + for (i = 0; i < 256; i++) { + palette[i].red = palcol[i].r; + palette[i].green = palcol[i].g; + palette[i].blue = palcol[i].b; + } + PNGFUNC(set_PLTE)(png, info, palette, 256); + /* Create a buffer for scanlines of pixels. */ - rows = (png_bytepp)malloc(sizeof(png_bytep) * h); - for (y = 0; y < h; y++) { + rows = (png_bytep *)malloc(sizeof(png_bytep) * h); + for (i = 0; i < h; i++) { /* Create a buffer for this scanline. */ - rows[y] = (png_bytep)malloc(PNGFUNC(get_rowbytes)(png, info)); + rows[i] = (pix + (i * pitch)); } - /* - * Process all scanlines in the image. - * - * Since the bitmap is in 'bottom-up' mode, we have to - * convert all pixels to RGB mode, but also 'flip' the - * image to the normal top-down mode. - */ - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - /* Get pointer to pixel in bitmap data. */ - b = &pix[((y * w) + x) * 4]; - - /* Transform if needed. */ - if (invert_display) { - rgb = (uint32_t *)b; - *rgb = video_color_transform(*rgb); - } - - /* Get pointer to png row data. */ - r = &rows[(h - 1) - y][x * 3]; - - /* Copy the pixel data. */ - r[0] = b[2]; - r[1] = b[1]; - r[2] = b[0]; - } - } - - /* Write image to the file. */ - PNGFUNC(write_image)(png, rows); - - /* No longer need the row buffers. */ - for (y = 0; y < h; y++) - free(rows[y]); - free(rows); - - PNGFUNC(write_end)(png, NULL); - - PNGFUNC(destroy_write_struct)(&png, &info); + PNGFUNC(set_rows)(png, info, rows); + + PNGFUNC(write_png)(png, info, 0, NULL); /* Clean up. */ - (void)fclose(fp); + (void)fclose(fp); - return(1); + PNGFUNC(destroy_write_struct)(&png, &info); + + /* No longer need the row buffers. */ + free(rows); } diff --git a/src/printer/png_struct.h b/src/printer/png_struct.h index 8aa306fb2..6647b41b9 100644 --- a/src/printer/png_struct.h +++ b/src/printer/png_struct.h @@ -8,7 +8,7 @@ * * Definitions for the centralized PNG image handler. * - * Version: @(#)png_struct.h 1.0.1 2018/09/01 + * Version: @(#)png_struct.h 1.0.2 2018/11/19 * * Author: Fred N. van Kempen, * @@ -52,14 +52,11 @@ extern "C" { #endif -extern int png_load(void); -extern void png_unload(void); - extern int png_write_gray(wchar_t *path, int invert, uint8_t *pix, int16_t w, int16_t h); -extern int png_write_rgb(wchar_t *fn, - uint8_t *pix, int16_t w, int16_t h); +extern void png_write_rgb(wchar_t *fn, + uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE palcol); #ifdef __cplusplus } diff --git a/src/printer/printer.h b/src/printer/printer.h index f5fe558ff..88e52f8f5 100644 --- a/src/printer/printer.h +++ b/src/printer/printer.h @@ -58,7 +58,8 @@ #define FONT_FILE_OCRB L"ocra.ttf" -extern const uint16_t *select_codepage(uint16_t num); +extern const void +select_codepage(uint16_t code, uint16_t *curmap); #endif /*PRINTER_H*/ diff --git a/src/printer/prt_cpmap.c b/src/printer/prt_cpmap.c index 5540f1872..d29ace8a4 100644 --- a/src/printer/prt_cpmap.c +++ b/src/printer/prt_cpmap.c @@ -572,18 +572,22 @@ static const struct { /* Select a ASCII->Unicode mapping by CP number */ -const uint16_t * -select_codepage(uint16_t code) +const void +select_codepage(uint16_t code, uint16_t *curmap) { - int i; + int i = 0; + const uint16_t *map_to_use; - for (i = 0; maps[i].code != -1; i++) - if (maps[i].code == code) return(maps[i].map); + map_to_use = maps[0].map; - if (code == 0) - return(maps[0].map); - - //ERRLOG("CPMAP: unsupported code page %i, using CP437...\n", code); - - return(maps[0].map); + while (maps[i].code != 0) { + if (maps[i].code == code) { + map_to_use = maps[i].map; + break; + } + i++; + } + + for (i = 0; i < 256; i++) + curmap[i] = map_to_use[i]; } diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index a08c625bf..0a711e2ea 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -66,6 +66,7 @@ #include "../plat_dynld.h" #include "../ui.h" #include "../lpt.h" +#include "../video/video.h" #include "png_struct.h" #include "printer.h" #include "prt_devs.h" @@ -74,7 +75,7 @@ /* Default page values (for now.) */ #define COLOR_BLACK 7<<5 #define PAGE_WIDTH 8.5 /* standard U.S. Letter */ -#define PAGE_HEIGHT 11 +#define PAGE_HEIGHT 11.0 #define PAGE_LMARGIN 0.0 #define PAGE_RMARGIN PAGE_WIDTH #define PAGE_TMARGIN 0.0 @@ -85,7 +86,7 @@ #ifdef _WIN32 -# define PATH_FREETYPE_DLL "libfreetype-6.dll" +# define PATH_FREETYPE_DLL "freetype.dll" #else # define PATH_FREETYPE_DLL "libfreetype.so.6" #endif @@ -179,8 +180,8 @@ static dllimp_t ft_imports[] = { /* Some helper macros. */ #define PARAM16(x) (dev->esc_parms[x+1] * 256 + dev->esc_parms[x]) -#define PIXX ((uint32_t)floor(dev->curr_x * dev->dpi + 0.5)) -#define PIXY ((uint32_t)floor(dev->curr_y * dev->dpi + 0.5)) +#define PIXX ((unsigned)floor(dev->curr_x * dev->dpi + 0.5)) +#define PIXY ((unsigned)floor(dev->curr_y * dev->dpi + 0.5)) typedef struct { @@ -198,6 +199,9 @@ typedef struct { typedef struct { const char *name; + int64_t timeout; + + wchar_t page_fn[260]; uint8_t color; /* page data (TODO: make configurable) */ @@ -218,9 +222,9 @@ typedef struct { /* tabstops */ double horizontal_tabs[32]; - int16_t num_horizontal_tabs; + uint8_t num_horizontal_tabs; double vertical_tabs[16]; - int16_t num_vertical_tabs; + uint8_t num_vertical_tabs; /* bit graphics data */ uint16_t bg_h_density; /* in dpi */ @@ -233,12 +237,12 @@ typedef struct { /* handshake data */ uint8_t data; - int8_t ack; - int8_t select; - int8_t busy; - int8_t int_pending; - int8_t error; - int8_t autofeed; + uint8_t ack; + uint8_t select; + uint8_t busy; + uint8_t int_pending; + uint8_t error; + uint8_t autofeed; /* ESC command data */ int8_t esc_seen; /* set to 1 if an ESC char was seen */ @@ -246,7 +250,7 @@ typedef struct { uint16_t esc_pending; /* in which ESC command are we */ uint8_t esc_parms_req; uint8_t esc_parms_curr; - uint8_t esc_parms[10]; /* 10 should be enough for everybody */ + uint8_t esc_parms[20]; /* 20 should be enough for everybody */ /* internal page data */ wchar_t fontpath[1024]; @@ -256,14 +260,14 @@ typedef struct { uint16_t current_font; FT_Face fontface; int8_t lq_typeface; - int8_t font_style; - int8_t print_quality; + uint16_t font_style; + uint8_t print_quality; uint8_t font_score; double extra_intra_space; /* extra spacing between chars (inch) */ /* other internal data */ uint16_t char_tables[4]; /* the character tables for ESC t */ - uint16_t curr_char_table; /* the active char table index */ + uint8_t curr_char_table; /* the active char table index */ uint16_t curr_cpmap[256]; /* current ASCII->Unicode map table */ int8_t multipoint_mode; /* multipoint mode, ESC X */ @@ -281,14 +285,33 @@ typedef struct { double defined_unit; /* internal unit for some ESC/P * commands. -1 = use default */ - int8_t msb; /* MSB mode, -1 = off */ + uint8_t msb; /* MSB mode, -1 = off */ uint8_t ctrl; + + uint8_t char_read; + + PALETTE palcol; } escp_t; +static void +update_font(escp_t *dev); +static void +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add); +static void +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken); +static void +init_codepage(escp_t *dev, uint16_t num); +static void +reset_printer(escp_t *dev); +static void +setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns); +static void +print_bit_graph(escp_t *dev, uint8_t ch); static void new_page(escp_t *dev, int8_t save, int8_t resetx); + /* Codepage table, needed for ESC t ( */ static const uint16_t codepages[15] = { 0, 437, 932, 850, 851, 853, 855, 860, @@ -349,157 +372,24 @@ static const uint16_t intCharSets[15][12] = { }; -/* Select a ASCII->Unicode mapping by CP number */ -static void -init_codepage(escp_t *dev, uint16_t num) -{ - const uint16_t *cp; - - /* Get the codepage map for this number. */ - cp = select_codepage(num); - - /* Copy the map over since it might get modified later. */ - memcpy(dev->curr_cpmap, cp, 256 * sizeof(uint16_t)); -} +#ifdef ENABLE_ESCP_LOG +int escp_do_log = ENABLE_ESCP_LOG; static void -update_font(escp_t *dev) +escp_log(const char *fmt, ...) { - wchar_t path[1024]; - wchar_t *fn; - char temp[1024]; - FT_Matrix matrix; - double hpoints = 10.5; - double vpoints = 10.5; + va_list ap; - /* We need the FreeType library. */ - if (ft_lib == NULL) return; - - /* Release current font if we have one. */ - if (dev->fontface) - ft_Done_Face(dev->fontface); - - if (dev->print_quality == QUALITY_DRAFT) { - fn = FONT_FILE_DOTMATRIX; - } - else { - switch (dev->lq_typeface) { - case TYPEFACE_ROMAN: - //pclog("Roman TTF\n"); - fn = FONT_FILE_ROMAN; - break; - - case TYPEFACE_SANSSERIF: - //pclog("Sansserif TTF\n"); - fn = FONT_FILE_SANSSERIF; - break; - - case TYPEFACE_COURIER: - //pclog("Courier TTF\n"); - fn = FONT_FILE_COURIER; - break; - - case TYPEFACE_SCRIPT: - //pclog("Script TTF\n"); - fn = FONT_FILE_SCRIPT; - break; - - case TYPEFACE_OCRA: - //pclog("Ocra TTF\n"); - fn = FONT_FILE_OCRA; - break; - - case TYPEFACE_OCRB: - //pclog("Ocrb TTF\n"); - fn = FONT_FILE_OCRB; - break; - - default: - //pclog("Dot matrix TTF\n"); - fn = FONT_FILE_DOTMATRIX; - } - } - - /* Create a full pathname for the ROM file. */ - wcscpy(path, dev->fontpath); - wcscat(path, fn); - - /* Convert (back) to ANSI for the FreeType API. */ - wcstombs(temp, path, sizeof(temp)); - - //pclog("Font face=%d\n", dev->fontface); - - /* Load the new font. */ - if (ft_New_Face(ft_lib, temp, 0, &dev->fontface)) { - //pclog("ESC/P: unable to load font '%s'\n", temp); - //pclog("ESC/P: text printing disabled\n"); - dev->fontface = 0; - } - - if (dev->multipoint_mode == 0) { - dev->actual_cpi = dev->cpi; - - if ((dev->cpi != 10.0) && !(dev->font_style & STYLE_CONDENSED)) { - hpoints *= 10.0 / dev->cpi; - vpoints *= 10.0 / dev->cpi; - } - - if (! (dev->font_style & STYLE_PROP)) { - if ((dev->cpi == 10.0) && (dev->font_style & STYLE_CONDENSED)) { - dev->actual_cpi = 17.14; - hpoints *= 10.0 / 17.14; - vpoints *= 10.0 / 17.14; - } - - if ((dev->cpi == 12) && (dev->font_style & STYLE_CONDENSED)) { - dev->actual_cpi = 20.0; - hpoints *= 10.0 / 20.0; - vpoints *= 10.0 / 20.0; - } - } - - if (dev->font_style & (STYLE_PROP | STYLE_CONDENSED)) { - hpoints /= 2.0; - vpoints /= 2.0; - } - - if ((dev->font_style & STYLE_DOUBLEWIDTH) || - (dev->font_style & STYLE_DOUBLEWIDTHONELINE)) { - dev->actual_cpi /= 2.0; - hpoints *= 2.0; - } - - if (dev->font_style & STYLE_DOUBLEHEIGHT) - vpoints *= 2.0; - } else { - /* Multipoint mode. */ - dev->actual_cpi = dev->multipoint_cpi; - hpoints = vpoints = dev->multipoint_size; - } - - if ((dev->font_style & STYLE_SUPERSCRIPT) || - (dev->font_style & STYLE_SUBSCRIPT)) { - hpoints *= 2.0 / 3.0; - vpoints *= 2.0 / 3.0; - dev->actual_cpi /= 2.0 / 3.0; - } - - ft_Set_Char_Size(dev->fontface, - (uint16_t)(hpoints * 64), - (uint16_t)(vpoints * 64), - dev->dpi, dev->dpi); - - if ((dev->font_style & STYLE_ITALICS) || - (dev->char_tables[dev->curr_char_table] == 0)) { - /* Italics transformation. */ - matrix.xx = 0x10000L; - matrix.xy = (FT_Fixed)(0.20 * 0x10000L); - matrix.yx = 0; - matrix.yy = 0x10000L; - ft_Set_Transform(dev->fontface, &matrix, 0); - } + if (escp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } } +#else +#define escp_log(fmt, ...) +#endif /* Dump the current page into a formatted file. */ @@ -507,12 +397,10 @@ static void dump_page(escp_t *dev) { wchar_t path[1024]; - wchar_t temp[128]; wcscpy(path, dev->pagepath); - plat_tempfile(temp, NULL, L".png"); - wcscat(path, temp); - png_write_gray(path, 1, dev->page->pixels, dev->page->w, dev->page->h); + wcscat(path, dev->page_fn); + png_write_rgb(path, dev->page->pixels, dev->page->w, dev->page->h, dev->page->pitch, dev->palcol); } @@ -528,86 +416,1360 @@ new_page(escp_t *dev, int8_t save, int8_t resetx) /* Clear page. */ dev->curr_y = dev->top_margin; dev->page->dirty = 0; - memset(dev->page->pixels, 0x00, dev->page->h * dev->page->pitch); + memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); + + /* Make the page's file name. */ + plat_tempfile(dev->page_fn, NULL, L".png"); +} + + +static void +timeout_timer(void *priv) +{ + escp_t *dev = (escp_t *) priv; + + if (dev->page->dirty) + new_page(dev, 1, 1); + + dev->timeout = 0LL; +} + + +static void +fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, escp_t *dev) +{ + uint8_t colormask; + int i; + + float red = (float)redmax / (float)30.9; + float green = (float)greenmax / (float)30.9; + float blue = (float)bluemax / (float)30.9; + + colormask = colorID<<=5; + + for(i = 0; i < 32; i++) { + dev->palcol[i+colormask].r = 255 - (uint8_t)floor(red * (float)i); + dev->palcol[i+colormask].g = 255 - (uint8_t)floor(green * (float)i); + dev->palcol[i+colormask].b = 255 - (uint8_t)floor(blue * (float)i); + } } static void reset_printer(escp_t *dev) { - int16_t i; + int i; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; - dev->page_width = PAGE_WIDTH; - dev->page_height = PAGE_HEIGHT; - dev->left_margin = PAGE_LMARGIN; - dev->right_margin = PAGE_RMARGIN; - dev->top_margin = PAGE_TMARGIN; - dev->bottom_margin = PAGE_BMARGIN; - dev->dpi = PAGE_DPI; - dev->cpi = PAGE_CPI; - dev->lpi = PAGE_LPI; - - dev->hmi = -1.0; dev->curr_x = dev->curr_y = 0.0; - dev->linespacing = 1.0 / dev->lpi; - - dev->char_tables[0] = 0; /* italics */ - dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ - dev->curr_char_table = 1; - init_codepage(dev, dev->char_tables[dev->curr_char_table]); - - dev->num_horizontal_tabs = 32; - for (i = 0; i < 32; i++) - dev->horizontal_tabs[i] = i * 8.0 / dev->cpi; - dev->num_vertical_tabs = -1; - - dev->current_font = FONT_COURIER; - dev->lq_typeface = TYPEFACE_COURIER; - dev->fontface = 0; - dev->multipoint_mode = 0; - dev->multipoint_size = 0.0; - dev->multipoint_cpi = 0.0; - dev->font_style = 0; - dev->font_score = 0; - dev->print_quality = QUALITY_DRAFT; - - dev->bg_h_density = dev->bg_v_density = 0; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = dev->bg_bytes_read = 0; - dev->bg_remaining_bytes = 0; - memset(dev->bg_column, 0x00, sizeof(dev->bg_column)); - dev->esc_seen = 0; dev->fss_seen = 0; dev->esc_pending = 0; dev->esc_parms_req = dev->esc_parms_curr = 0; - memset(dev->esc_parms, 0x00, sizeof(dev->esc_parms)); - - dev->msb = -1; - dev->print_everything_count = 0; - dev->print_upper_control = 0; - if (dev->page != NULL) - dev->page->dirty = 0; + dev->top_margin = dev->left_margin = 0.0; + dev->right_margin = dev->page_width = PAGE_WIDTH; + dev->bottom_margin = dev->page_height = PAGE_HEIGHT; + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; dev->extra_intra_space = 0.0; - dev->defined_unit = -1.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; dev->density_k = 0; dev->density_l = 1; dev->density_y = 2; - dev->density_z = 3; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ + dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ + dev->defined_unit = -1.0; + dev->multipoint_mode = 0; + dev->multipoint_size = 0.0; + dev->multipoint_cpi = 0.0; + dev->hmi = -1; + dev->msb = 255; + dev->print_everything_count = 0; + dev->lq_typeface = TYPEFACE_COURIER; + + init_codepage(dev, dev->char_tables[dev->curr_char_table]); update_font(dev); - //pclog("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", - //dev->page_width, dev->page_height, - //(int)dev->dpi, (int)dev->cpi, (int)dev->lpi); + new_page(dev, 0, 1); + + for (i = 0; i < 32; i++) + dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); + dev->num_horizontal_tabs = 32; + dev->num_vertical_tabs = 255; + + if (dev->page != NULL) + dev->page->dirty = 0; + + escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", + dev->page_width, dev->page_height, (int)dev->dpi, + (int)dev->cpi, (int)dev->lpi); +} + + +static void +reset_printer_hard(escp_t *dev) +{ + dev->char_read = 0; + dev->timeout = 0LL; + reset_printer(dev); +} + + +/* Select a ASCII->Unicode mapping by CP number */ +static void +init_codepage(escp_t *dev, uint16_t num) +{ + /* Get the codepage map for this number. */ + select_codepage(num, dev->curr_cpmap); +} + + +static void +update_font(escp_t *dev) +{ + wchar_t path[1024]; + wchar_t *fn; + char temp[1024]; + FT_Matrix matrix; + double hpoints = 10.5; + double vpoints = 10.5; + + /* We need the FreeType library. */ + if (ft_lib == NULL) + return; + + /* Release current font if we have one. */ + if (dev->fontface) + ft_Done_Face(dev->fontface); + + if (dev->print_quality == QUALITY_DRAFT) + fn = FONT_FILE_DOTMATRIX; + else switch (dev->lq_typeface) { + case TYPEFACE_ROMAN: + fn = FONT_FILE_ROMAN; + break; + case TYPEFACE_SANSSERIF: + fn = FONT_FILE_SANSSERIF; + break; + case TYPEFACE_COURIER: + fn = FONT_FILE_COURIER; + break; + case TYPEFACE_SCRIPT: + fn = FONT_FILE_SCRIPT; + break; + case TYPEFACE_OCRA: + fn = FONT_FILE_OCRA; + break; + case TYPEFACE_OCRB: + fn = FONT_FILE_OCRB; + break; + default: + fn = FONT_FILE_DOTMATRIX; + } + + /* Create a full pathname for the ROM file. */ + wcscpy(path, dev->fontpath); + plat_path_slash(path); + wcscat(path, fn); + + /* Convert (back) to ANSI for the FreeType API. */ + wcstombs(temp, path, sizeof(temp)); + + escp_log("Temp file=%s\n", temp); + + /* Load the new font. */ + if (ft_New_Face(ft_lib, temp, 0, &dev->fontface)) { + escp_log("ESC/P: unable to load font '%s'\n", temp); + dev->fontface = NULL; + } + + if (!dev->multipoint_mode) { + dev->actual_cpi = dev->cpi; + + if (!(dev->font_style & STYLE_CONDENSED)) { + hpoints *= 10.0 / dev->cpi; + vpoints *= 10.0 / dev->cpi; + } + + if (!(dev->font_style & STYLE_PROP)) { + if ((dev->cpi == 10.0) && (dev->font_style & STYLE_CONDENSED)) { + dev->actual_cpi = 17.14; + hpoints *= 10.0 / 17.14; + } + + if ((dev->cpi == 12) && (dev->font_style & STYLE_CONDENSED)) { + dev->actual_cpi = 20.0; + hpoints *= 10.0 / 20.0; + vpoints *= 10.0 / 12.0; + } + } + else if (dev->font_style & STYLE_CONDENSED) + hpoints /= 2.0; + + if ((dev->font_style & STYLE_DOUBLEWIDTH) || + (dev->font_style & STYLE_DOUBLEWIDTHONELINE)) { + dev->actual_cpi /= 2.0; + hpoints *= 2.0; + } + + if (dev->font_style & STYLE_DOUBLEHEIGHT) + vpoints *= 2.0; + } else { + /* Multipoint mode. */ + dev->actual_cpi = dev->multipoint_cpi; + hpoints = vpoints = dev->multipoint_size; + } + + if ((dev->font_style & STYLE_SUPERSCRIPT) || (dev->font_style & STYLE_SUBSCRIPT)) { + hpoints *= 2.0 / 3.0; + vpoints *= 2.0 / 3.0; + dev->actual_cpi /= 2.0 / 3.0; + } + + ft_Set_Char_Size(dev->fontface, + (uint16_t)(hpoints * 64), (uint16_t)(vpoints * 64), + dev->dpi, dev->dpi); + + if ((dev->font_style & STYLE_ITALICS) || + (dev->char_tables[dev->curr_char_table] == 0)) { + /* Italics transformation. */ + matrix.xx = 0x10000L; + matrix.xy = (FT_Fixed)(0.20 * 0x10000L); + matrix.yx = 0; + matrix.yy = 0x10000L; + ft_Set_Transform(dev->fontface, &matrix, 0); + } +} + + +/* This is the actual ESC/P interpreter. */ +static int +process_char(escp_t *dev, uint8_t ch) +{ + double new_x, new_y; + double move_to; + double unit_size; + double reverse; + double new_top, new_bottom; + uint16_t rel_move; + int16_t i; + + escp_log("Esc_seen=%d, fss_seen=%d\n", dev->esc_seen, dev->fss_seen); + /* Determine number of additional command params that are expected. */ + if (dev->esc_seen || dev->fss_seen) { + dev->esc_pending = ch; + if (dev->fss_seen) + dev->esc_pending |= 0x800; + dev->esc_seen = dev->fss_seen = 0; + dev->esc_parms_curr = 0; + + escp_log("Command pending=%02x, font path=%ls\n", dev->esc_pending, dev->fontpath); + switch (dev->esc_pending) { + case 0x02: // Undocumented + case 0x0a: // Reverse line feed + case 0x0c: // Return to top of current page + case 0x0e: // Select double-width printing (one line) (ESC SO) + case 0x0f: // Select condensed printing (ESC SI) + case 0x23: // Cancel MSB control (ESC #) + case 0x30: // Select 1/8-inch line spacing (ESC 0) + case 0x31: // Select 7/60-inch line spacing + case 0x32: // Select 1/6-inch line spacing (ESC 2) + case 0x34: // Select italic font (ESC 4) + case 0x35: // Cancel italic font (ESC 5) + case 0x36: // Enable printing of upper control codes (ESC 6) + case 0x37: // Enable upper control codes (ESC 7) + case 0x38: // Disable paper-out detector + case 0x39: // Enable paper-out detector + case 0x3c: // Unidirectional mode (one line) (ESC <) + case 0x3d: // Set MSB to 0 (ESC =) + case 0x3e: // Set MSB to 1 (ESC >) + case 0x40: // Initialize printer (ESC @) + case 0x45: // Select bold font (ESC E) + case 0x46: // Cancel bold font (ESC F) + case 0x47: // Select double-strike printing (ESC G) + case 0x48: // Cancel double-strike printing (ESC H) + case 0x4d: // Select 10.5-point, 12-cpi (ESC M) + case 0x4f: // Cancel bottom margin + case 0x50: // Select 10.5-point, 10-cpi (ESC P) + case 0x54: // Cancel superscript/subscript printing (ESC T) + case 0x5e: // Enable printing of all character codes on next character + case 0x67: // Select 10.5-point, 15-cpi (ESC g) + + case 0x834: // Select italic font (FS 4) (= ESC 4) + case 0x835: // Cancel italic font (FS 5) (= ESC 5) + case 0x846: // Select forward feed mode (FS F) + case 0x852: // Select reverse feed mode (FS R) + dev->esc_parms_req = 0; + break; + + case 0x19: // Control paper loading/ejecting (ESC EM) + case 0x20: // Set intercharacter space (ESC SP) + case 0x21: // Master select (ESC !) + case 0x2b: // Set n/360-inch line spacing (ESC +) + case 0x2d: // Turn underline on/off (ESC -) + case 0x2f: // Select vertical tab channel (ESC /) + case 0x33: // Set n/180-inch line spacing (ESC 3) + case 0x41: // Set n/60-inch line spacing + case 0x43: // Set page length in lines (ESC C) + case 0x49: // Select character type and print pitch + case 0x4a: // Advance print position vertically (ESC J n) + case 0x4e: // Set bottom margin (ESC N) + case 0x51: // Set right margin (ESC Q) + case 0x52: // Select an international character set (ESC R) + case 0x53: // Select superscript/subscript printing (ESC S) + case 0x55: // Turn unidirectional mode on/off (ESC U) + case 0x57: // Turn double-width printing on/off (ESC W) + case 0x61: // Select justification (ESC a) + case 0x66: // Absolute horizontal tab in columns [conflict] + case 0x68: // Select double or quadruple size + case 0x69: // Immediate print + case 0x6a: // Reverse paper feed + case 0x6b: // Select typeface (ESC k) + case 0x6c: // Set left margin (ESC 1) + case 0x70: // Turn proportional mode on/off (ESC p) + case 0x72: // Select printing color (ESC r) + case 0x73: // Select low-speed mode (ESC s) + case 0x74: // Select character table (ESC t) + case 0x77: // Turn double-height printing on/off (ESC w) + case 0x78: // Select LQ or draft (ESC x) + case 0x7e: // Select/Deselect slash zero (ESC ~) + case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) + case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) + case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) + case 0x843: // Select LQ type style (FS C) (= ESC k) + case 0x845: // Select character width (FS E) + case 0x849: // Select character table (FS I) (= ESC t) + case 0x853: // Select High Speed/High Density elite pitch (FS S) + case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + dev->esc_parms_req = 1; + break; + + case 0x24: // Set absolute horizontal print position (ESC $) + case 0x3f: // Reassign bit-image mode (ESC ?) + case 0x4b: // Select 60-dpi graphics (ESC K) + case 0x4c: // Select 120-dpi graphics (ESC L) + case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) + case 0x5a: // Select 240-dpi graphics (ESC Z) + case 0x5c: // Set relative horizontal print position (ESC \) + case 0x63: // Set horizontal motion index (HMI) (ESC c) + case 0x65: // Set vertical tab stops every n lines (ESC e) + case 0x85a: // Print 24-bit hex-density graphics (FS Z) + dev->esc_parms_req = 2; + break; + + case 0x2a: // Select bit image (ESC *) + case 0x58: // Select font by pitch and point (ESC X) + dev->esc_parms_req = 3; + break; + + case 0x5b: // Select character height, width, line spacing + dev->esc_parms_req = 7; + break; + + case 0x62: // Set vertical tabs in VFU channels (ESC b) + case 0x42: // Set vertical tabs (ESC B) + dev->num_vertical_tabs = 0; + return 1; + + case 0x44: // Set horizontal tabs (ESC D) + dev->num_horizontal_tabs = 0; + return 1; + + case 0x25: // Select user-defined set (ESC %) + case 0x26: // Define user-defined characters (ESC &) + case 0x3a: // Copy ROM to RAM (ESC :) + escp_log("ESC/P: User-defined characters not supported (0x%02x).\n", dev->esc_pending); + return 1; + + case 0x28: // Two bytes sequence + /* return and wait for second ESC byte */ + return 1; + + case 0x2e: + fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); + exit(-1); + return 1; + + default: + escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", + dev->esc_pending >= 0x20 ? dev->esc_pending : '?', dev->esc_pending); + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + + if (dev->esc_parms_req > 0) { + /* return and wait for parameters to appear */ + return 1; + } + } + + /* parameter checking for the 2-byte ESC/P2 commands */ + if (dev->esc_pending == '(') { + dev->esc_pending = 0x0200 + ch; + + escp_log("Two-byte command pending=%03x, font path=%ls\n", dev->esc_pending, dev->fontpath); + switch (dev->esc_pending) { + case 0x0242: // Bar code setup and print (ESC (B) + case 0x025e: // Print data as characters (ESC (^) + dev->esc_parms_req = 2; + break; + + case 0x0255: // Set unit (ESC (U) + dev->esc_parms_req = 3; + break; + + case 0x0243: // Set page length in defined unit (ESC (C) + case 0x0256: // Set absolute vertical print position (ESC (V) + case 0x0276: // Set relative vertical print position (ESC (v) + dev->esc_parms_req = 4; + break; + + case 0x0228: // Assign character table (ESC (t) + case 0x022d: // Select line/score (ESC (-) + dev->esc_parms_req = 5; + break; + + case 0x0263: // Set page format (ESC (c) + dev->esc_parms_req = 6; + break; + + default: + /* ESC ( commands are always followed by a "number of parameters" word parameter */ + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; /* dummy value to be checked later */ + return 1; + } + + /* If we need parameters, return and wait for them to appear. */ + if (dev->esc_parms_req > 0) + return 1; + } + + /* Ignore VFU channel setting. */ + if (dev->esc_pending == 0x62) { + dev->esc_pending = 0x42; + return 1; + } + + /* Collect vertical tabs. */ + if (dev->esc_pending == 0x42) { + /* check if we're done */ + if ((ch == 0) || + (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double)ch * dev->linespacing)) { + dev->esc_pending = 0; + } else { + if (dev->num_vertical_tabs < 16) + dev->vertical_tabs[dev->num_vertical_tabs++] = (double)ch * dev->linespacing; + } + } + + /* Collect horizontal tabs. */ + if (dev->esc_pending == 0x44) { + /* check if we're done... */ + if ((ch == 0) || + (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double)ch * (1.0 / dev->cpi))) { + dev->esc_pending = 0; + } else { + if (dev->num_horizontal_tabs < 32) + dev->horizontal_tabs[dev->num_horizontal_tabs++] = (double)ch * (1.0 / dev->cpi); + } + } + + /* Check if we're still collecting parameters for the current command. */ + if (dev->esc_parms_curr < dev->esc_parms_req) { + /* store current parameter */ + dev->esc_parms[dev->esc_parms_curr++] = ch; + + /* do we still need to continue collecting parameters? */ + if (dev->esc_parms_curr < dev->esc_parms_req) + return 1; + } + + /* Handle the pending ESC command. */ + if (dev->esc_pending != 0) { + switch (dev->esc_pending) { + case 0x02: /* undocumented; ignore */ + break; + + case 0x0e: /* select double-width (one line) (ESC SO) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + break; + + case 0x0f: /* select condensed printing (ESC SI) */ + if (! dev->multipoint_mode && (dev->cpi != 15.0)) { + dev->hmi = -1; + dev->font_style |= STYLE_CONDENSED; + update_font(dev); + } + break; + + case 0x19: /* control paper loading/ejecting (ESC EM) */ + /* We are not really loading paper, so most + * commands can be ignored */ + if (dev->esc_parms[0] == 'R') + new_page(dev, 1, 0); + + break; + case 0x20: /* set intercharacter space (ESC SP) */ + if (! dev->multipoint_mode) { + dev->extra_intra_space = (double)dev->esc_parms[0] / (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + dev->hmi = -1; + update_font(dev); + } + break; + + case 0x21: /* master select (ESC !) */ + dev->cpi = dev->esc_parms[0] & 0x01 ? 12.0 : 10.0; + + /* Reset first seven bits. */ + dev->font_style &= 0xFF80; + if (dev->esc_parms[0] & 0x02) + dev->font_style |= STYLE_PROP; + if (dev->esc_parms[0] & 0x04) + dev->font_style |= STYLE_CONDENSED; + if (dev->esc_parms[0] & 0x08) + dev->font_style |= STYLE_BOLD; + if (dev->esc_parms[0] & 0x10) + dev->font_style |= STYLE_DOUBLESTRIKE; + if (dev->esc_parms[0] & 0x20) + dev->font_style |= STYLE_DOUBLEWIDTH; + if (dev->esc_parms[0] & 0x40) + dev->font_style |= STYLE_ITALICS; + if (dev->esc_parms[0] & 0x80) { + dev->font_score = SCORE_SINGLE; + dev->font_style |= STYLE_UNDERLINE; + } + + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x23: /* cancel MSB control (ESC #) */ + dev->msb = 255; + break; + + case 0x24: /* set abs horizontal print position (ESC $) */ + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = 60.0; + + new_x = dev->left_margin + ((double)PARAM16(0) / unit_size); + if (new_x <= dev->right_margin) + dev->curr_x = new_x; + break; + + case 0x85a: /* Print 24-bit hex-density graphics (FS Z) */ + setup_bit_image(dev, 40, PARAM16(0)); + break; + + case 0x2a: /* select bit image (ESC *) */ + setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); + break; + + case 0x2b: /* set n/360-inch line spacing (ESC +) */ + case 0x833: /* Set n/360-inch line spacing (FS 3) */ + dev->linespacing = (double)dev->esc_parms[0] / 360.0; + break; + + case 0x2d: /* turn underline on/off (ESC -) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_UNDERLINE; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->font_style |= STYLE_UNDERLINE; + dev->font_score = SCORE_SINGLE; + } + update_font(dev); + break; + + case 0x2f: /* select vertical tab channel (ESC /) */ + /* Ignore */ + break; + + case 0x30: /* select 1/8-inch line spacing (ESC 0) */ + dev->linespacing = 1.0 / 8.0; + break; + + case 0x31: /* select 7/60-inch line spacing */ + dev->linespacing = 7.0 / 60.0; + break; + + case 0x32: /* select 1/6-inch line spacing (ESC 2) */ + dev->linespacing = 1.0 / 6.0; + break; + + case 0x33: /* set n/180-inch line spacing (ESC 3) */ + dev->linespacing = (double)dev->esc_parms[0] / 180.0; + break; + + case 0x34: /* select italic font (ESC 4) */ + dev->font_style |= STYLE_ITALICS; + update_font(dev); + break; + + case 0x35: /* cancel italic font (ESC 5) */ + dev->font_style &= ~STYLE_ITALICS; + update_font(dev); + break; + + case 0x36: /* enable printing of upper control codes (ESC 6) */ + dev->print_upper_control = 1; + break; + + case 0x37: /* enable upper control codes (ESC 7) */ + dev->print_upper_control = 0; + break; + + case 0x3c: /* unidirectional mode (one line) (ESC <) */ + /* We don't have a print head, so just + * ignore this. */ + break; + + case 0x3d: /* set MSB to 0 (ESC =) */ + dev->msb = 0; + break; + + case 0x3e: /* set MSB to 1 (ESC >) */ + dev->msb = 1; + break; + + case 0x3f: /* reassign bit-image mode (ESC ?) */ + if (dev->esc_parms[0] == 'K') + dev->density_k = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'L') + dev->density_l = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'Y') + dev->density_y = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'Z') + dev->density_z = dev->esc_parms[1]; + break; + + case 0x40: /* initialize printer (ESC @) */ + reset_printer(dev); + break; + + case 0x41: /* set n/60-inch line spacing */ + case 0x841: + dev->linespacing = (double)dev->esc_parms[0] / 60.0; + break; + + case 0x43: /* set page length in lines (ESC C) */ + if (dev->esc_parms[0] != 0) { + dev->page_height = dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; + } else { /* == 0 => Set page length in inches */ + dev->esc_parms_req = 1; + dev->esc_parms_curr = 0; + dev->esc_pending = 0x100; /* dummy value for later */ + return 1; + } + break; + + case 0x45: /* select bold font (ESC E) */ + dev->font_style |= STYLE_BOLD; + update_font(dev); + break; + + case 0x46: /* cancel bold font (ESC F) */ + dev->font_style &= ~STYLE_BOLD; + update_font(dev); + break; + + case 0x47: /* select dobule-strike printing (ESC G) */ + dev->font_style |= STYLE_DOUBLESTRIKE; + break; + + case 0x48: /* cancel double-strike printing (ESC H) */ + dev->font_style &= ~STYLE_DOUBLESTRIKE; + break; + + case 0x4a: /* advance print pos vertically (ESC J n) */ + dev->curr_y += (double)((double)dev->esc_parms[0] / 180.0); + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + break; + + case 0x4b: /* select 60-dpi graphics (ESC K) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_k, PARAM16(0)); + break; + + case 0x4c: /* select 120-dpi graphics (ESC L) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_l, PARAM16(0)); + break; + + case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ + dev->cpi = 12.0; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x4e: /* set bottom margin (ESC N) */ + dev->top_margin = 0.0; + dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; + break; + + case 0x4f: /* cancel bottom (and top) margin */ + dev->top_margin = 0.0; + dev->bottom_margin = dev->page_height; + break; + + case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ + dev->cpi = 10.0; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x51: /* set right margin */ + dev->right_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; + break; + + case 0x52: /* select an intl character set (ESC R) */ + if (dev->esc_parms[0] <= 13 || dev->esc_parms[0] == '@') { + if (dev->esc_parms[0] == '@') + dev->esc_parms[0] = 14; + + dev->curr_cpmap[0x23] = intCharSets[dev->esc_parms[0]][0]; + dev->curr_cpmap[0x24] = intCharSets[dev->esc_parms[0]][1]; + dev->curr_cpmap[0x40] = intCharSets[dev->esc_parms[0]][2]; + dev->curr_cpmap[0x5b] = intCharSets[dev->esc_parms[0]][3]; + dev->curr_cpmap[0x5c] = intCharSets[dev->esc_parms[0]][4]; + dev->curr_cpmap[0x5d] = intCharSets[dev->esc_parms[0]][5]; + dev->curr_cpmap[0x5e] = intCharSets[dev->esc_parms[0]][6]; + dev->curr_cpmap[0x60] = intCharSets[dev->esc_parms[0]][7]; + dev->curr_cpmap[0x7b] = intCharSets[dev->esc_parms[0]][8]; + dev->curr_cpmap[0x7c] = intCharSets[dev->esc_parms[0]][9]; + dev->curr_cpmap[0x7d] = intCharSets[dev->esc_parms[0]][10]; + dev->curr_cpmap[0x7e] = intCharSets[dev->esc_parms[0]][11]; + } + break; + + case 0x53: /* select superscript/subscript printing (ESC S) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style |= STYLE_SUBSCRIPT; + if (dev->esc_parms[0] == 1 || dev->esc_parms[1] == '1') + dev->font_style |= STYLE_SUPERSCRIPT; + update_font(dev); + break; + + case 0x54: /* cancel superscript/subscript printing (ESC T) */ + dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + update_font(dev); + break; + + case 0x55: /* turn unidirectional mode on/off (ESC U) */ + /* We don't have a print head, so just ignore this. */ + break; + + case 0x57: /* turn double-width printing on/off (ESC W) */ + if (!dev->multipoint_mode) { + dev->hmi = -1; + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_DOUBLEWIDTH; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') + dev->font_style |= STYLE_DOUBLEWIDTH; + update_font(dev); + } + break; + + case 0x58: /* select font by pitch and point (ESC X) */ + dev->multipoint_mode = 1; + /* Copy currently non-multipoint CPI if no value was set so far. */ + if (dev->multipoint_cpi == 0.0) { + dev->multipoint_cpi= dev->cpi; + } + if (dev->esc_parms[0] > 0) { /* set CPI */ + if (dev->esc_parms[0] == 1) { + /* Proportional spacing. */ + dev->font_style |= STYLE_PROP; + } else if (dev->esc_parms[0] >= 5) + dev->multipoint_cpi = 360.0 / (double)dev->esc_parms[0]; + } + if (dev->multipoint_size == 0.0) + dev->multipoint_size = 10.5; + if (PARAM16(1) > 0) { + /* set points */ + dev->multipoint_size = ((double)PARAM16(1)) / 2.0; + } + update_font(dev); + break; + + case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_y, PARAM16(0)); + break; + + case 0x5a: /* select 240-dpi graphics (ESC Z) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_z, PARAM16(0)); + break; + + case 0x5c: /* set relative horizontal print pos (ESC \) */ + rel_move = PARAM16(0); + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + dev->curr_x += ((double)rel_move / unit_size); + break; + + case 0x61: /* select justification (ESC a) */ + /* Ignore. */ + break; + + case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + dev->hmi = (double)PARAM16(0) / 360.0; + dev->extra_intra_space = 0.0; + break; + + case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ + dev->cpi = 15; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x846: // Select forward feed mode (FS F) - set reverse not implemented yet + if (dev->linespacing < 0) + dev->linespacing *= -1; + break; + + case 0x6a: // Reverse paper feed (ESC j) + reverse = (double)PARAM16(0) / (double)216.0; + reverse = dev->curr_y - reverse; + if (reverse < dev->left_margin) + dev->curr_y = dev->left_margin; + else + dev->curr_y = reverse; + break; + + case 0x6b: /* select typeface (ESC k) */ + if (dev->esc_parms[0] <= 11 || dev->esc_parms[0] == 30 || dev->esc_parms[0] == 31) { + dev->lq_typeface = dev->esc_parms[0]; + } + update_font(dev); + break; + + case 0x6c: /* set left margin (ESC 1) */ + dev->left_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; + if (dev->curr_x < dev->left_margin) + dev->curr_x = dev->left_margin; + break; + + case 0x70: /* Turn proportional mode on/off (ESC p) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_PROP; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->font_style |= STYLE_PROP; + dev->print_quality = QUALITY_LQ; + } + dev->multipoint_mode = 0; + dev->hmi = -1; + update_font(dev); + break; + + case 0x72: /* select printing color (ESC r) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) + dev->color = COLOR_BLACK; + else + dev->color = dev->esc_parms[0] << 5; + break; + + case 0x73: /* select low-speed mode (ESC s) */ + /* Ignore. */ + break; + + case 0x74: /* select character table (ESC t) */ + case 0x849: /* Select character table (FS I) */ + if (dev->esc_parms[0] < 4) { + dev->curr_char_table = dev->esc_parms[0]; + } else if ((dev->esc_parms[0] >= '0') && (dev->esc_parms[0] <= '3')) { + dev->curr_char_table = dev->esc_parms[0] - '0'; + } + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + update_font(dev); + break; + + case 0x77: /* turn double-height printing on/off (ESC w) */ + if (! dev->multipoint_mode) { + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_DOUBLEHEIGHT; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') + dev->font_style |= STYLE_DOUBLEHEIGHT; + update_font(dev); + } + break; + + case 0x78: /* select LQ or draft (ESC x) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') { + dev->print_quality = QUALITY_DRAFT; + dev->font_style |= STYLE_CONDENSED; + } + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->print_quality = QUALITY_LQ; + dev->font_style &= ~STYLE_CONDENSED; + } + dev->hmi = -1; + update_font(dev); + break; + + /* Our special command markers. */ + case 0x0100: /* set page length in inches (ESC C NUL) */ + dev->page_height = (double)dev->esc_parms[0]; + dev->bottom_margin = dev->page_height; + dev->top_margin = 0.0; + break; + + case 0x0101: /* skip unsupported ESC ( command */ + dev->esc_parms_req = PARAM16(0); + dev->esc_parms_curr = 0; + break; + + /* Extended ESC ( commands */ + case 0x0228: /* assign character table (ESC (t) */ + case 0x0274: + if (dev->esc_parms[2] < 4 && dev->esc_parms[3] < 16) { + dev->char_tables[dev->esc_parms[2]] = codepages[dev->esc_parms[3]]; + if (dev->esc_parms[2] == dev->curr_char_table) + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + } + break; + + case 0x022d: /* select line/score (ESC (-) */ + dev->font_style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE); + dev->font_score = dev->esc_parms[4]; + if (dev->font_score) { + if (dev->esc_parms[3] == 1) + dev->font_style |= STYLE_UNDERLINE; + if (dev->esc_parms[3] == 2) + dev->font_style |= STYLE_STRIKETHROUGH; + if (dev->esc_parms[3] == 3) + dev->font_style |= STYLE_OVERSCORE; + } + update_font(dev); + break; + + case 0x0242: /* bar code setup and print (ESC (B) */ + //ERRLOG("ESC/P: Barcode printing not supported.\n"); + + /* Find out how many bytes to skip. */ + dev->esc_parms_req = PARAM16(0); + dev->esc_parms_curr = 0; + break; + + case 0x0243: /* set page length in defined unit (ESC (C) */ + if (dev->esc_parms[0] && (dev->defined_unit> 0)) { + dev->page_height = dev->bottom_margin = (double)PARAM16(2) * dev->defined_unit; + dev->top_margin = 0.0; + } + break; + + case 0x0255: /* set unit (ESC (U) */ + dev->defined_unit = 3600.0 / (double)dev->esc_parms[2]; + break; + + case 0x0256: /* set abse vertical print pos (ESC (V) */ + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = 360.0; + new_y = dev->top_margin + (double)PARAM16(2) * unit_size; + if (new_y > dev->bottom_margin) + new_page(dev, 1, 0); + else + dev->curr_y = new_y; + break; + + case 0x025e: /* print data as characters (ESC (^) */ + dev->print_everything_count = PARAM16(0); + break; + + case 0x0263: /* set page format (ESC (c) */ + if (dev->defined_unit > 0.0) { + new_top = (double)PARAM16(2) * dev->defined_unit; + new_bottom = (double)PARAM16(4) * dev->defined_unit; + if (new_top >= new_bottom) + break; + if (new_top < dev->page_height) + dev->top_margin = new_top; + if (new_bottom < dev->page_height) + dev->bottom_margin = new_bottom; + if (dev->top_margin > dev->curr_y) + dev->curr_y = dev->top_margin; + } + break; + + case 0x0276: /* set relative vertical print pos (ESC (v) */ + { + unit_size = dev->defined_unit; + if (unit_size < 0.0) + unit_size = 360.0; + new_y = dev->curr_y + (double)((int16_t)PARAM16(2)) * unit_size; + if (new_y > dev->top_margin) { + if (new_y > dev->bottom_margin) + new_page(dev, 1, 0); + else + dev->curr_y = new_y; + } + } + break; + + default: + break; + } + + dev->esc_pending = 0; + return 1; + } + + escp_log("CH=%02x\n", ch); + + /* Now handle the "regular" control characters. */ + switch (ch) { + case 0x00: + return 1; + + case 0x07: /* Beeper (BEL) */ + /* TODO: beep? */ + return 1; + + case 0x08: /* Backspace (BS) */ + new_x = dev->curr_x - (1.0 / dev->actual_cpi); + if (dev->hmi > 0) + new_x = dev->curr_x - dev->hmi; + if (new_x >= dev->left_margin) + dev->curr_x = new_x; + return 1; + + case 0x09: /* Tab horizontally (HT) */ + /* Find tab right to current pos. */ + move_to = -1.0; + for (i = 0; i < dev->num_horizontal_tabs; i++) { + if (dev->horizontal_tabs[i] > dev->curr_x) + move_to = dev->horizontal_tabs[i]; + } + + /* Nothing found or out of page bounds => Ignore. */ + if (move_to > 0.0 && move_to < dev->right_margin) + dev->curr_x = move_to; + + return 1; + + case 0x0b: /* Tab vertically (VT) */ + if (dev->num_vertical_tabs == 0) { + /* All tabs cleared? => Act like CR */ + dev->curr_x = dev->left_margin; + } else if (dev->num_vertical_tabs < 0) { + /* No tabs set since reset => Act like LF */ + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + } else { + /* Find tab below current pos. */ + move_to = -1; + for (i = 0; i < dev->num_vertical_tabs; i++) { + if (dev->vertical_tabs[i] > dev->curr_y) + move_to = dev->vertical_tabs[i]; + } + + /* Nothing found => Act like FF. */ + if (move_to > dev->bottom_margin || move_to < 0) + new_page(dev, 1, 0); + else + dev->curr_y = move_to; + } + + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + return 1; + + case 0x0c: /* Form feed (FF) */ + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + new_page(dev, 1, 1); + return 1; + + case 0x0d: /* Carriage Return (CR) */ + dev->curr_x = dev->left_margin; + if (!dev->autofeed) + return 1; + /*FALLTHROUGH*/ + + case 0x0a: /* Line feed */ + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + return 1; + + case 0x0e: /* select Real64-width printing (one line) (SO) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + return 1; + + case 0x0f: /* select condensed printing (SI) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_CONDENSED; + update_font(dev); + } + return 1; + + case 0x11: /* select printer (DC1) */ + /* Ignore. */ + return 0; + + case 0x12: /* cancel condensed printing (DC2) */ + dev->hmi = -1; + dev->font_style &= ~STYLE_CONDENSED; + update_font(dev); + return 1; + + case 0x13: /* deselect printer (DC3) */ + /* Ignore. */ + return 1; + + case 0x14: /* cancel double-width printing (one line) (DC4) */ + dev->hmi = -1; + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + return 1; + + case 0x18: /* cancel line (CAN) */ + return 1; + + case 0x1b: /* ESC */ + dev->esc_seen = 1; + return 1; + + case 0x1c: /* FS (IBM commands) */ + dev->fss_seen = 1; + return 1; + + default: + return 0; + } + + /* This is a printable character -> print it. */ + return 0; +} + + +static void +handle_char(escp_t *dev, uint8_t ch) +{ + FT_UInt char_index; + uint16_t pen_x, pen_y; + uint16_t line_start, line_y; + double x_advance; + + dev->char_read = 1; + + if (dev->page == NULL) + return; + + /* MSB mode */ + if (dev->msb != 255) { + if (dev->msb == 0) + ch &= 0x7f; + else if (dev->msb == 1) + ch |= 0x80; + } + + if (dev->bg_remaining_bytes > 0) { + print_bit_graph(dev, ch); + return; + } + + /* "print everything" mode? aka. ESC ( ^ */ + if (dev->print_everything_count > 0) { + escp_log("Print everything count=%d\n", dev->print_everything_count); + /* do not process command char, just continue */ + dev->print_everything_count--; + } else if (process_char(dev, ch)) { + /* command was processed */ + return; + } + + /* We cannot print if we have no font loaded. */ + if (dev->fontface == NULL) + return; + + if (ch == 0x01) + ch = 0x20; + + /* ok, so we need to print the character now */ + if (ft_lib) { + char_index = ft_Get_Char_Index(dev->fontface, dev->curr_cpmap[ch]); + ft_Load_Glyph(dev->fontface, char_index, FT_LOAD_DEFAULT); + ft_Render_Glyph(dev->fontface->glyph, FT_RENDER_MODE_NORMAL); + } + + pen_x = PIXX + dev->fontface->glyph->bitmap_left; + pen_y = (uint16_t)(PIXY - dev->fontface->glyph->bitmap_top + dev->fontface->size->metrics.ascender / 64); + + if (dev->font_style & STYLE_SUBSCRIPT) + pen_y += dev->fontface->glyph->bitmap.rows / 2; + + /* mark the page as dirty if anything is drawn */ + if ((ch != 0x20) || (dev->font_score != SCORE_NONE)) + dev->page->dirty = 1; + + /* draw the glyph */ + blit_glyph(dev, pen_x, pen_y, 0); + blit_glyph(dev, pen_x + 1, pen_y, 1); + + /* doublestrike -> draw glyph a second time, 1px below */ + if (dev->font_style & STYLE_DOUBLESTRIKE) { + blit_glyph(dev, pen_x, pen_y + 1, 1); + blit_glyph(dev, pen_x + 1, pen_y + 1, 1); + } + + /* bold -> draw glyph a second time, 1px to the right */ + if (dev->font_style & STYLE_BOLD) { + blit_glyph(dev, pen_x + 1, pen_y, 1); + blit_glyph(dev, pen_x + 2, pen_y, 1); + blit_glyph(dev, pen_x + 3, pen_y, 1); + } + + line_start = PIXX; + + if (dev->font_style & STYLE_PROP) + x_advance = dev->fontface->glyph->advance.x / (dev->dpi * 64.0); + else { + if (dev->hmi < 0) + x_advance = 1.0 / dev->actual_cpi; + else + x_advance = dev->hmi; + } + + x_advance += dev->extra_intra_space; + dev->curr_x += x_advance; + + /* Line printing (underline etc.) */ + if (dev->font_score != SCORE_NONE && (dev->font_style & (STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE))) { + /* Find out where to put the line. */ + line_y = PIXY; + + if (dev->font_style & STYLE_UNDERLINE) + line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.9)); + if (dev->font_style & STYLE_STRIKETHROUGH) + line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.45)); + if (dev->font_style & STYLE_OVERSCORE) + line_y = PIXY - ((dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) ? 5 : 0); + + draw_hline(dev, pen_x, PIXX, line_y, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); + + if (dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) + draw_hline(dev, line_start, PIXX, line_y + 5, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); + } + + if ((dev->curr_x + x_advance) > dev->right_margin) { + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + } +} + + +/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ +static void +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) +{ + FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; + unsigned x, y; + uint8_t src, *dst; + + /* check if freetype is available */ + if (ft_lib == NULL) + return; + + for (y = 0; y < bitmap->rows; y++) { + for (x = 0; x < bitmap->width; x++) { + src = *(bitmap->buffer + x + y * bitmap->pitch); + /* ignore background, and respect page size */ + if (src > 0 && (destx + x < (unsigned)dev->page->w) && (desty + y < (unsigned)dev->page->h)) { + dst = (uint8_t *)dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; + src >>= 3; + + if (add) { + if (((*dst) & 0x1f) + src > 31) + *dst |= (dev->color | 0x1f); + else { + *dst += src; + *dst |= dev->color; + } + } else + *dst = src|dev->color; + } + } + } +} + + +/* Draw anti-aliased line. */ +static void +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) +{ + unsigned breakmod = dev->dpi / 15; + unsigned gapstart = (breakmod * 4) / 5; + unsigned x; + + for (x = from_x; x <= to_x; x++) { + /* Skip parts if broken line or going over the border. */ + if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { + if (y > 0 && (y - 1) < dev->page->h) + *((uint8_t*)dev->page->pixels + x + (y - 1) * (unsigned)dev->page->pitch) = 240; + if (y < dev->page->h) + *((uint8_t*)dev->page->pixels + x + y * (unsigned)dev->page->pitch) = !broken ? 255 : 240; + if (y + 1 < dev->page->h) + *((uint8_t*)dev->page->pixels + x + (y + 1) * (unsigned)dev->page->pitch) = 240; + } + } +} + + +static int8_t +print_ack(escp_t *dev) +{ + if (dev->char_read) { + dev->char_read = 0; + return 1; + } + + return 0; } static void setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) { + escp_log("Density=%d\n", density); switch (density) { case 0: dev->bg_h_density = 60; @@ -708,7 +1870,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; default: - pclog("ESC/P: Unsupported bit image density %d.\n", density); + escp_log("ESC/P: Unsupported bit image density %d.\n", density); + break; } dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; @@ -716,965 +1879,12 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) } -/* This is the actual ESC/P interpreter. */ -static int -process_char(escp_t *dev, uint8_t ch) -{ - double new_x, new_y; - double move_to; - double unit_size; - uint16_t rel_move; - int16_t i; - - //pclog("Esc_seen=%d, fss_seen=%d\n", dev->esc_seen, dev->fss_seen); - /* Determine number of additional command params that are expected. */ - if (dev->esc_seen || dev->fss_seen) { - dev->esc_pending = ch; - if (dev->fss_seen) dev->esc_pending |= 0x800; - dev->esc_seen = dev->fss_seen = 0; - dev->esc_parms_curr = 0; - - //pclog("Command pending=%02x\n", dev->esc_pending); - switch (dev->esc_pending) { - case 0x02: // Undocumented - case 0x0a: // Reverse line feed - case 0x0c: // Return to top of current page - case 0x0e: // Select double-width printing (one line) (ESC SO) - case 0x0f: // Select condensed printing (ESC SI) - case 0x23: // Cancel MSB control (ESC #) - case 0x30: // Select 1/8-inch line spacing (ESC 0) - case 0x32: // Select 1/6-inch line spacing (ESC 2) - case 0x34: // Select italic font (ESC 4) - case 0x35: // Cancel italic font (ESC 5) - case 0x36: // Enable printing of upper control codes (ESC 6) - case 0x37: // Enable upper control codes (ESC 7) - case 0x3c: // Unidirectional mode (one line) (ESC <) - case 0x3d: // Set MSB to 0 (ESC =) - case 0x3e: // Set MSB to 1 (ESC >) - case 0x40: // Initialize printer (ESC @) - case 0x45: // Select bold font (ESC E) - case 0x46: // Cancel bold font (ESC F) - case 0x47: // Select double-strike printing (ESC G) - case 0x48: // Cancel double-strike printing (ESC H) - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - case 0x54: // Cancel superscript/subscript printing (ESC T) - case 0x5e: // Enable printing of all character codes on next character - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - case 0x73: // Select low-speed mode (ESC s) - case 0x834: // Select italic font (FS 4) (= ESC 4) - case 0x835: // Cancel italic font (FS 5) (= ESC 5) - case 0x846: // Select forward feed mode (FS F) - case 0x852: // Select reverse feed mode (FS R) - dev->esc_parms_req = 0; - break; - - case 0x19: // Control paper loading/ejecting (ESC EM) - case 0x20: // Set intercharacter space (ESC SP) - case 0x21: // Master select (ESC !) - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x2d: // Turn underline on/off (ESC -) - case 0x2f: // Select vertical tab channel (ESC /) - case 0x33: // Set n/180-inch line spacing (ESC 3) - case 0x41: // Set n/60-inch line spacing - case 0x43: // Set page length in lines (ESC C) - case 0x4a: // Advance print position vertically (ESC J n) - case 0x4e: // Set bottom margin (ESC N) - case 0x51: // Set right margin (ESC Q) - case 0x52: // Select an international character set (ESC R) - case 0x53: // Select superscript/subscript printing (ESC S) - case 0x55: // Turn unidirectional mode on/off (ESC U) - case 0x57: // Turn double-width printing on/off (ESC W) - case 0x61: // Select justification (ESC a) - case 0x6b: // Select typeface (ESC k) - case 0x6c: // Set left margin (ESC 1) - case 0x70: // Turn proportional mode on/off (ESC p) - case 0x72: // Select printing color (ESC r) - case 0x74: // Select character table (ESC t) - case 0x77: // Turn double-height printing on/off (ESC w) - case 0x78: // Select LQ or draft (ESC x) - case 0x7e: // Select/Deselect slash zero (ESC ~) - case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) - case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) - case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) - case 0x843: // Select LQ type style (FS C) (= ESC k) - case 0x845: // Select character width (FS E) - case 0x849: // Select character table (FS I) (= ESC t) - case 0x853: // Select High Speed/High Density elite pitch (FS S) - case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) - dev->esc_parms_req = 1; - break; - - case 0x24: // Set absolute horizontal print position (ESC $) - case 0x3f: // Reassign bit-image mode (ESC ?) - case 0x4b: // Select 60-dpi graphics (ESC K) - case 0x4c: // Select 120-dpi graphics (ESC L) - case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) - case 0x5a: // Select 240-dpi graphics (ESC Z) - case 0x5c: // Set relative horizontal print position (ESC \) - case 0x63: // Set horizontal motion index (HMI) (ESC c) - case 0x65: // Set vertical tab stops every n lines (ESC e) - case 0x85a: // Print 24-bit hex-density graphics (FS Z) - dev->esc_parms_req = 2; - break; - - case 0x2a: // Select bit image (ESC *) - case 0x58: // Select font by pitch and point (ESC X) - dev->esc_parms_req = 3; - break; - - case 0x5b: // Select character height, width, line spacing - dev->esc_parms_req = 7; - break; - - case 0x62: // Set vertical tabs in VFU channels (ESC b) - case 0x42: // Set vertical tabs (ESC B) - dev->num_vertical_tabs = 0; - return 1; - - case 0x44: // Set horizontal tabs (ESC D) - dev->num_horizontal_tabs = 0; - return 1; - - case 0x25: // Select user-defined set (ESC %) - case 0x26: // Define user-defined characters (ESC &) - case 0x3a: // Copy ROM to RAM (ESC :) - //ERRLOG("ESC/P: User-defined characters not supported.\n"); - return 1; - - case 0x28: // Two bytes sequence - /* return and wait for second ESC byte */ - return 1; - - default: - //ERRLOG("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", - // dev->esc_pending >= 0x20 ? dev->esc_pending : '?', - // dev->esc_pending); - dev->esc_parms_req = 0; - dev->esc_pending = 0; - return 1; - } - - if (dev->esc_parms_req > 0) { - /* return and wait for parameters to appear */ - return 1; - } - } - - /* parameter checking for the 2-byte ESC/P2 commands */ - if (dev->esc_pending == '(') { - dev->esc_pending = 0x0200 + ch; - - switch (dev->esc_pending) { - case 0x0242: // Bar code setup and print (ESC (B) - case 0x025e: // Print data as characters (ESC (^) - dev->esc_parms_req = 2; - break; - - case 0x0255: // Set unit (ESC (U) - dev->esc_parms_req = 3; - break; - - case 0x0243: // Set page length in defined unit (ESC (C) - case 0x0256: // Set absolute vertical print position (ESC (V) - case 0x0276: // Set relative vertical print position (ESC (v) - dev->esc_parms_req = 4; - break; - - case 0x0228: // Assign character table (ESC (t) - case 0x022d: // Select line/score (ESC (-) - dev->esc_parms_req = 5; - break; - - case 0x0263: // Set page format (ESC (c) - dev->esc_parms_req = 6; - break; - - default: - // ESC ( commands are always followed by a "number of parameters" word parameter - //ERRLOG("ESC/P: Skipping unsupported extended command ESC ( %c (0x%02x).\n", - // dev->esc_pending >= 0x20 ? dev->esc_pending : '?', - // dev->esc_pending); - dev->esc_parms_req = 2; - dev->esc_pending = 0x101; /* dummy value to be checked later */ - return 1; - } - - /* If we need parameters, return and wait for them to appear. */ - if (dev->esc_parms_req > 0) return 1; - } - - /* Ignore VFU channel setting. */ - if (dev->esc_pending == 0x62) { - dev->esc_pending = 0x42; - return 1; - } - - /* Collect vertical tabs. */ - if (dev->esc_pending == 0x42) { - /* check if we're done */ - if ((ch == 0) || - (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double)ch * dev->linespacing)) { - dev->esc_pending = 0; - } else { - if (dev->num_vertical_tabs < 16) { - dev->vertical_tabs[dev->num_vertical_tabs++] = (double)ch * dev->linespacing; - } - } - } - - /* Collect horizontal tabs. */ - if (dev->esc_pending == 0x44) { - /* check if we're done... */ - if ((ch == 0) || - (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double)ch * (1.0 / dev->cpi))) { - dev->esc_pending = 0; - } else { - if (dev->num_horizontal_tabs < 32) { - dev->horizontal_tabs[dev->num_horizontal_tabs++] = (double)ch * (1.0 / dev->cpi); - } - } - } - - /* Check if we're still collecting parameters for the current command. */ - if (dev->esc_parms_curr < dev->esc_parms_req) { - /* store current parameter */ - dev->esc_parms[dev->esc_parms_curr++] = ch; - - /* do we still need to continue collecting parameters? */ - if (dev->esc_parms_curr < dev->esc_parms_req) - return 1; - } - - /* Handle the pending ESC command. */ - if (dev->esc_pending != 0) { - switch (dev->esc_pending) { - case 0x02: /* undocumented; ignore */ - break; - - case 0x0e: /* select double-width (one line) (ESC SO) */ - if (! dev->multipoint_mode) { - dev->hmi = -1; - dev->font_style |= STYLE_DOUBLEWIDTHONELINE; - update_font(dev); - } - break; - - case 0x0f: /* select condensed printing (ESC SI) */ - if (! dev->multipoint_mode) { - dev->hmi = -1; - dev->font_style |= STYLE_CONDENSED; - update_font(dev); - } - break; - - case 0x19: /* control paper loading/ejecting (ESC EM) */ - /* We are not really loading paper, so most - * commands can be ignored */ - if (dev->esc_parms[0] == 'R') - new_page(dev, 1, 0); - - break; - case 0x20: /* set intercharacter space (ESC SP) */ - if (! dev->multipoint_mode) { - dev->extra_intra_space = (double)dev->esc_parms[0] / (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); - dev->hmi = -1; - update_font(dev); - } - break; - - case 0x21: /* master select (ESC !) */ - dev->cpi = dev->esc_parms[0] & 0x01 ? 12.0 : 10.0; - - /* Reset first seven bits. */ - dev->font_style &= ~0x7f; - if (dev->esc_parms[0] & 0x02) - dev->font_style |= STYLE_PROP; - if (dev->esc_parms[0] & 0x04) - dev->font_style |= STYLE_CONDENSED; - if (dev->esc_parms[0] & 0x08) - dev->font_style |= STYLE_BOLD; - if (dev->esc_parms[0] & 0x10) - dev->font_style |= STYLE_DOUBLESTRIKE; - if (dev->esc_parms[0] & 0x20) - dev->font_style |= STYLE_DOUBLEWIDTH; - if (dev->esc_parms[0] & 0x40) - dev->font_style |= STYLE_ITALICS; - if (dev->esc_parms[0] & 0x80) { - dev->font_score = SCORE_SINGLE; - dev->font_style |= STYLE_UNDERLINE; - } - - dev->hmi = -1; - dev->multipoint_mode = 0; - update_font(dev); - break; - - case 0x23: /* cancel MSB control (ESC #) */ - dev->msb = -1; - break; - - case 0x24: /* set abs horizontal print position (ESC $) */ - unit_size = dev->defined_unit; - if (unit_size < 0) - unit_size = 60.0; - - new_x = dev->left_margin + (double)PARAM16(0) / unit_size; - if (new_x <= dev->right_margin) - dev->curr_x = new_x; - break; - - case 0x85a: /* Print 24-bit hex-density graphics (FS Z) */ - setup_bit_image(dev, 40, PARAM16(0)); - break; - - case 0x2a: /* select bit image (ESC *) */ - setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); - break; - - case 0x2b: /* set n/360-inch line spacing (ESC +) */ - case 0x833: /* Set n/360-inch line spacing (FS 3) */ - dev->linespacing = (double)dev->esc_parms[0] / 360.0; - break; - - case 0x2d: /* turn underline on/off (ESC -) */ - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') - dev->font_style &= ~STYLE_UNDERLINE; - if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { - dev->font_style |= STYLE_UNDERLINE; - dev->font_score = SCORE_SINGLE; - } - update_font(dev); - break; - - case 0x2f: /* select vertical tab channel (ESC /) */ - /* Ignore */ - break; - - case 0x30: /* select 1/8-inch line spacing (ESC 0) */ - dev->linespacing = 1.0 / 8.0; - break; - - case 0x32: /* select 1/6-inch line spacing (ESC 2) */ - dev->linespacing = 1.0 / 6.0; - break; - - case 0x33: /* set n/180-inch line spacing (ESC 3) */ - dev->linespacing = (double)dev->esc_parms[0] / 180.0; - break; - - case 0x34: /* select italic font (ESC 4) */ - dev->font_style |= STYLE_ITALICS; - update_font(dev); - break; - - case 0x35: /* cancel italic font (ESC 5) */ - dev->font_style &= ~STYLE_ITALICS; - update_font(dev); - break; - - case 0x36: /* enable printing of upper control codes (ESC 6) */ - dev->print_upper_control = 1; - break; - - case 0x37: /* enable upper control codes (ESC 7) */ - dev->print_upper_control = 0; - break; - - case 0x3c: /* unidirectional mode (one line) (ESC <) */ - /* We don't have a print head, so just - * ignore this. */ - break; - - case 0x3d: /* set MSB to 0 (ESC =) */ - dev->msb = 0; - break; - - case 0x3e: /* set MSB to 1 (ESC >) */ - dev->msb = 1; - break; - - case 0x3f: /* reassign bit-image mode (ESC ?) */ - if (dev->esc_parms[0] == 'K') - dev->density_k = dev->esc_parms[1]; - if (dev->esc_parms[0] == 'L') - dev->density_l = dev->esc_parms[1]; - if (dev->esc_parms[0] == 'Y') - dev->density_y = dev->esc_parms[1]; - if (dev->esc_parms[0] == 'Z') - dev->density_z = dev->esc_parms[1]; - break; - - case 0x40: /* initialize printer (ESC @) */ - reset_printer(dev); - break; - - case 0x41: /* set n/60-inch line spacing */ - dev->linespacing = (double)dev->esc_parms[0] / 60.0; - break; - - case 0x43: /* set page length in lines (ESC C) */ - if (dev->esc_parms[0]) { - dev->page_height = dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; - } else { /* == 0 => Set page length in inches */ - dev->esc_parms_req = 1; - dev->esc_parms_curr = 0; - dev->esc_pending = 0x100; /* dummy value for later */ - return 1; - } - break; - - case 0x45: /* select bold font (ESC E) */ - dev->font_style |= STYLE_BOLD; - update_font(dev); - break; - - case 0x46: /* cancel bold font (ESC F) */ - dev->font_style &= ~STYLE_BOLD; - update_font(dev); - break; - - case 0x47: /* select dobule-strike printing (ESC G) */ - dev->font_style |= STYLE_DOUBLESTRIKE; - break; - - case 0x48: /* cancel double-strike printing (ESC H) */ - dev->font_style &= ~STYLE_DOUBLESTRIKE; - break; - - case 0x4a: /* advance print pos vertically (ESC J n) */ - dev->curr_y += (double)dev->esc_parms[0] / 180.0; - if (dev->curr_y > dev->bottom_margin) { - new_page(dev, 1, 0); - } - break; - - case 0x4b: /* select 60-dpi graphics (ESC K) */ - /* TODO: graphics stuff */ - setup_bit_image(dev, dev->density_k, PARAM16(0)); - break; - - case 0x4c: /* select 120-dpi graphics (ESC L) */ - /* TODO: graphics stuff */ - setup_bit_image(dev, dev->density_l, PARAM16(0)); - break; - - case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ - dev->cpi = 12.0; - dev->hmi = -1; - dev->multipoint_mode = 0; - update_font(dev); - break; - - case 0x4e: /* set bottom margin (ESC N) */ - dev->top_margin = 0.0; - dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; - break; - - case 0x4f: /* cancel bottom (and top) margin */ - dev->top_margin = 0.0; - dev->bottom_margin = dev->page_height; - break; - - case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ - dev->cpi = 10.0; - dev->hmi = -1; - dev->multipoint_mode = 0; - update_font(dev); - break; - - case 0x51: /* set right margin */ - dev->right_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; - break; - - case 0x52: /* select an intl character set (ESC R) */ - if (dev->esc_parms[0] <= 13 || dev->esc_parms[0] == '@') { - if (dev->esc_parms[0] == '@') - dev->esc_parms[0] = 14; - - dev->curr_cpmap[0x23] = intCharSets[dev->esc_parms[0]][0]; - dev->curr_cpmap[0x24] = intCharSets[dev->esc_parms[0]][1]; - dev->curr_cpmap[0x40] = intCharSets[dev->esc_parms[0]][2]; - dev->curr_cpmap[0x5b] = intCharSets[dev->esc_parms[0]][3]; - dev->curr_cpmap[0x5c] = intCharSets[dev->esc_parms[0]][4]; - dev->curr_cpmap[0x5d] = intCharSets[dev->esc_parms[0]][5]; - dev->curr_cpmap[0x5e] = intCharSets[dev->esc_parms[0]][6]; - dev->curr_cpmap[0x60] = intCharSets[dev->esc_parms[0]][7]; - dev->curr_cpmap[0x7b] = intCharSets[dev->esc_parms[0]][8]; - dev->curr_cpmap[0x7c] = intCharSets[dev->esc_parms[0]][9]; - dev->curr_cpmap[0x7d] = intCharSets[dev->esc_parms[0]][10]; - dev->curr_cpmap[0x7e] = intCharSets[dev->esc_parms[0]][11]; - } - break; - - case 0x53: /* select superscript/subscript printing (ESC S) */ - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') - dev->font_style |= STYLE_SUBSCRIPT; - if (dev->esc_parms[0] == 1 || dev->esc_parms[1] == '1') - dev->font_style |= STYLE_SUPERSCRIPT; - update_font(dev); - break; - - case 0x54: /* cancel superscript/subscript printing (ESC T) */ - dev->font_style &= ~(STYLE_SUPERSCRIPT | STYLE_SUBSCRIPT); - update_font(dev); - break; - - case 0x55: /* turn unidirectional mode on/off (ESC U) */ - /* We don't have a print head, so just ignore this. */ - break; - - case 0x57: /* turn double-width printing on/off (ESC W) */ - if (!dev->multipoint_mode) { - dev->hmi = -1; - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') - dev->font_style &= ~STYLE_DOUBLEWIDTH; - if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') - dev->font_style |= STYLE_DOUBLEWIDTH; - update_font(dev); - } - break; - - case 0x58: /* select font by pitch and point (ESC X) */ - dev->multipoint_mode = 1; - /* Copy currently non-multipoint CPI if no value was set so far. */ - if (dev->multipoint_cpi == 0.0) { - dev->multipoint_cpi= dev->cpi; - } - if (dev->esc_parms[0] > 0) { /* set CPI */ - if (dev->esc_parms[0] == 1) { - /* Proportional spacing. */ - dev->font_style |= STYLE_PROP; - } else if (dev->esc_parms[0] >= 5) { - dev->multipoint_cpi = 360.0 / (double)dev->esc_parms[0]; - } - } - if (dev->multipoint_size == 0.0) { - dev->multipoint_size = 10.5; - } - if (PARAM16(1) > 0) { - /* set points */ - dev->multipoint_size = ((double)PARAM16(1)) / 2.0; - } - update_font(dev); - break; - - case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ - /* TODO: graphics stuff */ - setup_bit_image(dev, dev->density_y, PARAM16(0)); - break; - - case 0x5a: /* select 240-dpi graphics (ESC Z) */ - /* TODO: graphics stuff */ - setup_bit_image(dev, dev->density_z, PARAM16(0)); - break; - - case 0x5c: /* set relative horizontal print pos (ESC \) */ - rel_move = PARAM16(0); - unit_size = dev->defined_unit; - if (unit_size < 0) - unit_size = (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); - dev->curr_x += ((double)rel_move / unit_size); - break; - - case 0x61: /* select justification (ESC a) */ - /* Ignore. */ - break; - - case 0x63: /* set horizontal motion index (HMI) (ESC c) */ - dev->hmi = (double)PARAM16(0) / 360.0; - dev->extra_intra_space = 0.0; - break; - - case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ - dev->cpi = 15; - dev->hmi = -1; - dev->multipoint_mode = 0; - update_font(dev); - break; - - case 0x6b: /* select typeface (ESC k) */ - if (dev->esc_parms[0] <= 11 || dev->esc_parms[0] == 30 || dev->esc_parms[0] == 31) { - dev->lq_typeface = dev->esc_parms[0]; - } - update_font(dev); - break; - - case 0x6c: /* set left margin (ESC 1) */ - dev->left_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; - if (dev->curr_x < dev->left_margin) - dev->curr_x = dev->left_margin; - break; - - case 0x70: /* Turn proportional mode on/off (ESC p) */ - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') - dev->font_style &= ~STYLE_PROP; - if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { - dev->font_style |= STYLE_PROP; - dev->print_quality = QUALITY_LQ; - } - dev->multipoint_mode = 0; - dev->hmi = -1; - update_font(dev); - break; - - case 0x72: /* select printing color (ESC r) */ - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) - dev->color = COLOR_BLACK; - else - dev->color = dev->esc_parms[0] << 5; - break; - - case 0x73: /* select low-speed mode (ESC s) */ - /* Ignore. */ - break; - - case 0x74: /* select character table (ESC t) */ - case 0x849: /* Select character table (FS I) */ - if (dev->esc_parms[0] < 4) { - dev->curr_char_table = dev->esc_parms[0]; - } else if ((dev->esc_parms[0] >= '0') && (dev->esc_parms[0] <= '3')) { - dev->curr_char_table = dev->esc_parms[0] - '0'; - } - init_codepage(dev, dev->char_tables[dev->curr_char_table]); - update_font(dev); - break; - - case 0x77: /* turn double-height printing on/off (ESC w) */ - if (! dev->multipoint_mode) { - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') - dev->font_style &= ~STYLE_DOUBLEHEIGHT; - if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') - dev->font_style |= STYLE_DOUBLEHEIGHT; - update_font(dev); - } - break; - - case 0x78: /* select LQ or draft (ESC x) */ - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') - dev->print_quality = QUALITY_DRAFT; - if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') - dev->print_quality = QUALITY_LQ; - update_font(dev); - break; - - /* Our special command markers. */ - case 0x0100: /* set page length in inches (ESC C NUL) */ - dev->page_height = (double)dev->esc_parms[0]; - dev->bottom_margin = dev->page_height; - dev->top_margin = 0.0; - break; - - case 0x0101: /* skip unsupported ESC ( command */ - dev->esc_parms_req = PARAM16(0); - dev->esc_parms_curr = 0; - break; - - /* Extended ESC ( commands */ - case 0x0228: /* assign character table (ESC (t) */ - case 0x0274: - if (dev->esc_parms[2] < 4 && dev->esc_parms[3] < 16) { - dev->char_tables[dev->esc_parms[2]] = codepages[dev->esc_parms[3]]; - if (dev->esc_parms[2] == dev->curr_char_table) { - init_codepage(dev, dev->char_tables[dev->curr_char_table]); - } - } - break; - - case 0x022d: /* select line/score (ESC (-) */ - dev->font_style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE); - dev->font_score = dev->esc_parms[4]; - if (dev->font_score) { - if (dev->esc_parms[3] == 1) - dev->font_style |= STYLE_UNDERLINE; - if (dev->esc_parms[3] == 2) - dev->font_style |= STYLE_STRIKETHROUGH; - if (dev->esc_parms[3] == 3) - dev->font_style |= STYLE_OVERSCORE; - } - update_font(dev); - break; - - case 0x0242: /* bar code setup and print (ESC (B) */ - //ERRLOG("ESC/P: Barcode printing not supported.\n"); - - /* Find out how many bytes to skip. */ - dev->esc_parms_req = PARAM16(0); - dev->esc_parms_curr = 0; - break; - - case 0x0243: /* set page length in defined unit (ESC (C) */ - if (dev->esc_parms[0] && (dev->defined_unit> 0)) { - dev->page_height = dev->bottom_margin = (double)PARAM16(2) * dev->defined_unit; - dev->top_margin = 0.0; - } - break; - - case 0x0255: /* set unit (ESC (U) */ - dev->defined_unit = 3600.0 / (double)dev->esc_parms[2]; - break; - - case 0x0256: /* set abse vertical print pos (ESC (V) */ - unit_size = dev->defined_unit; - if (unit_size < 0) - unit_size = 360.0; - new_y = dev->top_margin + (double)PARAM16(2) * unit_size; - if (new_y > dev->bottom_margin) - new_page(dev, 1, 0); - else - dev->curr_y = new_y; - break; - - case 0x025e: /* print data as characters (ESC (^) */ - dev->print_everything_count = PARAM16(0); - break; - - case 0x0263: /* set page format (ESC (c) */ - if (dev->defined_unit > 0.0) { - dev->top_margin = (double)PARAM16(2) * dev->defined_unit; - dev->bottom_margin = (double)PARAM16(4) * dev->defined_unit; - } - break; - - case 0x0276: /* set relative vertical print pos (ESC (v) */ - { - unit_size = dev->defined_unit; - if (unit_size < 0.0) - unit_size = 360.0; - new_y = dev->curr_y + (double)((int16_t)PARAM16(2)) * unit_size; - if (new_y > dev->top_margin) { - if (new_y > dev->bottom_margin) { - new_page(dev, 1, 0); - } else { - dev->curr_y = new_y; - } - } - } - break; - - default: - //ERRLOG("ESC/P: Unhandled ESC command.\n"); - break; - } - - dev->esc_pending = 0; - return 1; - } - - //pclog("CH=%02x\n", ch); - /* Now handle the "regular" control characters. */ - switch (ch) { - case 0x00: - return 1; - - case 0x07: /* Beeper (BEL) */ - /* TODO: beep? */ - return 1; - - case 0x08: /* Backspace (BS) */ - new_x = dev->curr_x - (1.0 / dev->actual_cpi); - if (dev->hmi > 0) - new_x = dev->curr_x - dev->hmi; - if (new_x >= dev->left_margin) - dev->curr_x = new_x; - return 1; - - case 0x09: /* Tab horizontally (HT) */ - /* Find tab right to current pos. */ - move_to = -1.0; - for (i = 0; i < dev->num_horizontal_tabs; i++) { - if (dev->horizontal_tabs[i] > dev->curr_x) { - move_to = dev->horizontal_tabs[i]; - break; - } - } - - /* Nothing found or out of page bounds => Ignore. */ - if (move_to > 0.0 && move_to < dev->right_margin) - dev->curr_x = move_to; - return 1; - - case 0x0b: /* Tab vertically (VT) */ - if (dev->num_vertical_tabs == 0) { - /* All tabs cleared? => Act like CR */ - dev->curr_x = dev->left_margin; - } else if (dev->num_vertical_tabs < 0) { - /* No tabs set since reset => Act like LF */ - dev->curr_x = dev->left_margin; - dev->curr_y += dev->linespacing; - if (dev->curr_y > dev->bottom_margin) - new_page(dev, 1, 0); - } else { - /* Find tab below current pos. */ - move_to = -1; - for (i = 0; i < dev->num_vertical_tabs; i++) { - if (dev->vertical_tabs[i] > dev->curr_y) { - move_to = dev->vertical_tabs[i]; - break; - } - } - - /* Nothing found => Act like FF. */ - if (move_to > dev->bottom_margin || move_to < 0) - new_page(dev, 1, 0); - else - dev->curr_y = move_to; - } - - if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { - dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; - update_font(dev); - } - return 1; - - case 0x0c: /* Form feed (FF) */ - if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { - dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; - update_font(dev); - } - new_page(dev, 1, 1); - return 1; - - case 0x0d: /* Carriage Return (CR) */ - dev->curr_x = dev->left_margin; - if (!dev->autofeed) - { - return 1; - } - /*FALLTHROUGH*/ - - case 0x0a: /* Line feed */ - if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { - dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; - update_font(dev); - } - dev->curr_x = dev->left_margin; - dev->curr_y += dev->linespacing; - if (dev->curr_y > dev->bottom_margin) { - new_page(dev, 1, 0); - } - return 1; - - case 0x0e: /* select Real64-width printing (one line) (SO) */ - if (! dev->multipoint_mode) { - dev->hmi = -1; - dev->font_style |= STYLE_DOUBLEWIDTHONELINE; - update_font(dev); - } - return 1; - - case 0x0f: /* select condensed printing (SI) */ - if (! dev->multipoint_mode) { - dev->hmi = -1; - dev->font_style |= STYLE_CONDENSED; - update_font(dev); - } - return 1; - - case 0x11: /* select printer (DC1) */ - /* Ignore. */ - return 1; - - case 0x12: /* cancel condensed printing (DC2) */ - dev->hmi = -1; - dev->font_style &= ~STYLE_CONDENSED; - update_font(dev); - return 1; - - case 0x13: /* deselect printer (DC3) */ - /* Ignore. */ - return 1; - - case 0x14: /* cancel double-width printing (one line) (DC4) */ - dev->hmi = -1; - dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; - update_font(dev); - return 1; - - case 0x18: /* cancel line (CAN) */ - return 1; - - case 0x1b: /* ESC */ - dev->esc_seen = 1; - return 1; - - case 0x1c: /* FS (IBM commands) */ - dev->fss_seen = 1; - return 1; - - default: - break; - } - - /* This is a printable character -> print it. */ - return 0; -} - - -/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ -static void -blit_glyph(escp_t *dev, uint16_t destx, uint16_t desty, int8_t add) -{ - FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; - uint16_t x, y; - uint8_t src, *dst; - - /* check if freetype is available */ - if (ft_lib == NULL) return; - - for (y = 0; y < bitmap->rows; y++) { - for (x = 0; x < bitmap->width; x++) { - src = *(bitmap->buffer + y * bitmap->pitch + x); - /* ignore background, and respect page size */ - if (src > 0 && (destx + x < dev->page->w) && (desty + y < dev->page->h)) { - dst = (uint8_t *)dev->page->pixels + x + destx + (y + desty) * dev->page->pitch; - src >>= 3; - - if (add) { - if (((*dst) & 0x1f) + src > 31) - *dst |= (dev->color | 0x1f); - else { - *dst += src; - *dst |= dev->color; - } - } - else - *dst = src|dev->color; - } - } - } -} - - -/* Draw anti-aliased line. */ -static void -draw_hline(escp_t *dev, uint16_t from_x, uint16_t to_x, uint16_t y, int8_t broken) -{ - uint16_t breakmod = dev->dpi / 15; - uint16_t gapstart = (breakmod * 4) / 5; - uint16_t x; - - for (x = from_x; x <= to_x; x++) { - /* Skip parts if broken line or going over the border. */ - if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { - if (y > 0 && (y - 1) < dev->page->h) - *((uint8_t*)dev->page->pixels + x + (y - 1)*dev->page->pitch) = 120; - if (y < dev->page->h) - *((uint8_t*)dev->page->pixels + x + y * dev->page->pitch) = !broken ? 255 : 120; - if (y + 1 < dev->page->h) - *((uint8_t*)dev->page->pixels + x + (y + 1)*dev->page->pitch) = 120; - } - } -} - - static void print_bit_graph(escp_t *dev, uint8_t ch) { uint8_t pixel_w; /* width of the "pixel" */ uint8_t pixel_h; /* height of the "pixel" */ - uint8_t i, j, xx, yy; + unsigned i, j, xx, yy; double old_y; dev->bg_column[dev->bg_bytes_read++] = ch; @@ -1689,14 +1899,11 @@ print_bit_graph(escp_t *dev, uint8_t ch) pixel_w = 1; pixel_h = 1; - if (dev->bg_adjacent) - { + if (dev->bg_adjacent) { /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; } - - for (i = 0; i < dev->bg_bytes_per_column; i++) { /* for each byte */ @@ -1706,15 +1913,13 @@ print_bit_graph(escp_t *dev, uint8_t ch) /* draw a "pixel" */ for (xx = 0; xx < pixel_w; xx++) { for (yy = 0; yy < pixel_h; yy++) { - if (((PIXX + xx) < dev->page->w) && ((PIXY + yy) < dev->page->h)) { + if (((PIXX + xx) < (unsigned)dev->page->w) && ((PIXY + yy) < (unsigned)dev->page->h)) *((uint8_t *)dev->page->pixels + (PIXX + xx) + (PIXY + yy)*dev->page->pitch) |= (dev->color | 0x1f); - //((uint8_t *)(dev->page->pixels))[(PIXY + yy) * dev->page->pitch + (PIXX + xx)] |= (dev->color | 0x1f); - } } } } - dev->curr_y += 1.0 / dev->bg_v_density; + dev->curr_y += 1.0 / (double)dev->bg_v_density; } } @@ -1724,126 +1929,20 @@ print_bit_graph(escp_t *dev, uint8_t ch) /* Restore Y-position. */ dev->curr_y = old_y; + dev->bg_bytes_read = 0; + /* Advance print head. */ dev->curr_x += 1.0 / dev->bg_h_density; } -static void -handle_char(escp_t *dev) -{ - FT_UInt char_index; - uint16_t pen_x, pen_y; - uint8_t ch = dev->data; - uint16_t line_start, line_y; - double x_advance; - - if (dev->page == NULL) return; - - /* MSB mode */ - if (dev->msb != 255) { - if (dev->msb == 0) - ch &= 0x7f; - else if (dev->msb == 1) - ch |= 0x80; - } - - if (dev->bg_remaining_bytes > 0) { - print_bit_graph(dev, ch); - return; - } - - //pclog("Device data=%02x\n", ch); - - /* "print everything" mode? aka. ESC ( ^ */ - if (dev->print_everything_count > 0) { - /* do not process command char, just continue */ - dev->print_everything_count--; - } else if (process_char(dev, ch)) { - /* command was processed */ - return; - } - - /* We cannot print if we have no font loaded. */ - if (dev->fontface == 0) return; - - /* ok, so we need to print the character now */ - if (ft_lib) { - char_index = ft_Get_Char_Index(dev->fontface, dev->curr_cpmap[ch]); - ft_Load_Glyph(dev->fontface, char_index, FT_LOAD_DEFAULT); - ft_Render_Glyph(dev->fontface->glyph, FT_RENDER_MODE_NORMAL); - } - - pen_x = PIXX + dev->fontface->glyph->bitmap_left; - pen_y = (uint16_t)(PIXY - dev->fontface->glyph->bitmap_top + dev->fontface->size->metrics.ascender / 64); - - if (dev->font_style & STYLE_SUBSCRIPT) - pen_y += dev->fontface->glyph->bitmap.rows / 2; - - /* mark the page as dirty if anything is drawn */ - if ((ch != 0x20) || (dev->font_score != SCORE_NONE)) - dev->page->dirty = 1; - - /* draw the glyph */ - blit_glyph(dev, pen_x, pen_y, 0); - - /* doublestrike -> draw glyph a second time, 1px below */ - if (dev->font_style & STYLE_DOUBLESTRIKE) - blit_glyph(dev, pen_x, pen_y + 1, 1); - - /* bold -> draw glyph a second time, 1px to the right */ - if (dev->font_style & STYLE_BOLD) - blit_glyph(dev, pen_x + 1, pen_y, 1); - - line_start = PIXX; - - if (dev->font_style & STYLE_PROP) { - x_advance = dev->fontface->glyph->advance.x / (dev->dpi * 64.0); - } else { - if (dev->hmi < 0) - x_advance = 1.0 / dev->actual_cpi; - else - x_advance = dev->hmi; - } - - x_advance += dev->extra_intra_space; - dev->curr_x += x_advance; - - /* Line printing (underline etc.) */ - if (dev->font_score != SCORE_NONE && (dev->font_style & (STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE))) { - /* Find out where to put the line. */ - line_y = PIXY; - - if (dev->font_style & STYLE_UNDERLINE) - line_y = pen_y + 5 + dev->fontface->glyph->bitmap.rows; - if (dev->font_style & STYLE_STRIKETHROUGH) - line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.ascender / 128.0)); - if (dev->font_style & STYLE_OVERSCORE) - line_y = PIXY - ((dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) ? 5 : 0); - - draw_hline(dev, pen_x, PIXX, line_y, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); - - if (dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) - draw_hline(dev, line_start, PIXX, line_y + 5, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); - } - - if ((dev->curr_x + x_advance) > dev->right_margin) { - dev->curr_x = dev->left_margin; - dev->curr_y += dev->linespacing; - if (dev->curr_y > dev->bottom_margin) - new_page(dev, 1, 0); - } -} - - static void write_data(uint8_t val, void *priv) { escp_t *dev = (escp_t *)priv; - //DBGLOG(1, "ESC/P: data(%02x)\n", val); - - if (dev == NULL) return; + if (dev == NULL) + return; dev->data = val; } @@ -1854,12 +1953,8 @@ write_ctrl(uint8_t val, void *priv) { escp_t *dev = (escp_t *)priv; - ////pclog("ESC/P: ctrl(%02x)\n", val); - - if (dev == NULL) return; - - /* set autofeed value */ - dev->autofeed = val & 0x02 ? 1 : 0; + if (dev == NULL) + return; if (val & 0x08) { /* SELECT */ /* select printer */ @@ -1870,48 +1965,57 @@ write_ctrl(uint8_t val, void *priv) /* reset printer */ dev->select = 0; - reset_printer(dev); + reset_printer_hard(dev); } - - //pclog("Write control %02x\n", val & 1); - if (!(val & 0x01) && (dev->ctrl & 0x01)) { /* STROBE */ + /* Data is strobed to the parallel printer on the falling edge of the + strobe bit. */ + if (!(val & 0x01) && (dev->ctrl & 0x01)) { /* Process incoming character. */ - handle_char(dev); + handle_char(dev, dev->data); /* ACK it, will be read on next READ STATUS. */ dev->ack = 1; + + dev->timeout = 500000LL * TIMER_USEC; } dev->ctrl = val; + + dev->autofeed = ((val & 0x02) > 0); +} + + +static uint8_t +read_data(void *priv) +{ + escp_t *dev = (escp_t *)priv; + + return dev->data; +} + + +static uint8_t +read_ctrl(void *priv) +{ + escp_t *dev = (escp_t *)priv; + + return 0xe0 | dev->autofeed ? 0x02 : 0x00 | (dev->ctrl & 0xfd); } static uint8_t read_status(void *priv) { - escp_t *dev = (escp_t *)priv; - uint8_t ret; + escp_t *dev = (escp_t *)priv; + uint8_t ret = 0x1f; - if (dev == NULL) { - ret = 0xdf; - - return(ret); - } - else { - ret = 0x1f; - - if (!dev->busy) - ret |= 0x80; - - if (!dev->ack) - ret |= 0x40; + ret |= 0x80; - //DEBUG("ESC/P: status(%02x)\n", ret); - - return(ret); - } + if (!print_ack(dev)) + ret |= 0x40; + return(ret); } @@ -1920,15 +2024,15 @@ escp_init(const lpt_device_t *INFO) { const char *fn = PATH_FREETYPE_DLL; escp_t *dev; + int i; - //pclog("ESC/P: LPT printer '%s' initializing\n", INFO->name); + escp_log("ESC/P: LPT printer '%s' initializing\n", INFO->name); /* Dynamically load FreeType. */ if (ft_handle == NULL) { ft_handle = dynld_module(fn, ft_imports); if (ft_handle == NULL) { - ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081); - //ERRLOG("ESC/P: unable to load FreeType DLL !\n"); + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2120); return(NULL); } } @@ -1936,8 +2040,7 @@ escp_init(const lpt_device_t *INFO) /* Initialize FreeType. */ if (ft_lib == NULL) { if (ft_Init_FreeType(&ft_lib)) { - ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081); - //ERRLOG("ESC/P: error initializing FreeType !\n"); + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2120); dynld_close(ft_lib); ft_lib = NULL; return(NULL); @@ -1953,8 +2056,7 @@ escp_init(const lpt_device_t *INFO) /* Create a full pathname for the font files. */ wcscpy(dev->fontpath, exe_path); plat_path_slash(dev->fontpath); - wcscpy(dev->fontpath, L"roms/printer/"); - wcscat(dev->fontpath, L"fonts/"); + wcscat(dev->fontpath, L"roms/printer/fonts/"); /* Create the full path for the page images. */ plat_append_filename(dev->pagepath, usr_path, L"printer"); @@ -1962,8 +2064,9 @@ escp_init(const lpt_device_t *INFO) plat_dir_create(dev->pagepath); plat_path_slash(dev->pagepath); - /* Initialize parameters. */ - reset_printer(dev); + dev->page_width = PAGE_WIDTH; + dev->page_height = PAGE_HEIGHT; + dev->dpi = PAGE_DPI; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *)malloc(sizeof(psurface_t)); @@ -1973,8 +2076,41 @@ escp_init(const lpt_device_t *INFO) dev->page->pixels = (uint8_t *)malloc(dev->page->pitch * dev->page->h); memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); - //pclog("ESC/P: created a virtual page of dimensions %d x %d pixels.\n", - //dev->page->w, dev->page->h); + /* Initialize parameters. */ + for (i = 0; i < 32; i++) { + dev->palcol[i].r = 255; + dev->palcol[i].g = 255; + dev->palcol[i].b = 255; + } + + /* 0 = all white needed for logic 000 */ + fill_palette( 0, 0, 0, 1, dev); + /* 1 = magenta* 001 */ + fill_palette( 0, 255, 0, 1, dev); + /* 2 = cyan* 010 */ + fill_palette(255, 0, 0, 2, dev); + /* 3 = "violet" 011 */ + fill_palette(255, 255, 0, 3, dev); + /* 4 = yellow* 100 */ + fill_palette( 0, 0, 255, 4, dev); + /* 5 = red 101 */ + fill_palette( 0, 255, 255, 5, dev); + /* 6 = green 110 */ + fill_palette(255, 0, 255, 6, dev); + /* 7 = black 111 */ + fill_palette(255, 255, 255, 7, dev); + + dev->color = COLOR_BLACK; + dev->fontface = 0; + dev->autofeed = 0; + + reset_printer(dev); + + escp_log("ESC/P: created a virtual page of dimensions %d x %d pixels.\n", + dev->page->w, dev->page->h); + + timer_add(timeout_timer, &dev->timeout, &dev->timeout, dev); + return(dev); } @@ -2006,5 +2142,7 @@ const lpt_device_t lpt_prt_escp_device = { escp_close, write_data, write_ctrl, - read_status + read_data, + read_status, + read_ctrl }; diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index 24bf95cbe..ec862f2dc 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -101,6 +101,9 @@ typedef struct { /* Output file name. */ wchar_t filename[1024]; + /* Printer timeout. */ + int64_t timeout; + /* page data (TODO: make configurable) */ double page_width, /* all in inches */ page_height, @@ -193,6 +196,18 @@ new_page(prnt_t *dev) } +static void +timeout_timer(void *priv) +{ + prnt_t *dev = (prnt_t *) priv; + + if (dev->page->dirty) + new_page(dev); + + dev->timeout = 0LL; +} + + static void reset_printer(prnt_t *dev) { @@ -221,6 +236,8 @@ reset_printer(prnt_t *dev) /* Create a file for this page. */ plat_tempfile(dev->filename, NULL, L".txt"); + + dev->timeout = 0LL; } @@ -280,7 +297,7 @@ process_char(prnt_t *dev, uint8_t ch) case 0x11: /* select printer (DC1) */ /* Ignore. */ - return 1; + return 0; case 0x12: /* cancel condensed printing (DC2) */ /* Ignore. */ @@ -375,6 +392,8 @@ write_ctrl(uint8_t val, void *priv) /* ACK it, will be read on next READ STATUS. */ dev->ack = 1; + + dev->timeout = 500000LL * TIMER_USEC; } dev->ctrl = val; @@ -427,6 +446,8 @@ prnt_init(const lpt_device_t *INFO) //DEBUG("PRNT: created a virtual %ix%i page.\n", dev->page->w, dev->page->h); + timer_add(timeout_timer, &dev->timeout, &dev->timeout, dev); + return(dev); } @@ -458,5 +479,7 @@ const lpt_device_t lpt_prt_text_device = { prnt_close, write_data, write_ctrl, - read_status + NULL, + read_status, + NULL }; diff --git a/src/rom.c b/src/rom.c index 70768af9b..c16499dc1 100644 --- a/src/rom.c +++ b/src/rom.c @@ -13,7 +13,7 @@ * - c386sx16 BIOS fails checksum * - the loadfont() calls should be done elsewhere * - * Version: @(#)rom.c 1.0.42 2018/11/02 + * Version: @(#)rom.c 1.0.43 2019/01/13 * * Authors: Sarah Walker, * Miran Grca, @@ -519,6 +519,13 @@ rom_load_bios(int rom_id) biosmask = 0x3fff; return(1); + case ROM_ZD_SUPERS: /* [8088] Zenith Data Systems SupersPort */ + if (!rom_load_linear( + L"roms/machines/zdsupers/z184m v3.1d.10d", + 0x000000, 32768, 0, rom)) break; + biosmask = 0x7fff; + return(1); + case ROM_CMDPC30: if (! rom_load_interleaved( L"roms/machines/cmdpc30/commodore pc 30 iii even.bin", diff --git a/src/rom.h b/src/rom.h index e330de1a1..b48805a6b 100644 --- a/src/rom.h +++ b/src/rom.h @@ -8,7 +8,7 @@ * * Definitions for the ROM image handler. * - * Version: @(#)rom.h 1.0.20 2018/11/02 + * Version: @(#)rom.h 1.0.21 2019/01/13 * * Author: Fred N. van Kempen, * Copyright 2018 Fred N. van Kempen. @@ -58,7 +58,8 @@ enum { ROM_PC3086, ROM_OLIM24, ROM_TANDY1000SL2, - + ROM_ZD_SUPERS, + ROM_T3100E, ROM_AMI286, diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 3b81c9eb3..8ac6e3e4a 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -11,7 +11,7 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.43 2018/10/28 + * Version: @(#)scsi_buslogic.c 1.0.44 2018/11/11 * * Authors: TheCollector1995, * Miran Grca, @@ -1575,6 +1575,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA335"; dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 15; /* wide SCSI */ break; case CHIP_BUSLOGIC_ISA: default: @@ -1588,6 +1589,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA421E"; dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 15; /* wide SCSI */ break; case CHIP_BUSLOGIC_MCA: strcpy(dev->name, "BT-640A"); @@ -1602,6 +1604,7 @@ buslogic_init(const device_t *info) dev->pos_regs[1] = 0x07; mca_add(buslogic_mca_read, buslogic_mca_write, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 15; /* wide SCSI */ break; case CHIP_BUSLOGIC_VLB: strcpy(dev->name, "BT-445S"); @@ -1610,11 +1613,14 @@ buslogic_init(const device_t *info) 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"; + autoscsi_rom_size = 0x8000; + has_scam_rom = 1; + scam_rom_name = L"roms/scsi/buslogic/BT-445S_SCAM.rom"; + scam_rom_size = 0x0200; + dev->fw_rev = "AA507B"; dev->bit32 = 1; dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 15; /* wide SCSI */ break; case CHIP_BUSLOGIC_PCI: strcpy(dev->name, "BT-958D"); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 5dce001eb..782f41d5c 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)scsi_cdrom.c 1.0.68 2018/11/02 + * Version: @(#)scsi_cdrom.c 1.0.69 2018/11/11 * * Author: Miran Grca, * @@ -2025,6 +2025,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_PLAY_AUDIO_TRACK_INDEX: case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: + len = 0; + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); switch(cdb[0]) { @@ -2168,7 +2170,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (ret) { scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, - len, 0); + alloc_length, 0); } else scsi_cdrom_buf_free(dev); return; diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index 1140be35d..def2cb6bc 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -2652,6 +2652,7 @@ ncr53c8xx_init(const device_t *info) if (dev->has_bios) rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); if (dev->chip >= CHIP_825) { + if (dev->chip == CHIP_875) { dev->chip_rev = 0x04; dev->nvr_path = L"ncr53c875.nvr"; diff --git a/src/serial.c b/src/serial.c index 5b8896081..5756c6d97 100644 --- a/src/serial.c +++ b/src/serial.c @@ -56,11 +56,37 @@ serial_reset_port(serial_t *dev) dev->iir = dev->ier = dev->lcr = dev->fcr = 0; dev->fifo_enabled = 0; dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; - memset(dev->xmit_fifo, 0, 14); + memset(dev->xmit_fifo, 0, 16); memset(dev->rcvr_fifo, 0, 14); } +void +serial_transmit_period(serial_t *dev) +{ + double ddlab, byte_period, bits, dusec; + + ddlab = (double) dev->dlab; + /* Bit period based on DLAB. */ + byte_period = (16000000.0 * ddlab) / 1846200.0; + /* Data bits according to LCR 1,0. */ + bits = (double) ((dev->lcr & 0x03) + 5); + /* Stop bits. */ + if (dev->lcr & 0x04) + bits += !(dev->lcr & 0x03) ? 1.5 : 2.0; + else + bits += 1.0; + /* Parity bits. */ + if (dev->lcr & 0x08) + bits += 1.0; + byte_period *= bits; + dusec = (double) TIMER_USEC; + byte_period *= dusec; + + dev->transmit_period = (int64_t) byte_period; +} + + void serial_update_ints(serial_t *dev) { @@ -73,7 +99,7 @@ serial_update_ints(serial_t *dev) stat = 1; dev->iir = 6; } else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_RECEIVE)) { - /* Recieved data available */ + /* Received data available */ stat = 1; dev->iir = 4; } else if ((dev->ier & 2) && (dev->int_status & SERIAL_INT_TRANSMIT)) { @@ -99,21 +125,19 @@ serial_update_ints(serial_t *dev) void serial_write_fifo(serial_t *dev, uint8_t dat) { - uint8_t old_lsr; serial_log("serial_write_fifo(%08X, %02X, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled); if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { /* FIFO mode. */ dev->rcvr_fifo[dev->rcvr_fifo_pos++] = dat; - dev->rcvr_fifo_pos %= dev->fifo_len; - old_lsr = dev->lsr; + dev->rcvr_fifo_pos %= dev->rcvr_fifo_len; dev->lsr &= 0xfe; dev->lsr |= (!dev->rcvr_fifo_pos); dev->int_status &= SERIAL_INT_RECEIVE; - if (!dev->rcvr_fifo_pos) + if (!dev->rcvr_fifo_pos) { dev->int_status |= SERIAL_INT_RECEIVE; - if ((old_lsr ^ dev->lsr) & 0x01) serial_update_ints(dev); + } } else { /* Non-FIFO mode. */ dev->dat = dat; @@ -125,7 +149,7 @@ serial_write_fifo(serial_t *dev, uint8_t dat) void -serial_dev_write(serial_t *dev, uint8_t val) +serial_transmit(serial_t *dev, uint8_t val) { if (dev->mctrl & 0x10) serial_write_fifo(dev, val); @@ -134,47 +158,84 @@ serial_dev_write(serial_t *dev, uint8_t val) } +static void +serial_transmit_timer(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + if (dev->fifo_enabled) { + serial_transmit(dev, dev->xmit_fifo[dev->xmit_fifo_pos++]); + if (dev->xmit_fifo_pos == 16) { + dev->transmit_delay = 0LL; + dev->xmit_fifo_pos = 0; + /* Mark both FIFO and shift register as empty. */ + dev->lsr |= 0x40; + } else + dev->transmit_delay += dev->transmit_period; + } else { + serial_transmit(dev, dev->thr); + dev->transmit_delay = 0LL; + /* Mark both THR and shift register as empty. */ + dev->lsr |= 0x40; + } +} + + void serial_write(uint16_t addr, uint8_t val, void *p) { serial_t *dev = (serial_t *)p; - uint8_t new_msr, old_lsr, i; + uint8_t new_msr, old_lsr, old; serial_log("UART: Write %02X to port %02X\n", val, addr); switch (addr & 7) { case 0: if (dev->lcr & 0x80) { - dev->dlab1 = val; + dev->dlab = (dev->dlab & 0xff00) | val; + serial_transmit_period(dev); return; } if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { /* FIFO mode. */ dev->xmit_fifo[dev->xmit_fifo_pos++] = val; - dev->xmit_fifo_pos %= dev->fifo_len; + dev->xmit_fifo_pos &= 0x0f; old_lsr = dev->lsr; - dev->lsr &= 0xdf; - if (!dev->xmit_fifo_pos) { - for (i = 0; i < dev->fifo_len; i++) - serial_dev_write(dev, dev->xmit_fifo[i]); + /* Indicate FIFO is no longer empty. */ + if (dev->xmit_fifo_pos) { + /* FIFO not yet full. */ + /* Update interrupts. */ + dev->lsr &= 0x9f; + if ((old_lsr ^ dev->lsr) & 0x20) + serial_update_ints(dev); + } else { + /* FIFO full, begin transmitting. */ + dev->transmit_delay = dev->transmit_period; + dev->lsr &= 0xbf; + /* Update interrupts. */ dev->lsr |= 0x20; dev->int_status |= SERIAL_INT_TRANSMIT; - } - if ((old_lsr ^ dev->lsr) & 0x20) serial_update_ints(dev); + } } else { /* Non-FIFO mode. */ + /* Begin transmitting. */ + dev->transmit_delay = dev->transmit_period; dev->thr = val; + /* Clear bit 6 because shift register is full. */ + dev->lsr &= 0xbf; + /* But set bit 5 before THR is empty. */ dev->lsr |= 0x20; + /* Update interrupts. */ dev->int_status |= SERIAL_INT_TRANSMIT; - serial_dev_write(dev, val); serial_update_ints(dev); } break; case 1: if (dev->lcr & 0x80) { - dev->dlab2 = val; + dev->dlab = (dev->dlab & 0x00ff) | (val << 8); + serial_transmit_period(dev); return; } dev->ier = val & 0xf; @@ -184,6 +245,13 @@ serial_write(uint16_t addr, uint8_t val, void *p) if (dev->type >= SERIAL_NS16550) { dev->fcr = val & 0xf9; dev->fifo_enabled = val & 0x01; + if (!dev->fifo_enabled) { + memset(dev->rcvr_fifo, 0, 14); + memset(dev->xmit_fifo, 0, 14); + dev->rcvr_fifo_pos = dev->xmit_fifo_pos = 0; + dev->rcvr_fifo_len = 1; + break; + } if (val & 0x02) { memset(dev->rcvr_fifo, 0, 14); dev->rcvr_fifo_pos = 0; @@ -194,22 +262,25 @@ serial_write(uint16_t addr, uint8_t val, void *p) } switch ((val >> 6) & 0x03) { case 0: - dev->fifo_len = 1; + dev->rcvr_fifo_len = 1; break; case 1: - dev->fifo_len = 4; + dev->rcvr_fifo_len = 4; break; case 2: - dev->fifo_len = 8; + dev->rcvr_fifo_len = 8; break; case 3: - dev->fifo_len = 14; + dev->rcvr_fifo_len = 14; break; } } break; case 3: + old = dev->lcr; dev->lcr = val; + if ((old ^ val) & 0x0f) + serial_transmit_period(dev); break; case 4: if ((val & 2) && !(dev->mctrl & 2)) { @@ -261,25 +332,23 @@ uint8_t serial_read(uint16_t addr, void *p) { serial_t *dev = (serial_t *)p; - uint8_t old_lsr, ret = 0; + uint8_t ret = 0; switch (addr & 7) { case 0: if (dev->lcr & 0x80) { - ret = dev->dlab1; + ret = dev->dlab & 0xff; break; } if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { /* FIFO mode. */ ret = dev->rcvr_fifo[dev->rcvr_fifo_pos++]; - dev->rcvr_fifo_pos %= dev->fifo_len; - old_lsr = dev->lsr; + dev->rcvr_fifo_pos %= dev->rcvr_fifo_len; if (!dev->rcvr_fifo_pos) { dev->lsr &= 0xfe; dev->int_status &= ~SERIAL_INT_RECEIVE; - if ((old_lsr ^ dev->lsr) & 0x01) - serial_update_ints(dev); + serial_update_ints(dev); } } else { ret = dev->dat; @@ -287,10 +356,11 @@ serial_read(uint16_t addr, void *p) dev->int_status &= ~SERIAL_INT_RECEIVE; serial_update_ints(dev); } + serial_log("Read data: %02X\n", ret); break; case 1: if (dev->lcr & 0x80) - ret = dev->dlab2; + ret = (dev->dlab >> 8) & 0xff; else ret = dev->ier; break; @@ -401,23 +471,26 @@ serial_init(const device_t *info) serial_t *dev = (serial_t *) malloc(sizeof(serial_t)); memset(dev, 0, sizeof(serial_t)); - dev->base_address = next_inst ? 0x03f8 : 0x02f8; dev->inst = next_inst; if (serial_enabled[next_inst]) { serial_log("Adding serial port %i...\n", next_inst); - io_sethandler(dev->base_address, 0x0008, - serial_read, NULL, NULL, serial_write, NULL, NULL, dev); - dev->irq = next_inst ? 4 : 3; dev->type = info->local; memset(&(serial_devices[next_inst]), 0, sizeof(serial_device_t)); dev->sd = &(serial_devices[next_inst]); dev->sd->serial = dev; serial_reset_port(dev); - if (next_inst) + if (next_inst || (info->flags & DEVICE_PCJR)) serial_setup(dev, SERIAL2_ADDR, SERIAL2_IRQ); else serial_setup(dev, SERIAL1_ADDR, SERIAL1_IRQ); + + /* Default to 1200,N,7. */ + dev->dlab = 96; + dev->fcr = 0x06; + serial_transmit_period(dev); + dev->transmit_delay = 0LL; + timer_add(serial_transmit_timer, &dev->transmit_delay, &dev->transmit_delay, dev); } next_inst++; @@ -426,6 +499,20 @@ serial_init(const device_t *info) } +void +serial_standalone_init(void) { + if (next_inst == 0) { + if (PCJR) + device_add(&i8250_pcjr_device); + else { + device_add_inst(&i8250_device, 1); + device_add_inst(&i8250_device, 2); + } + } else if (next_inst == 1) + device_add_inst(&i8250_device, 2); +}; + + const device_t i8250_device = { "Intel 8250(-compatible) UART", 0, @@ -435,6 +522,15 @@ const device_t i8250_device = { NULL }; +const device_t i8250_pcjr_device = { + "Intel 8250(-compatible) UART for PCjr", + DEVICE_PCJR, + SERIAL_8250, + serial_init, serial_close, NULL, + NULL, NULL, NULL, + NULL +}; + const device_t ns16540_device = { "National Semiconductor NS16540(-compatible) UART", 0, diff --git a/src/serial.h b/src/serial.h index 722a4e6a1..6293af003 100644 --- a/src/serial.h +++ b/src/serial.h @@ -8,7 +8,7 @@ * * Definitions for the SERIAL card. * - * Version: @(#)serial.h 1.0.8 2018/11/04 + * Version: @(#)serial.h 1.0.9 2018/11/12 * * Author: Fred N. van Kempen, * Copyright 2017,2018 Fred N. van Kempen. @@ -35,7 +35,7 @@ typedef struct serial_s { uint8_t lsr, thr, mctrl, rcr, iir, ier, lcr, msr; - uint8_t dlab1, dlab2; + uint16_t dlab; uint8_t dat; uint8_t int_status; uint8_t scratch; @@ -45,11 +45,11 @@ typedef struct serial_s inst; uint16_t base_address; - uint8_t fifo_len, fifo_enabled; + uint8_t fifo_enabled, rcvr_fifo_len; uint8_t rcvr_fifo_pos, rcvr_fifo[14]; - uint8_t xmit_fifo_pos, xmit_fifo[14]; + uint8_t xmit_fifo_pos, xmit_fifo[16]; - int64_t recieve_delay; + int64_t transmit_delay, transmit_period; struct serial_device_s *sd; } serial_t; @@ -68,11 +68,14 @@ extern serial_t * serial_attach(int port, void (*dev_write)(struct serial_s *serial, void *p, uint8_t data), void *priv); extern void serial_remove(serial_t *dev); +extern void serial_set_type(serial_t *dev, int type); extern void serial_setup(serial_t *dev, uint16_t addr, int irq); extern void serial_clear_fifo(serial_t *dev); extern void serial_write_fifo(serial_t *dev, uint8_t dat); +extern void serial_standalone_init(void); extern const device_t i8250_device; +extern const device_t i8250_pcjr_device; extern const device_t ns16540_device; extern const device_t ns16550_device; diff --git a/src/sio_fdc37c66x.c b/src/sio_fdc37c66x.c index 9185b397a..4f6ce8719 100644 --- a/src/sio_fdc37c66x.c +++ b/src/sio_fdc37c66x.c @@ -9,7 +9,7 @@ * Implementation of the SMC FDC37C663 and FDC37C665 Super * I/O Chips. * - * Version: @(#)sio_fdc37c66x.c 1.0.13 2018/11/05 + * Version: @(#)sio_fdc37c66x.c 1.0.14 2018/11/12 * * Authors: Sarah Walker, * Miran Grca, @@ -208,8 +208,8 @@ fdc37c66x_reset(fdc37c66x_t *dev) serial_remove(dev->uart[0]); serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_remove(dev->uart[0]); - serial_setup(dev->uart[0], SERIAL2_ADDR, SERIAL2_IRQ); + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); lpt2_remove(); diff --git a/src/sio_fdc37c93x.c b/src/sio_fdc37c93x.c index adf5d45f4..ab9cfabfb 100644 --- a/src/sio_fdc37c93x.c +++ b/src/sio_fdc37c93x.c @@ -9,7 +9,7 @@ * Implementation of the SMC FDC37C932FR and FDC37C935 Super * I/O Chips. * - * Version: @(#)sio_fdc37c93x.c 1.0.14 2018/11/05 + * Version: @(#)sio_fdc37c93x.c 1.0.15 2018/11/12 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. diff --git a/src/sio_pc87306.c b/src/sio_pc87306.c index 8901b4b02..f0f3e48b0 100644 --- a/src/sio_pc87306.c +++ b/src/sio_pc87306.c @@ -8,7 +8,7 @@ * * Emulation of the NatSemi PC87306 Super I/O chip. * - * Version: @(#)sio_pc87306.c 1.0.14 2018/11/05 + * Version: @(#)sio_pc87306.c 1.0.15 2018/11/12 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -370,7 +370,7 @@ pc87306_reset(pc87306_t *dev) serial_remove(dev->uart[0]); serial_remove(dev->uart[1]); serial_handler(dev, 0); - serial_handler(dev, 0); + serial_handler(dev, 1); fdc_reset(dev->fdc); pc87306_gpio_init(dev); } diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 5c99d0f06..822213d11 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -225,7 +225,7 @@ void* fluidsynth_init(const device_t *info) /* Try loading the DLL. */ #ifdef _WIN32 - fluidsynth_handle = dynld_module("libfluidsynth-1.dll", fluidsynth_imports); + fluidsynth_handle = dynld_module("libfluidsynth.dll", fluidsynth_imports); #else fluidsynth_handle = dynld_module("libfluidsynth.so", fluidsynth_imports); #endif diff --git a/src/sound/snd_lpt_dac.c b/src/sound/snd_lpt_dac.c index 0e271ea2d..c92201d57 100644 --- a/src/sound/snd_lpt_dac.c +++ b/src/sound/snd_lpt_dac.c @@ -111,7 +111,9 @@ const lpt_device_t lpt_dac_device = dac_close, dac_write_data, dac_write_ctrl, - dac_read_status + NULL, + dac_read_status, + NULL }; const lpt_device_t lpt_dac_stereo_device = { @@ -120,5 +122,7 @@ const lpt_device_t lpt_dac_stereo_device = dac_close, dac_write_data, dac_write_ctrl, - dac_read_status + NULL, + dac_read_status, + NULL }; diff --git a/src/sound/snd_lpt_dss.c b/src/sound/snd_lpt_dss.c index bacd1e706..48ed68949 100644 --- a/src/sound/snd_lpt_dss.c +++ b/src/sound/snd_lpt_dss.c @@ -116,5 +116,7 @@ const lpt_device_t dss_device = dss_close, dss_write_data, dss_write_ctrl, - dss_read_status + NULL, + dss_read_status, + NULL }; diff --git a/src/sound/snd_speaker.c b/src/sound/snd_speaker.c index 5defaa2c1..6ddb772a9 100644 --- a/src/sound/snd_speaker.c +++ b/src/sound/snd_speaker.c @@ -8,61 +8,62 @@ #include "snd_speaker.h" -int speaker_mute = 0; -int speaker_gated = 0; +int speaker_mute = 0, speaker_gated = 0; int speaker_enable = 0, was_speaker_enable = 0; - int gated,speakval,speakon; -static int16_t speaker_buffer[SOUNDBUFLEN]; +static int32_t speaker_buffer[SOUNDBUFLEN]; static int speaker_pos = 0; -void speaker_update(void) +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; + int32_t val; - if (!speaker_enable) - was_speaker_enable = 0; + if (speaker_pos >= sound_pos_global) + return; - speaker_buffer[speaker_pos] = 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; -static void speaker_get_buffer(int32_t *buffer, int len, void *p) -{ - int c; + if (!speaker_enable) + was_speaker_enable = 0; - speaker_update(); - - if (!speaker_mute) - { - for (c = 0; c < len * 2; c++) - buffer[c] += speaker_buffer[c >> 1]; - } - - speaker_pos = 0; + speaker_buffer[speaker_pos] = val; + } } -void speaker_init(void) +static void +speaker_get_buffer(int32_t *buffer, int len, void *p) { - sound_add_handler(speaker_get_buffer, NULL); - speaker_mute = 0; + 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/sound/sound.c b/src/sound/sound.c index c9f66b519..0879c3536 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.25 2018/10/28 + * Version: @(#)sound.c 1.0.26 2019/01/13 * * Authors: Sarah Walker, * Miran Grca, @@ -439,6 +439,10 @@ sound_card_reset(void) mpu401_device_add(); if (GUS) device_add(&gus_device); +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) + if (GUSMAX) + device_add(&gusmax_device); +#endif if (GAMEBLASTER) device_add(&cms_device); if (SSI2001) diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 59a8f3ca3..3a59a8999 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -177,7 +177,7 @@ static void ati18800_recalctimings(svga_t *svga) svga->vblankstart <<= 1; } - if (!svga->scrblank && (ati18800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + if (!svga->scrblank && ((ati18800->regs[0xb0] & 0x02) || (ati18800->regs[0xb0] & 0x04))) /*Extended 256 colour modes*/ { svga->render = svga_render_8bpp_highres; svga->bpp = 8; @@ -210,7 +210,7 @@ static void *ati18800_init(const device_t *info) break; }; - svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ + svga_init(&ati18800->svga, ati18800, 1 << 20, /*512kb*/ ati18800_recalctimings, ati18800_in, ati18800_out, NULL, diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 965a56f4b..4850d13c4 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -123,37 +123,20 @@ static void ati28800_out(uint16_t addr, uint8_t val, void *p) case 0x1cf: old=ati28800->regs[ati28800->index]; ati28800->regs[ati28800->index] = val; - pclog("ATI write reg=%02x\n", ati28800->index); + ati28800_log("ATI write reg=%02x\n", ati28800->index); switch (ati28800->index) { - case 0xb2: case 0xbe: case 0xbd: if (ati28800->regs[0xbe] & 8) /*Read/write bank mode*/ { - if (ati28800->regs[0xbd] & 4) - { - svga->read_bank = (((ati28800->regs[0xb2] >> 5) & 7) * 0x20000); - svga->write_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x20000); - } - else - { svga->read_bank = (((ati28800->regs[0xb2] >> 5) & 7) * 0x10000); svga->write_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x10000); - } } else /*Single bank mode*/ { - if (ati28800->regs[0xbd] & 4) - { - svga->read_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x20000); - svga->write_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x20000); - } - else - { svga->read_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x10000); svga->write_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x10000); - } } break; case 0xb3: @@ -183,6 +166,7 @@ static void ati28800_out(uint16_t addr, uint8_t val, void *p) 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) @@ -321,7 +305,7 @@ static uint8_t ati28800_in(uint16_t addr, void *p) temp = svga->crtcreg; break; case 0x3D5: - temp = svga->crtc[svga->crtcreg]; + temp = svga->crtc[svga->crtcreg]; break; default: temp = svga_in(addr, svga); @@ -381,9 +365,11 @@ static void ati28800_recalctimings(svga_t *svga) { case 0x00: svga->clock = cpuclock / 42954000.0; break; case 0x01: svga->clock = cpuclock / 48771000.0; break; + case 0x02: pclog ("clock 2\n"); 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 0x06: pclog ("clock 2\n"); 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; @@ -396,15 +382,15 @@ static void ati28800_recalctimings(svga_t *svga) default: break; } - if(ati28800->regs[0xb8] & 0x40) svga->clock *= 2; + if(ati28800->regs[0xb8] & 0x40) + svga->clock *= 2; - - if (ati28800->regs[0xb6] & 0x10) - { - svga->hdisp <<= 1; - svga->htotal <<= 1; - svga->rowoffset <<= 1; - } + if (ati28800->regs[0xb6] & 0x10) + { + svga->hdisp <<= 1; + svga->htotal <<= 1; + svga->rowoffset <<= 1; + } if(svga->crtc[0x17] & 4) { diff --git a/src/video/vid_att20c49x_ramdac.c b/src/video/vid_att20c49x_ramdac.c new file mode 100644 index 000000000..bc3af28e8 --- /dev/null +++ b/src/video/vid_att20c49x_ramdac.c @@ -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. + * + * Emulation of a AT&T 20c490/491 and 492/493 RAMDAC. + * + * Version: @(#)vid_att20c49x_ramdac.c 1.0.1 2019/01/12 + * + * 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 "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_att20c49x_ramdac.h" + +enum +{ + ATT_490_1 = 0, + ATT_492_3 +}; + +void +att49x_ramdac_out(uint16_t addr, uint8_t val, att49x_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + ramdac->ctrl = val; + if (ramdac->type == ATT_490_1) + svga_set_ramdac_type(svga, (val & 2) ? RAMDAC_8BIT : RAMDAC_6BIT); + switch (val) + { + case 0: + svga->bpp = 8; + break; + + case 0x20: + svga->bpp = 15; + break; + + case 0x40: + svga->bpp = 24; + break; + + case 0x60: + svga->bpp = 16; + break; + + case 0x80: + case 0xa0: + svga->bpp = 15; + break; + + case 0xc0: + svga->bpp = 16; + break; + + case 0xe0: + svga->bpp = 24; + break; + } + 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 +att49x_ramdac_in(uint16_t addr, att49x_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; + temp = svga_in(addr, svga); + + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + temp = ramdac->ctrl; + break; + } + ramdac->state++; + break; + case 0x3C7: + case 0x3C8: + case 0x3C9: + ramdac->state = 0; + break; + } + + return temp; +} + + +static void * +att49x_ramdac_init(const device_t *info) +{ + att49x_ramdac_t *ramdac = (att49x_ramdac_t *) malloc(sizeof(att49x_ramdac_t)); + memset(ramdac, 0, sizeof(att49x_ramdac_t)); + + ramdac->type = info->local; + + return ramdac; +} + + +static void +att49x_ramdac_close(void *priv) +{ + att49x_ramdac_t *ramdac = (att49x_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t att490_ramdac_device = +{ + "AT&T 20c490/20c491 RAMDAC", + 0, ATT_490_1, + att49x_ramdac_init, att49x_ramdac_close, + NULL, NULL, NULL, NULL +}; + +const device_t att492_ramdac_device = +{ + "AT&T 20c492/20c493 RAMDAC", + 0, ATT_492_3, + att49x_ramdac_init, att49x_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_att20c49x_ramdac.h b/src/video/vid_att20c49x_ramdac.h new file mode 100644 index 000000000..2a191afcf --- /dev/null +++ b/src/video/vid_att20c49x_ramdac.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. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of a Sierra SC1502X RAMDAC. + * + * Used by the TLIVESA1 driver for ET4000. + * + * Version: @(#)vid_sc1502x_ramdac.h 1.0.0 2018/10/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +typedef struct +{ + int type; + int state; + uint8_t ctrl; +} att49x_ramdac_t; + +extern void att49x_ramdac_out(uint16_t addr, uint8_t val, att49x_ramdac_t *ramdac, svga_t *svga); +extern uint8_t att49x_ramdac_in(uint16_t addr, att49x_ramdac_t *ramdac, svga_t *svga); + +extern const device_t att490_ramdac_device; +extern const device_t att492_ramdac_device; diff --git a/src/video/vid_av9194.c b/src/video/vid_av9194.c new file mode 100644 index 000000000..ad3f706a1 --- /dev/null +++ b/src/video/vid_av9194.c @@ -0,0 +1,102 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * AV9194 clock generator emulation. + * + * Used by the S3 86c801 (V7-Mirage) card. + * + * Version: @(#)vid_av9194.c 1.0.1 2019/01/12 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "vid_av9194.h" + + +float +av9194_getclock(int clock, void *p) +{ + float ret = 0.0; + + switch (clock & 0x0f) + { + case 0: + ret = 25175000.0; + break; + case 1: + ret = 28322000.0; + break; + case 2: + ret = 40000000.0; + break; + case 4: + ret = 50000000.0; + break; + case 5: + ret = 77000000.0; + break; + case 6: + ret = 36000000.0; + break; + case 7: + ret = 44900000.0; + break; + case 8: + ret = 130000000.0; + break; + case 9: + ret = 120000000.0; + break; + case 0xa: + ret = 80000000.0; + break; + case 0xb: + ret = 31500000.0; + break; + case 0xc: + ret = 110000000.0; + break; + case 0xd: + ret = 65000000.0; + break; + case 0xe: + ret = 75000000.0; + break; + case 0xf: + ret = 94500000.0; + break; + } + + return ret; +} + + +static void * +av9194_init(const device_t *info) +{ + /* Return something non-NULL. */ + return (void *) &av9194_device; +} + + +const device_t av9194_device = +{ + "AV9194 Clock Generator", + 0, 0, + av9194_init, NULL, + NULL, NULL, NULL, NULL +}; + diff --git a/src/video/vid_av9194.h b/src/video/vid_av9194.h new file mode 100644 index 000000000..11760fe53 --- /dev/null +++ b/src/video/vid_av9194.h @@ -0,0 +1,21 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * AV9194 clock generator emulation. + * + * Used by the S3 86c801 (V7-Mirage) card. + * + * Version: @(#)vid_av9194.c 1.0.1 2019/01/12 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +float av9194_getclock(int clock, void *p); + +extern const device_t av9194_device; diff --git a/src/video/vid_bt48x_ramdac.c b/src/video/vid_bt48x_ramdac.c index e1ff57810..6fb88771b 100644 --- a/src/video/vid_bt48x_ramdac.c +++ b/src/video/vid_bt48x_ramdac.c @@ -9,7 +9,7 @@ * Emulation of the Brooktree BT484-485A true colour RAMDAC * family. * - * Version: @(#)vid_bt48x_ramdac.c 1.0.14 2018/10/19 + * Version: @(#)vid_bt48x_ramdac.c 1.0.16 2019/01/12 * * Authors: Miran Grca, * TheCollector1995, @@ -42,22 +42,24 @@ enum { static void bt48x_set_bpp(bt48x_ramdac_t *ramdac, svga_t *svga) { - if (!(ramdac->cr2 & 0x20)) + if ((!(ramdac->cr2 & 0x20)) || ((ramdac->type >= BT485A) && ((ramdac->cr3 & 0x60) == 0x60))) svga->bpp = 8; - else switch ((ramdac->cr1 >> 5) & 0x03) { - case 0: + else if ((ramdac->type >= BT485A) && ((ramdac->cr3 & 0x60) == 0x40)) + svga->bpp = 24; + else switch (ramdac->cr1 & 0x60) { + case 0x00: svga->bpp = 32; break; - case 1: + case 0x20: if (ramdac->cr1 & 0x08) svga->bpp = 16; else svga->bpp = 15; break; - case 2: + case 0x40: svga->bpp = 8; break; - case 3: + case 0x60: svga->bpp = 4; break; } @@ -80,7 +82,9 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r switch (rs) { case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ case 0x03: + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ svga->dac_pos = 0; svga->dac_status = addr & 0x03; svga->dac_addr = val; @@ -93,12 +97,6 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r 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) */ - 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; @@ -112,7 +110,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r svga->dac_pos++; break; case 2: - index = ramdac->ext_addr & 3; + index = svga->dac_addr & 3; ramdac->extpal[index].r = svga->dac_r; ramdac->extpal[index].g = svga->dac_g; ramdac->extpal[index].b = val; @@ -127,7 +125,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r if (o32 != svga->overscan_color) svga_recalctimings(svga); } - ramdac->ext_addr = (ramdac->ext_addr + 1) & 0xff; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; svga->dac_pos = 0; break; } @@ -147,10 +145,12 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r break; case 0x0a: if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { - switch ((svga->dac_addr & 0xff)) { + switch ((svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f))) { case 0x01: /* Command Register 3 (RS value = 1010) */ ramdac->cr3 = val; + if (ramdac->type >= BT485A) + bt48x_set_bpp(ramdac, svga); 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; @@ -224,16 +224,15 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_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 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ temp = svga_in(addr, svga); break; case 0x03: /* Palette Read Index Register (RS value = 0011) */ + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ 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 = (ramdac->ext_addr - 1) & 3; + index = (svga->dac_addr - 1) & 3; svga->dac_status = 3; switch (svga->dac_pos) { case 0: @@ -252,7 +251,7 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *ramdac, svga_t break; case 2: svga->dac_pos=0; - ramdac->ext_addr = ramdac->ext_addr + 1; + svga->dac_addr = svga->dac_addr + 1; if (svga->ramdac_type == RAMDAC_8BIT) temp = ramdac->extpal[index].b; else @@ -263,9 +262,6 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_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; @@ -274,8 +270,9 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *ramdac, svga_t break; case 0x0a: if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { - switch ((svga->dac_addr & 0xff)) { + switch ((svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f))) { case 0x00: + default: temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); break; case 0x01: diff --git a/src/video/vid_bt48x_ramdac.h b/src/video/vid_bt48x_ramdac.h index 18d2d2229..186e70101 100644 --- a/src/video/vid_bt48x_ramdac.h +++ b/src/video/vid_bt48x_ramdac.h @@ -9,7 +9,7 @@ * Header of the emulation of the Brooktree BT484-BT485A * true colour RAMDAC family. * - * Version: @(#)vid_bt485_ramdac.h 1.0.4 2018/10/04 + * Version: @(#)vid_bt485_ramdac.h 1.0.5 2019/01/12 * * Authors: Miran Grca, * TheCollector1995, @@ -31,7 +31,6 @@ typedef struct uint8_t cr4; uint8_t status; uint8_t type; - uint8_t ext_addr; } bt48x_ramdac_t; extern void bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *ramdac, svga_t *svga); diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 70ad65a5f..449ab3a0d 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -8,7 +8,7 @@ * * Emulation of the old and new IBM CGA graphics cards. * - * Version: @(#)vid_cga.c 1.0.17 2018/09/19 + * Version: @(#)vid_cga.c 1.0.19 2019/01/18 * * Authors: Sarah Walker, * Miran Grca, @@ -43,488 +43,560 @@ 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 + 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_cga = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; 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(); +#ifdef CGA_DEBUG +void +cga_print(cga_t *cga) +{ + int x_res = cga->crtc[0x02]; + int hchar = 3; + char ncol = '4'; + + if (!(cga->cgamode & 0x08)) + return; + +#if 0 + if (cga->cgamode & 1) + x_res <<= 3; + else if (!(cga->cgamode & 2)) + x_res <<= 4; + else if (!(cga->cgamode & 16)) + x_res <<= 3; + else + x_res <<= 4; +#else + if ((cga->cgamode & 0x12) == 0x02) + hchar++; + else if ((cga->cgamode & 0x03) == 0x00) + hchar++; + x_res <<= hchar; +#endif + + if ((cga->cgamode & 0x12) == 0x12) + ncol = '8'; + else if ((cga->cgamode & 0x03) == 0x01) + ncol = '8'; + if ((cga->cgamode & 0x12) == 0x10) + ncol = 't'; + else if ((cga->cgamode & 0x03) == 0x03) + ncol = 'g'; + +#if 0 + pclog("HSync Pos: %i chars (%i p), VSync Pos: %i chars (%i p)\n", cga->crtc[0x02], x_res, + cga->crtc[0x07], cga->crtc[0x07] * (cga->crtc[0x09] + 1)); +#else + pclog("[%c%c%i] HSync Pos: %i chars (%i p), VSync Pos: %i chars (%i p)\n", + (cga->cgamode & 2) ? 'G' : 'T', ncol, hchar, + cga->crtc[0x02], x_res, + cga->crtc[0x07], cga->crtc[0x07] * (cga->crtc[0x09] + 1)); +#endif +} +#endif + + +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: + old = cga->cgamode; + cga->cgamode = val; + + if (old ^ val) { + if ((old ^ val) & 0x05) + update_cga16_color(val); + + cga_recalctimings(cga); + } + return; + case 0x3D9: + old = cga->cgacol; + cga->cgacol = val; + if (old ^ val) + cga_recalctimings(cga); + 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) +{ + int ws_array[16] = {3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8}; + int ws; + + ws = ws_array[cycles & 0xf]; + cycles -= ws; +} + + +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; + uint8_t border; + 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 << 1)][c] = + buffer->line[(cga->displine << 1) + 1][c] = 0; + if (cga->cgamode & 1) { + buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = + buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = 0; + } else { + buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = + buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = 0; + } + } else { + buffer->line[(cga->displine << 1)][c] = + buffer->line[(cga->displine << 1) + 1][c] = (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) { + buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = + buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; + } else { + buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = + buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; + } + } + } + if (cga->cgamode & 1) { + for (x = 0; x < cga->crtc[1]; x++) { + if (cga->cgamode & 8) { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + } else + chr = attr = 0; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + cols[1] = (attr & 15) + 16; + if (cga->cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + cols[1] = cols[0]; + } else + cols[0] = (attr >> 4) + 16; + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer->line[(cga->displine << 1)][(x << 3) + c + 8] = + buffer->line[(cga->displine << 1) + 1][(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 << 1)][(x << 3) + c + 8] = + buffer->line[(cga->displine << 1) + 1][(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++) { + if (cga->cgamode & 8) { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + } else + chr = attr = 0; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + cols[1] = (attr & 15) + 16; + if (cga->cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80)) + cols[1] = cols[0]; + } else + cols[0] = (attr >> 4) + 16; + cga->ma++; + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer->line[(cga->displine << 1) + 1][(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 << 1)][(x << 4) + (c << 1) + 8] = + buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer->line[(cga->displine << 1) + 1][(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++) { + if (cga->cgamode & 8) + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + else + dat = 0; + cga->ma++; + for (c = 0; c < 8; c++) { + buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer->line[(cga->displine << 1) + 1][(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++) { + if (cga->cgamode & 8) + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + else + dat = 0; + cga->ma++; + for (c = 0; c < 16; c++) { + buffer->line[(cga->displine << 1)][(x << 4) + c + 8] = + buffer->line[(cga->displine << 1) + 1][(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 << 1), (cga->crtc[1] << 3) + 16, cols[0]); + hline(buffer, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 3) + 16, cols[0]); + } else { + hline(buffer, 0, (cga->displine << 1), (cga->crtc[1] << 4) + 16, cols[0]); + hline(buffer, 0, (cga->displine << 1) + 1, (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 << 1)][c] = buffer->line[(cga->displine << 1)][c] & 0xf; + buffer32->line[(cga->displine << 1) + 1][c] = buffer->line[(cga->displine << 1) + 1][c] & 0xf; } - cga->cgamode = val; - return; - case 0x3D9: - cga->cgacol = val; - return; - } + if (cga->cgamode & 0x10) + border = 0x00; + else + border = cga->cgacol & 0x0f; + + Composite_Process(cga->cgamode, border, x >> 2, buffer32->line[(cga->displine << 1)]); + Composite_Process(cga->cgamode, border, x >> 2, buffer32->line[(cga->displine << 1) + 1]); + } + + 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; + 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++; +#ifdef CGA_DEBUG + cga_print(cga); +#endif + if ((cga->cgamode & 8) && x && (cga->lastline - cga->firstline) && + ((x != xsize) || (((cga->lastline - cga->firstline) << 1) != ysize) || + video_force_resize_get())) { + xsize = x; + ysize = (cga->lastline - cga->firstline) << 1; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 400; + set_screen_size(xsize, ysize + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (cga->composite) + video_blit_memtoscreen(0, (cga->firstline - 4) << 1, 0, ((cga->lastline - cga->firstline) + 8) << 1, + xsize, ((cga->lastline - cga->firstline) + 8) << 1); + else + video_blit_memtoscreen_8(0, (cga->firstline - 4) << 1, 0, ((cga->lastline - cga->firstline) + 8) << 1, + xsize, ((cga->lastline - cga->firstline) + 8) << 1); + 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)]; + } + } } -uint8_t cga_in(uint16_t addr, void *p) + +void +cga_init(cga_t *cga) { - 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; + cga->composite = 0; } -void cga_waitstates(void *p) + +void * +cga_standalone_init(const device_t *info) { - cga_t *cga = (cga_t *)p; - int cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); - - cycles -= 8 - (cycle & 7); + int display_type; + cga_t *cga = malloc(sizeof(cga_t)); - cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); - cycles -= 16 - (cycle & 15); + memset(cga, 0, sizeof(cga_t)); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_cga); - cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); - cycles -= 3 - (cycle % 3); + 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 /*cga->vram*/, 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_write(uint32_t addr, uint8_t val, void *p) + +void +cga_close(void *p) { - cga_t *cga = (cga_t *)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); + free(cga->vram); + free(cga); } -uint8_t cga_read(uint32_t addr, void *p) + +void +cga_speed_changed(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]; + cga_t *cga = (cga_t *) p; + + cga_recalctimings(cga); } -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)); - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_cga); - - 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[] = { @@ -587,6 +659,7 @@ const device_config_t cga_config[] = } }; + const device_t cga_device = { "CGA", diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index a48488030..31fb49807 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.26 2018/10/21 + * Version: @(#)vid_cl_54xx.c 1.0.27 2019/01/13 * * Authors: Sarah Walker, * Barry Rodewald, @@ -39,6 +39,8 @@ #include "vid_svga_render.h" #include "vid_cl54xx.h" +#define BIOS_GD5420_PATH L"video/cirruslogic/5420.vbi" +#define BIOS_GD5422_PATH L"video/cirruslogic/cl5422.bin" #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" @@ -52,6 +54,10 @@ #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_CLGD5402 0x89 +#define CIRRUS_ID_CLGD5420 0x8a +#define CIRRUS_ID_CLGD5422 0x8c +#define CIRRUS_ID_CLGD5424 0x94 #define CIRRUS_ID_CLGD5426 0x90 #define CIRRUS_ID_CLGD5428 0x98 #define CIRRUS_ID_CLGD5429 0x9c @@ -171,6 +177,8 @@ typedef struct gd54xx_t uint8_t pci_regs[256]; uint8_t int_line; + uint8_t fc; /* Feature Connector */ + int card; uint32_t lfb_base; @@ -208,15 +216,24 @@ 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 5422+ */ +static int +gd54xx_is_5422(svga_t *svga) +{ + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) + return 1; + else + return 0; +} /* 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; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) + return 1; + else + return 0; } @@ -278,7 +295,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if (svga->seqaddr > 5) { o = svga->seqregs[svga->seqaddr & 0x1f]; svga->seqregs[svga->seqaddr & 0x1f] = val; - switch (svga->seqaddr & 0x1f) { + switch (svga->seqaddr) { case 6: val &= 0x17; if (val == 0x12) @@ -286,6 +303,28 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) else svga->seqregs[6] = 0x0f; break; + + case 0x0a: + if (gd54xx_is_5434(svga)) + svga->seqregs[0x0a] = val; + else { /* Hack to force memory size on some GD-542x BIOSes*/ + val &= 0xe7; + switch (gd54xx->vram_size) { + case 0x80000: + svga->seqregs[0x0a] = val | 0x08; + break; + + case 0x100000: + svga->seqregs[0x0a] = val | 0x10; + break; + + case 0x200000: + svga->seqregs[0x0a] = val | 0x18; + break; + } + } + break; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ gd54xx->vclk_n[svga->seqaddr-0x0b] = val; break; @@ -311,20 +350,48 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) 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)); + svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); else - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); + svga->hwcursor.addr = ((gd54xx->vram_size - 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)); + svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((val & 0x3c) * 256)); else - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); + svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((val & 0x3f) * 256)); + break; + case 0x15: + if (gd54xx_is_5434(svga)) { + /* Hack to force memory size on some GD-543x BIOSes*/ + val &= 0xf8; + switch (gd54xx->vram_size) { + case 0x100000: + svga->seqregs[0x15] = val | 0x2; + break; + + case 0x200000: + svga->seqregs[0x15] = val | 0x3; + break; + + case 0x400000: + svga->seqregs[0x15] = val | 0x4; + break; + } + } else + return; break; case 0x07: - svga->set_reset_disabled = svga->seqregs[7] & 1; + if (!gd54xx_is_5422(svga)) { + svga->seqregs[svga->seqaddr] &= 0x0f; + gd543x_recalc_mapping(gd54xx); + } + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) + svga->set_reset_disabled = svga->seqregs[7] & 1; case 0x17: - gd543x_recalc_mapping(gd54xx); + if (gd54xx_is_5422(svga)) + gd543x_recalc_mapping(gd54xx); + else + return; break; } return; @@ -660,6 +727,15 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx) { svga_t *svga = &gd54xx->svga; + if (!gd54xx_is_5422(svga)) { + gd54xx->bank[0] = (svga->gdcreg[0x09] & 0x7f) << 12; + + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) + gd54xx->bank[1] = (svga->gdcreg[0x0a] & 0x7f) << 12; + else + gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; + } + else { if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) gd54xx->bank[0] = svga->gdcreg[0x09] << 14; else @@ -670,11 +746,15 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx) gd54xx->bank[1] = svga->gdcreg[0x0a] << 14; else gd54xx->bank[1] = svga->gdcreg[0x0a] << 12; - } else - gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; + } + else + + gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; + } } + static void gd543x_recalc_mapping(gd54xx_t *gd54xx) { @@ -842,19 +922,24 @@ gd54xx_recalctimings(svga_t *svga) 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; + if (gd54xx_is_5422(svga)) { + 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; + if (gd54xx->vram_size == (1 << 19)) /* Note : why 512Kb VRAM cards do not wrap */ + svga->vram_display_mask = gd54xx->vram_mask; + else + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; } static @@ -918,37 +1003,44 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) svga->hwcursor_latch.addr += pitch; } + +static void +gd54xx_rop(gd54xx_t *gd54xx, uint8_t *res, uint8_t *dst, const uint8_t *src) { + switch (gd54xx->blt.rop) { + case 0x00: *res = 0x00; 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; + } +} + + 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; - } + gd54xx_rop(gd54xx, &res, &dst, (const uint8_t *) &src); - /* handle transparency compare */ - if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ + /* 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))) + 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; } @@ -1653,7 +1745,10 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) break; case 0x0b: gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); - gd54xx->blt.height &= 0x03ff; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.height &= 0x07ff; + else + gd54xx->blt.height &= 0x03ff; break; case 0x0c: gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; @@ -1843,6 +1938,20 @@ gd543x_mmio_readl(uint32_t addr, void *p) } +static uint8_t +gd54xx_color_expand(gd54xx_t *gd54xx, int mask, int shift) +{ + uint8_t ret; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) + ret = gd54xx->blt.fg_col >> (shift << 3); + else + ret = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + + return ret; +} + + static void gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) { @@ -1850,6 +1959,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) int x_max = 0; int shift = 0, last_x = 0; + uint32_t src_addr = gd54xx->blt.src_addr; switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { case CIRRUS_BLTMODE_PIXELWIDTH8: @@ -1881,7 +1991,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) 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; + gd54xx->blt.y_count = src_addr & 7; else gd54xx->blt.y_count = 0; @@ -1915,13 +2025,12 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) 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); + mask = !!(cpu_dat >> 31); else - mask = cpu_dat & 0x80; + 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: @@ -1935,7 +2044,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) break; } - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + src = gd54xx_color_expand(gd54xx, mask, shift); if (shift == last_x) { cpu_dat <<= 1; @@ -1952,22 +2061,23 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { case 0x00: src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; + src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); 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)]; + src = svga->vram[(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)]; + src = svga->vram[(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)]; + src = svga->vram[(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)]; + src = svga->vram[(src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; break; } mask = 1; @@ -1975,23 +2085,23 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) 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); + mask = svga->vram[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); + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.x_count & 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); + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.x_count % 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); + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.x_count & 3); break; } - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + src = gd54xx_color_expand(gd54xx, mask, shift); break; case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { @@ -2000,37 +2110,36 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) shift = 0; break; case CIRRUS_BLTMODE_PIXELWIDTH16: - shift = (gd54xx->blt.dst_addr & 1); + shift = (gd54xx->blt.x_count & 1); break; case CIRRUS_BLTMODE_PIXELWIDTH24: - shift = (gd54xx->blt.dst_addr % 3); + shift = (gd54xx->blt.x_count % 3); break; case CIRRUS_BLTMODE_PIXELWIDTH32: - shift = (gd54xx->blt.dst_addr & 3); + shift = (gd54xx->blt.x_count & 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); + mask = svga->vram[(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); + mask = svga->vram[(src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.x_count & 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); + mask = svga->vram[(src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.x_count % 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); + mask = svga->vram[(src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.x_count & 3); break; } - - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + src = gd54xx_color_expand(gd54xx, mask, shift); } break; } @@ -2039,34 +2148,13 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) 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_rop(gd54xx, (uint8_t *) &dst, (uint8_t *) &dst, (const uint8_t *) &src); + + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)) + mask = !mask; + 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); @@ -2075,7 +2163,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) 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++; + src_addr++; } gd54xx->blt.width--; @@ -2087,11 +2175,11 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) 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); + src_addr = 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++; + src_addr++; break; } @@ -2210,18 +2298,28 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) 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_t *gd54xx = malloc(sizeof(gd54xx_t)); + svga_t *svga = &gd54xx->svga; + int id = info->local & 0xff; + int vram; + wchar_t *romfn = NULL; + memset(gd54xx, 0, sizeof(gd54xx_t)); - gd54xx->pci = !!(info->flags & DEVICE_PCI); - gd54xx->vlb = !!(info->flags & DEVICE_VLB); + gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->vlb = !!(info->flags & DEVICE_VLB); - gd54xx->rev = 0; - gd54xx->has_bios = 1; - switch (id) { + gd54xx->rev = 0; + gd54xx->has_bios = 1; + switch (id) { + case CIRRUS_ID_CLGD5402: + case CIRRUS_ID_CLGD5420: + romfn = BIOS_GD5420_PATH; + break; + case CIRRUS_ID_CLGD5422: + case CIRRUS_ID_CLGD5424: + romfn = BIOS_GD5422_PATH; + break; + case CIRRUS_ID_CLGD5426: romfn = BIOS_GD5426_PATH; break; @@ -2273,39 +2371,63 @@ static void 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 (id >= CIRRUS_ID_CLGD5420) + vram = device_get_config_int("memory"); + else + vram = 0; + if (vram) + gd54xx->vram_size = vram << 20; + else + gd54xx->vram_size = 1 << 19; + + gd54xx->vram_mask = gd54xx->vram_size - 1; - if (romfn) - rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + 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); + 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, + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size, gd54xx_recalctimings, gd54xx_in, gd54xx_out, gd54xx_hwcursor_draw, NULL); - svga->ven_write = gd54xx_write_modes45; + svga->ven_write = 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_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); + 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); + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); - svga->hwcursor.yoff = 32; - svga->hwcursor.xoff = 0; + 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; + if (id >= CIRRUS_ID_CLGD5420) { + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[2] = 0x45; + gd54xx->vclk_d[2] = 0x30; + gd54xx->vclk_n[3] = 0x7e; + gd54xx->vclk_d[3] = 0x33; + } + else { + gd54xx->vclk_n[0] = 0x66; + gd54xx->vclk_d[0] = 0x3b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[1] = 0x45; + gd54xx->vclk_d[1] = 0x2c; + gd54xx->vclk_n[1] = 0x7e; + gd54xx->vclk_d[1] = 0x33; + } gd54xx->bank[1] = 0x8000; @@ -2323,6 +2445,18 @@ static void return gd54xx; } +static int +gd5420_available(void) +{ + return rom_present(BIOS_GD5420_PATH); +} + +static int +gd5422_available(void) +{ + return rom_present(BIOS_GD5422_PATH); +} + static int gd5426_available(void) { @@ -2423,6 +2557,26 @@ gd54xx_force_redraw(void *p) gd54xx->svga.fullchange = changeframecount; } +static const device_config_t gd5422_config[] = +{ + { + "memory","Memory size",CONFIG_SELECTION,"",1, + { + { + "512 KB",0 + }, + { + "1 MB",1 + }, + { + "" + } + }, + }, + { + "","",-1 + } +}; static const device_config_t gd5428_config[] = { @@ -2505,6 +2659,55 @@ static const device_config_t gd5434_config[] = } }; +const device_t gd5402_isa_device = +{ + "Cirrus Logic GD-5402 (ACUMOS AVGA2)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5402, + gd54xx_init, gd54xx_close, + NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + NULL, +}; + +const device_t gd5420_isa_device = +{ + "Cirrus Logic GD-5420", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5420, + gd54xx_init, gd54xx_close, + NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5422_config, +}; +const device_t gd5422_isa_device = { + "Cirrus Logic GD-5422", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5422, + gd54xx_init, gd54xx_close, + NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5422_config, +}; + +const device_t gd5424_vlb_device = { + "Cirrus Logic GD-5424", + DEVICE_VLB, + CIRRUS_ID_CLGD5424, + gd54xx_init, gd54xx_close, + NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5422_config, +}; + const device_t gd5426_vlb_device = { "Cirrus Logic CL-GD 5426 (VLB)", diff --git a/src/video/vid_cl54xx.h b/src/video/vid_cl54xx.h index 654a6326e..7c8c9dc51 100644 --- a/src/video/vid_cl54xx.h +++ b/src/video/vid_cl54xx.h @@ -1,6 +1,12 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +#if defined(DEV_BRANCH) +extern const device_t gd5402_isa_device; +extern const device_t gd5420_isa_device; +extern const device_t gd5422_isa_device; +extern const device_t gd5424_vlb_device; +#endif extern const device_t gd5426_vlb_device; extern const device_t gd5428_isa_device; extern const device_t gd5428_vlb_device; diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_compaq_cga.c index c502aa6dd..e02a9ede5 100644 --- a/src/video/vid_compaq_cga.c +++ b/src/video/vid_compaq_cga.c @@ -376,7 +376,7 @@ void *compaq_cga_init(const device_t *info) 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); + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, self->cga.vram, MEM_MAPPING_EXTERNAL, self); io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, self); if (info->local) { diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index df05ccd13..dc1012034 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -9,7 +9,7 @@ * Emulation of the EGA, Chips & Technologies SuperEGA, and * AX JEGA graphics cards. * - * Version: @(#)vid_ega.c 1.0.18 2018/09/19 + * Version: @(#)vid_ega.c 1.0.19 2018/12/31 * * Authors: Sarah Walker, * Miran Grca, @@ -200,7 +200,7 @@ void ega_out(uint16_t addr, uint8_t val, void *p) ega->attrff ^= 1; break; case 0x3c2: - egaswitchread = val & 0xc; + egaswitchread = (val & 0xc) >> 2; ega->vres = !(val & 0x80); ega->pallook = ega->vres ? pallook16 : pallook64; ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ @@ -308,13 +308,7 @@ uint8_t ega_in(uint16_t addr, void *p) 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; - } + return (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; break; case 0x3c4: return ega->seqaddr; @@ -968,7 +962,7 @@ void ega_init(ega_t *ega, int monitor_type, int is_mono) egaswitches = monitor_type & 0xf; ega->vram_limit = 256 * 1024; - ega->vrammask = ega->vram_limit-1; + ega->vrammask = ega->vram_limit - 1; old_overscan_color = 0; @@ -1030,10 +1024,10 @@ static void *ega_standalone_init(const device_t *info) } monitor_type = device_get_config_int("monitor_type"); - ega_init(ega, monitor_type, (monitor_type & 0xf) == 10); + ega_init(ega, monitor_type, (monitor_type & 0x0F) == 0x0B); ega->vram_limit = device_get_config_int("memory") * 1024; - ega->vrammask = ega->vram_limit-1; + 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); @@ -1185,6 +1179,15 @@ static void ega_speed_changed(void *p) } +/* SW1 SW2 SW3 SW4 + OFF OFF ON OFF Monochrome (5151) 1011 0x0B + ON OFF OFF ON Color 40x25 (5153) 0110 0x06 + OFF OFF OFF ON Color 80x25 (5153) 0111 0x07 + ON ON ON OFF Enhanced Color - Normal Mode (5154) 1000 0x08 + OFF ON ON OFF Enhanced Color - Enhanced Mode (5154) 1001 0x09 + + 0 = Switch closed (ON); + 1 = Switch open (OFF). */ static const device_config_t ega_config[] = { { @@ -1211,28 +1214,32 @@ static const device_config_t ega_config[] = .selection = { { - .description = "EGA Colour, 40x25", - .value = 6 + .description = "Monochrome (5151/MDA) (white)", + .value = 0x0B | (DISPLAY_WHITE << 4) }, { - .description = "EGA Colour, 80x25", - .value = 7 + .description = "Monochrome (5151/MDA) (green)", + .value = 0x0B | (DISPLAY_GREEN << 4) }, { - .description = "EGA Colour, ECD", - .value = 9 + .description = "Monochrome (5151/MDA) (amber)", + .value = 0x0B | (DISPLAY_AMBER << 4) }, { - .description = "EGA Monochrome (white)", - .value = 10 | (DISPLAY_WHITE << 4) + .description = "Color 40x25 (5153/CGA)", + .value = 0x06 }, { - .description = "EGA Monochrome (green)", - .value = 10 | (DISPLAY_GREEN << 4) + .description = "Color 80x25 (5153/CGA)", + .value = 0x07 }, { - .description = "EGA Monochrome (amber)", - .value = 10 | (DISPLAY_AMBER << 4) + .description = "Enhanced Color - Normal Mode (5154/ECD)", + .value = 0x08 + }, + { + .description = "Enhanced Color - Enhanced Mode (5154/ECD)", + .value = 0x09 }, { .description = "" diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 04d3df04f..7962b59f1 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -8,7 +8,7 @@ * * Hercules emulation. * - * Version: @(#)vid_hercules.c 1.0.15 2018/10/28 + * Version: @(#)vid_hercules.c 1.0.16 2018/11/18 * * Authors: Sarah Walker, * Miran Grca, @@ -382,7 +382,7 @@ hercules_init(const device_t *info) mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, hercules_read,NULL,NULL, hercules_write,NULL,NULL, - NULL, MEM_MAPPING_EXTERNAL, dev); + dev->vram, MEM_MAPPING_EXTERNAL, dev); io_sethandler(0x03b0, 16, hercules_in,NULL,NULL, hercules_out,NULL,NULL, dev); diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index c69424382..071d8b89b 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -8,7 +8,7 @@ * * Hercules Plus emulation. * - * Version: @(#)vid_herculesplus.c 1.0.13 2018/10/28 + * Version: @(#)vid_herculesplus.c 1.0.14 2018/11/18 * * Authors: Sarah Walker, * Miran Grca, @@ -613,7 +613,7 @@ herculesplus_init(const device_t *info) mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, herculesplus_read,NULL,NULL, herculesplus_write,NULL,NULL, - NULL, MEM_MAPPING_EXTERNAL, dev); + dev->vram, MEM_MAPPING_EXTERNAL, dev); io_sethandler(0x03b0, 16, herculesplus_in,NULL, NULL, herculesplus_out,NULL,NULL, dev); diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index c7c2040cd..79c122b0f 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -8,7 +8,7 @@ * * S3 emulation. * - * Version: @(#)vid_s3.c 1.0.25 2018/10/04 + * Version: @(#)vid_s3.c 1.0.26 2019/01/12 * * Authors: Sarah Walker, * Miran Grca, @@ -33,9 +33,14 @@ #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_sdac_ramdac.h" +#include "vid_att20c49x_ramdac.h" #include "vid_bt48x_ramdac.h" +#include "vid_av9194.h" #include "vid_icd2061.h" +#include "../cpu/cpu.h" +#define ROM_V7MIRAGE_86C801 L"roms/video/s3/v7mirage.vbi" +#define ROM_PHOENIX_86C805 L"roms/video/s3/805.vbi" #define ROM_PARADISE_BAHAMAS64 L"roms/video/s3/bahamas64.bin" #define ROM_PHOENIX_VISION864 L"roms/video/s3/86c864p.bin" #define ROM_DIAMOND_STEALTH64_964 L"roms/video/s3/964_107h.rom" @@ -53,17 +58,23 @@ enum S3_PHOENIX_TRIO64, S3_PHOENIX_TRIO64_ONBOARD, S3_PHOENIX_VISION864, - S3_DIAMOND_STEALTH64_764 + S3_DIAMOND_STEALTH64_764, + S3_V7MIRAGE_86C801, + S3_PHOENIX_86C805 }; enum { + S3_86C801, + S3_86C805, S3_VISION864, S3_VISION964, S3_TRIO32, S3_TRIO64 }; +static video_timings_t timing_s3_86c801 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_86c805 = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_stealth64 = {VIDEO_BUS, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_s3_vision864 = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_vision964 = {VIDEO_BUS, 2, 2, 4, 20, 20, 35}; @@ -116,7 +127,6 @@ typedef struct s3_t rom_t bios_rom; svga_t svga; - icd2061_t icd2061; uint8_t bank; uint8_t ma_ext; @@ -131,8 +141,6 @@ typedef struct s3_t int packed_mmio; - int p86c911_compat; - uint32_t linear_base, linear_size; uint8_t pci_regs[256]; @@ -140,7 +148,8 @@ typedef struct s3_t uint32_t vram_mask; uint8_t status_9ae8; - + uint8_t data_available; + struct { uint16_t subsys_cntl; @@ -1011,7 +1020,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x3c2: if (s3->chip == S3_VISION964) { if (((val >> 2) & 3) != 3) - icd2061_write(&s3->icd2061, (val >> 2) & 3); + icd2061_write(svga->clock_gen, (val >> 2) & 3); } break; @@ -1037,18 +1046,20 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: if ((svga->crtc[0x55] & 0x03) == 0x00) - rs2 = !!(svga->crtc[0x43] & 2); + rs2 = !!(svga->crtc[0x43] & 0x02); else rs2 = (svga->crtc[0x55] & 0x01); if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) svga_out(addr, val, svga); else if (s3->chip == S3_VISION964) { - if (!(svga->crtc[0x45] & 0x02)) + if (!(svga->crtc[0x45] & 0x20)) rs3 = !!(svga->crtc[0x55] & 0x02); else rs3 = 0; bt48x_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } else + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + att49x_ramdac_out(addr, val, svga->ramdac, svga); + else sdac_ramdac_out(addr, rs2, val, svga->ramdac, svga); return; @@ -1060,7 +1071,14 @@ void s3_out(uint16_t addr, uint8_t val, void *p) 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 >= 0x20) && (svga->crtcreg < 0x40) && + (svga->crtcreg != 0x36) && (svga->crtcreg != 0x38) && + (svga->crtcreg != 0x39) && ((svga->crtc[0x38] & 0xcc) != 0x48)) + return; + if ((svga->crtcreg >= 0x40) && ((svga->crtc[0x39] & 0xe0) != 0xa0)) + return; + if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) + return; old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; switch (svga->crtcreg) @@ -1132,6 +1150,8 @@ void s3_out(uint16_t addr, uint8_t val, void *p) 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; + else if ((s3->chip == S3_86C801 || s3->chip == S3_86C805) && (svga->bpp == 15 || svga->bpp == 16)) + svga->hwcursor.x >>= 1; break; case 0x4a: @@ -1173,7 +1193,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x42: if (s3->chip == S3_VISION964) { if (((svga->miscout >> 2) & 3) == 3) - icd2061_write(&s3->icd2061, svga->crtc[0x42] & 0x0f); + icd2061_write(svga->clock_gen, svga->crtc[0x42] & 0x0f); } break; @@ -1233,7 +1253,9 @@ uint8_t s3_in(uint16_t addr, void *p) else if (s3->chip == S3_VISION964) { rs3 = !!(svga->crtc[0x55] & 0x02); return bt48x_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } else + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + return att49x_ramdac_in(addr, svga->ramdac, svga); + else return sdac_ramdac_in(addr, rs2, svga->ramdac, svga); break; @@ -1259,6 +1281,10 @@ uint8_t s3_in(uint16_t addr, void *p) return temp; case 0x69: return s3->ma_ext; case 0x6a: return s3->bank; + /* Phoenix S3 video BIOS'es seem to expect CRTC registers 6B and 6C + to be mirrors of 59 and 5A. */ + case 0x6b: return svga->crtc[0x59]; + case 0x6c: return svga->crtc[0x5a] & 0x80; } return svga->crtc[svga->crtcreg]; } @@ -1295,9 +1321,15 @@ void s3_recalctimings(svga_t *svga) svga->clock = cpuclock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); else svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) { + svga->interlace = svga->crtc[0x42] & 0x20; + if (((svga->miscout >> 2) & 3) == 3) + svga->clock = cpuclock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); + else + svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); } else { svga->interlace = svga->crtc[0x42] & 0x20; - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); } switch (svga->crtc[0x67] >> 4) @@ -1315,19 +1347,22 @@ void s3_recalctimings(svga_t *svga) case 8: svga->render = svga_render_8bpp_highres; break; - case 15: - svga->render = svga_render_15bpp_highres; - if (s3->chip != S3_VISION964) + case 15: + svga->render = svga_render_15bpp_highres; + if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) svga->hdisp /= 2; break; case 16: svga->render = svga_render_16bpp_highres; - if (s3->chip != S3_VISION964) + if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) svga->hdisp /= 2; break; - case 24: + case 24: svga->render = svga_render_24bpp_highres; - svga->hdisp /= 3; + if (s3->chip != S3_86C801 && s3->chip != S3_86C805) + svga->hdisp /= 3; + else + svga->hdisp = (svga->hdisp * 2) / 3; break; case 32: svga->render = svga_render_32bpp_highres; @@ -1341,7 +1376,7 @@ void s3_recalctimings(svga_t *svga) 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); @@ -1377,8 +1412,9 @@ void s3_updatemapping(s3_t *s3) break; } - if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + if ((svga->crtc[0x58] & 0x10) || (s3->accel.advfunc_cntl & 0x10)) { + /*Linear framebuffer*/ mem_mapping_disable(&svga->mapping); s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); @@ -1397,6 +1433,8 @@ void s3_updatemapping(s3_t *s3) switch (s3->chip) { case S3_TRIO32: case S3_TRIO64: + case S3_86C801: + case S3_86C805: s3->linear_size = 0x400000; break; default: @@ -1469,6 +1507,7 @@ void s3_accel_out(uint16_t port, uint8_t val, void *p) break; case 0x4ae8: s3->accel.advfunc_cntl = val; + s3_updatemapping(s3); break; } } @@ -1541,19 +1580,29 @@ uint8_t s3_accel_in(uint16_t port, void *p) case 0x9ae8: if (!s3->blitter_busy) wake_fifo_thread(s3); - if (FIFO_FULL) + if (FIFO_FULL && s3->chip != S3_86C801 && s3->chip != S3_86C805) 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*/ + if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + { + if (!FIFO_EMPTY) + temp |= 0x02; + if (s3->data_available) + temp |= 0x01; + } else - temp |= s3->status_9ae8; /*FIFO empty*/ - if (FIFO_FULL) - temp |= 0xf8; /*FIFO full*/ + { + 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: @@ -1805,7 +1854,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat 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; @@ -1845,6 +1894,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->bpp == 0) compare &= 0xff; if (s3->bpp == 1) compare &= 0xffff; + switch (cmd) { case 1: /*Draw line*/ @@ -1859,10 +1909,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - + s3->data_available = 0; + if ((s3->accel.cmd & 0x100) && !cpu_input) { s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + s3->data_available = 1; return; /*Wait for data from CPU*/ } @@ -2008,10 +2060,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - + s3->data_available = 0; + if ((s3->accel.cmd & 0x100) && !cpu_input) { s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + s3->data_available = 1; return; /*Wait for data from CPU*/ } @@ -2741,15 +2795,14 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) s3_updatemapping(s3); break; - case 0x12: - svga->crtc[0x5a] = val & 0x80; - /* svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); */ - s3_updatemapping(s3); + case 0x12: + svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); + s3_updatemapping(s3); + break; + case 0x13: + svga->crtc[0x59] = val; + s3_updatemapping(s3); break; - case 0x13: - svga->crtc[0x59] = val; - s3_updatemapping(s3); - break; case 0x30: case 0x32: case 0x33: if (!s3->has_bios) @@ -2795,6 +2848,16 @@ static void *s3_init(const device_t *info) uint32_t vram_size; switch(info->local) { + case S3_V7MIRAGE_86C801: + bios_fn = ROM_V7MIRAGE_86C801; + chip = S3_86C801; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); + break; + case S3_PHOENIX_86C805: + bios_fn = ROM_PHOENIX_86C805; + chip = S3_86C805; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + break; case S3_PARADISE_BAHAMAS64: bios_fn = ROM_PARADISE_BAHAMAS64; chip = S3_VISION864; @@ -2882,39 +2945,43 @@ static void *s3_init(const device_t *info) s3_hwcursor_draw, NULL); - switch (vram) { - case 0: /* 512 kB */ - svga->vram_mask = (1 << 19) - 1; - svga->vram_max = 2 << 20; - break; - case 1: /* 1 MB */ - /* VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus. + if (s3->chip != S3_86C801 && s3->chip != S3_86C805) { + switch (vram) { + case 0: /* 512 kB */ + svga->vram_mask = (1 << 19) - 1; + svga->vram_max = 2 << 20; + break; + case 1: /* 1 MB */ + /* 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: /*2 MB */ - /* 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: /*8MB*/ - svga->vram_mask = (8 << 20) - 1; - svga->vram_max = 8 << 20; - break; + 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: /*2 MB */ + /* 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: /*8MB*/ + 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 + else if (info->flags & DEVICE_VLB) svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else + svga->crtc[0x36] = 3 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); svga->crtc[0x37] = 1 | (7 << 5); svga->vblank_start = s3_vblank_start; @@ -2939,6 +3006,34 @@ static void *s3_init(const device_t *info) s3->int_line = 0; switch(info->local) { + case S3_V7MIRAGE_86C801: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&att490_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + + case S3_PHOENIX_86C805: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&att492_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + case S3_PARADISE_BAHAMAS64: case S3_PHOENIX_VISION864: svga->decode_mask = (8 << 20) - 1; @@ -2962,12 +3057,12 @@ static void *s3_init(const device_t *info) s3->id_ext = s3->id_ext_pci = stepping; s3->packed_mmio = 1; svga->crtc[0x5a] = 0x0a; - + svga->ramdac = device_add(&bt485_ramdac_device); svga->clock_gen = device_add(&icd2061_device); svga->getclock = icd2061_getclock; break; - + case S3_PHOENIX_TRIO32: svga->decode_mask = (4 << 20) - 1; s3->id = 0xe1; /*Trio32*/ @@ -3003,6 +3098,16 @@ static void *s3_init(const device_t *info) return s3; } +static int s3_v7mirage_86c801_available(void) +{ + return rom_present(ROM_V7MIRAGE_86C801); +} + +static int s3_phoenix_86c805_available(void) +{ + return rom_present(ROM_PHOENIX_86C805); +} + static int s3_bahamas64_available(void) { return rom_present(ROM_PARADISE_BAHAMAS64); @@ -3159,6 +3264,34 @@ static const device_config_t s3_config[] = } }; +const device_t s3_v7mirage_86c801_isa_device = +{ + "SPEA V7 Mirage (S3 86c801) ISA", + DEVICE_AT | DEVICE_ISA, + S3_V7MIRAGE_86C801, + s3_init, + s3_close, + NULL, + s3_v7mirage_86c801_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_phoenix_86c805_vlb_device = +{ + "Phoenix S3 86c805 VLB", + DEVICE_VLB, + S3_PHOENIX_86C805, + s3_init, + s3_close, + NULL, + s3_phoenix_86c805_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + const device_t s3_bahamas64_vlb_device = { "Paradise Bahamas 64 (S3 Vision864) VLB", diff --git a/src/video/vid_s3.h b/src/video/vid_s3.h index 8678d48d1..337a7eae5 100644 --- a/src/video/vid_s3.h +++ b/src/video/vid_s3.h @@ -9,7 +9,7 @@ * Emulation of the S3 Trio32, S3 Trio64, and S3 Vision864 * graphics cards. * - * Version: @(#)vid_s3.h 1.0.3 2018/09/19 + * Version: @(#)vid_s3.h 1.0.4 2019/01/12 * * Author: Sarah Walker, * Miran Grca, @@ -17,6 +17,8 @@ * Copyright 2016-2018 Miran Grca. */ +const device_t s3_v7mirage_86c801_isa_device; +const device_t s3_phoenix_86c805_vlb_device; const device_t s3_bahamas64_vlb_device; const device_t s3_bahamas64_pci_device; const device_t s3_9fx_vlb_device; @@ -32,4 +34,3 @@ const device_t s3_diamond_stealth64_pci_device; const device_t s3_diamond_stealth64_vlb_device; const device_t s3_diamond_stealth64_964_pci_device; const device_t s3_diamond_stealth64_964_vlb_device; -/* const device_t s3_miro_vision964_device; */ diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 83a71ba5e..77b929946 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -2967,7 +2967,7 @@ static void dest_pixel_lit_texture_modulate(s3d_state_t *state) 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; + uint8_t *vram = svga->vram; int x_dir = s3d_tri->tlr ? 1 : -1; @@ -3022,7 +3022,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 y_count -= diff_y; } if ((state->y - y_count) < s3d_tri->clip_t) - y_count = state->y - s3d_tri->clip_t; + y_count = (state->y - s3d_tri->clip_t) + 1; } dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); @@ -3065,7 +3065,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (xe < s3d_tri->clip_l) goto tri_skip_line; if (xe > s3d_tri->clip_r) - xe = s3d_tri->clip_r; + xe = s3d_tri->clip_r + 1; if (x < s3d_tri->clip_l) { int diff_x = s3d_tri->clip_l - x; @@ -3090,7 +3090,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (xe > s3d_tri->clip_r) goto tri_skip_line; if (xe < s3d_tri->clip_l) - xe = s3d_tri->clip_l; + xe = s3d_tri->clip_l - 1; if (x > s3d_tri->clip_r) { int diff_x = x - s3d_tri->clip_r; @@ -3115,6 +3115,9 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 dest_addr = dest_offset + (x * (bpp + 1)); z_addr = z_offset + (x << 1); + x &= 0xfff; + xe &= 0xfff; + for (; x != xe; x = (x + x_dir) & 0xfff) { update = 1; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 59d99c3fd..4f2cd3120 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -33,6 +33,7 @@ #include "vid_ati18800.h" #include "vid_ati28800.h" +//#include "vid_ati_mach8.h" #include "vid_ati_mach64.h" #include "vid_cga.h" #include "vid_cl54xx.h" @@ -49,6 +50,7 @@ #include "vid_oak_oti.h" #include "vid_paradise.h" #include "vid_s3.h" +//#include "vid_s3_911.h" #include "vid_s3_virge.h" #include "vid_sigma.h" #include "vid_tgui9440.h" @@ -73,6 +75,7 @@ video_cards[] = { { "None", "none", NULL }, { "Internal", "internal", NULL }, { "[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device }, + //{ "[ISA] ATI Graphics Ultra (Mach8)", "mach8_isa", &mach8_device }, { "[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device }, { "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device }, { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device }, @@ -85,6 +88,11 @@ video_cards[] = { #endif { "[ISA] CGA", "cga", &cga_device }, { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device }, +#if defined(DEV_BRANCH) + { "[ISA] Cirrus Logic CL-GD 5402", "cl_gd5402_isa", &gd5402_isa_device }, + { "[ISA] Cirrus Logic CL-GD 5420", "cl_gd5420_isa", &gd5420_isa_device }, + { "[ISA] Cirrus Logic CL-GD 5422", "cl_gd5422_isa", &gd5422_isa_device }, +#endif { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device }, { "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device }, { "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device }, @@ -106,9 +114,11 @@ video_cards[] = { { "[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device }, { "[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device }, { "[ISA] Sigma Color 400", "sigma400", &sigma_device }, + { "[ISA] SPEA V7 Mirage (S3 86c801)", "px_s3_v7_801_isa", &s3_v7mirage_86c801_isa_device }, #if defined(DEV_BRANCH) && defined(USE_TI) { "[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device }, #endif + { "[ISA] Trident TVGA8900B", "tvga8900b", &tvga8900b_device }, { "[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device }, { "[ISA] Trigem Korean VGA (ET4000AX)", "tgkorvga", &et4000k_isa_device }, { "[ISA] Tseng ET4000AX", "et4000ax", &et4000_isa_device }, @@ -140,6 +150,9 @@ video_cards[] = { { "[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device }, { "[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device }, { "[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device }, +#if defined(DEV_BRANCH) + { "[VLB] Cirrus Logic CL-GD 5424", "cl_gd5424_vlb", &gd5424_vlb_device }, +#endif { "[VLB] Cirrus Logic CL-GD 5428", "cl_gd5428_vlb", &gd5428_vlb_device }, { "[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device }, { "[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device }, @@ -152,6 +165,7 @@ video_cards[] = { { "[VLB] Diamond Stealth 64 VRAM (S3 Vision964)", "stealth64v_vlb", &s3_diamond_stealth64_964_vlb_device }, { "[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device }, { "[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device }, + { "[VLB] Phoenix S3 86c805", "px_86c805_vlb", &s3_phoenix_86c805_vlb_device }, { "[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device }, { "[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device }, { "[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device }, diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 53c05725c..8f6874236 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -258,7 +258,7 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) break; case 0xC: if (svga->seqregs[0xe] & 0x80) - svga->seqregs[0xc] = val; + svga->seqregs[0xc] = val; break; case 0xd: if (tgui->oldmode) @@ -517,15 +517,6 @@ void tgui_recalctimings(svga_t *svga) 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) { diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 77c8236f5..cddc0690c 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -8,7 +8,7 @@ * * Trident TVGA (8900D) emulation. * - * Version: @(#)vid_tvga.c 1.0.8 2018/10/04 + * Version: @(#)vid_tvga.c 1.0.9 2018/12/28 * * Authors: Sarah Walker, * Miran Grca, @@ -32,6 +32,11 @@ #include "vid_tkd8001_ramdac.h" #include "vid_tvga.h" +#define TVGA8900B_ID 0x03 +#define TVGA8900CLD_ID 0x33 + +#define ROM_TVGA_8900B L"roms/video/tvga/tvga8900B.VBI" +#define ROM_TVGA_8900CLD L"roms/video/tvga/trident.bin" typedef struct tvga_t { @@ -41,6 +46,7 @@ typedef struct tvga_t svga_t svga; rom_t bios_rom; + uint8_t card_id; uint8_t tvga_3d8, tvga_3d9; int oldmode; @@ -184,7 +190,7 @@ uint8_t tvga_in(uint16_t addr, void *p) if ((svga->seqaddr & 0xf) == 0xb) { tvga->oldmode = 0; - return 0x33; /*TVGA8900D*/ + return tvga->card_id; /*Must be at least a TVGA8900*/ } if ((svga->seqaddr & 0xf) == 0xd) { @@ -237,15 +243,16 @@ void tvga_recalctimings(svga_t *svga) 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 ((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; @@ -253,7 +260,7 @@ void tvga_recalctimings(svga_t *svga) svga->hdisp_time *= 2; } - svga->interlace = (svga->crtc[0x1e] & 4); + svga->interlace = (svga->crtc[0x1e] & 4); if (svga->interlace) svga->rowoffset >>= 1; @@ -273,7 +280,7 @@ void tvga_recalctimings(svga_t *svga) switch (svga->bpp) { case 8: - svga->render = svga_render_8bpp_highres; + svga->render = svga_render_8bpp_highres; break; case 15: svga->render = svga_render_15bpp_highres; @@ -293,8 +300,9 @@ void tvga_recalctimings(svga_t *svga) } -static void *tvga8900d_init(const device_t *info) +static void *tvga_init(const device_t *info) { + const wchar_t *bios_fn; tvga_t *tvga = malloc(sizeof(tvga_t)); memset(tvga, 0, sizeof(tvga_t)); @@ -302,8 +310,23 @@ static void *tvga8900d_init(const device_t *info) 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); + + tvga->card_id = info->local; + + switch (info->local) + { + case TVGA8900B_ID: + bios_fn = ROM_TVGA_8900B; + break; + case TVGA8900CLD_ID: + bios_fn = ROM_TVGA_8900CLD; + break; + default: + free(tvga); + return NULL; + } + + rom_init(&tvga->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&tvga->svga, tvga, tvga->vram_size, tvga_recalctimings, @@ -318,9 +341,14 @@ static void *tvga8900d_init(const device_t *info) return tvga; } +static int tvga8900b_available(void) +{ + return rom_present(ROM_TVGA_8900B); +} + static int tvga8900d_available(void) { - return rom_present(L"roms/video/tvga/trident.bin"); + return rom_present(ROM_TVGA_8900CLD); } void tvga_close(void *p) @@ -371,12 +399,26 @@ static const device_config_t tvga_config[] = } }; +const device_t tvga8900b_device = +{ + "Trident TVGA 8900B", + DEVICE_ISA, + TVGA8900B_ID, + tvga_init, + tvga_close, + NULL, + tvga8900b_available, + tvga_speed_changed, + tvga_force_redraw, + tvga_config +}; + const device_t tvga8900d_device = { "Trident TVGA 8900D", DEVICE_ISA, - 0, - tvga8900d_init, + TVGA8900CLD_ID, + tvga_init, tvga_close, NULL, tvga8900d_available, diff --git a/src/video/vid_tvga.h b/src/video/vid_tvga.h index 43e1b778b..6a4f0105a 100644 --- a/src/video/vid_tvga.h +++ b/src/video/vid_tvga.h @@ -1,4 +1,5 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +extern const device_t tvga8900b_device; extern const device_t tvga8900d_device; diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 005f264eb..400e40520 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)86Box.rc 1.0.42 2018/09/06 + * Version: @(#)86Box.rc 1.0.44 2018/11/19 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -850,7 +850,7 @@ 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_2081 "Unable to initialize FluidSynth, libfluidsynth.dll is required" IDS_2082 "Bus" IDS_2083 "File" IDS_2084 "C" @@ -887,8 +887,10 @@ BEGIN 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" + IDS_2118 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" IDS_2119 "You must save the settings first before attempting to configure the memory boards" + IDS_2120 "Unable to initialize FreeType, freetype.dll is required" + IDS_2121 "Unable to initialize SDL, SDL2.dll is required" END STRINGTABLE DISCARDABLE diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index b93b201fe..9ecc4692c 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.134 2018/10/26 +# Version: @(#)Makefile.mingw 1.0.136 2019/01/13 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -47,6 +47,9 @@ ifeq ($(DEV_BUILD), y) ifndef D2D D2D := y endif + ifndef GUS_MAX + GUS_MAX := y + endif ifndef I686 I686 := y endif @@ -87,6 +90,9 @@ else ifndef D2D D2D := n endif + ifndef GUS_MAX + GUS_MAX := n + endif ifndef I686 I686 := n endif @@ -295,7 +301,7 @@ ifneq ($(WX), n) 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_d2d.o win_d3d.o win_sdl.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 @@ -323,6 +329,7 @@ ifeq ($(D2D), y) OPTS += -DUSE_D2D RFLAGS += -DUSE_D2D D2DLIB := -ld2d1 +D2DOBJ := win_d2d.o endif ifeq ($(VNC), y) @@ -361,6 +368,11 @@ OPTS += -DUSE_CRASHDUMP DEVBROBJ += win_crashdump.o endif +ifeq ($(GUS_MAX), y) + OPTS += -DUSE_GUSMAX + DEVBROBJ += snd_cs423x.o +endif + ifeq ($(I686), y) OPTS += -DUSE_I686 endif @@ -431,6 +443,7 @@ 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_xt_zenith.o \ m_pcjr.o \ m_amstrad.o \ m_europc.o \ @@ -461,7 +474,7 @@ DEVOBJ := bugger.o isamem.o isartc.o lpt.o $(SERIAL) \ 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 + fdd_mfm.o fdd_td0.o HDDOBJ := hdd.o \ hdd_image.o hdd_table.o \ @@ -470,7 +483,7 @@ HDDOBJ := hdd.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 @@ -539,6 +552,7 @@ VIDOBJ := video.o \ vid_ati18800.o vid_ati28800.o \ vid_ati_mach64.o vid_ati68860_ramdac.o \ vid_bt48x_ramdac.o \ + vid_av9194.o \ vid_icd2061.o vid_ics2595.o \ vid_cl54xx.o \ vid_et4000.o vid_sc1502x_ramdac.o \ @@ -548,6 +562,7 @@ VIDOBJ := video.o \ vid_ti_cf62011.o \ vid_tvga.o \ vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_att20c49x_ramdac.o \ vid_s3.o vid_s3_virge.o \ vid_sdac_ramdac.o \ vid_voodoo.o @@ -560,7 +575,7 @@ PLATOBJ := win.o \ OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ $(USBOBJ) $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ - $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ + $(PLATOBJ) $(UIOBJ) $(D2DOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ $(DEVBROBJ) ifdef EXOBJ OBJ += $(EXOBJ) diff --git a/src/win/resource.h b/src/win/resource.h index 376f086f4..d27f9b3c8 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -8,7 +8,7 @@ * * Windows resource defines. * - * Version: @(#)resource.h 1.0.28 2018/09/02 + * Version: @(#)resource.h 1.0.30 2019/01/19 * * Authors: Sarah Walker, * Miran Grca, @@ -149,6 +149,7 @@ #define IDC_CHECK_MPU401 1077 #define IDC_CONFIGURE_MPU401 1078 #define IDC_CHECK_FLOAT 1079 +#define IDC_CHECK_GUSMAX 1080 #define IDC_COMBO_NET_TYPE 1090 /* network config */ #define IDC_COMBO_PCAP 1091 @@ -264,10 +265,18 @@ #define IDM_VID_RESIZE 40040 #define IDM_VID_REMEMBER 40041 #define IDM_VID_DDRAW 40050 +#ifdef USE_D2D #define IDM_VID_D2D 40051 #define IDM_VID_D3D 40052 #define IDM_VID_SDL 40053 #define IDM_VID_VNC 40054 +#else +#define IDM_VID_D3D 40051 +#define IDM_VID_SDL 40052 +#ifdef USE_VNC +#define IDM_VID_VNC 40053 +#endif +#endif #define IDM_VID_SCALE_1X 40055 #define IDM_VID_SCALE_2X 40056 #define IDM_VID_SCALE_3X 40057 diff --git a/src/win/win.c b/src/win/win.c index bd3b259c8..51e2292dc 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,7 +8,7 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.54 2018/10/18 + * Version: @(#)win.c 1.0.55 2018/11/19 * * Authors: Sarah Walker, * Miran Grca, @@ -86,7 +86,9 @@ static struct { } vid_apis[2][RENDERERS_NUM] = { { { "DDraw", 1, (int(*)(void*))ddraw_init, ddraw_close, NULL, ddraw_pause }, +#ifdef USE_D2D { "D2D", 1, (int(*)(void*))d2d_init, d2d_close, NULL, d2d_pause }, +#endif { "D3D", 1, (int(*)(void*))d3d_init, d3d_close, d3d_resize, d3d_pause }, { "SDL", 1, (int(*)(void*))sdl_init, sdl_close, NULL, sdl_pause } #ifdef USE_VNC @@ -95,7 +97,9 @@ static struct { }, { { "DDraw", 1, (int(*)(void*))ddraw_init_fs, ddraw_close, NULL, ddraw_pause }, +#ifdef USE_D2D { "D2D", 1, (int(*)(void*))d2d_init_fs, d2d_close, NULL, d2d_pause }, +#endif { "D3D", 1, (int(*)(void*))d3d_init_fs, d3d_close, NULL, d3d_pause }, { "SDL", 1, (int(*)(void*))sdl_init_fs, sdl_close, sdl_resize, sdl_pause } #ifdef USE_VNC @@ -633,7 +637,6 @@ plat_vidapi_name(int api) case 1: name = "d2d"; break; -#endif case 2: name = "d3d"; @@ -642,9 +645,22 @@ plat_vidapi_name(int api) case 3: name = "sdl"; break; +#else + case 1: + name = "d3d"; + break; + + case 2: + name = "sdl"; + break; +#endif #ifdef USE_VNC +#ifdef USE_D2D case 4: +#else + case 3: +#endif name = "vnc"; break; #endif @@ -753,7 +769,7 @@ take_screenshot(void) time_t now; win_log("Screenshot: video API is: %i\n", vid_api); - if ((vid_api < 0) || (vid_api > 2)) return; + if ((vid_api < 0) || (vid_api >= RENDERERS_NUM)) return; memset(fn, 0, sizeof(fn)); memset(path, 0, sizeof(path)); @@ -780,7 +796,6 @@ take_screenshot(void) case 1: /* d2d */ d2d_take_screenshot(path); break; -#endif case 2: /* d3d9 */ d3d_take_screenshot(path); @@ -789,9 +804,22 @@ take_screenshot(void) case 3: /* sdl */ sdl_take_screenshot(path); break; +#else + case 1: /* d3d9 */ + d3d_take_screenshot(path); + break; + + case 2: /* sdl */ + sdl_take_screenshot(path); + break; +#endif #ifdef USE_VNC +#ifdef USE_D2D case 4: /* vnc */ +#else + case 3: /* vnc */ +#endif vnc_take_screenshot(path); break; #endif diff --git a/src/win/win.h b/src/win/win.h index 69c47b61a..416b6e52a 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -59,10 +59,18 @@ #define WM_SENDSSTATUS 0x8896 #ifdef USE_VNC +#ifdef USE_D2D #define RENDERERS_NUM 5 #else #define RENDERERS_NUM 4 #endif +#else +#ifdef USE_D2D +#define RENDERERS_NUM 4 +#else +#define RENDERERS_NUM 3 +#endif +#endif extern HINSTANCE hinstance; diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp index c62b1bff0..4e7c144e6 100644 --- a/src/win/win_ddraw.cpp +++ b/src/win/win_ddraw.cpp @@ -11,7 +11,7 @@ * NOTES: This code should be re-merged into a single init() with a * 'fullscreen' argument, indicating FS mode is requested. * - * Version: @(#)win_ddraw.cpp 1.0.12 2018/10/18 + * Version: @(#)win_ddraw.cpp 1.0.13 2018/11/18 * * Authors: Sarah Walker, * Miran Grca, @@ -186,9 +186,7 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) } if (ys2 <= 250) { - bmpInfo.bmiHeader.biSizeImage <<= 1; - - pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage); + pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage << 1); if (pBuf2 == NULL) { ddraw_log("[SavePNG] Unable to Allocate Secondary Bitmap Memory"); free(pBuf); @@ -196,7 +194,6 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) return; } - bmpInfo.bmiHeader.biHeight <<= 1; } ddraw_log("save png w=%i h=%i\n", bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); @@ -205,6 +202,11 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS); + if (pBuf2) { + bmpInfo.bmiHeader.biSizeImage <<= 1; + bmpInfo.bmiHeader.biHeight <<= 1; + } + 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); diff --git a/src/win/win_joystick.cpp b/src/win/win_joystick.cpp index 2985c2da5..1a2ee031c 100644 --- a/src/win/win_joystick.cpp +++ b/src/win/win_joystick.cpp @@ -8,7 +8,7 @@ * * Joystick interface to host device. * - * Version: @(#)win_joystick.cpp 1.0.10 2018/10/18 + * Version: @(#)win_joystick.cpp 1.0.11 2018/11/11 * * Authors: Sarah Walker, * Miran Grca, @@ -85,7 +85,7 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback( 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)); + memcpy(state->axis[state->nr_axes].name, lpddoi->tszName, strlen(state->axis[state->nr_axes].name) + 1); 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; @@ -103,13 +103,13 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback( } else if (lpddoi->guidType == GUID_Button) { - strncpy(state->button[state->nr_buttons].name, lpddoi->tszName, sizeof(state->button[state->nr_buttons].name)); + memcpy(state->button[state->nr_buttons].name, lpddoi->tszName, strlen(state->button[state->nr_buttons].name) + 1); 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)); + memcpy(state->pov[state->nr_povs].name, lpddoi->tszName, strlen(state->pov[state->nr_povs].name) + 1); joystick_log("POV %i : %s %x %x\n", state->nr_povs, state->pov[state->nr_povs].name, lpddoi->dwOfs, lpddoi->dwType); state->nr_povs++; } @@ -155,7 +155,7 @@ void joystick_init() 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); + memcpy(plat_joystick_state[c].name, device_instance.tszInstanceName, 260); memset(&devcaps, 0, sizeof(devcaps)); devcaps.dwSize = sizeof(devcaps); diff --git a/src/win/win_jsconf.c b/src/win/win_jsconf.c index 39a02740b..7fa1e52ce 100644 --- a/src/win/win_jsconf.c +++ b/src/win/win_jsconf.c @@ -29,6 +29,7 @@ static void rebuild_axis_button_selections(HWND hdlg) HWND h; int joystick; int c, d; + char s[269]; h = GetDlgItem(hdlg, IDC_CONFIG_BASE); joystick = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -53,8 +54,6 @@ static void rebuild_axis_button_selections(HWND hdlg) } 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); @@ -98,8 +97,6 @@ static void rebuild_axis_button_selections(HWND hdlg) { 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); @@ -294,6 +291,7 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) int y = 10; int id = IDC_CONFIG_BASE; int c; + char s[269]; joystickconfig_changed = 0; @@ -462,8 +460,6 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) for (c = 0; c < joystick_get_pov_count(type)*2; c++) { - char s[80]; - /*Combo box*/ item = (DLGITEMTEMPLATE *)data; item->x = 70; diff --git a/src/win/win_new_floppy.c b/src/win/win_new_floppy.c index e0d800f06..5a4dd7a1f 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -8,7 +8,7 @@ * * Handle the New Floppy Image dialog. * - * Version: @(#)win_new_floppy.c 1.0.9 2018/10/02 + * Version: @(#)win_new_floppy.c 1.0.10 2019/01/17 * * Authors: Miran Grca, * @@ -75,7 +75,7 @@ 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 version = 0x020C; uint16_t dflags = 0; uint16_t tflags = 0; uint32_t index_hole_pos = 0; diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index efc2b6156..8f7510489 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -12,7 +12,7 @@ * we will not use that, but, instead, use a new window which * coverrs the entire desktop. * - * Version: @(#)win_sdl.c 1.0.3 2018/10/21 + * Version: @(#)win_sdl.c 1.0.4 2018/11/18 * * Authors: Fred N. van Kempen, * Michael Drüing, @@ -67,11 +67,12 @@ #include "../plat.h" #include "../plat_dynld.h" #include "../video/video.h" +#include "../ui.h" #include "win.h" #include "win_sdl.h" -#define PATH_SDL_DLL "sdl2.dll" +#define PATH_SDL_DLL "SDL2.dll" static void *sdl_handle = NULL; /* handle to libSDL2 DLL */ @@ -289,10 +290,10 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) sdl_UnlockTexture(sdl_tex); if (sdl_fs) { - pclog("sdl_blit(%i, %i, %i, %i, %i, %i) (%i, %i)\n", x, y, y1, y2, w, h, unscaled_size_x, efscrnsz_y); + sdl_log("sdl_blit(%i, %i, %i, %i, %i, %i) (%i, %i)\n", x, y, y1, y2, w, h, unscaled_size_x, efscrnsz_y); if (w == unscaled_size_x) sdl_resize(w, h); - pclog("(%08X, %08X, %08X)\n", sdl_win, sdl_render, sdl_tex); + sdl_log("(%08X, %08X, %08X)\n", sdl_win, sdl_render, sdl_tex); } r_src.x = 0; @@ -373,7 +374,7 @@ sdl_init_common(int fs) /* 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); + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2121); return(0); } @@ -615,7 +616,7 @@ sdl_resize(int x, int y) if ((x == cur_w) && (y == cur_h)) return; - pclog("sdl_resize(%i, %i)\n", x, y); + sdl_log("sdl_resize(%i, %i)\n", x, y); ww = x; wh = y; sdl_stretch(&ww, &wh, &wx, &wy); diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 86ef51bdb..08c4a17f9 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -21,6 +21,9 @@ #include #include #undef BITMAP +#ifdef ENABLE_SETTINGS_LOG +#include +#endif #include #include #include @@ -95,16 +98,14 @@ static int temp_float; /* Network category */ static int temp_net_type, temp_net_card; -static char temp_pcap_dev[520]; +static char temp_pcap_dev[522]; /* 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_hdc, temp_scsi_card, temp_ide_ter, temp_ide_qua; static int temp_bugger; static int temp_isartc; static int temp_isamem[ISAMEM_MAX]; @@ -236,19 +237,29 @@ win_settings_init(void) /* Network category */ temp_net_type = network_type; memset(temp_pcap_dev, 0, sizeof(temp_pcap_dev)); - strcpy(temp_pcap_dev, network_host); +#ifdef ENABLE_SETTINGS_LOG + assert(sizeof(temp_pcap_dev) == sizeof(network_host)); +#endif + memcpy(temp_pcap_dev, network_host, sizeof(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); +#ifdef ENABLE_SETTINGS_LOG + assert(sizeof(temp_lpt_device_names) == sizeof(lpt_device_names)); +#endif + for (i = 0; i < 3; i++) { +#ifdef ENABLE_SETTINGS_LOG + assert(sizeof(temp_lpt_device_names[i]) == sizeof(lpt_device_names[i])); +#endif + memcpy(temp_lpt_device_names[i], lpt_device_names[i], sizeof(lpt_device_names[i])); + } 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_hdc = hdc_current; temp_ide_ter = ide_ter_enabled; temp_ide_qua = ide_qua_enabled; temp_bugger = bugger_enabled; @@ -355,7 +366,7 @@ win_settings_changed(void) /* 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 || (hdc_current != temp_hdc); i = i || (temp_ide_ter != ide_ter_enabled); i = i || (temp_ide_qua != ide_qua_enabled); i = i || (temp_bugger != bugger_enabled); @@ -452,20 +463,14 @@ win_settings_save(void) /* 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); + memcpy(lpt_device_names[i], temp_lpt_device_names[i], sizeof(temp_lpt_device_names[i])); 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); + hdc_current = temp_hdc; ide_ter_enabled = temp_ide_ter; ide_qua_enabled = temp_ide_qua; bugger_enabled = temp_bugger; @@ -570,7 +575,7 @@ win_settings_machine_recalc_cpu_m(HWND hdlg) char *stransi; temp_romset = machine_getromset_ex(temp_machine); - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_CPU); SendMessage(h, CB_RESETCONTENT, 0, 0); @@ -603,7 +608,7 @@ win_settings_machine_recalc_machine(HWND hdlg) device_t *d; temp_romset = machine_getromset_ex(temp_machine); - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); d = (device_t *) machine_getdevice(temp_machine); @@ -662,7 +667,7 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); for (c = 0; c < ROM_MAX; c++) @@ -765,7 +770,7 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; case WM_SAVESETTINGS: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *)malloc(512); #ifdef USE_DYNAREC @@ -872,11 +877,10 @@ 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); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *) malloc(512); recalc_vid_list(hdlg); @@ -887,10 +891,9 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) 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)) + if (video_card_has_config(temp_gfxcard)) EnableWindow(h, TRUE); else EnableWindow(h, FALSE); @@ -903,17 +906,16 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_COMBO_VIDEO: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); 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 = gfx; + temp_gfxcard = video_card_getid(stransi); h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); - if (video_card_has_config(gfx)) + if (video_card_has_config(temp_gfxcard)) EnableWindow(h, TRUE); else EnableWindow(h, FALSE); @@ -935,7 +937,7 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; case IDC_CONFIGURE_VID: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *) malloc(512); h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); @@ -950,7 +952,7 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; case WM_SAVESETTINGS: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *) malloc(512); h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); @@ -1150,7 +1152,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_SOUND); c = d = 0; @@ -1356,7 +1358,7 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); for (i = 0; i < 3; i++) { h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); @@ -1419,63 +1421,44 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) static void -recalc_hdc_list(HWND hdlg, int machine, int use_selected_hdc) +recalc_hdc_list(HWND hdlg) { - 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); + HWND h = GetDlgItem(hdlg, IDC_COMBO_HDC); + int c = 0, d = 0; + int found_card = 0; + WCHAR szText[512]; SendMessage(h, CB_RESETCONTENT, 0, 0); - c = d = 0; + SendMessage(h, CB_SETCURSEL, 0, 0); + while (1) { - s = hdc_get_name(c); - if (s[0] == 0) + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !(machines[temp_machine].flags & MACHINE_HDC)) { + c++; + continue; + } + + char *s = hdc_get_name(c); + + if (!s[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; + if (hdc_available(c) && + device_is_valid(hdc_get_device(c), machines[temp_machine].flags)) { + mbstowcs(szText, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if (c == temp_hdc) { + SendMessage(h, CB_SETCURSEL, d, 0); + found_card = 1; + } + + d++; } + c++; - d++; } - - if (!valid) + if (!found_card) SendMessage(h, CB_SETCURSEL, 0, 0); - - EnableWindow(h, d ? TRUE : FALSE); - - free(lptsTemp); } @@ -1487,15 +1470,27 @@ static BOOL CALLBACK win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; - int c, d, e, temp_hdc_type; + int c, d; + int e; LPTSTR lptsTemp; + char *stransi; const device_t *scsi_dev; const device_t *dev; char *s; switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); + + /*HD controller config*/ + recalc_hdc_list(hdlg); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + if (hdc_has_config(temp_hdc)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); /*SCSI config*/ h = GetDlgItem(hdlg, IDC_COMBO_SCSI); @@ -1532,11 +1527,6 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa 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); @@ -1612,25 +1602,43 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa EnableWindow(h, FALSE); } + free(stransi); 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)]); + case IDC_CONFIGURE_HDC: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); - h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); - EnableWindow(h, hdc_has_config(temp_hdc_type) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(hdc_get_id(stransi))); + + free(stransi); + free(lptsTemp); 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)]); + case IDC_COMBO_HDC: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(temp_hdc_type)); + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_hdc = hdc_get_id(stransi); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + if (hdc_has_config(temp_hdc)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + free(stransi); + free(lptsTemp); break; case IDC_CONFIGURE_SCSI: @@ -1720,12 +1728,13 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa return FALSE; case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); + 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"); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_hdc = hdc_get_id(stransi); h = GetDlgItem(hdlg, IDC_COMBO_SCSI); temp_scsi_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; @@ -1742,6 +1751,9 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa h = GetDlgItem(hdlg, IDC_CHECK_BUGGER); temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); + free(stransi); + free(lptsTemp); + default: return FALSE; } @@ -1796,7 +1808,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"None"); @@ -1961,7 +1973,7 @@ add_locations(HWND hdlg) HWND h; int i = 0; - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); for (i = 0; i < 5; i++) @@ -3806,7 +3818,7 @@ cdrom_add_locations(HWND hdlg) HWND h; int i = 0; - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) { @@ -3914,7 +3926,7 @@ zip_add_locations(HWND hdlg) HWND h; int i = 0; - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); for (i = ZIP_BUS_DISABLED; i <= ZIP_BUS_SCSI; i++) { @@ -4514,6 +4526,7 @@ win_settings_confirm(HWND hdlg, int button) EndDialog(hdlg, 0); plat_pause(0); win_settings_communicate_closure(); + return button ? TRUE : FALSE; } else return button ? FALSE : TRUE; diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index 92151d87b..13c6c9b20 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -485,6 +485,7 @@ ui_sb_update_panes(void) int c_mfm, c_esdi, c_xta; int c_ide, c_scsi; int do_net; + char *hdc_name; if (sb_ready) { sb_ready = 0; @@ -526,6 +527,7 @@ ui_sb_update_panes(void) if (fdd_get_type(i) != 0) sb_parts++; } + hdc_name = hdc_get_internal_name(hdc_current); for (i=0; i * Miran Grca, @@ -156,11 +156,17 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_DDRAW+0, MF_UNCHECKED); #ifdef USE_D2D CheckMenuItem(menuMain, IDM_VID_DDRAW+1, MF_UNCHECKED); -#endif CheckMenuItem(menuMain, IDM_VID_DDRAW+2, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_DDRAW+3, MF_UNCHECKED); #ifdef USE_VNC CheckMenuItem(menuMain, IDM_VID_DDRAW+4, MF_UNCHECKED); +#endif +#else + 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 #endif CheckMenuItem(menuMain, IDM_VID_FS_FULL+0, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_FS_FULL+1, MF_UNCHECKED);