]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
PCem v16 merge. Original files.
authorToni Wilen <twilen@winuae.net>
Sat, 29 Aug 2020 16:56:46 +0000 (19:56 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 29 Aug 2020 16:56:46 +0000 (19:56 +0300)
120 files changed:
pcem/386.cpp
pcem/386.h [deleted file]
pcem/386_common.cpp [new file with mode: 0644]
pcem/386_common.h
pcem/386_dynarec.cpp
pcem/386_dynarec_ops.cpp [new file with mode: 0644]
pcem/386_ops.h
pcem/8087.h [new file with mode: 0644]
pcem/808x.cpp
pcem/codegen.h
pcem/codegen_backend.h [new file with mode: 0644]
pcem/codegen_backend_x86-64.h [new file with mode: 0644]
pcem/codegen_backend_x86-64_defs.h [new file with mode: 0644]
pcem/codegen_backend_x86.h [new file with mode: 0644]
pcem/codegen_backend_x86_defs.h [new file with mode: 0644]
pcem/codegen_x86-64.h [deleted file]
pcem/codegen_x86.h [deleted file]
pcem/config.h
pcem/cpu.cpp
pcem/cpu.h
pcem/fdc.h
pcem/ibm.h
pcem/keyboard.cpp
pcem/keyboard.h
pcem/keyboard_at.cpp
pcem/mca.h
pcem/mem.cpp
pcem/mem.h
pcem/model.h
pcem/mouse_ps2.cpp
pcem/mouse_serial.cpp
pcem/nvr.cpp [moved from pcem/pcemnvr.cpp with 73% similarity]
pcem/nvr.h
pcem/pcemglue.cpp
pcem/pcemglue.h
pcem/pic.cpp
pcem/pit.cpp
pcem/pit.h
pcem/plat-keyboard.h
pcem/plat-midi.h
pcem/plat-mouse.h
pcem/rom.h
pcem/serial.cpp
pcem/serial.h
pcem/sound.h
pcem/sound_cms.cpp
pcem/sound_dbopl.cpp
pcem/sound_dbopl.h
pcem/sound_emu8k.h
pcem/sound_mpu401_uart.cpp
pcem/sound_mpu401_uart.h
pcem/sound_opl.cpp
pcem/sound_opl.h
pcem/sound_sb.cpp
pcem/sound_sb.h
pcem/sound_sb_dsp.cpp
pcem/sound_sb_dsp.h
pcem/thread.h [new file with mode: 0644]
pcem/timer.cpp
pcem/timer.h
pcem/vid_cl5429.cpp [new file with mode: 0644]
pcem/vid_cl5429.h [new file with mode: 0644]
pcem/vid_s3.cpp [new file with mode: 0644]
pcem/vid_s3.h [new file with mode: 0644]
pcem/vid_s3_virge.cpp [new file with mode: 0644]
pcem/vid_s3_virge.h [new file with mode: 0644]
pcem/vid_sdac_ramdac.cpp [new file with mode: 0644]
pcem/vid_sdac_ramdac.h [new file with mode: 0644]
pcem/vid_svga.cpp [new file with mode: 0644]
pcem/vid_svga.h [new file with mode: 0644]
pcem/vid_svga_render.cpp [new file with mode: 0644]
pcem/vid_svga_render.h [new file with mode: 0644]
pcem/vid_unk_ramdac.h [new file with mode: 0644]
pcem/vid_vga.h [new file with mode: 0644]
pcem/video.h
pcem/x86.h
pcem/x86_flags.h
pcem/x86_ops.h
pcem/x86_ops_3dnow.h [new file with mode: 0644]
pcem/x86_ops_arith.h
pcem/x86_ops_atomic.h
pcem/x86_ops_bcd.h
pcem/x86_ops_bit.h
pcem/x86_ops_bitscan.h
pcem/x86_ops_call.h
pcem/x86_ops_flag.h
pcem/x86_ops_inc_dec.h
pcem/x86_ops_int.h
pcem/x86_ops_jump.h
pcem/x86_ops_misc.h
pcem/x86_ops_mmx.h
pcem/x86_ops_mmx_arith.h
pcem/x86_ops_mmx_cmp.h
pcem/x86_ops_mmx_mov.h
pcem/x86_ops_mmx_pack.h
pcem/x86_ops_mmx_shift.h
pcem/x86_ops_mov.h
pcem/x86_ops_mov_ctrl.h
pcem/x86_ops_mov_seg.h
pcem/x86_ops_movx.h
pcem/x86_ops_msr.h
pcem/x86_ops_mul.h
pcem/x86_ops_pmode.h
pcem/x86_ops_prefix.h
pcem/x86_ops_rep.h
pcem/x86_ops_ret.h
pcem/x86_ops_set.h
pcem/x86_ops_shift.h
pcem/x86_ops_stack.h
pcem/x86_ops_string.h
pcem/x86_ops_xchg.h
pcem/x86seg.cpp
pcem/x87.cpp
pcem/x87.h
pcem/x87_ops.h
pcem/x87_ops_arith.h
pcem/x87_ops_loadstore.h
pcem/x87_ops_misc.h
pcem/x87_timings.cpp [new file with mode: 0644]
pcem/x87_timings.h [new file with mode: 0644]

index 9a07a2af35be9d20cd8228feff883d53113c83a2..e99ef1f68869604e8fbcb8ecda64813a8a9166ce 100644 (file)
@@ -2,7 +2,6 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ibm.h"
-#include "386.h"
 #include "x86.h"
 #include "x87.h"
 #include "mem.h"
 #include "nmi.h"
 
 #include "386_common.h"
+#include "codegen.h"
 
+#undef CPU_BLOCK_END
 #define CPU_BLOCK_END()
 
-extern int codegen_flags_changed;
-
-extern int nmi_enable;
-
-int inscounts[256];
-uint32_t oldpc2;
-
-int trap;
-
-
-
-extern int cpl_override;
-
-int has_fpu;
-extern int fpucount;
-uint16_t rds;
-uint16_t ea_rseg;
-
-extern int is486;
-extern int cgate32;
-
-
-
-extern uint8_t romext[32768];
-extern uint8_t *ram,*rom;
-
-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;
-
-extern uint16_t *mod1add[2][8];
-extern uint32_t *mod1seg[8];
-
 static inline void fetch_ea_32_long(uint32_t rmdat)
 {
         eal_r = eal_w = NULL;
         easeg = cpu_state.ea_seg->base;
-        ea_rseg = cpu_state.ea_seg->seg;
         if (cpu_rm == 4)
         {
                 uint8_t sib = rmdat >> 8;
@@ -89,8 +47,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat)
                 else if ((sib & 6) == 4 && !cpu_state.ssegs)
                 {
                         easeg = ss;
-                        ea_rseg = SS;
-                        cpu_state.ea_seg = &_ss;
+                        cpu_state.ea_seg = &cpu_state.seg_ss;
                 }
                 if (((sib >> 3) & 7) != 4) 
                         cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6);
@@ -103,8 +60,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat)
                         if (cpu_rm == 5 && !cpu_state.ssegs)
                         {
                                 easeg = ss;
-                                ea_rseg = SS;
-                                cpu_state.ea_seg = &_ss;
+                                cpu_state.ea_seg = &cpu_state.seg_ss;
                         }
                         if (cpu_mod == 1) 
                         { 
@@ -135,8 +91,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
 {
         eal_r = eal_w = NULL;
         easeg = cpu_state.ea_seg->base;
-        ea_rseg = cpu_state.ea_seg->seg;
-        if (!cpu_mod && cpu_rm == 6) 
+        if (!cpu_mod && cpu_rm == 6)
         { 
                 cpu_state.eaaddr = getword();
         }
@@ -158,8 +113,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
                 if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs)
                 {
                         easeg = ss;
-                        ea_rseg = SS;
-                        cpu_state.ea_seg = &_ss;
+                        cpu_state.ea_seg = &cpu_state.seg_ss;
                 }
                 cpu_state.eaaddr &= 0xFFFF;
         }
@@ -182,19 +136,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
 #define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2
 #define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++
 #define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2
-extern int xout;
-
-int oldi;
 
-uint32_t testr[9];
-extern int dontprint;
-
-#undef NOTRM
-#define NOTRM   if (!(msw & 1) || (eflags & VM_FLAG))\
-                { \
-                        x86_int(6); \
-                        return 0; \
-                }
 
 #define OP_TABLE(name) ops_ ## name
 
@@ -203,13 +145,6 @@ extern int dontprint;
 
 #include "x86_ops.h"
 
-#undef NOTRM
-#define NOTRM   if (!(msw & 1) || (eflags & VM_FLAG))\
-                { \
-                        x86_int(6); \
-                        break; \
-                }
-
 void exec386(int cycs)
 {
         uint8_t temp;
@@ -222,42 +157,33 @@ void exec386(int cycs)
 //        output=3;
         while (cycles>0)
         {
-                int cycle_period = (timer_count >> TIMER_SHIFT) + 1;
+                int cycle_period = (timer_target - (uint32_t)tsc) + 1;
                 
                 x86_was_reset = 0;
                 cycdiff=0;
                 oldcyc=cycles;
-                timer_start_period(cycles << TIMER_SHIFT);
 //                pclog("%i %02X\n", ins, ram[8]);
                 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;
+                        int ins_cycles = cycles;
+                        
                 cpu_state.oldpc = cpu_state.pc;
-                oldcpl=CPL;
                 cpu_state.op32 = use32;
                 
-dontprint=0;
-
-                cpu_state.ea_seg = &_ds;
+                cpu_state.ea_seg = &cpu_state.seg_ds;
                 cpu_state.ssegs = 0;
                 
                 fetchdat = fastreadl(cs + cpu_state.pc);
 
                 if (!cpu_state.abrt)
-                {               
-                        trap = flags & T_FLAG;
-                        opcode = fetchdat & 0xFF;
+                {
+                        uint8_t opcode = fetchdat & 0xFF;
                         fetchdat >>= 8;
+                        trap = cpu_state.flags & T_FLAG;
 
                         if (output == 3)
                         {
-                                pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X %f  %02X%02X %02X%02X %02X%02X  %02X\n",CS,cs,cpu_state.pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0xB270+0x3F5], ram[0xB270+0x3F4], ram[0xB270+0x3F7], ram[0xB270+0x3F6], ram[0xB270+0x3F9], ram[0xB270+0x3F8], ram[0x4430+0x0D49]);
+                                pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X\n",CS,cs,cpu_state.pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,cpu_state.flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask);
                         }
                         cpu_state.pc++;
                         x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
@@ -265,29 +191,17 @@ dontprint=0;
                                 break;
                 }
 
-                if (!use32) cpu_state.pc &= 0xffff;
-
                 if (cpu_state.abrt)
                 {
                         flags_rebuild();
 //                        pclog("Abort\n");
 //                        if (CS == 0x228) pclog("Abort at %04X:%04X - %i %i %i\n",CS,pc,notpresent,nullseg,abrt);
-/*                        if (testr[0]!=EAX) pclog("EAX corrupted %08X\n",pc);
-                        if (testr[1]!=EBX) pclog("EBX corrupted %08X\n",pc);
-                        if (testr[2]!=ECX) pclog("ECX corrupted %08X\n",pc);
-                        if (testr[3]!=EDX) pclog("EDX corrupted %08X\n",pc);
-                        if (testr[4]!=ESI) pclog("ESI corrupted %08X\n",pc);
-                        if (testr[5]!=EDI) pclog("EDI corrupted %08X\n",pc);
-                        if (testr[6]!=EBP) pclog("EBP corrupted %08X\n",pc);
-                        if (testr[7]!=ESP) pclog("ESP corrupted %08X\n",pc);*/
-/*                        if (testr[8]!=flags) pclog("FLAGS corrupted %08X\n",pc);*/
                         tempi = cpu_state.abrt;
                         cpu_state.abrt = 0;
                         x86_doabrt(tempi);
                         if (cpu_state.abrt)
                         {
                                 cpu_state.abrt = 0;
-                                CS = oldcs;
                                 cpu_state.pc = cpu_state.oldpc;
                                 pclog("Double fault %i\n", ins);
                                 pmodeint(8, 0);
@@ -300,26 +214,28 @@ dontprint=0;
                                 }
                         }
                 }
+                ins_cycles -= cycles;
+                tsc += ins_cycles;
+                
                 cycdiff=oldcyc-cycles;
 
                 if (trap)
                 {
                         flags_rebuild();
 //                        oldpc=pc;
-//                        oldcs=CS;
                         if (msw&1)
                         {
                                 pmodeint(1,0);
                         }
                         else
                         {
-                                writememw(ss,(SP-2)&0xFFFF,flags);
+                                writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
                                 writememw(ss,(SP-4)&0xFFFF,CS);
                                 writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
                                 SP-=6;
                                 addr = (1 << 2) + idt.base;
-                                flags&=~I_FLAG;
-                                flags&=~T_FLAG;
+                                cpu_state.flags &= ~I_FLAG;
+                                cpu_state.flags &= ~T_FLAG;
                                 cpu_state.pc=readmemw(0,addr);
                                 loadcs(readmemw(0,addr+2));
                         }
@@ -327,7 +243,6 @@ dontprint=0;
                 else if (nmi && nmi_enable && nmi_mask)
                 {
                         cpu_state.oldpc = cpu_state.pc;
-                        oldcs = CS;
 //                        pclog("NMI\n");
                         x86_int(2);
                         nmi_enable = 0;
@@ -337,7 +252,7 @@ dontprint=0;
                                 nmi = 0;
                         }
                 }
-                else if ((flags&I_FLAG) && pic_intpending)
+                else if ((cpu_state.flags & I_FLAG) && pic_intpending)
                 {
                         temp=picinterrupt();
                         if (temp!=0xFF)
@@ -353,14 +268,13 @@ dontprint=0;
                                 }
                                 else
                                 {
-                                        writememw(ss,(SP-2)&0xFFFF,flags);
+                                        writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
                                         writememw(ss,(SP-4)&0xFFFF,CS);
                                         writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
                                         SP-=6;
                                         addr = (temp << 2) + idt.base;
-                                        flags&=~I_FLAG;
-                                        flags&=~T_FLAG;
-                                        oxpc=cpu_state.pc;
+                                        cpu_state.flags &= ~I_FLAG;
+                                        cpu_state.flags &= ~T_FLAG;
                                         cpu_state.pc=readmemw(0,addr);
                                         loadcs(readmemw(0,addr+2));
 //                                        if (temp==0x76) pclog("INT to %04X:%04X\n",CS,pc);
@@ -380,8 +294,7 @@ dontprint=0;
                 }
                 }
                 
-                tsc += cycdiff;
-                
-                timer_end_period(cycles << TIMER_SHIFT);
+               if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc))
+                       timer_process();
         }
 }
diff --git a/pcem/386.h b/pcem/386.h
deleted file mode 100644 (file)
index eada519..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-extern void cpu_386_flags_extract();
-extern void cpu_386_flags_rebuild();
-
-void pmodeint(int num, int soft);
-void loadcscall(uint16_t seg);
-void loadcsjmp(uint16_t seg, uint32_t oxpc);
-void pmoderetf(int is32, uint16_t off);
-void pmodeiret(int is32);
-void x86_int_sw(int num);
-int x86_int_sw_rm(int num);
-
-int divl(uint32_t val);
-int idivl(int32_t val);
diff --git a/pcem/386_common.cpp b/pcem/386_common.cpp
new file mode 100644 (file)
index 0000000..8919652
--- /dev/null
@@ -0,0 +1,249 @@
+#include "ibm.h"
+#include "x86.h"
+#include "386_common.h"
+#include "x86_flags.h"
+#include "codegen.h"
+
+x86seg gdt, ldt, idt, tr;
+
+uint32_t cr2, cr3, cr4;
+uint32_t dr[8];
+
+uint32_t use32;
+int stack32;
+int optype;
+
+int trap;
+
+uint32_t rmdat;
+
+uint32_t *eal_r, *eal_w;
+
+int nmi_enable = 1;
+
+int cpl_override=0;
+
+int fpucount=0;
+
+uint16_t cpu_cur_status = 0;
+
+uint32_t pccache;
+uint8_t *pccache2;
+
+void x86_int(int num)
+{
+        uint32_t addr;
+//        pclog("x86_int %02x %04x:%04x\n", num, CS,pc);
+        flags_rebuild();
+        cpu_state.pc=cpu_state.oldpc;
+        if (msw&1)
+        {
+                pmodeint(num,0);
+        }
+        else
+        {
+                addr = (num << 2) + idt.base;
+
+                if ((num << 2) + 3 > idt.limit)
+                {
+                        if (idt.limit < 35)
+                        {
+                                cpu_state.abrt = 0;
+                                softresetx86();
+                                cpu_set_edx();
+                                pclog("Triple fault in real mode - reset\n");
+                        }
+                        else
+                                x86_int(8);
+                }
+                else
+                {
+                        if (stack32)
+                        {
+                                writememw(ss,ESP-2,cpu_state.flags);
+                                writememw(ss,ESP-4,CS);
+                                writememw(ss,ESP-6,cpu_state.pc);
+                                ESP-=6;
+                        }
+                        else
+                        {
+                                writememw(ss,((SP-2)&0xFFFF),cpu_state.flags);
+                                writememw(ss,((SP-4)&0xFFFF),CS);
+                                writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
+                                SP-=6;
+                        }
+
+                        cpu_state.flags &= ~I_FLAG;
+                        cpu_state.flags &= ~T_FLAG;
+                        cpu_state.pc=readmemw(0,addr);
+                        loadcs(readmemw(0,addr+2));
+                }
+        }
+        cycles-=70;
+        CPU_BLOCK_END();
+}
+
+void x86_int_sw(int num)
+{
+        uint32_t addr;
+//        pclog("x86_int_sw %02x %04x:%04x\n", num, CS,pc);
+//        pclog("x86_int\n");
+        flags_rebuild();
+        cycles -= timing_int;
+        if (msw&1)
+        {
+                pmodeint(num,1);
+        }
+        else
+        {
+                addr = (num << 2) + idt.base;
+
+                if ((num << 2) + 3 > idt.limit)
+                {
+                        x86_int(13);
+                }
+                else
+                {
+                        if (stack32)
+                        {
+                                writememw(ss,ESP-2,cpu_state.flags);
+                                writememw(ss,ESP-4,CS);
+                                writememw(ss,ESP-6,cpu_state.pc);
+                                ESP-=6;
+                        }
+                        else
+                        {
+                                writememw(ss,((SP-2)&0xFFFF),cpu_state.flags);
+                                writememw(ss,((SP-4)&0xFFFF),CS);
+                                writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
+                                SP-=6;
+                        }
+
+                        cpu_state.flags &= ~I_FLAG;
+                        cpu_state.flags &= ~T_FLAG;
+                        cpu_state.pc=readmemw(0,addr);
+                        loadcs(readmemw(0,addr+2));
+                        cycles -= timing_int_rm;
+                }
+        }
+        trap = 0;
+        CPU_BLOCK_END();
+}
+
+int x86_int_sw_rm(int num)
+{
+        uint32_t addr;
+        uint16_t new_pc, new_cs;
+
+        flags_rebuild();
+        cycles -= timing_int;
+
+        addr = num << 2;
+        new_pc = readmemw(0, addr);
+        new_cs = readmemw(0, addr + 2);
+
+        if (cpu_state.abrt) return 1;
+
+        writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); if (cpu_state.abrt) {pclog("abrt5\n"); return 1; }
+        writememw(ss,((SP-4)&0xFFFF),CS);
+        writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {pclog("abrt6\n"); return 1; }
+        SP-=6;
+
+        cpu_state.eflags &= ~VIF_FLAG;
+        cpu_state.flags &= ~T_FLAG;
+        cpu_state.pc = new_pc;
+        loadcs(new_cs);
+
+        cycles -= timing_int_rm;
+        trap = 0;
+        CPU_BLOCK_END();
+
+        return 0;
+}
+
+void x86illegal()
+{
+//        pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode);
+
+//        if (output)
+//        {
+//                dumpregs();
+//                exit(-1);
+//        }
+        x86_int(6);
+}
+
+int checkio(int port)
+{
+        uint16_t t;
+        uint8_t d;
+        cpl_override = 1;
+        t = readmemw(tr.base, 0x66);
+        cpl_override = 0;
+//        pclog("CheckIO 1 %08X  %04x %02x\n",tr.base, eflags, _cs.access);
+        if (cpu_state.abrt) return 0;
+//        pclog("CheckIO %04X %01X %01X %02X %04X %04X %08X ",CS,CPL,IOPL,port,t,t+(port>>3),tr.base+t+(port>>3));
+        if ((t+(port>>3))>tr.limit) return 1;
+        cpl_override = 1;
+        d = readmembl(tr.base + t + (port >> 3));
+//        d=readmemb(tr.base,t+(port>>3));
+        cpl_override = 0;
+//      pclog("%02X %02X\n",d,d&(1<<(port&7)));
+        return d&(1<<(port&7));
+}
+
+#define divexcp() { \
+                pclog("Divide exception at %04X(%06X):%04X\n",CS,cs,cpu_state.pc); \
+                x86_int(0); \
+}
+
+int divl(uint32_t val)
+{
+        if (val==0)
+        {
+                divexcp();
+                return 1;
+        }
+        uint64_t num=(((uint64_t)EDX)<<32)|EAX;
+        uint64_t quo=num/val;
+        uint32_t rem=num%val;
+        uint32_t quo32=(uint32_t)(quo&0xFFFFFFFF);
+        if (quo!=(uint64_t)quo32)
+        {
+                divexcp();
+                return 1;
+        }
+        EDX=rem;
+        EAX=quo32;
+        return 0;
+}
+int idivl(int32_t val)
+{
+        if (val==0)
+        {
+                divexcp();
+                return 1;
+        }
+        int64_t num=(((uint64_t)EDX)<<32)|EAX;
+        int64_t quo=num/val;
+        int32_t rem=num%val;
+        int32_t quo32=(int32_t)(quo&0xFFFFFFFF);
+        if (quo!=(int64_t)quo32)
+        {
+                divexcp();
+                return 1;
+        }
+        EDX=rem;
+        EAX=quo32;
+        return 0;
+}
+
+
+void cpu_386_flags_extract()
+{
+        flags_extract();
+}
+void cpu_386_flags_rebuild()
+{
+        flags_rebuild();
+}
index c8bbd6e882b751e4860555a89434f20bf1c01b73..c01b9c70eaa7187da4f9c12b8a044bc8fd6e6e6b 100644 (file)
@@ -1,21 +1,19 @@
-extern uint16_t ea_rseg;
+#ifndef _386_COMMON_H_
+#define _386_COMMON_H_
 
-#undef readmemb
-#undef writememb
+#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) )
+#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
+#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
+#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
 
-
-#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) )
-#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
-
-#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
-
-#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
-#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
-#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
+#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
+#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
+#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
+#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
 
 int checkio(int port);
 
-#define check_io_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \
+#define check_io_perm(port) if (!IOPLp || (cpu_state.eflags&VM_FLAG)) \
                         { \
                                 int tempi = checkio(port); \
                                 if (cpu_state.abrt) return 1; \
@@ -26,26 +24,35 @@ int checkio(int port);
                                 } \
                         }
 
-#define checkio_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \
-                        { \
-                                int tempi = checkio(port); \
-                                if (cpu_state.abrt) break; \
-                                if (tempi) \
-                                { \
-                                        x86gpf(NULL,0); \
-                                        break; \
-                                } \
-                        }
+#define SEG_CHECK_READ(seg)                             \
+        do                                              \
+        {                                               \
+                if ((seg)->base == 0xffffffff)          \
+                {                                       \
+                        x86gpf("Segment can't read", 0);\
+                        return 1;                       \
+                }                                       \
+        } while (0)
+
+#define SEG_CHECK_WRITE(seg)                    \
+        do                                              \
+        {                                               \
+                if ((seg)->base == 0xffffffff)          \
+                {                                       \
+                        x86gpf("Segment can't write", 0);\
+                        return 1;                       \
+                }                                       \
+        } while (0)
 
 #define CHECK_READ(seg, low, high)  \
-        if ((low < (seg)->limit_low) || (high > (seg)->limit_high) || ((msw & 1) && !(eflags & VM_FLAG) && (((seg)->access & 10) == 8)))       \
+        if ((low < (seg)->limit_low) || (high > (seg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((seg)->access & 10) == 8)))       \
         {                                       \
                 x86gpf("Limit check", 0);       \
                 return 1;                       \
         }
 
 #define CHECK_WRITE(seg, low, high)  \
-        if ((low < (seg)->limit_low) || (high > (seg)->limit_high) || !((seg)->access & 2) || ((msw & 1) && !(eflags & VM_FLAG) && ((seg)->access & 8)))       \
+        if ((low < (seg)->limit_low) || (high > (seg)->limit_high) || !((seg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((seg)->access & 8)))       \
         {                                       \
                 x86gpf("Limit check", 0);       \
                 return 1;                       \
@@ -59,7 +66,7 @@ int checkio(int port);
         }
 
 
-#define NOTRM   if (!(msw & 1) || (eflags & VM_FLAG))\
+#define NOTRM   if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\
                 { \
                         x86_int(6); \
                         return 1; \
@@ -124,6 +131,17 @@ static inline uint32_t fastreadl(uint32_t a)
         return val;
 }
 
+static inline void *get_ram_ptr(uint32_t a)
+{
+        if ((a >> 12) == pccache)
+                return &pccache2[a];
+        else
+        {
+                uint8_t *t = getpccache(a);
+                return &t[a];
+        }
+}
+
 static inline uint8_t getbyte()
 {
         cpu_state.pc++;
@@ -156,32 +174,30 @@ static inline uint8_t geteab()
                 return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm&3].b.l;
         if (eal_r)
                 return *(uint8_t *)eal_r;
-        return readmemb(easeg, cpu_state.eaaddr);
+        return readmemb(easeg,cpu_state.eaaddr);
 }
 
 static inline uint16_t geteaw()
 {
         if (cpu_mod == 3)
                 return cpu_state.regs[cpu_rm].w;
-//        cycles-=3;
         if (eal_r)
                 return *(uint16_t *)eal_r;
-        return readmemw(easeg, cpu_state.eaaddr);
+        return readmemw(easeg,cpu_state.eaaddr);
 }
 
 static inline uint32_t geteal()
 {
         if (cpu_mod == 3)
                 return cpu_state.regs[cpu_rm].l;
-//        cycles-=3;
         if (eal_r)
                 return *eal_r;
-        return readmeml(easeg, cpu_state.eaaddr);
+        return readmeml(easeg,cpu_state.eaaddr);
 }
 
 static inline uint64_t geteaq()
 {
-        return readmemq(easeg, cpu_state.eaaddr);
+        return readmemq(easeg,cpu_state.eaaddr);
 }
 
 static inline uint8_t geteab_mem()
@@ -202,24 +218,20 @@ static inline uint32_t geteal_mem()
 
 static inline void seteaq(uint64_t v)
 {
-        writememql(easegcpu_state.eaaddr, v);
+        writememql(easeg+cpu_state.eaaddr, v);
 }
 
-#define seteab(v) if (cpu_mod!=3) { if (eal_w) *(uint8_t *)eal_w=v;  else writememb386l(easeg,cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v
-#define seteaw(v) if (cpu_mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v);    } else cpu_state.regs[cpu_rm].w=v
-#define seteal(v) if (cpu_mod!=3) { if (eal_w) *eal_w=v;             else writememll(easeg,cpu_state.eaaddr,v);    } else cpu_state.regs[cpu_rm].l=v
+#define seteab(v) if (cpu_mod!=3) { if (eal_w) *(uint8_t *)eal_w=v;  else writemembl(easeg+cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v
+#define seteaw(v) if (cpu_mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v);    } else cpu_state.regs[cpu_rm].w=v
+#define seteal(v) if (cpu_mod!=3) { if (eal_w) *eal_w=v;             else writememll(easeg+cpu_state.eaaddr,v);    } else cpu_state.regs[cpu_rm].l=v
 
-#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v;  else writememb386l(easeg,cpu_state.eaaddr,v);
-#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v);
-#define seteal_mem(v) if (eal_w) *eal_w=v;             else writememll(easeg,cpu_state.eaaddr,v);
+#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v;  else writemembl(easeg+cpu_state.eaaddr,v);
+#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v);
+#define seteal_mem(v) if (eal_w) *eal_w=v;             else writememll(easeg+cpu_state.eaaddr,v);
 
 #define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++
 #define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2
 #define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++
 #define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2
 
-
-#define rmdat rmdat32
-#define fetchdat rmdat32
-
-void x86_int(int num);
+#endif
index e0c068ff63b49d6a182ac4eda7e251b041f16ea2..b7ab1bfd97814faf97d0004632a82ef97f6b6b05 100644 (file)
@@ -2,12 +2,12 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ibm.h"
-#include "386.h"
 #include "x86.h"
 #include "x86_ops.h"
 #include "x87.h"
 #include "mem.h"
 #include "codegen.h"
+#include "codegen_backend.h"
 #include "cpu.h"
 #include "fdc.h"
 #include "nmi.h"
 
 #define CPU_BLOCK_END() cpu_block_end = 1
 
-uint32_t cpu_cur_status = 0;
-
-int cpu_reps, cpu_reps_latched;
-int cpu_notreps, cpu_notreps_latched;
-
 int inrecomp = 0;
 int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks;
 int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched;
 
 int cpu_block_end = 0;
 
-int nmi_enable = 1;
-
-extern int inscounts[256];
-extern uint32_t oldpc2;
-
-extern int trap;
-
-
-
-extern int cpl_override;
-
-extern int has_fpu;
-int fpucount=0;
-extern uint16_t rds;
-extern uint16_t ea_rseg;
-
-extern int is486;
-extern int cgate32;
-
-
-extern uint8_t romext[32768];
-extern uint8_t *ram,*rom;
-
-extern uint32_t rmdat32;
-extern uint32_t backupregs[16];
-int oddeven=0;
-extern int inttype;
-
-
-extern uint32_t oldcs2;
-extern uint32_t oldecx;
-
-extern uint32_t *eal_r, *eal_w;
 
-extern uint16_t *mod1add[2][8];
-extern uint32_t *mod1seg[8];
 
 static inline void fetch_ea_32_long(uint32_t rmdat)
 {
         eal_r = eal_w = NULL;
         easeg = cpu_state.ea_seg->base;
-        ea_rseg = cpu_state.ea_seg->seg;
         if (cpu_rm == 4)
         {
                 uint8_t sib = rmdat >> 8;
@@ -97,8 +56,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat)
                 else if ((sib & 6) == 4 && !cpu_state.ssegs)
                 {
                         easeg = ss;
-                        ea_rseg = SS;
-                        cpu_state.ea_seg = &_ss;
+                        cpu_state.ea_seg = &cpu_state.seg_ss;
                 }
                 if (((sib >> 3) & 7) != 4) 
                         cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6);
@@ -111,8 +69,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat)
                         if (cpu_rm == 5 && !cpu_state.ssegs)
                         {
                                 easeg = ss;
-                                ea_rseg = SS;
-                                cpu_state.ea_seg = &_ss;
+                                cpu_state.ea_seg = &cpu_state.seg_ss;
                         }
                         if (cpu_mod == 1) 
                         { 
@@ -143,8 +100,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
 {
         eal_r = eal_w = NULL;
         easeg = cpu_state.ea_seg->base;
-        ea_rseg = cpu_state.ea_seg->seg;
-        if (!cpu_mod && cpu_rm == 6) 
+        if (!cpu_mod && cpu_rm == 6)
         { 
                 cpu_state.eaaddr = getword();
         }
@@ -166,8 +122,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
                 if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs)
                 {
                         easeg = ss;
-                        ea_rseg = SS;
-                        cpu_state.ea_seg = &_ss;
+                        cpu_state.ea_seg = &cpu_state.seg_ss;
                 }
                 cpu_state.eaaddr &= 0xFFFF;
         }
@@ -186,151 +141,6 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
 
 #include "x86_flags.h"
 
-void x86_int(int num)
-{
-        uint32_t addr;
-//        pclog("x86_int %02x %04x:%04x\n", num, CS,pc);
-        flags_rebuild();
-        cpu_state.pc=cpu_state.oldpc;
-        if (msw&1)
-        {
-                pmodeint(num,0);
-        }
-        else
-        {
-                addr = (num << 2) + idt.base;
-
-                if ((num << 2) + 3 > idt.limit)
-                {
-                        if (idt.limit < 35)
-                        {
-                                cpu_state.abrt = 0;
-                                softresetx86();
-                                cpu_set_edx();
-                                pclog("Triple fault in real mode - reset\n");
-                        }
-                        else
-                                x86_int(8);
-                }
-                else
-                {
-                        if (stack32)
-                        {
-                                writememw(ss,ESP-2,flags);
-                                writememw(ss,ESP-4,CS);
-                                writememw(ss,ESP-6,cpu_state.pc);
-                                ESP-=6;
-                        }
-                        else
-                        {
-                                writememw(ss,((SP-2)&0xFFFF),flags);
-                                writememw(ss,((SP-4)&0xFFFF),CS);
-                                writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
-                                SP-=6;
-                        }
-
-                        flags&=~I_FLAG;
-                        flags&=~T_FLAG;
-                        oxpc=cpu_state.pc;
-                        cpu_state.pc=readmemw(0,addr);
-                        loadcs(readmemw(0,addr+2));
-                }
-        }
-        cycles-=70;
-        CPU_BLOCK_END();
-}
-
-void x86_int_sw(int num)
-{
-        uint32_t addr;
-//        pclog("x86_int_sw %02x %04x:%04x\n", num, CS,pc);
-//        pclog("x86_int\n");
-        flags_rebuild();
-        cycles -= timing_int;
-        if (msw&1)
-        {
-                pmodeint(num,1);
-        }
-        else
-        {
-                addr = (num << 2) + idt.base;
-
-                if ((num << 2) + 3 > idt.limit)
-                {
-                        x86_int(13);
-                }
-                else
-                {
-                        if (stack32)
-                        {
-                                writememw(ss,ESP-2,flags);
-                                writememw(ss,ESP-4,CS);
-                                writememw(ss,ESP-6,cpu_state.pc);
-                                ESP-=6;
-                        }
-                        else
-                        {
-                                writememw(ss,((SP-2)&0xFFFF),flags);
-                                writememw(ss,((SP-4)&0xFFFF),CS);
-                                writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
-                                SP-=6;
-                        }
-
-                        flags&=~I_FLAG;
-                        flags&=~T_FLAG;
-                        oxpc=cpu_state.pc;
-                        cpu_state.pc=readmemw(0,addr);
-                        loadcs(readmemw(0,addr+2));
-                        cycles -= timing_int_rm;
-                }
-        }
-        trap = 0;
-        CPU_BLOCK_END();
-}
-
-int x86_int_sw_rm(int num)
-{
-        uint32_t addr;
-        uint16_t new_pc, new_cs;
-        
-        flags_rebuild();
-        cycles -= timing_int;
-
-        addr = num << 2;
-        new_pc = readmemw(0, addr);
-        new_cs = readmemw(0, addr + 2);
-
-        if (cpu_state.abrt) return 1;
-
-        writememw(ss,((SP-2)&0xFFFF),flags); if (cpu_state.abrt) {pclog("abrt5\n"); return 1; }
-        writememw(ss,((SP-4)&0xFFFF),CS);
-        writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {pclog("abrt6\n"); return 1; }
-        SP-=6;
-
-        eflags &= ~VIF_FLAG;
-        flags &= ~T_FLAG;
-        cpu_state.pc = new_pc;
-        loadcs(new_cs);
-        oxpc=cpu_state.pc;
-
-        cycles -= timing_int_rm;
-        trap = 0;
-        CPU_BLOCK_END();
-        
-        return 0;
-}
-
-void x86illegal()
-{
-//        pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode);
-        
-//        if (output)
-//        {
-//                dumpregs();
-//                exit(-1);
-//        }
-        x86_int(6);
-}
 
 /*Prefetch emulation is a fairly simplistic model:
   - All instruction bytes must be fetched before it starts.
@@ -402,6 +212,8 @@ static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int
         }
         
         prefetch_prefixes = 0;
+        if (prefetch_bytes > 16)
+                prefetch_bytes = 16;
 }
 
 static void prefetch_flush()
@@ -416,89 +228,6 @@ static void prefetch_flush()
 #define PREFETCH_FLUSH() prefetch_flush()
 
 
-int checkio(int port)
-{
-        uint16_t t;
-        uint8_t d;
-        cpl_override = 1;
-        t = readmemw(tr.base, 0x66);
-        cpl_override = 0;
-//        pclog("CheckIO 1 %08X  %04x %02x\n",tr.base, eflags, _cs.access);
-        if (cpu_state.abrt) return 0;
-//        pclog("CheckIO %04X %01X %01X %02X %04X %04X %08X ",CS,CPL,IOPL,port,t,t+(port>>3),tr.base+t+(port>>3));
-        if ((t+(port>>3))>tr.limit) return 1;
-        cpl_override = 1;
-        d = readmemb386l(0, tr.base + t + (port >> 3));
-//        d=readmemb(tr.base,t+(port>>3));
-        cpl_override = 0;
-//      pclog("%02X %02X\n",d,d&(1<<(port&7)));
-        return d&(1<<(port&7));
-}
-
-int xout=0;
-
-
-#define divexcp() { \
-                pclog("Divide exception at %04X(%06X):%04X\n",CS,cs,cpu_state.pc); \
-                x86_int(0); \
-}
-
-int divl(uint32_t val)
-{
-        if (val==0) 
-        {
-                divexcp();
-                return 1;
-        }
-        uint64_t num=(((uint64_t)EDX)<<32)|EAX;
-        uint64_t quo=num/val;
-        uint32_t rem=num%val;
-        uint32_t quo32=(uint32_t)(quo&0xFFFFFFFF);
-        if (quo!=(uint64_t)quo32) 
-        {
-                divexcp();
-                return 1;
-        }
-        EDX=rem;
-        EAX=quo32;
-        return 0;
-}
-int idivl(int32_t val)
-{
-        if (val==0) 
-        {       
-                divexcp();
-                return 1;
-        }
-        int64_t num=(((uint64_t)EDX)<<32)|EAX;
-        int64_t quo=num/val;
-        int32_t rem=num%val;
-        int32_t quo32=(int32_t)(quo&0xFFFFFFFF);
-        if (quo!=(int64_t)quo32) 
-        {
-                divexcp();
-                return 1;
-        }
-        EDX=rem;
-        EAX=quo32;
-        return 0;
-}
-
-
-void cpu_386_flags_extract()
-{
-        flags_extract();
-}
-void cpu_386_flags_rebuild()
-{
-        flags_rebuild();
-}
-
-extern int oldi;
-
-extern uint32_t testr[9];
-int dontprint=0;
-
 #define OP_TABLE(name) ops_ ## name
 #define CLOCK_CYCLES(c) cycles -= (c)
 #define CLOCK_CYCLES_ALWAYS(c) cycles -= (c)
@@ -506,7 +235,7 @@ int dontprint=0;
 #include "386_ops.h"
 
 
-#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG))
+#define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG))
 //#define CACHE_ON() 0
 
 static int cycles_main = 0;
@@ -518,7 +247,7 @@ void exec386_dynarec(int cycs)
         int cycdiff;
         int oldcyc;
         int cyc_period = cycs / 2000; /*5us*/
-//output = 3;
+
         cycles_main += cycs;
         while (cycles_main > 0)
         {
@@ -527,424 +256,389 @@ void exec386_dynarec(int cycs)
                 cycles += cyc_period;
                 cycles_start = cycles;
 
-                timer_start_period(cycles << TIMER_SHIFT);
-//        output=3;
-        while (cycles>0)
-        {
-                oldcs = CS;
-                cpu_state.oldpc = cpu_state.pc;
-                oldcpl = CPL;
-                cpu_state.op32 = use32;
-
-
-                cycdiff=0;
-                oldcyc=cycles;
-//                if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x\n", CS, pc, SS,ESP);
-                if (!CACHE_ON()) /*Interpret block*/
+                while (cycles>0)
                 {
-                        cpu_block_end = 0;
-                        x86_was_reset = 0;
-//                        if (output) pclog("Interpret block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  %04x\n", CS, pc, AX, BX, CX, DX, SI, DI, SP);
-                        while (!cpu_block_end)
+                        oldcyc=cycles;
+//                        if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x\n", CS, pc, SS,ESP);
+                        if (!CACHE_ON()) /*Interpret block*/
                         {
-                                oldcs=CS;
-                                cpu_state.oldpc = cpu_state.pc;
-                                oldcpl=CPL;
-                                cpu_state.op32 = use32;
+                                cpu_block_end = 0;
+                                x86_was_reset = 0;
+//                                if (output) pclog("Interpret block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  %04x\n", CS, pc, AX, BX, CX, DX, SI, DI, SP);
+                                while (!cpu_block_end)
+                                {
+                                        cpu_state.oldpc = cpu_state.pc;
+                                        cpu_state.op32 = use32;
 
-                                cpu_state.ea_seg = &_ds;
-                                cpu_state.ssegs = 0;
+                                        cpu_state.ea_seg = &cpu_state.seg_ds;
+                                        cpu_state.ssegs = 0;
                 
-                                fetchdat = fastreadl(cs + cpu_state.pc);
-//                                if (!fetchdat)
-//                                        fatal("Dead with cache off\n");
-                                if (!cpu_state.abrt)
-                                {               
-                                        trap = flags & T_FLAG;
-                                        opcode = fetchdat & 0xFF;
-                                        fetchdat >>= 8;
+                                        fetchdat = fastreadl(cs + cpu_state.pc);
 
-//                                        if (output == 3)
-//                                                pclog("int %04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X %f  %02X%02X %02X%02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0x8f13f], ram[0x8f13e], ram[0x8f141], ram[0x8f140]);
+                                        if (!cpu_state.abrt)
+                                        {
+                                                uint8_t opcode = fetchdat & 0xFF;
+                                                fetchdat >>= 8;
+                                                trap = cpu_state.flags & T_FLAG;
 
-                                        cpu_state.pc++;
-                                        x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
-                                }
+//                                                if (output == 3)
+//                                                        pclog("int %04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X %f  %02X%02X %02X%02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0x8f13f], ram[0x8f13e], ram[0x8f141], ram[0x8f140]);
 
-                                if (!use32) cpu_state.pc &= 0xffff;
+                                                cpu_state.pc++;
+                                                x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
+                                        }
 
-                                if (((cs + cpu_state.pc) >> 12) != pccache)
-                                        CPU_BLOCK_END();
+                                        if (((cs + cpu_state.pc) >> 12) != pccache)
+                                                CPU_BLOCK_END();
 
-/*                                if (ssegs)
-                                {
-                                        ds=oldds;
-                                        ss=oldss;
-                                        ssegs=0;
-                                }*/
-                                if (cpu_state.abrt)
-                                        CPU_BLOCK_END();
-                                if (trap)
-                                        CPU_BLOCK_END();
-                                if (nmi && nmi_enable && nmi_mask)
-                                        CPU_BLOCK_END();
+                                        if (cpu_state.abrt)
+                                                CPU_BLOCK_END();
+                                        if (trap)
+                                                CPU_BLOCK_END();
+                                        if (nmi && nmi_enable && nmi_mask)
+                                                CPU_BLOCK_END();
                                         
-                                ins++;
-                                insc++;
-                                
-/*                                if ((cs + pc) == 4)
-                                        fatal("4\n");*/
-/*                                if (ins >= 141400000)
-                                        output = 3;*/
+                                        ins++;
+                                        insc++;
+                                }
                         }
-                }
-                else
-                {
-                uint32_t phys_addr = get_phys(cs+cpu_state.pc);
-                int hash = HASH(phys_addr);
-                codeblock_t *block = codeblock_hash[hash];
-                int valid_block = 0;
-                trap = 0;
-
-                if (block && !cpu_state.abrt)
-                {
-                        page_t *page = &pages[phys_addr >> 12];
-
-                        /*Block must match current CS, PC, code segment size,
-                          and physical address. The physical address check will
-                          also catch any page faults at this stage*/
-                        valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) &&
-                                      (block->phys == phys_addr) && !((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) &&
-                                      ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK));
-                        if (!valid_block)
+                        else
                         {
-                                uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
-                                
-                                if (page->code_present_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] & mask)
+                                uint32_t phys_addr = get_phys(cs+cpu_state.pc);
+                                int hash = HASH(phys_addr);
+                                codeblock_t *block = &codeblock[codeblock_hash[hash]];
+                                int valid_block = 0;
+
+                                if (!cpu_state.abrt)
                                 {
-                                        /*Walk page tree to see if we find the correct block*/
-                                        codeblock_t *new_block = codeblock_tree_find(phys_addr, cs);
-                                        if (new_block)
+                                        page_t *page = &pages[phys_addr >> 12];
+
+                                        /*Block must match current CS, PC, code segment size,
+                                          and physical address. The physical address check will
+                                          also catch any page faults at this stage*/
+                                        valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) &&
+                                                      (block->phys == phys_addr) && !((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) &&
+                                                      ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK));
+                                        if (!valid_block)
+                                        {
+                                                uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+                                                int byte_offset = (phys_addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
+                                                uint64_t byte_mask = 1ull << (PAGE_BYTE_MASK_MASK & 0x3f);
+
+                                                if ((page->code_present_mask & mask) || (page->byte_code_present_mask[byte_offset] & byte_mask))
+                                                {
+                                                        /*Walk page tree to see if we find the correct block*/
+                                                        codeblock_t *new_block = codeblock_tree_find(phys_addr, cs);
+                                                        if (new_block)
+                                                        {
+                                                                valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) &&
+                                                                                (new_block->phys == phys_addr) && !((new_block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) &&
+                                                                                ((new_block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK));
+                                                                if (valid_block)
+                                                                {
+                                                                        block = new_block;
+                                                                        codeblock_hash[hash] = get_block_nr(block);
+                                                                }
+                                                        }
+                                                }
+                                        }
+
+                                        if (valid_block && (block->page_mask & *block->dirty_mask))
+                                        {
+                                                codegen_check_flush(page, page->dirty_mask, phys_addr);
+                                                if (block->pc == BLOCK_PC_INVALID)
+                                                        valid_block = 0;
+                                                else if (block->flags & CODEBLOCK_IN_DIRTY_LIST)
+                                                        block->flags &= ~CODEBLOCK_WAS_RECOMPILED;
+                                        }
+                                        if (valid_block && block->page_mask2)
+                                        {
+                                                /*We don't want the second page to cause a page
+                                                  fault at this stage - that would break any
+                                                  code crossing a page boundary where the first
+                                                  page is present but the second isn't. Instead
+                                                  allow the first page to be interpreted and for
+                                                  the page fault to occur when the page boundary
+                                                  is actually crossed.*/
+                                                uint32_t phys_addr_2 = get_phys_noabrt(block->pc + ((block->flags & CODEBLOCK_BYTE_MASK) ? 0x40 : 0x400));
+                                                page_t *page_2 = &pages[phys_addr_2 >> 12];
+                                                if ((block->phys_2 ^ phys_addr_2) & ~0xfff)
+                                                        valid_block = 0;
+                                                else if (block->page_mask2 & *block->dirty_mask2)
+                                                {
+                                                        codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2);
+                                                        if (block->pc == BLOCK_PC_INVALID)
+                                                                valid_block = 0;
+                                                        else if (block->flags & CODEBLOCK_IN_DIRTY_LIST)
+                                                                block->flags &= ~CODEBLOCK_WAS_RECOMPILED;
+                                                }
+                                        }
+                                        if (valid_block && (block->flags & CODEBLOCK_IN_DIRTY_LIST))
                                         {
-                                                valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) &&
-                                                                (new_block->phys == phys_addr) && !((new_block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) &&
-                                                                ((new_block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK));
-                                                if (valid_block)
-                                                        block = new_block;
+                                                block->flags &= ~CODEBLOCK_WAS_RECOMPILED;
+                                                if (block->flags & CODEBLOCK_BYTE_MASK)
+                                                        block->flags |= CODEBLOCK_NO_IMMEDIATES;
+                                                else
+                                                        block->flags |= CODEBLOCK_BYTE_MASK;
+                                        }
+                                        if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED) && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != (cpu_state.TOP & 7))
+                                        {
+                                                /*FPU top-of-stack does not match the value this block was compiled
+                                                  with, re-compile using dynamic top-of-stack*/
+                                                block->flags &= ~(CODEBLOCK_STATIC_TOP | CODEBLOCK_WAS_RECOMPILED);
                                         }
                                 }
-                        }
 
-                        if (valid_block && (block->page_mask & *block->dirty_mask))
-                        {
-                                codegen_check_flush(page, page->dirty_mask[(phys_addr >> 10) & 3], phys_addr);
-                                page->dirty_mask[(phys_addr >> 10) & 3] = 0;
-                                if (block->pc == BLOCK_PC_INVALID)
-                                        valid_block = 0;
-                        }
-                        if (valid_block && block->page_mask2)
-                        {
-                                /*We don't want the second page to cause a page
-                                  fault at this stage - that would break any
-                                  code crossing a page boundary where the first
-                                  page is present but the second isn't. Instead
-                                  allow the first page to be interpreted and for
-                                  the page fault to occur when the page boundary
-                                  is actually crossed.*/
-                                uint32_t phys_addr_2 = get_phys_noabrt(block->endpc);
-                                page_t *page_2 = &pages[phys_addr_2 >> 12];
-                                if ((block->phys_2 ^ phys_addr_2) & ~0xfff)
-                                        valid_block = 0;
-                                else if (block->page_mask2 & *block->dirty_mask2)
+                                if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED))
                                 {
-                                        codegen_check_flush(page_2, page_2->dirty_mask[(phys_addr_2 >> 10) & 3], phys_addr_2);
-                                        page_2->dirty_mask[(phys_addr_2 >> 10) & 3] = 0;
-                                        if (block->pc == BLOCK_PC_INVALID)
-                                                valid_block = 0;
-                                }
-                        }
-                        if (valid_block && block->was_recompiled && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != cpu_state.TOP)
-                        {
-                                /*FPU top-of-stack does not match the value this block was compiled
-                                  with, re-compile using dynamic top-of-stack*/
-                                block->flags &= ~CODEBLOCK_STATIC_TOP;
-                                block->was_recompiled = 0;
-                        }
-                }
+                                        void (*code)() = (void *)&block->data[BLOCK_START];
 
-                if (valid_block && block->was_recompiled)
-                {
-                        void (*code)() = (void(*)(void))&block->data[BLOCK_START];
-
-                        codeblock_hash[hash] = block;
-//                        if (output) pclog("Run block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  ESP=%08x %04x  %08x %08x  %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc);
-
-inrecomp=1;
-                        code();
-inrecomp=0;
-                        if (!use32) cpu_state.pc &= 0xffff;
-//                        cpu_recomp_ins += block->ins;
-                        cpu_recomp_blocks++;
-/*                        ins += codeblock_ins[index];
-                        insc += codeblock_ins[index];*/
-/*                        pclog("Exit block now %04X:%04X\n", CS, pc);*/
-                }
-                else if (valid_block && !cpu_state.abrt)
-                {
-                        uint32_t start_pc = cpu_state.pc;
-                        
-//                        pclog("Hash %08x %i\n", codeblock_hash_pc[HASH(cs + pc)], codeblock_page_dirty[(cs + pc) >> 12]);
-                        cpu_block_end = 0;
-                        x86_was_reset = 0;
+//                                        if (output) pclog("Run block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  ESP=%08x %04x  %08x %08x  %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc);
 
-                        cpu_new_blocks++;
+                                        inrecomp=1;
+                                        code();
+                                        inrecomp=0;
+
+                                        cpu_recomp_blocks++;
+                                }
+                                else if (valid_block && !cpu_state.abrt)
+                                {
+                                        uint32_t start_pc = cs+cpu_state.pc;
+                                        const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000;
+                                        
+                                        cpu_block_end = 0;
+                                        x86_was_reset = 0;
+
+                                        cpu_new_blocks++;
                         
-                        codegen_block_start_recompile(block);
-                        codegen_in_recompile = 1;
+                                        codegen_block_start_recompile(block);
+                                        codegen_in_recompile = 1;
 
-//                        if (output) pclog("Recompile block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  ESP=%04x %04x  %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]);
-                        while (!cpu_block_end)
-                        {
-                                oldcs=CS;
-                                cpu_state.oldpc = cpu_state.pc;
-                                oldcpl=CPL;
-                                cpu_state.op32 = use32;
+//                                        if (output) pclog("Recompile block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  ESP=%04x %04x  %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]);
+                                        while (!cpu_block_end)
+                                        {
+                                                cpu_state.oldpc = cpu_state.pc;
+                                                cpu_state.op32 = use32;
 
-                                cpu_state.ea_seg = &_ds;
-                                cpu_state.ssegs = 0;
+                                                cpu_state.ea_seg = &cpu_state.seg_ds;
+                                                cpu_state.ssegs = 0;
                 
-                                fetchdat = fastreadl(cs + cpu_state.pc);
-//                                if (fetchdat == 0xffffffff)
-//                                        fatal("Dead ffffffff\n");
-//                                if (!fetchdat)
-//                                        fatal("Dead\n");
-                                if (!cpu_state.abrt)
-                                {               
-                                        trap = flags & T_FLAG;
-                                        opcode = fetchdat & 0xFF;
-                                        fetchdat >>= 8;
+                                                fetchdat = fastreadl(cs + cpu_state.pc);
+
+                                                if (!cpu_state.abrt)
+                                                {
+                                                        uint8_t opcode = fetchdat & 0xFF;
+                                                        fetchdat >>= 8;
+                                                        
+                                                        trap = cpu_state.flags & T_FLAG;
 
-//                                        if (output == 3)
-//                                                pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X  %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache);
+//                                                        if (output == 3)
+//                                                                pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X  %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache);
 
-                                        cpu_state.pc++;
+                                                        cpu_state.pc++;
                                                 
-                                        codegen_generate_call(opcode, x86_opcodes[(opcode | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1);
+                                                        codegen_generate_call(opcode, x86_opcodes[(opcode | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1);
 
-                                        x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
+                                                        x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
 
-                                        if (x86_was_reset)
-                                                break;
-                                }
+                                                        if (x86_was_reset)
+                                                                break;
+                                                }
 
-                                if (!use32) cpu_state.pc &= 0xffff;
-
-                                /*Cap source code at 4000 bytes per block; this
-                                  will prevent any block from spanning more than
-                                  2 pages. In practice this limit will never be
-                                  hit, as host block size is only 2kB*/
-                                if ((cpu_state.pc - start_pc) > 1000)
-                                        CPU_BLOCK_END();
+                                                /*Cap source code at 4000 bytes per block; this
+                                                  will prevent any block from spanning more than
+                                                  2 pages. In practice this limit will never be
+                                                  hit, as host block size is only 2kB*/
+                                                if (((cs+cpu_state.pc) - start_pc) >= max_block_size)
+                                                        CPU_BLOCK_END();
                                         
-                                if (trap)
-                                        CPU_BLOCK_END();
+                                                if (trap)
+                                                        CPU_BLOCK_END();
 
-                                if (nmi && nmi_enable && nmi_mask)
-                                        CPU_BLOCK_END();
+                                                if (nmi && nmi_enable && nmi_mask)
+                                                        CPU_BLOCK_END();
 
-                                if (cpu_state.abrt)
-                                {
-                                        codegen_block_remove();
-                                        CPU_BLOCK_END();
-                                }
+                                                if (cpu_state.abrt)
+                                                {
+                                                        codegen_block_remove();
+                                                        CPU_BLOCK_END();
+                                                }
 
-                                ins++;
-                                insc++;
-                        }
+                                                ins++;
+                                                insc++;
+                                        }
                         
-                        if (!cpu_state.abrt && !x86_was_reset)
-                                codegen_block_end_recompile(block);
+                                        if (!cpu_state.abrt && !x86_was_reset)
+                                                codegen_block_end_recompile(block);
                         
-                        if (x86_was_reset)
-                                codegen_reset();
+                                        if (x86_was_reset)
+                                                codegen_reset();
 
-                        codegen_in_recompile = 0;
-//                        output &= ~2;
-                }
-                else if (!cpu_state.abrt)
-                {
-                        /*Mark block but do not recompile*/
-                        uint32_t start_pc = cpu_state.pc;
+                                        codegen_in_recompile = 0;
+                                }
+                                else if (!cpu_state.abrt)
+                                {
+                                        /*Mark block but do not recompile*/
+                                        uint32_t start_pc = cs+cpu_state.pc;
+                                        const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000;
 
-//                        pclog("Hash %08x %i\n", codeblock_hash_pc[HASH(cs + pc)], codeblock_page_dirty[(cs + pc) >> 12]);
-                        cpu_block_end = 0;
-                        x86_was_reset = 0;
+                                        cpu_block_end = 0;
+                                        x86_was_reset = 0;
 
-//                        cpu_new_blocks++;
-                        
-                        codegen_block_init(phys_addr);
+                                        codegen_block_init(phys_addr);
 
-//                        if (output) pclog("Recompile block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  ESP=%04x %04x  %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]);
-                        while (!cpu_block_end)
-                        {
-                                oldcs=CS;
-                                cpu_state.oldpc = cpu_state.pc;
-                                oldcpl=CPL;
-                                cpu_state.op32 = use32;
+//                                        if (output) pclog("Recompile block at %04x:%04x  %04x %04x %04x %04x  %04x %04x  ESP=%04x %04x  %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]);
+                                        while (!cpu_block_end)
+                                        {
+                                                cpu_state.oldpc = cpu_state.pc;
+                                                cpu_state.op32 = use32;
 
-                                cpu_state.ea_seg = &_ds;
-                                cpu_state.ssegs = 0;
+                                                cpu_state.ea_seg = &cpu_state.seg_ds;
+                                                cpu_state.ssegs = 0;
                 
-                                codegen_endpc = (cs + cpu_state.pc) + 8;
-                                fetchdat = fastreadl(cs + cpu_state.pc);
-
-                                if (!cpu_state.abrt)
-                                {               
-                                        trap = flags & T_FLAG;
-                                        opcode = fetchdat & 0xFF;
-                                        fetchdat >>= 8;
+                                                codegen_endpc = (cs + cpu_state.pc) + 8;
+                                                fetchdat = fastreadl(cs + cpu_state.pc);
 
-//                                        if (output == 3)
-//                                                pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X  %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache);
+                                                if (!cpu_state.abrt)
+                                                {
+                                                        uint8_t opcode = fetchdat & 0xFF;
+                                                        fetchdat >>= 8;
 
-                                        cpu_state.pc++;
-                                                
-                                        x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
-
-                                        if (x86_was_reset)
-                                                break;
-                                }
+                                                        trap = cpu_state.flags & T_FLAG;
 
-                                if (!use32) cpu_state.pc &= 0xffff;
+//                                                        if (output == 3)
+//                                                                pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X  %08X %i %i %02X %02X %02X   %02X %02X  %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache);
 
-                                /*Cap source code at 4000 bytes per block; this
-                                  will prevent any block from spanning more than
-                                  2 pages. In practice this limit will never be
-                                  hit, as host block size is only 2kB*/
-                                if ((cpu_state.pc - start_pc) > 1000)
-                                        CPU_BLOCK_END();
+                                                        cpu_state.pc++;
+                                                
+                                                        x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
+
+                                                        if (x86_was_reset)
+                                                                break;
+                                                }
+
+                                                /*Cap source code at 4000 bytes per block; this
+                                                  will prevent any block from spanning more than
+                                                  2 pages. In practice this limit will never be
+                                                  hit, as host block size is only 2kB*/
+                                                if (((cs+cpu_state.pc) - start_pc) >= max_block_size)
+                                                        CPU_BLOCK_END();
                                         
-                                if (trap)
-                                        CPU_BLOCK_END();
+                                                if (trap)
+                                                        CPU_BLOCK_END();
 
-                                if (nmi && nmi_enable && nmi_mask)
-                                        CPU_BLOCK_END();
+                                                if (nmi && nmi_enable && nmi_mask)
+                                                        CPU_BLOCK_END();
 
-                                if (cpu_state.abrt)
-                                {
-                                        codegen_block_remove();
-                                        CPU_BLOCK_END();
-                                }
+                                                if (cpu_state.abrt)
+                                                {
+                                                        codegen_block_remove();
+                                                        CPU_BLOCK_END();
+                                                }
 
-                                ins++;
-                                insc++;
-                        }
+                                                ins++;
+                                                insc++;
+                                        }
                         
-                        if (!cpu_state.abrt && !x86_was_reset)
-                                codegen_block_end();
+                                        if (!cpu_state.abrt && !x86_was_reset)
+                                                codegen_block_end();
                         
-                        if (x86_was_reset)
-                                codegen_reset();
+                                        if (x86_was_reset)
+                                                codegen_reset();
+                                }
+                                else
+                                        cpu_state.oldpc = cpu_state.pc;
 
-//                        output &= ~2;
-                }
-//                        if (output && (SP & 1))
-//                                fatal("odd SP\n");
-                }
+                        }
 
-                cycdiff=oldcyc-cycles;
-                tsc += cycdiff;
-                
-//                timer_end_period(cycles);
+                        cycdiff=oldcyc-cycles;
+                        tsc += cycdiff;
                 
-                if (cpu_state.abrt)
-                {
-                        flags_rebuild();
-                        tempi = cpu_state.abrt;
-                        cpu_state.abrt = 0;
-                        x86_doabrt(tempi);
                         if (cpu_state.abrt)
                         {
+                                flags_rebuild();
+                                tempi = cpu_state.abrt;
                                 cpu_state.abrt = 0;
-                                CS = oldcs;
-                                cpu_state.pc = cpu_state.oldpc;
-                                pclog("Double fault %i\n", ins);
-                                pmodeint(8, 0);
+                                x86_doabrt(tempi);
                                 if (cpu_state.abrt)
                                 {
                                         cpu_state.abrt = 0;
-                                        softresetx86();
-                                        cpu_set_edx();
-                                        pclog("Triple fault - reset\n");
+                                        cpu_state.pc = cpu_state.oldpc;
+                                        pclog("Double fault %i\n", ins);
+                                        pmodeint(8, 0);
+                                        if (cpu_state.abrt)
+                                        {
+                                                cpu_state.abrt = 0;
+                                                softresetx86();
+                                                cpu_set_edx();
+                                                pclog("Triple fault - reset\n");
+                                        }
                                 }
                         }
-                }
                 
-                if (trap)
-                {
-
-                        flags_rebuild();
-//                        oldpc=pc;
-//                        oldcs=CS;
-                        if (msw&1)
-                        {
-                                pmodeint(1,0);
-                        }
-                        else
+                        if (trap)
                         {
-                                writememw(ss,(SP-2)&0xFFFF,flags);
-                                writememw(ss,(SP-4)&0xFFFF,CS);
-                                writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
-                                SP-=6;
-                                addr = (1 << 2) + idt.base;
-                                flags&=~I_FLAG;
-                                flags&=~T_FLAG;
-                                cpu_state.pc=readmemw(0,addr);
-                                loadcs(readmemw(0,addr+2));
-                        }
-                }
-                else if (nmi && nmi_enable && nmi_mask)
-                {
-                        cpu_state.oldpc = cpu_state.pc;
-                        oldcs = CS;
-//                        pclog("NMI\n");
-                        x86_int(2);
-                        nmi_enable = 0;
-                        if (nmi_auto_clear)
-                        {
-                                nmi_auto_clear = 0;
-                                nmi = 0;
-                        }
-                }
-                else if ((flags&I_FLAG) && pic_intpending)
-                {
-                        temp=picinterrupt();
-                        if (temp!=0xFF)
-                        {
-//                                pclog("IRQ %02X %04X:%04X %04X:%04X\n", temp, SS, SP, CS, pc);
-                                CPU_BLOCK_END();
+                                trap = 0;
                                 flags_rebuild();
                                 if (msw&1)
                                 {
-                                        pmodeint(temp,0);
+                                        pmodeint(1,0);
                                 }
                                 else
                                 {
-                                        writememw(ss,(SP-2)&0xFFFF,flags);
+                                        writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
                                         writememw(ss,(SP-4)&0xFFFF,CS);
                                         writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
                                         SP-=6;
-                                        addr=temp<<2;
-                                        flags&=~I_FLAG;
-                                        flags&=~T_FLAG;
-                                        oxpc=cpu_state.pc;
+                                        addr = (1 << 2) + idt.base;
+                                        cpu_state.flags &= ~I_FLAG;
+                                        cpu_state.flags &= ~T_FLAG;
                                         cpu_state.pc=readmemw(0,addr);
                                         loadcs(readmemw(0,addr+2));
                                 }
                         }
+                        else if (nmi && nmi_enable && nmi_mask)
+                        {
+                                cpu_state.oldpc = cpu_state.pc;
+//                                pclog("NMI\n");
+                                x86_int(2);
+                                nmi_enable = 0;
+                                if (nmi_auto_clear)
+                                {
+                                        nmi_auto_clear = 0;
+                                        nmi = 0;
+                                }
+                        }
+                        else if ((cpu_state.flags & I_FLAG) && pic_intpending)
+                        {
+                                temp=picinterrupt();
+                                if (temp!=0xFF)
+                                {
+//                                        pclog("IRQ %02X %04X:%04X %04X:%04X\n", temp, SS, SP, CS, pc);
+                                        CPU_BLOCK_END();
+                                        flags_rebuild();
+                                        if (msw&1)
+                                        {
+                                                pmodeint(temp,0);
+                                        }
+                                        else
+                                        {
+                                                writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
+                                                writememw(ss,(SP-4)&0xFFFF,CS);
+                                                writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
+                                                SP-=6;
+                                                addr=temp<<2;
+                                                cpu_state.flags &= ~I_FLAG;
+                                                cpu_state.flags &= ~T_FLAG;
+                                                cpu_state.pc=readmemw(0,addr);
+                                                loadcs(readmemw(0,addr+2));
+                                        }
+                                }
+                        }
                 }
-        }
-                timer_end_period(cycles << TIMER_SHIFT);
+        
+               if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc))
+                       timer_process();
                 cycles_main -= (cycles_start - cycles);
         }
 }
diff --git a/pcem/386_dynarec_ops.cpp b/pcem/386_dynarec_ops.cpp
new file mode 100644 (file)
index 0000000..e1bbfe1
--- /dev/null
@@ -0,0 +1,58 @@
+#include "ibm.h"
+#include "cpu.h"
+#include "x86.h"
+#include "x86_ops.h"
+#include "x87.h"
+#include "x86_flags.h"
+#include "mem.h"
+#include "nmi.h"
+#include "pic.h"
+#include "codegen.h"
+
+#define CPU_BLOCK_END() cpu_block_end = 1
+
+#include "386_common.h"
+
+
+static inline void fetch_ea_32_long(uint32_t rmdat)
+{
+        eal_r = eal_w = NULL;
+        easeg = cpu_state.ea_seg->base;
+        if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
+        {
+                uint32_t addr = easeg + cpu_state.eaaddr;
+                if ( readlookup2[addr >> 12] != -1)
+                   eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr);
+                if (writelookup2[addr >> 12] != -1)
+                   eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr);
+        }
+}
+
+static inline void fetch_ea_16_long(uint32_t rmdat)
+{
+        eal_r = eal_w = NULL;
+        easeg = cpu_state.ea_seg->base;
+        if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
+        {
+                uint32_t addr = easeg + cpu_state.eaaddr;
+                if ( readlookup2[addr >> 12] != -1)
+                   eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr);
+                if (writelookup2[addr >> 12] != -1)
+                   eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr);
+        }
+}
+
+#define fetch_ea_16(rmdat)              cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat);
+#define fetch_ea_32(rmdat)              cpu_state.pc++; if (cpu_mod != 3) fetch_ea_32_long(rmdat);
+
+
+#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, read_ls, writes, write_ls, ea32)
+#define PREFETCH_PREFIX()
+#define PREFETCH_FLUSH()
+
+#define OP_TABLE(name) dynarec_ops_ ## name
+/*Temporary*/
+#define CLOCK_CYCLES(c)
+#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c)
+
+#include "386_ops.h"
index 47407503e5be83f6638f1ec6d147b3e943998bb9..5c73ccb4159db4d34b3b3c1e6f90fec04ee07ffc 100644 (file)
@@ -104,6 +104,15 @@ static inline uint32_t POP_L_seg(uint32_t seg)
         return ret;
 }
 
+static int ILLEGAL(uint32_t fetchdat)
+{
+        cpu_state.pc = cpu_state.oldpc;
+
+//        fatal("Illegal instruction %08X\n", fetchdat);
+        x86illegal();
+        return 0;
+}
+
 #include "x86_ops_arith.h"
 #include "x86_ops_atomic.h"
 #include "x86_ops_bcd.h"
@@ -118,6 +127,7 @@ static inline uint32_t POP_L_seg(uint32_t seg)
 #include "x86_ops_jump.h"
 #include "x86_ops_misc.h"
 #include "x86_ops_mmx.h"
+#include "x86_ops_3dnow.h"
 #include "x86_ops_mmx_arith.h"
 #include "x86_ops_mmx_cmp.h"
 #include "x86_ops_mmx_logic.h"
@@ -140,15 +150,6 @@ static inline uint32_t POP_L_seg(uint32_t seg)
 #include "x86_ops_string.h"
 #include "x86_ops_xchg.h"
 
-static int ILLEGAL(uint32_t fetchdat)
-{
-        cpu_state.pc = cpu_state.oldpc;
-
-//        fatal("Illegal instruction %08X\n", fetchdat);
-        x86illegal();
-        return 0;
-}
-
 static int op0F_w_a16(uint32_t fetchdat)
 {
         int opcode = fetchdat & 0xff;
@@ -279,7 +280,7 @@ OpFn OP_TABLE(386_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a16,     op0F01_w_a16,   opLAR_w_a16,    opLSL_w_a16,    ILLEGAL,        ILLEGAL,        opCLTS,         opLOADALL386,   opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL,        opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -301,7 +302,7 @@ OpFn OP_TABLE(386_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a16,     op0F01_l_a16,   opLAR_l_a16,    opLSL_l_a16,    ILLEGAL,        ILLEGAL,        opCLTS,         opLOADALL386,   opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL,        opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -323,7 +324,7 @@ OpFn OP_TABLE(386_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a32,     op0F01_w_a32,   opLAR_w_a32,    opLSL_w_a32,    ILLEGAL,        ILLEGAL,        opCLTS,         opLOADALL386,   opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL,        opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -345,7 +346,7 @@ OpFn OP_TABLE(386_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a32,     op0F01_l_a32,   opLAR_l_a32,    opLSL_l_a32,    ILLEGAL,        ILLEGAL,        opCLTS,         opLOADALL386,   opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL,        opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -370,7 +371,7 @@ OpFn OP_TABLE(winchip_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a16,     op0F01_w_a16,   opLAR_w_a16,    opLSL_w_a16,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL,        opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -392,7 +393,7 @@ OpFn OP_TABLE(winchip_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a16,     op0F01_l_a16,   opLAR_l_a16,    opLSL_l_a16,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL,        opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -414,7 +415,7 @@ OpFn OP_TABLE(winchip_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a32,     op0F01_w_a32,   opLAR_w_a32,    opLSL_w_a32,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL,        opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -436,7 +437,98 @@ OpFn OP_TABLE(winchip_0f)[1024] =
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
 /*00*/  op0F00_a32,     op0F01_l_a32,   opLAR_l_a32,    opLSL_l_a32,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
-/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL,        opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+
+/*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*50*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*60*/  opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32,  opPCMPGTW_a32,  opPCMPGTD_a32,  opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL,        ILLEGAL,        opMOVD_l_mm_a32,opMOVQ_q_mm_a32,
+/*70*/  ILLEGAL,        opPSxxW_imm,    opPSxxD_imm,    opPSxxQ_imm,    opPCMPEQB_a32,  opPCMPEQW_a32,  opPCMPEQD_a32,  opEMMS,         ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opMOVD_mm_l_a32,opMOVQ_mm_q_a32,
+
+/*80*/  opJO_l,         opJNO_l,        opJB_l,         opJNB_l,        opJE_l,         opJNE_l,        opJBE_l,        opJNBE_l,       opJS_l,         opJNS_l,        opJP_l,         opJNP_l,        opJL_l,         opJNL_l,        opJLE_l,        opJNLE_l,
+/*90*/  opSETO_a32,     opSETNO_a32,    opSETB_a32,     opSETNB_a32,    opSETE_a32,     opSETNE_a32,    opSETBE_a32,    opSETNBE_a32,   opSETS_a32,     opSETNS_a32,    opSETP_a32,     opSETNP_a32,    opSETL_a32,     opSETNL_a32,    opSETLE_a32,    opSETNLE_a32,
+/*a0*/  opPUSH_FS_l,    opPOP_FS_l,     opCPUID,        opBT_l_r_a32,   opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL,        ILLEGAL,        opPUSH_GS_l,    opPOP_GS_l,     ILLEGAL,        opBTS_l_r_a32,  opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL,        opIMUL_l_l_a32,
+/*b0*/  opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32,    opBTR_l_r_a32,  opLFS_l_a32,    opLGS_l_a32,    opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL,        ILLEGAL,        opBA_l_a32,     opBTC_l_r_a32,  opBSF_l_a32,    opBSR_l_a32,    opMOVSX_l_b_a32,opMOVSX_l_w_a32,
+
+/*c0*/  opXADD_b_a32,   opXADD_l_a32,   ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opCMPXCHG8B_a32,opBSWAP_EAX,    opBSWAP_ECX,    opBSWAP_EDX,    opBSWAP_EBX,    opBSWAP_ESP,    opBSWAP_EBP,    opBSWAP_ESI,    opBSWAP_EDI,
+/*d0*/  ILLEGAL,        opPSRLW_a32,    opPSRLD_a32,    opPSRLQ_a32,    ILLEGAL,        opPMULLW_a32,   ILLEGAL,        ILLEGAL,        opPSUBUSB_a32,  opPSUBUSW_a32,  NULL,           opPAND_a32,     opPADDUSB_a32,  opPADDUSW_a32,  NULL,           opPANDN_a32,
+/*e0*/  ILLEGAL,        opPSRAW_a32,    opPSRAD_a32,    ILLEGAL,        ILLEGAL,        opPMULHW_a32,   ILLEGAL,        ILLEGAL,        opPSUBSB_a32,   opPSUBSW_a32,   NULL,           opPOR_a32,      opPADDSB_a32,   opPADDSW_a32,   NULL,           opPXOR_a32,
+/*f0*/  ILLEGAL,        opPSLLW_a32,    opPSLLD_a32,    opPSLLQ_a32,    ILLEGAL,        opPMADDWD_a32,  ILLEGAL,        ILLEGAL,        opPSUBB_a32,    opPSUBW_a32,    opPSUBD_a32,    ILLEGAL,        opPADDB_a32,    opPADDW_a32,    opPADDD_a32,    ILLEGAL,
+};
+
+OpFn OP_TABLE(winchip2_0f)[1024] =
+{
+        /*16-bit data, 16-bit addr*/
+/*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/
+/*00*/  op0F00_a16,     op0F01_w_a16,   opLAR_w_a16,    opLSL_w_a16,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        opPREFETCH_a16, opFEMMS,        op3DNOW_a16,
+/*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL,        opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+
+/*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*50*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*60*/  opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16,  opPCMPGTW_a16,  opPCMPGTD_a16,  opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL,        ILLEGAL,        opMOVD_l_mm_a16,opMOVQ_q_mm_a16,
+/*70*/  ILLEGAL,        opPSxxW_imm,    opPSxxD_imm,    opPSxxQ_imm,    opPCMPEQB_a16,  opPCMPEQW_a16,  opPCMPEQD_a16,  opEMMS,         ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opMOVD_mm_l_a16,opMOVQ_mm_q_a16,
+
+/*80*/  opJO_w,         opJNO_w,        opJB_w,         opJNB_w,        opJE_w,         opJNE_w,        opJBE_w,        opJNBE_w,       opJS_w,         opJNS_w,        opJP_w,         opJNP_w,        opJL_w,         opJNL_w,        opJLE_w,        opJNLE_w,
+/*90*/  opSETO_a16,     opSETNO_a16,    opSETB_a16,     opSETNB_a16,    opSETE_a16,     opSETNE_a16,    opSETBE_a16,    opSETNBE_a16,   opSETS_a16,     opSETNS_a16,    opSETP_a16,     opSETNP_a16,    opSETL_a16,     opSETNL_a16,    opSETLE_a16,    opSETNLE_a16,
+/*a0*/  opPUSH_FS_w,    opPOP_FS_w,     opCPUID,        opBT_w_r_a16,   opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL,        ILLEGAL,        opPUSH_GS_w,    opPOP_GS_w,     ILLEGAL,        opBTS_w_r_a16,  opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL,        opIMUL_w_w_a16,
+/*b0*/  opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16,    opBTR_w_r_a16,  opLFS_w_a16,    opLGS_w_a16,    opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL,        ILLEGAL,        opBA_w_a16,     opBTC_w_r_a16,  opBSF_w_a16,    opBSR_w_a16,    opMOVSX_w_b_a16,ILLEGAL,
+
+/*c0*/  opXADD_b_a16,   opXADD_w_a16,   ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opCMPXCHG8B_a16,opBSWAP_EAX,    opBSWAP_ECX,    opBSWAP_EDX,    opBSWAP_EBX,    opBSWAP_ESP,    opBSWAP_EBP,    opBSWAP_ESI,    opBSWAP_EDI,
+/*d0*/  ILLEGAL,        opPSRLW_a16,    opPSRLD_a16,    opPSRLQ_a16,    ILLEGAL,        opPMULLW_a16,   ILLEGAL,        ILLEGAL,        opPSUBUSB_a16,  opPSUBUSW_a16,  NULL,           opPAND_a16,     opPADDUSB_a16,  opPADDUSW_a16,  NULL,           opPANDN_a16,
+/*e0*/  ILLEGAL,        opPSRAW_a16,    opPSRAD_a16,    ILLEGAL,        ILLEGAL,        opPMULHW_a16,   ILLEGAL,        ILLEGAL,        opPSUBSB_a16,   opPSUBSW_a16,   NULL,           opPOR_a16,      opPADDSB_a16,   opPADDSW_a16,   NULL,           opPXOR_a16,
+/*f0*/  ILLEGAL,        opPSLLW_a16,    opPSLLD_a16,    opPSLLQ_a16,    ILLEGAL,        opPMADDWD_a16,  ILLEGAL,        ILLEGAL,        opPSUBB_a16,    opPSUBW_a16,    opPSUBD_a16,    ILLEGAL,        opPADDB_a16,    opPADDW_a16,    opPADDD_a16,    ILLEGAL,
+
+        /*32-bit data, 16-bit addr*/
+/*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/
+/*00*/  op0F00_a16,     op0F01_l_a16,   opLAR_l_a16,    opLSL_l_a16,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        opPREFETCH_a16, opFEMMS,        op3DNOW_a16,
+/*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL,        opMOV_TRx_r_a16,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+
+/*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*50*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*60*/  opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16,  opPCMPGTW_a16,  opPCMPGTD_a16,  opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL,        ILLEGAL,        opMOVD_l_mm_a16,opMOVQ_q_mm_a16,
+/*70*/  ILLEGAL,        opPSxxW_imm,    opPSxxD_imm,    opPSxxQ_imm,    opPCMPEQB_a16,  opPCMPEQW_a16,  opPCMPEQD_a16,  opEMMS,         ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opMOVD_mm_l_a16,opMOVQ_mm_q_a16,
+
+/*80*/  opJO_l,         opJNO_l,        opJB_l,         opJNB_l,        opJE_l,         opJNE_l,        opJBE_l,        opJNBE_l,       opJS_l,         opJNS_l,        opJP_l,         opJNP_l,        opJL_l,         opJNL_l,        opJLE_l,        opJNLE_l,
+/*90*/  opSETO_a16,     opSETNO_a16,    opSETB_a16,     opSETNB_a16,    opSETE_a16,     opSETNE_a16,    opSETBE_a16,    opSETNBE_a16,   opSETS_a16,     opSETNS_a16,    opSETP_a16,     opSETNP_a16,    opSETL_a16,     opSETNL_a16,    opSETLE_a16,    opSETNLE_a16,
+/*a0*/  opPUSH_FS_l,    opPOP_FS_l,     opCPUID,        opBT_l_r_a16,   opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL,        ILLEGAL,        opPUSH_GS_l,    opPOP_GS_l,     ILLEGAL,        opBTS_l_r_a16,  opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL,        opIMUL_l_l_a16,
+/*b0*/  opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16,    opBTR_l_r_a16,  opLFS_l_a16,    opLGS_l_a16,    opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL,        ILLEGAL,        opBA_l_a16,     opBTC_l_r_a16,  opBSF_l_a16,    opBSR_l_a16,    opMOVSX_l_b_a16,opMOVSX_l_w_a16,
+
+/*c0*/  opXADD_b_a16,   opXADD_l_a16,   ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opCMPXCHG8B_a16,opBSWAP_EAX,    opBSWAP_ECX,    opBSWAP_EDX,    opBSWAP_EBX,    opBSWAP_ESP,    opBSWAP_EBP,    opBSWAP_ESI,    opBSWAP_EDI,
+/*d0*/  ILLEGAL,        opPSRLW_a16,    opPSRLD_a16,    opPSRLQ_a16,    ILLEGAL,        opPMULLW_a16,   ILLEGAL,        ILLEGAL,        opPSUBUSB_a16,  opPSUBUSW_a16,  NULL,           opPAND_a16,     opPADDUSB_a16,  opPADDUSW_a16,  NULL,           opPANDN_a16,
+/*e0*/  ILLEGAL,        opPSRAW_a16,    opPSRAD_a16,    ILLEGAL,        ILLEGAL,        opPMULHW_a16,   ILLEGAL,        ILLEGAL,        opPSUBSB_a16,   opPSUBSW_a16,   NULL,           opPOR_a16,      opPADDSB_a16,   opPADDSW_a16,   NULL,           opPXOR_a16,
+/*f0*/  ILLEGAL,        opPSLLW_a16,    opPSLLD_a16,    opPSLLQ_a16,    ILLEGAL,        opPMADDWD_a16,  ILLEGAL,        ILLEGAL,        opPSUBB_a16,    opPSUBW_a16,    opPSUBD_a16,    ILLEGAL,        opPADDB_a16,    opPADDW_a16,    opPADDD_a16,    ILLEGAL,
+
+        /*16-bit data, 32-bit addr*/
+/*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/
+/*00*/  op0F00_a32,     op0F01_w_a32,   opLAR_w_a32,    opLSL_w_a32,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        opPREFETCH_a32, opFEMMS,        op3DNOW_a32,
+/*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL,        opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+
+/*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*50*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*60*/  opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32,  opPCMPGTW_a32,  opPCMPGTD_a32,  opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL,        ILLEGAL,        opMOVD_l_mm_a32,opMOVQ_q_mm_a32,
+/*70*/  ILLEGAL,        opPSxxW_imm,    opPSxxD_imm,    opPSxxQ_imm,    opPCMPEQB_a32,  opPCMPEQW_a32,  opPCMPEQD_a32,  opEMMS,         ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opMOVD_mm_l_a32,opMOVQ_mm_q_a32,
+
+/*80*/  opJO_w,         opJNO_w,        opJB_w,         opJNB_w,        opJE_w,         opJNE_w,        opJBE_w,        opJNBE_w,       opJS_w,         opJNS_w,        opJP_w,         opJNP_w,        opJL_w,         opJNL_w,        opJLE_w,        opJNLE_w,
+/*90*/  opSETO_a32,     opSETNO_a32,    opSETB_a32,     opSETNB_a32,    opSETE_a32,     opSETNE_a32,    opSETBE_a32,    opSETNBE_a32,   opSETS_a32,     opSETNS_a32,    opSETP_a32,     opSETNP_a32,    opSETL_a32,     opSETNL_a32,    opSETLE_a32,    opSETNLE_a32,
+/*a0*/  opPUSH_FS_w,    opPOP_FS_w,     opCPUID,        opBT_w_r_a32,   opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL,        ILLEGAL,        opPUSH_GS_w,    opPOP_GS_w,     ILLEGAL,        opBTS_w_r_a32,  opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL,        opIMUL_w_w_a32,
+/*b0*/  opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32,    opBTR_w_r_a32,  opLFS_w_a32,    opLGS_w_a32,    opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL,        ILLEGAL,        opBA_w_a32,     opBTC_w_r_a32,  opBSF_w_a32,    opBSR_w_a32,    opMOVSX_w_b_a32,ILLEGAL,
+
+/*c0*/  opXADD_b_a32,   opXADD_w_a32,   ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opCMPXCHG8B_a32,opBSWAP_EAX,    opBSWAP_ECX,    opBSWAP_EDX,    opBSWAP_EBX,    opBSWAP_ESP,    opBSWAP_EBP,    opBSWAP_ESI,    opBSWAP_EDI,
+/*d0*/  ILLEGAL,        opPSRLW_a32,    opPSRLD_a32,    opPSRLQ_a32,    ILLEGAL,        opPMULLW_a32,   ILLEGAL,        ILLEGAL,        opPSUBUSB_a32,  opPSUBUSW_a32,  NULL,           opPAND_a32,     opPADDUSB_a32,  opPADDUSW_a32,  NULL,           opPANDN_a32,
+/*e0*/  ILLEGAL,        opPSRAW_a32,    opPSRAD_a32,    ILLEGAL,        ILLEGAL,        opPMULHW_a32,   ILLEGAL,        ILLEGAL,        opPSUBSB_a32,   opPSUBSW_a32,   NULL,           opPOR_a32,      opPADDSB_a32,   opPADDSW_a32,   NULL,           opPXOR_a32,
+/*f0*/  ILLEGAL,        opPSLLW_a32,    opPSLLD_a32,    opPSLLQ_a32,    ILLEGAL,        opPMADDWD_a32,  ILLEGAL,        ILLEGAL,        opPSUBB_a32,    opPSUBW_a32,    opPSUBD_a32,    ILLEGAL,        opPADDB_a32,    opPADDW_a32,    opPADDD_a32,    ILLEGAL,
+
+        /*32-bit data, 32-bit addr*/
+/*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/
+/*00*/  op0F00_a32,     op0F01_l_a32,   opLAR_l_a32,    opLSL_l_a32,    ILLEGAL,        ILLEGAL,        opCLTS,         ILLEGAL,        opINVD,         opWBINVD,       ILLEGAL,        ILLEGAL,        ILLEGAL,        opPREFETCH_a32, opFEMMS,        op3DNOW_a32,
+/*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*20*/  opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL,        opMOV_TRx_r_a32,ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 /*30*/  opWRMSR,        opRDTSC,        opRDMSR,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
 
 /*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
@@ -455,7 +547,7 @@ OpFn OP_TABLE(winchip_0f)[1024] =
 /*f0*/  ILLEGAL,        opPSLLW_a32,    opPSLLD_a32,    opPSLLQ_a32,    ILLEGAL,        opPMADDWD_a32,  ILLEGAL,        ILLEGAL,        opPSUBB_a32,    opPSUBW_a32,    opPSUBD_a32,    ILLEGAL,        opPADDB_a32,    opPADDW_a32,    opPADDD_a32,    ILLEGAL,
 };
 
-OpFn OP_TABLE(pentium_0f)[1024] = 
+OpFn OP_TABLE(pentium_0f)[1024] =
 {
         /*16-bit data, 16-bit addr*/
 /*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/        
diff --git a/pcem/8087.h b/pcem/8087.h
new file mode 100644 (file)
index 0000000..42f64d5
--- /dev/null
@@ -0,0 +1,98 @@
+/*This file is a series of macros to get the 386+ based x87 emulation working with
+  the 808x emulation*/
+#define X8087
+#define OP_TABLE(name) ops_808x_ ## name
+
+#define CLOCK_CYCLES(c) cycles -= (c)
+#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c)
+
+#define fetch_ea_16(fetchdat)
+#define fetch_ea_32(fetchdat)
+#define SEG_CHECK_READ(seg)
+#define SEG_CHECK_WRITE(seg)
+#define CHECK_WRITE(seg, addr_lo, addr_hi)
+#define PREFETCH_RUN(timing, bytes, rmdat, a, b, c, d, e)
+
+static uint32_t readmeml(uint32_t seg, uint32_t addr)
+{
+        return readmemw(seg, addr) | (readmemw(seg, addr+2) << 16);
+}
+static uint64_t readmemq(uint32_t seg, uint32_t addr)
+{
+        return (uint64_t)readmemw(seg, addr) | ((uint64_t)readmemw(seg, addr+2) << 16) |
+                        ((uint64_t)readmemw(seg, addr+4) << 32) |
+                        ((uint64_t)readmemw(seg, addr+6) << 48);
+}
+
+static void writememb_8087(uint32_t seg, uint32_t addr, uint8_t val)
+{
+        writememb(seg+addr, val);
+}
+static void writememl(uint32_t seg, uint32_t addr, uint32_t val)
+{
+        writememw(seg, addr, val & 0xffff);
+        writememw(seg, addr+2, (val >> 16) & 0xffff);
+}
+static void writememq(uint32_t seg, uint32_t addr, uint64_t val)
+{
+        writememw(seg, addr, val & 0xffff);
+        writememw(seg, addr+2, (val >> 16) & 0xffff);
+        writememw(seg, addr+4, (val >> 32) & 0xffff);
+        writememw(seg, addr+6, (val >> 48) & 0xffff);
+}
+
+static inline uint32_t geteal()
+{
+        if (cpu_mod == 3)
+                fatal("geteal cpu_mod==3\n");
+        return readmeml(easeg, cpu_state.eaaddr);
+}
+static inline uint64_t geteaq()
+{
+        if (cpu_mod == 3)
+                fatal("geteaq cpu_mod==3\n");
+        return readmemq(easeg, cpu_state.eaaddr);
+}
+static inline void seteal(uint32_t val)
+{
+        if (cpu_mod == 3)
+                fatal("seteal cpu_mod==3\n");
+        else
+                writememl(easeg, cpu_state.eaaddr, val);
+}
+static inline void seteaq(uint64_t val)
+{
+        if (cpu_mod == 3)
+                fatal("seteaq cpu_mod==3\n");
+        else
+                writememq(easeg, cpu_state.eaaddr, val);
+}
+
+#define flags_rebuild()
+
+#define CF_SET() (cpu_state.flags & C_FLAG)
+#define NF_SET() (cpu_state.flags & N_FLAG)
+#define PF_SET() (cpu_state.flags & P_FLAG)
+#define VF_SET() (cpu_state.flags & V_FLAG)
+#define ZF_SET() (cpu_state.flags & Z_FLAG)
+
+#define cond_O   ( VF_SET())
+#define cond_NO  (!VF_SET())
+#define cond_B   ( CF_SET())
+#define cond_NB  (!CF_SET())
+#define cond_E   ( ZF_SET())
+#define cond_NE  (!ZF_SET())
+#define cond_BE  ( CF_SET() ||  ZF_SET())
+#define cond_NBE (!CF_SET() && !ZF_SET())
+#define cond_S   ( NF_SET())
+#define cond_NS  (!NF_SET())
+#define cond_P   ( PF_SET())
+#define cond_NP  (!PF_SET())
+#define cond_L   (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0))
+#define cond_NL  (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0))
+#define cond_LE  (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) ||  (ZF_SET()))
+#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET()))
+
+#define writememb writememb_8087
+#include "x87_ops.h"
+#undef writememb
index 69e59bc1a54be022dbe28fb945af44a77f7e8a51..d81ee33517096bb38b14631f6150a9d4bd8e0859 100644 (file)
 #include "x87.h"
 #include "paths.h"
 
-int xt_cpu_multi;
+uint64_t xt_cpu_multi;
 int nmi = 0;
 int nmi_auto_clear = 0;
 
-int nextcyc=0;
-int cycdiff;
+int oldcpl;
+
+int tempc;
+static int noint=0;
+
+int output=0;
+int timetolive=0;
+int ins=0;
+
 int is8086=0;
 
-int memcycs;
-int nopageerrors=0;
+static uint32_t oldds;
+uint32_t oldss;
 
-void FETCHCOMPLETE();
+static int nextcyc=0;
+static int memcycs;
 
-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);
+static int cycdiff;
+static void FETCHCOMPLETE();
 
-#undef readmemb
-#undef readmemw
-uint8_t readmemb(uint32_t a)
+#define IRQTEST ((cpu_state.flags & I_FLAG) && (pic.pend&~pic.mask) && !noint)
+
+static uint8_t readmemb(uint32_t a)
 {
         if (a!=(cs+cpu_state.pc)) memcycs+=4;
         if (readlookup2[(a)>>12]==-1) return readmembl(a);
         else return *(uint8_t *)(readlookup2[(a) >> 12] + (a));
 }
 
-uint8_t readmembf(uint32_t a)
+static uint8_t readmembf(uint32_t a)
 {
         if (readlookup2[(a)>>12]==-1) return readmembl(a);
         else return *(uint8_t *)(readlookup2[(a) >> 12] + (a));
 }
 
-uint16_t readmemw(uint32_t s, uint16_t a)
+static uint16_t readmemw(uint32_t s, uint16_t a)
 {
         if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086);
-        if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) 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);
 }
 
@@ -76,48 +80,28 @@ void refreshread() { /*pclog("Refreshread\n"); */FETCHCOMPLETE(); memcycs+=4; }
                     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)
+static void writememb(uint32_t a, uint8_t v)
 {
         memcycs+=4;
         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)
+static void writememw(uint32_t s, uint32_t a, uint16_t v)
 {
         memcycs+=(8>>is8086);
-        if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) 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[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v);
-        else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v;
-}
-
 
-uint16_t oldcs;
-int oldcpl;
-
-int tempc;
-uint8_t opcode;
-uint16_t pc2,pc3;
-int noint=0;
 
-int output=0;
-
-extern int shadowbios;
-
-int ins=0;
 //#define readmemb(a) (((a)<0xA0000)?ram[a]:readmembl(a))
 
-int fetchcycles=0,fetchclocks;
+static int fetchcycles=0,fetchclocks;
+
+static uint8_t prefetchqueue[6];
+static uint16_t prefetchpc;
+static int prefetchw=0;
 
-uint8_t prefetchqueue[6];
-uint16_t prefetchpc;
-int prefetchw=0;
 static inline uint8_t FETCH()
 {
         uint8_t temp;
@@ -202,7 +186,7 @@ static inline void FETCHADD(int c)
 //        if (fetchcycles>24) fetchcycles=24;
 }
 
-void FETCHCOMPLETE()
+static void FETCHCOMPLETE()
 {
 //        pclog("Fetchcomplete %i %i %i\n",fetchcycles&3,fetchcycles,prefetchw);
         if (!(fetchcycles&3)) return;
@@ -343,9 +327,9 @@ reg = If mod=11,  (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit
 */
 
 uint32_t easeg;
-int rmdat;
+uint32_t rmdat;
 
-uint16_t zero=0;
+static uint16_t zero=0;
 uint16_t *mod1add[2][8];
 uint32_t *mod1seg[8];
 
@@ -442,7 +426,7 @@ static inline void seteaw(uint16_t val)
 
 /*Flags*/
 uint8_t znptable8[256];
-uint16_t znptable16[65536];
+static uint16_t znptable16[65536];
 
 void makeznptable()
 {
@@ -489,16 +473,11 @@ void makeznptable()
       
 //      makemod1table();
 }
-int timetolive=0;
-
-extern uint32_t oldcs2;
-extern uint32_t oldpc2;
 
 int indump = 0;
 
 void dumpregs()
 {
-#if 0
         int c,d=0,e=0;
 #ifndef RELEASE_BUILD
         FILE *f;
@@ -510,7 +489,6 @@ void dumpregs()
 //        savenvr();
 //        return;
         chdir(logs_path);
-        nopageerrors=1;
 /*        f=fopen("rram3.dmp","wb");
         for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f);
         fclose(f);*/
@@ -539,10 +517,10 @@ void dumpregs()
         fclose(f);*/
         pclog("Dumping rram4.dmp\n");
         f=fopen("rram4.dmp","wb");
-        for (c=0;c<0x0050000;c++) 
+        for (c=0;c<0x0050000;c++)
         {
                 cpu_state.abrt = 0;
-                putc(readmemb386l(0,c+0x80000000),f);
+                putc(readmembl(c+0x80000000),f);
         }
         fclose(f);
         pclog("Dumping done\n");        
@@ -581,22 +559,22 @@ void dumpregs()
            printf("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
            printf("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);
-        printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags);
-        printf("%04X:%04X %04X:%04X\n",oldcs,cpu_state.oldpc, oldcs2, oldpc2);
+        printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,cpu_state.flags);
+        printf("%04X\n",cpu_state.oldpc);
         printf("%i ins\n",ins);
         if (is386)
-           printf("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real");
+           printf("In %s mode\n",(msw&1)?((cpu_state.eflags&VM_FLAG)?"V86":"protected"):"real");
         else
            printf("In %s mode\n",(msw&1)?"protected":"real");
-        printf("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);
-        printf("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);
-        printf("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);
+        printf("CS : base=%06X limit=%08X access=%02X  limit_low=%08X limit_high=%08X\n",cs,cpu_state.seg_cs.limit,cpu_state.seg_cs.access, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high);
+        printf("DS : base=%06X limit=%08X access=%02X  limit_low=%08X limit_high=%08X\n",ds,cpu_state.seg_ds.limit,cpu_state.seg_ds.access, cpu_state.seg_ds.limit_low, cpu_state.seg_ds.limit_high);
+        printf("ES : base=%06X limit=%08X access=%02X  limit_low=%08X limit_high=%08X\n",es,cpu_state.seg_es.limit,cpu_state.seg_es.access, cpu_state.seg_es.limit_low, cpu_state.seg_es.limit_high);
         if (is386)
         {
-                printf("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);
-                printf("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);
+                printf("FS : base=%06X limit=%08X access=%02X  limit_low=%08X limit_high=%08X\n",cpu_state.seg_fs.base,cpu_state.seg_fs.limit,cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high);
+                printf("GS : base=%06X limit=%08X access=%02X  limit_low=%08X limit_high=%08X\n",gs,cpu_state.seg_gs.limit,cpu_state.seg_gs.access, cpu_state.seg_gs.limit_low, cpu_state.seg_gs.limit_high);
         }
-        printf("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);
+        printf("SS : base=%06X limit=%08X access=%02X  limit_low=%08X limit_high=%08X\n",ss,cpu_state.seg_ss.limit,cpu_state.seg_ss.access, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high);
         printf("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit);
         printf("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit);
         printf("IDT : base=%06X limit=%04X\n",idt.base,idt.limit);
@@ -615,20 +593,16 @@ void dumpregs()
         printf("Entries in readlookup : %i    writelookup : %i\n",d,e);
         x87_dumpregs();
         indump = 0;
-#endif
 }
 
-int resets = 0;
 int x86_was_reset = 0;
 void resetx86()
 {
         pclog("x86 reset\n");
-        resets++;
         ins = 0;
         use32=0;
         cpu_cur_status = 0;
         stack32=0;
-        cpu_hasCX8 = 0;
 //        i86_Reset();
 //        cs=0xFFFF0;
         msw=0;
@@ -639,7 +613,7 @@ void resetx86()
         cpu_cache_int_enabled = 0;
         cpu_update_waitstates();
         cr4 = 0;
-        eflags=0;
+        cpu_state.eflags=0;
         cgate32=0;
         if (AT)
         {
@@ -655,17 +629,15 @@ void resetx86()
         }
         idt.base = 0;
         idt.limit = is386 ? 0x03FF : 0xFFFF;
-        flags=2;
+        cpu_state.flags=2;
+        EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0;
         makeznptable();
         resetreadlookup();
         makemod1table();
         FETCHCLEAR();
         x87_reset();
         cpu_set_edx();
-        EAX = 0;
-        ESP=0;
         mmu_perm=4;
-        memset(inscounts, 0, sizeof(inscounts));
         x86seg_reset();
         codegen_reset();
         x86_was_reset = 1;
@@ -688,9 +660,8 @@ void softresetx86()
         cpu_cache_int_enabled = 0;
         cpu_update_waitstates();
         cr4 = 0;
-        eflags=0;
+        cpu_state.eflags=0;
         cgate32=0;
-        cpu_hasCX8 = 0;
         if (AT)
         {
                 loadcs(0xF000);
@@ -704,142 +675,194 @@ void softresetx86()
                 rammask = 0xfffff;
         }
         //rammask=0xFFFFFFFF;
-        flags=2;
+        cpu_state.flags=2;
         idt.base = 0;
-        idt.limit = is386 ? 0x03FF : 0xFFFF;
+        if (is386)
+        {
+                idt.limit = 0x03FF;
+                EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0;
+        }
+        else
+        {
+                idt.limit = 0xFFFF;
+        }
         x86seg_reset();
+        flushmmucache();
         x86_was_reset = 1;
+        FETCHCLEAR();
 }
 
 static void setznp8(uint8_t val)
 {
-        flags&=~0xC4;
-        flags|=znptable8[val];
+        cpu_state.flags &= ~0xC4;
+        cpu_state.flags |= znptable8[val];
 }
 
 static void setznp16(uint16_t val)
 {
-        flags&=~0xC4;
-        flags|=znptable16[val];
+        cpu_state.flags &= ~0xC4;
+        cpu_state.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;
+        uint16_t c = (uint16_t)a + (uint16_t)b;
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= znptable8[c&0xFF];
+        if (c & 0x100)
+                cpu_state.flags |= C_FLAG;
+        if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80))
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) + (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint16_t c = (uint16_t)a + (uint16_t)b;
+        cpu_state.flags &= ~0x8D4;
+        cpu_state.flags |= znptable8[c&0xFF];
+        if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80))
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) + (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint16_t c = (uint16_t)a + (uint16_t)b+tempc;
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= znptable8[c&0xFF];
+        if (c & 0x100)
+                cpu_state.flags |= C_FLAG;
+        if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80))
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) + (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint32_t c = (uint32_t)a + (uint32_t)b;
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= znptable16[c&0xFFFF];
+        if (c & 0x10000)
+                cpu_state.flags |= C_FLAG;
+        if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000))
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) + (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint32_t c = (uint32_t)a + (uint32_t)b;
+        cpu_state.flags &= ~0x8D4;
+        cpu_state.flags |= znptable16[c&0xFFFF];
+        if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000))
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) + (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint32_t c = (uint32_t)a + (uint32_t)b+tempc;
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= znptable16[c&0xFFFF];
+        if (c & 0x10000)
+                cpu_state.flags |= C_FLAG;
+        if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000))
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) + (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint16_t c = (uint16_t)a - (uint16_t)b;
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= znptable8[c&0xFF];
+        if (c & 0x100)
+                cpu_state.flags |= C_FLAG;
+        if ((a ^ b) & (a ^ c) & 0x80)
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) - (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint16_t c = (uint16_t)a - (uint16_t)b;
+        cpu_state.flags &= ~0x8D4;
+        cpu_state.flags |= znptable8[c&0xFF];
+        if ((a ^ b) & (a ^ c) & 0x80)
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) - (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint16_t c = (uint16_t)a - (((uint16_t)b) + tempc);
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= znptable8[c&0xFF];
+        if (c & 0x100)
+                cpu_state.flags |= C_FLAG;
+        if ((a ^ b) & (a ^ c) & 0x80)
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) - (b & 0xF)) & 0x10)
+                cpu_state.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 (output) printf("%04X %04X %i\n",a^b,a^c,flags&V_FLAG);
-        if (((a&0xF)-(b&0xF))&0x10)      flags|=A_FLAG;
+        uint32_t c = (uint32_t)a - (uint32_t)b;
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= znptable16[c&0xFFFF];
+        if (c & 0x10000)
+                cpu_state.flags |= C_FLAG;
+        if ((a ^ b) & (a ^ c) & 0x8000)
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) - (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint32_t c = (uint32_t)a - (uint32_t)b;
+        cpu_state.flags &= ~0x8D4;
+        cpu_state.flags |= (znptable16[c&0xFFFF]&~4);
+        cpu_state.flags |= (znptable8[c&0xFF]&4);
+        if ((a ^ b) & (a ^ c) & 0x8000)
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) - (b & 0xF)) & 0x10)
+                cpu_state.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;
+        uint32_t c = (uint32_t)a - (((uint32_t)b) + tempc);
+        cpu_state.flags &= ~0x8D5;
+        cpu_state.flags |= (znptable16[c&0xFFFF]&~4);
+        cpu_state.flags |= (znptable8[c&0xFF]&4);
+        if (c & 0x10000)
+                cpu_state.flags |= C_FLAG;
+        if ((a ^ b) & (a ^ c) & 0x8000)
+                cpu_state.flags |= V_FLAG;
+        if (((a & 0xF) - (b & 0xF)) & 0x10)
+                cpu_state.flags |= A_FLAG;
 }
 
 int current_diff = 0;
-void clockhardware()
+
+/*XT systems use the XT master oscillator (14.318 MHz) rather than the CPU clock
+  at the base timer frequency. Because there isn't an integer relationship
+  between the two frequencies, use fixed point arithmetic when updating TSC.*/
+static uint64_t tsc_frac = 0;
+
+static void clockhardware()
 {
         int diff = cycdiff - cycles - current_diff;
         
         current_diff += diff;
-  
-        timer_end_period(cycles*xt_cpu_multi);
+
+        tsc_frac += (uint64_t)diff * xt_cpu_multi;
+
+       tsc += (tsc_frac >> 32);
+        tsc_frac &= 0xffffffff;
+       if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc))
+               timer_process();
 }
 
 static int takeint = 0;
@@ -847,7 +870,7 @@ static int takeint = 0;
 
 int firstrepcycle=1;
 
-void rep(int fv)
+static void rep(int fv)
 {
         uint8_t temp;
         int c=CX;
@@ -894,8 +917,8 @@ void rep(int fv)
                 {
                         temp2=readmemb(ds+SI);
                         outb(DX,temp2);
-                        if (flags&D_FLAG) SI--;
-                        else              SI++;
+                        if (cpu_state.flags & D_FLAG) SI--;
+                        else                          SI++;
                         c--;
                         cycles-=5;
                 }
@@ -908,8 +931,8 @@ void rep(int fv)
                         temp2=readmemb(ds+SI);
                         writememb(es+DI,temp2);
 //                        if (output) printf("Moved %02X from %04X:%04X to %04X:%04X\n",temp2,ds>>4,SI,es>>4,DI);
-                        if (flags&D_FLAG) { DI--; SI--; }
-                        else              { DI++; SI++; }
+                        if (cpu_state.flags & D_FLAG) { DI--; SI--; }
+                        else                          { DI++; SI++; }
                         c--;
                         cycles-=17;
                         clockhardware();
@@ -926,8 +949,8 @@ void rep(int fv)
                         memcycs=0;
                         tempw=readmemw(ds,SI);
                         writememw(es,DI,tempw);
-                        if (flags&D_FLAG) { DI-=2; SI-=2; }
-                        else              { DI+=2; SI+=2; }
+                        if (cpu_state.flags & D_FLAG) { DI-=2; SI-=2; }
+                        else                          { DI+=2; SI+=2; }
                         c--;
                         cycles-=17;
                         clockhardware();
@@ -939,43 +962,43 @@ void rep(int fv)
 //                }
                 break;
                 case 0xA6: /*REP CMPSB*/
-                if (fv) flags|=Z_FLAG;
-                else    flags&=~Z_FLAG;
-                while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST)
+                if (fv) cpu_state.flags |= Z_FLAG;
+                else    cpu_state.flags &= ~Z_FLAG;
+                while ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0)) && !IRQTEST)
                 {
                         memcycs=0;
                         temp=readmemb(ds+SI);
                         temp2=readmemb(es+DI);
 //                        printf("CMPSB %c %c %i %05X %05X %04X:%04X\n",temp,temp2,c,ds+SI,es+DI,cs>>4,pc);
-                        if (flags&D_FLAG) { DI--; SI--; }
-                        else              { DI++; SI++; }
+                        if (cpu_state.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;
+                if (IRQTEST && c>0 && (fv==((cpu_state.flags & Z_FLAG)?1:0))) cpu_state.pc=ipc;
 //                if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); }
 //                else firstrepcycle=1;
                 break;
                 case 0xA7: /*REP CMPSW*/
-                if (fv) flags|=Z_FLAG;
-                else    flags&=~Z_FLAG;
-                while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST)
+                if (fv) cpu_state.flags |= Z_FLAG;
+                else    cpu_state.flags &= ~Z_FLAG;
+                while ((c>0) && (fv==((cpu_state.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; }
+                        if (cpu_state.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;
+                if (IRQTEST && c>0 && (fv==((cpu_state.flags & Z_FLAG)?1:0))) cpu_state.pc=ipc;
 //                if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); }
 //                else firstrepcycle=1;
 //                if (firstrepcycle) printf("REP CMPSW  %06X:%04X %06X:%04X %04X %04X\n",ds,SI,es,DI,tempw,tempw2);
@@ -985,8 +1008,8 @@ void rep(int fv)
                 {
                         memcycs=0;
                         writememb(es+DI,AL);
-                        if (flags&D_FLAG) DI--;
-                        else              DI++;
+                        if (cpu_state.flags & D_FLAG) DI--;
+                        else                          DI++;
                         c--;
                         cycles -= 10;
                         clockhardware();
@@ -1001,8 +1024,8 @@ void rep(int fv)
                 {
                         memcycs=0;
                         writememw(es,DI,AX);
-                        if (flags&D_FLAG) DI-=2;
-                        else              DI+=2;
+                        if (cpu_state.flags & D_FLAG) DI -= 2;
+                        else                          DI += 2;
                         c--;
                         cycles -= 10;
                         clockhardware();
@@ -1016,8 +1039,8 @@ void rep(int fv)
                 if (c>0)
                 {
                         temp2=readmemb(ds+SI);
-                        if (flags&D_FLAG) SI--;
-                        else              SI++;
+                        if (cpu_state.flags & D_FLAG) SI--;
+                        else                          SI++;
                         c--;
                         cycles-=4;
                 }
@@ -1028,8 +1051,8 @@ void rep(int fv)
                 if (c>0)
                 {
                         tempw2=readmemw(ds,SI);
-                        if (flags&D_FLAG) SI-=2;
-                        else              SI+=2;
+                        if (cpu_state.flags & D_FLAG) SI -= 2;
+                        else                          SI += 2;
                         c--;
                         cycles-=4;
                 }
@@ -1037,37 +1060,37 @@ void rep(int fv)
                 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)))
+                if (fv) cpu_state.flags |= Z_FLAG;
+                else    cpu_state.flags &= ~Z_FLAG;
+                if ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0)))
                 {
                         temp2=readmemb(es+DI);
 //                        if (output) printf("SCASB %02X %c %02X %05X  ",temp2,temp2,AL,es+DI);
                         setsub8(AL,temp2);
 //                        if (output && flags&Z_FLAG) printf("Match %02X %02X\n",AL,temp2);
-                        if (flags&D_FLAG) DI--;
-                        else              DI++;
+                        if (cpu_state.flags & D_FLAG) DI--;
+                        else                          DI++;
                         c--;
                         cycles -= 15;
                 }
 //if (output)                printf("%i %i %i %i\n",c,(c>0),(fv==((flags&Z_FLAG)?1:0)),((c>0) && (fv==((flags&Z_FLAG)?1:0))));
-                if ((c>0) && (fv==((flags&Z_FLAG)?1:0)))  { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); }
+                if ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0)))  { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); }
                 else firstrepcycle=1;
 //                cycles-=120;
                 break;
                 case 0xAF: /*REP SCASW*/
-                if (fv) flags|=Z_FLAG;
-                else    flags&=~Z_FLAG;
-                if ((c>0) && (fv==((flags&Z_FLAG)?1:0)))
+                if (fv) cpu_state.flags |= Z_FLAG;
+                else    cpu_state.flags &= ~Z_FLAG;
+                if ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0)))
                 {
                         tempw=readmemw(es,DI);
                         setsub16(AX,tempw);
-                        if (flags&D_FLAG) DI-=2;
-                        else              DI+=2;
+                        if (cpu_state.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(); }
+                if ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0)))  { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); }
                 else firstrepcycle=1;
                 break;
                 default:
@@ -1086,12 +1109,11 @@ void rep(int fv)
 }
 
 
-int inhlt=0;
-uint16_t lastpc,lastcs;
-int skipnextprint=0;
+static int inhlt=0;
+static int skipnextprint=0;
+
+#include "8087.h"
 
-int instime=0;
-//#if 0
 void execx86(int cycs)
 {
         uint8_t temp,temp2;
@@ -1109,25 +1131,20 @@ void execx86(int cycs)
 //        return;
         while (cycles>0)
         {
-//                old83=old82;
-//                old82=old8;
-//                old8=oldpc|(oldcs<<16);
-//                if (pc==0x96B && cs==0x9E040) { printf("Hit it\n"); output=1; timetolive=150; }
-//                if (pc<0x8000) printf("%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i\n",pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags,disctime);
+                uint8_t opcode;
+                
                 cycdiff=cycles;
-                timer_start_period(cycles*xt_cpu_multi);
                 current_diff = 0;
                 cycles-=nextcyc;
 //                if (instime) pclog("Cycles %i %i\n",cycles,cycdiff);
                 nextcyc=0;
 //        if (output) printf("CLOCK %i %i\n",cycdiff,cycles);
                 fetchclocks=0;
-                oldcs=CS;
                 cpu_state.oldpc = cpu_state.pc;
                 opcodestart:
                 opcode=FETCH();
-                tempc=flags&C_FLAG;
-                trap=flags&T_FLAG;
+                tempc = cpu_state.flags & C_FLAG;
+                trap = cpu_state.flags & T_FLAG;
                 cpu_state.pc--;
 //                output=1;
 //                if (output) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X\n",cs>>4,pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags&~0x200,rmdat);
@@ -1136,7 +1153,7 @@ void execx86(int cycs)
                 {
 //                        if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle)
 //                        {
-                                if (!skipnextprint) printf("%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]);
+                                if (!skipnextprint) printf("%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,cpu_state.flags, ins, ram, ram[0x1a925]);
                                 skipnextprint=0;
 //                                ins++;
 //                        }
@@ -1206,7 +1223,7 @@ void execx86(int cycs)
                         case 0x07: /*POP ES*/
                         if (cpu_state.ssegs) ss=oldss;
                         tempw=readmemw(ss,SP);
-                        loadseg(tempw,&_es);
+                        loadseg(tempw,&cpu_state.seg_es);
                         SP+=2;
                         cycles-=12;
                         break;
@@ -1216,7 +1233,7 @@ void execx86(int cycs)
                         temp=geteab();
                         temp|=getr8(cpu_reg);
                         setznp8(temp);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         seteab(temp);
                         cycles-=((cpu_mod==3)?3:24);
                         break;
@@ -1225,7 +1242,7 @@ void execx86(int cycs)
                         tempw=geteaw();
                         tempw|=cpu_state.regs[cpu_reg].w;
                         setznp16(tempw);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         seteaw(tempw);
                         cycles-=((cpu_mod==3)?3:24);
                         break;
@@ -1234,7 +1251,7 @@ void execx86(int cycs)
                         temp=geteab();
                         temp|=getr8(cpu_reg);
                         setznp8(temp);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         setr8(cpu_reg,temp);
                         cycles-=((cpu_mod==3)?3:13);
                         break;
@@ -1243,20 +1260,20 @@ void execx86(int cycs)
                         tempw=geteaw();
                         tempw|=cpu_state.regs[cpu_reg].w;
                         setznp16(tempw);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.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);
+                        cpu_state.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);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         cycles-=4;
                         break;
 
@@ -1269,7 +1286,7 @@ void execx86(int cycs)
                         case 0x0F: /*POP CS - 8088/8086 only*/
                         if (cpu_state.ssegs) ss=oldss;
                         tempw=readmemw(ss,SP);
-                        loadseg(tempw,&_cs);
+                        loadseg(tempw,&cpu_state.seg_cs);
                         SP+=2;
                         cycles-=12;
                         break;
@@ -1328,7 +1345,7 @@ void execx86(int cycs)
                         case 0x17: /*POP SS*/
                         if (cpu_state.ssegs) ss=oldss;
                         tempw=readmemw(ss,SP);
-                        loadseg(tempw,&_ss);
+                        loadseg(tempw,&cpu_state.seg_ss);
                         SP+=2;
                         noint=1;
                         cycles-=12;
@@ -1393,7 +1410,7 @@ void execx86(int cycs)
                         case 0x1F: /*POP DS*/
                         if (cpu_state.ssegs) ss=oldss;
                         tempw=readmemw(ss,SP);
-                        loadseg(tempw,&_ds);
+                        loadseg(tempw,&cpu_state.seg_ds);
                         if (cpu_state.ssegs) oldds=ds;
                         SP+=2;
                         cycles-=12;
@@ -1404,7 +1421,7 @@ void execx86(int cycs)
                         temp=geteab();
                         temp&=getr8(cpu_reg);
                         setznp8(temp);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         seteab(temp);
                         cycles-=((cpu_mod==3)?3:24);
                         break;
@@ -1413,7 +1430,7 @@ void execx86(int cycs)
                         tempw=geteaw();
                         tempw&=cpu_state.regs[cpu_reg].w;
                         setznp16(tempw);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         seteaw(tempw);
                         cycles-=((cpu_mod==3)?3:24);
                         break;
@@ -1422,7 +1439,7 @@ void execx86(int cycs)
                         temp=geteab();
                         temp&=getr8(cpu_reg);
                         setznp8(temp);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         setr8(cpu_reg,temp);
                         cycles-=((cpu_mod==3)?3:13);
                         break;
@@ -1431,20 +1448,20 @@ void execx86(int cycs)
                         tempw=geteaw();
                         tempw&=cpu_state.regs[cpu_reg].w;
                         setznp16(tempw);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.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);
+                        cpu_state.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);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         cycles-=4;
                         break;
 
@@ -1458,19 +1475,20 @@ void execx86(int cycs)
 //                        break;
 
                         case 0x27: /*DAA*/
-                        if ((flags&A_FLAG) || ((AL&0xF)>9))
+                        if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9))
                         {
-                                tempi=((uint16_t)AL)+6;
-                                AL+=6;
-                                flags|=A_FLAG;
-                                if (tempi&0x100) flags|=C_FLAG;
+                                tempi = ((uint16_t)AL) + 6;
+                                AL += 6;
+                                cpu_state.flags |= A_FLAG;
+                                if (tempi & 0x100)
+                                        cpu_state.flags |= C_FLAG;
                         }
 //                        else
 //                           flags&=~A_FLAG;
-                        if ((flags&C_FLAG) || (AL>0x9F))
+                        if ((cpu_state.flags & C_FLAG) || (AL > 0x9F))
                         {
-                                AL+=0x60;
-                                flags|=C_FLAG;
+                                AL += 0x60;
+                                cpu_state.flags |= C_FLAG;
                         }
 //                        else
 //                           flags&=~C_FLAG;
@@ -1532,19 +1550,20 @@ void execx86(int cycs)
                         cycles-=4;
                         goto opcodestart;
                         case 0x2F: /*DAS*/
-                        if ((flags&A_FLAG)||((AL&0xF)>9))
+                        if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9))
                         {
-                                tempi=((uint16_t)AL)-6;
-                                AL-=6;
-                                flags|=A_FLAG;
-                                if (tempi&0x100) flags|=C_FLAG;
+                                tempi = ((uint16_t)AL) - 6;
+                                AL -= 6;
+                                cpu_state.flags |= A_FLAG;
+                                if (tempi & 0x100)
+                                        cpu_state.flags |= C_FLAG;
                         }
 //                        else
 //                           flags&=~A_FLAG;
-                        if ((flags&C_FLAG)||(AL>0x9F))
+                        if ((cpu_state.flags & C_FLAG) || (AL > 0x9F))
                         {
-                                AL-=0x60;
-                                flags|=C_FLAG;
+                                AL -= 0x60;
+                                cpu_state.flags |= C_FLAG;
                         }
 //                        else
 //                           flags&=~C_FLAG;
@@ -1556,7 +1575,7 @@ void execx86(int cycs)
                         temp=geteab();
                         temp^=getr8(cpu_reg);
                         setznp8(temp);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         seteab(temp);
                         cycles-=((cpu_mod==3)?3:24);
                         break;
@@ -1565,7 +1584,7 @@ void execx86(int cycs)
                         tempw=geteaw();
                         tempw^=cpu_state.regs[cpu_reg].w;
                         setznp16(tempw);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         seteaw(tempw);
                         cycles-=((cpu_mod==3)?3:24);
                         break;
@@ -1574,7 +1593,7 @@ void execx86(int cycs)
                         temp=geteab();
                         temp^=getr8(cpu_reg);
                         setznp8(temp);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         setr8(cpu_reg,temp);
                         cycles-=((cpu_mod==3)?3:13);
                         break;
@@ -1583,20 +1602,20 @@ void execx86(int cycs)
                         tempw=geteaw();
                         tempw^=cpu_state.regs[cpu_reg].w;
                         setznp16(tempw);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.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);
+                        cpu_state.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);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         cycles-=4;
                         break;
 
@@ -1610,16 +1629,16 @@ void execx86(int cycs)
 //                        break;
 
                         case 0x37: /*AAA*/
-                        if ((flags&A_FLAG)||((AL&0xF)>9))
+                        if ((cpu_state.flags & A_FLAG)||((AL & 0xF) > 9))
                         {
-                                AL+=6;
+                                AL += 6;
                                 AH++;
-                                flags|=(A_FLAG|C_FLAG);
+                                cpu_state.flags |= (A_FLAG|C_FLAG);
                         }
                         else
-                           flags&=~(A_FLAG|C_FLAG);
-                        AL&=0xF;
-                        cycles-=8;
+                                cpu_state.flags &= ~(A_FLAG|C_FLAG);
+                        AL &= 0xF;
+                        cycles -= 8;
                         break;
 
                         case 0x38: /*CMP 8,reg*/
@@ -1671,16 +1690,16 @@ void execx86(int cycs)
 //                        break;
 
                         case 0x3F: /*AAS*/
-                        if ((flags&A_FLAG)||((AL&0xF)>9))
+                        if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9))
                         {
-                                AL-=6;
+                                AL -= 6;
                                 AH--;
-                                flags|=(A_FLAG|C_FLAG);
+                                cpu_state.flags |= (A_FLAG|C_FLAG);
                         }
                         else
-                           flags&=~(A_FLAG|C_FLAG);
-                        AL&=0xF;
-                        cycles-=8;
+                                cpu_state.flags &= ~(A_FLAG|C_FLAG);
+                        AL &= 0xF;
+                        cycles -= 8;
                         break;
 
                         case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/
@@ -1715,105 +1734,105 @@ void execx86(int cycs)
                        case 0x60: /*JO alias*/
                         case 0x70: /*JO*/
                         offset=(int8_t)FETCH();
-                        if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); }
+                        if (cpu_state.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(); }
+                        if (!(cpu_state.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(); }
+                        if (cpu_state.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(); }
+                        if (!(cpu_state.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(); }
+                        if (cpu_state.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(); }
+                        if (!(cpu_state.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(); }
+                        if (cpu_state.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(); }
+                        if (!(cpu_state.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(); }
+                        if (cpu_state.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(); }
+                        if (!(cpu_state.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(); }
+                        if (cpu_state.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(); }
+                        if (!(cpu_state.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;
+                        temp=(cpu_state.flags & N_FLAG)?1:0;
+                        temp2=(cpu_state.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;
+                        temp=(cpu_state.flags & N_FLAG)?1:0;
+                        temp2=(cpu_state.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(); }
+                        temp=(cpu_state.flags & N_FLAG)?1:0;
+                        temp2=(cpu_state.flags & V_FLAG)?1:0;
+                        if ((cpu_state.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(); }
+                        temp=(cpu_state.flags & N_FLAG)?1:0;
+                        temp2=(cpu_state.flags & V_FLAG)?1:0;
+                        if (!((cpu_state.flags & Z_FLAG) || (temp!=temp2)))  { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); }
                         cycles-=4;
                         break;
 
@@ -1831,7 +1850,7 @@ void execx86(int cycs)
                                 case 0x08: /*OR b,#8*/
                                 temp|=temp2;
                                 setznp8(temp);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 seteab(temp);
                                 cycles-=((cpu_mod==3)?4:23);
                                 break;
@@ -1850,7 +1869,7 @@ void execx86(int cycs)
                                 case 0x20: /*AND b,#8*/
                                 temp&=temp2;
                                 setznp8(temp);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 seteab(temp);
                                 cycles-=((cpu_mod==3)?4:23);
                                 break;
@@ -1862,7 +1881,7 @@ void execx86(int cycs)
                                 case 0x30: /*XOR b,#8*/
                                 temp^=temp2;
                                 setznp8(temp);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 seteab(temp);
                                 cycles-=((cpu_mod==3)?4:23);
                                 break;
@@ -1893,7 +1912,7 @@ void execx86(int cycs)
                                 case 0x08: /*OR w,#16*/
                                 tempw|=tempw2;
                                 setznp16(tempw);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 seteaw(tempw);
                                 cycles-=((cpu_mod==3)?4:23);
                                 break;
@@ -1907,7 +1926,7 @@ void execx86(int cycs)
                                 case 0x20: /*AND w,#16*/
                                 tempw&=tempw2;
                                 setznp16(tempw);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 seteaw(tempw);
                                 cycles-=((cpu_mod==3)?4:23);
                                 break;
@@ -1926,7 +1945,7 @@ void execx86(int cycs)
                                 case 0x30: /*XOR w,#16*/
                                 tempw^=tempw2;
                                 setznp16(tempw);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 seteaw(tempw);
                                 cycles-=((cpu_mod==3)?4:23);
                                 break;
@@ -1960,7 +1979,7 @@ void execx86(int cycs)
                                 tempw|=tempw2;
                                 setznp16(tempw);
                                 seteaw(tempw);
-                                flags&=~(C_FLAG|A_FLAG|V_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|A_FLAG|V_FLAG);
                                 cycles-=((cpu_mod==3)?4:23);
                                 break;
                                 case 0x10: /*ADC w,#8*/
@@ -1982,7 +2001,7 @@ void execx86(int cycs)
                                 setznp16(tempw);
                                 seteaw(tempw);
                                 cycles-=((cpu_mod==3)?4:23);
-                                flags&=~(C_FLAG|A_FLAG|V_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|A_FLAG|V_FLAG);
                                 break;
                                 case 0x28: /*SUB w,#8*/
                                 setsub16(tempw,tempw2);
@@ -1995,7 +2014,7 @@ void execx86(int cycs)
                                 setznp16(tempw);
                                 seteaw(tempw);
                                 cycles-=((cpu_mod==3)?4:23);
-                                flags&=~(C_FLAG|A_FLAG|V_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|A_FLAG|V_FLAG);
                                 break;
                                 case 0x38: /*CMP w,#8*/
                                 setsub16(tempw,tempw2);
@@ -2014,7 +2033,7 @@ void execx86(int cycs)
                         temp=geteab();
                         temp2=getr8(cpu_reg);
                         setznp8(temp&temp2);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         cycles-=((cpu_mod==3)?3:13);
                         break;
                         case 0x85: /*TEST w,reg*/
@@ -2022,7 +2041,7 @@ void execx86(int cycs)
                         tempw=geteaw();
                         tempw2=cpu_state.regs[cpu_reg].w;
                         setznp16(tempw&tempw2);
-                        flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         cycles-=((cpu_mod==3)?3:13);
                         break;
                         case 0x86: /*XCHG b,reg*/
@@ -2099,20 +2118,20 @@ void execx86(int cycs)
                         {
                                 case 0x00: /*ES*/
                                 tempw=geteaw();
-                                loadseg(tempw,&_es);
+                                loadseg(tempw,&cpu_state.seg_es);
                                 break;
                                 case 0x08: /*CS - 8088/8086 only*/
                                 tempw=geteaw();
-                                loadseg(tempw,&_cs);
+                                loadseg(tempw,&cpu_state.seg_cs);
                                 break;
                                 case 0x18: /*DS*/
                                 tempw=geteaw();
-                                loadseg(tempw,&_ds);
+                                loadseg(tempw,&cpu_state.seg_ds);
                                 if (cpu_state.ssegs) oldds=ds;
                                 break;
                                 case 0x10: /*SS*/
                                 tempw=geteaw();
-                                loadseg(tempw,&_ss);
+                                loadseg(tempw,&cpu_state.seg_ss);
                                 if (cpu_state.ssegs) oldss=ss;
 //                                printf("LOAD SS %04X %04X\n",tempw,SS);
 //                             printf("SS loaded with %04X %04X:%04X %04X %04X %04X\n",ss>>4,cs>>4,pc,CX,DX,es>>4);
@@ -2172,22 +2191,22 @@ void execx86(int cycs)
                         break;
                         case 0x9C: /*PUSHF*/
                         if (cpu_state.ssegs) ss=oldss;
-                        writememw(ss,((SP-2)&0xFFFF),flags|0xF000);
+                        writememw(ss, ((SP-2)&0xFFFF), cpu_state.flags | 0xF000);
                         SP-=2;
                         cycles-=14;
                         break;
                         case 0x9D: /*POPF*/
                         if (cpu_state.ssegs) ss=oldss;
-                        flags=readmemw(ss,SP)&0xFFF;
+                        cpu_state.flags = readmemw(ss,SP) & 0xFFF;
                         SP+=2;
                         cycles-=12;
                         break;
                         case 0x9E: /*SAHF*/
-                        flags=(flags&0xFF00)|AH;
+                        cpu_state.flags = (cpu_state.flags & 0xFF00) | AH;
                         cycles-=4;
                         break;
                         case 0x9F: /*LAHF*/
-                        AH=flags&0xFF;
+                        AH = cpu_state.flags & 0xFF;
                         cycles-=4;
                         break;
 
@@ -2217,23 +2236,23 @@ void execx86(int cycs)
                         case 0xA4: /*MOVSB*/
                         temp=readmemb(ds+SI);
                         writememb(es+DI,temp);
-                        if (flags&D_FLAG) { DI--; SI--; }
-                        else              { DI++; SI++; }
+                        if (cpu_state.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; }
+                        if (cpu_state.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++; }
+                        if (cpu_state.flags & D_FLAG) { DI--; SI--; }
+                        else                          { DI++; SI++; }
                         cycles-=30;
                         break;
                         case 0xA7: /*CMPSW*/
@@ -2241,60 +2260,60 @@ void execx86(int cycs)
                         tempw2=readmemw(es,DI);
 //                        printf("CMPSW %04X %04X\n",tempw,tempw2);
                         setsub16(tempw,tempw2);
-                        if (flags&D_FLAG) { DI-=2; SI-=2; }
-                        else              { DI+=2; SI+=2; }
+                        if (cpu_state.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);
+                        cpu_state.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);
+                        cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                         cycles-=5;
                         break;
                         case 0xAA: /*STOSB*/
                         writememb(es+DI,AL);
-                        if (flags&D_FLAG) DI--;
-                        else              DI++;
+                        if (cpu_state.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;
+                        if (cpu_state.flags & D_FLAG) DI -= 2;
+                        else                          DI += 2;
                         cycles-=11;
                         break;
                         case 0xAC: /*LODSB*/
                         AL=readmemb(ds+SI);
 //                        printf("LODSB %04X:%04X %02X %04X:%04X\n",cs>>4,pc,AL,ds>>4,SI);
-                        if (flags&D_FLAG) SI--;
-                        else              SI++;
+                        if (cpu_state.flags & D_FLAG) SI--;
+                        else                          SI++;
                         cycles-=16;
                         break;
                         case 0xAD: /*LODSW*/
 //                        if (times) printf("LODSW %04X:%04X\n",cs>>4,pc);
                         AX=readmemw(ds,SI);
-                        if (flags&D_FLAG) SI-=2;
-                        else              SI+=2;
+                        if (cpu_state.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++;
+                        if (cpu_state.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;
+                        if (cpu_state.flags & D_FLAG) DI -= 2;
+                        else                          DI += 2;
                         cycles-=19;
                         break;
 
@@ -2361,14 +2380,14 @@ void execx86(int cycs)
                         fetchea();
                         cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); //geteaw();
                         tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); //geteaw2();
-                        loadseg(tempw,&_es);
+                        loadseg(tempw,&cpu_state.seg_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);
+                        loadseg(tempw,&cpu_state.seg_ds);
                         if (cpu_state.ssegs) oldds=ds;
                         cycles-=24;
                         break;
@@ -2409,13 +2428,13 @@ void execx86(int cycs)
                         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);
+                        writememw(ss, ((SP-2)&0xFFFF), cpu_state.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.flags &= ~I_FLAG;
+                        cpu_state.flags &= ~T_FLAG;
 //                        printf("CC %04X:%04X  ",CS,pc);
                         cpu_state.pc=readmemw(0,addr);
                         loadcs(readmemw(0,addr+2));
@@ -2424,15 +2443,13 @@ void execx86(int cycs)
                         cycles-=72;
                         break;
                         case 0xCD: /*INT*/
-                        lastpc=cpu_state.pc;
-                        lastcs=CS;
                         temp=FETCH();
 
                         if (cpu_state.ssegs) ss=oldss;
-                        writememw(ss,((SP-2)&0xFFFF),flags|0xF000);
-                        writememw(ss,((SP-4)&0xFFFF),CS);
-                        writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
-                        flags&=~T_FLAG;
+                        writememw(ss, ((SP-2)&0xFFFF), cpu_state.flags | 0xF000);
+                        writememw(ss, ((SP-4)&0xFFFF), CS);
+                        writememw(ss, ((SP-6)&0xFFFF), cpu_state.pc);
+                        cpu_state.flags &= ~T_FLAG;
                         SP-=6;
                         addr=temp<<2;
                         cpu_state.pc=readmemw(0,addr);
@@ -2449,7 +2466,7 @@ void execx86(int cycs)
                         cpu_state.pc=readmemw(ss,SP);
 //                        printf("CF\n");
                         loadcs(readmemw(ss,((SP+2)&0xFFFF)));
-                        flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF;
+                        cpu_state.flags = readmemw(ss,((SP+4)&0xFFFF))&0xFFF;
                         SP+=6;
                         cycles-=44;
                         FETCHCLEAR();
@@ -2461,83 +2478,85 @@ void execx86(int cycs)
                         switch (rmdat&0x38)
                         {
                                 case 0x00: /*ROL b,1*/
-                                if (temp&0x80) flags|=C_FLAG;
-                                else           flags&=~C_FLAG;
+                                if (temp&0x80) cpu_state.flags |= C_FLAG;
+                                else           cpu_state.flags &= ~C_FLAG;
                                 temp<<=1;
-                                if (flags&C_FLAG) temp|=1;
+                                if (cpu_state.flags & C_FLAG)
+                                        temp |= 1;
                                 seteab(temp);
 //                                setznp8(temp);
-                                if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG;
-                                else                          flags&=~V_FLAG;
+                                if ((cpu_state.flags&C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG;
+                                else                                        cpu_state.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;
+                                if (temp&1) cpu_state.flags |= C_FLAG;
+                                else        cpu_state.flags &= ~C_FLAG;
                                 temp>>=1;
-                                if (flags&C_FLAG) temp|=0x80;
+                                if (cpu_state.flags & C_FLAG)
+                                        temp |= 0x80;
                                 seteab(temp);
 //                                setznp8(temp);
-                                if ((temp^(temp>>1))&0x40) flags|=V_FLAG;
-                                else                       flags&=~V_FLAG;
+                                if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG;
+                                else                       cpu_state.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;
+                                temp2 = cpu_state.flags & C_FLAG;
+                                if (temp&0x80) cpu_state.flags |= C_FLAG;
+                                else           cpu_state.flags &= ~C_FLAG;
                                 temp<<=1;
                                 if (temp2) temp|=1;
                                 seteab(temp);
 //                                setznp8(temp);
-                                if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG;
-                                else                          flags&=~V_FLAG;
+                                if ((cpu_state.flags & C_FLAG)^(temp>>7)) cpu_state.flags |= V_FLAG;
+                                else                                      cpu_state.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;
+                                temp2 = cpu_state.flags & C_FLAG;
+                                if (temp&1) cpu_state.flags |= C_FLAG;
+                                else        cpu_state.flags &= ~C_FLAG;
                                 temp>>=1;
                                 if (temp2) temp|=0x80;
                                 seteab(temp);
 //                                setznp8(temp);
-                                if ((temp^(temp>>1))&0x40) flags|=V_FLAG;
-                                else                       flags&=~V_FLAG;
+                                if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG;
+                                else                       cpu_state.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;
+                                if (temp&0x80) cpu_state.flags |= C_FLAG;
+                                else           cpu_state.flags &= ~C_FLAG;
+                                if ((temp^(temp<<1))&0x80) cpu_state.flags |= V_FLAG;
+                                else                       cpu_state.flags &= ~V_FLAG;
                                 temp<<=1;
                                 seteab(temp);
                                 setznp8(temp);
                                 cycles-=((cpu_mod==3)?2:23);
-                                flags|=A_FLAG;
+                                cpu_state.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;
+                                if (temp&1) cpu_state.flags |= C_FLAG;
+                                else        cpu_state.flags &= ~C_FLAG;
+                                if (temp&0x80) cpu_state.flags |= V_FLAG;
+                                else           cpu_state.flags &= ~V_FLAG;
                                 temp>>=1;
                                 seteab(temp);
                                 setznp8(temp);
                                 cycles-=((cpu_mod==3)?2:23);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
                                 case 0x38: /*SAR b,1*/
-                                if (temp&1) flags|=C_FLAG;
-                                else        flags&=~C_FLAG;
+                                if (temp&1) cpu_state.flags |= C_FLAG;
+                                else        cpu_state.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;
+                                cpu_state.flags |= A_FLAG;
+                                cpu_state.flags &= ~V_FLAG;
                                 break;
 
 //                                default:
@@ -2553,83 +2572,83 @@ void execx86(int cycs)
                         switch (rmdat&0x38)
                         {
                                 case 0x00: /*ROL w,1*/
-                                if (tempw&0x8000) flags|=C_FLAG;
-                                else              flags&=~C_FLAG;
+                                if (tempw&0x8000) cpu_state.flags |= C_FLAG;
+                                else              cpu_state.flags &= ~C_FLAG;
                                 tempw<<=1;
-                                if (flags&C_FLAG) tempw|=1;
+                                if (cpu_state.flags & C_FLAG) tempw|=1;
                                 seteaw(tempw);
 //                                setznp16(tempw);
-                                if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG;
-                                else                            flags&=~V_FLAG;
+                                if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG;
+                                else                                        cpu_state.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;
+                                if (tempw&1) cpu_state.flags |= C_FLAG;
+                                else         cpu_state.flags &= ~C_FLAG;
                                 tempw>>=1;
-                                if (flags&C_FLAG) tempw|=0x8000;
+                                if (cpu_state.flags & C_FLAG) tempw|=0x8000;
                                 seteaw(tempw);
 //                                setznp16(tempw);
-                                if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG;
-                                else                           flags&=~V_FLAG;
+                                if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG;
+                                else                           cpu_state.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;
+                                temp2 = cpu_state.flags & C_FLAG;
+                                if (tempw&0x8000) cpu_state.flags |= C_FLAG;
+                                else              cpu_state.flags &= ~C_FLAG;
                                 tempw<<=1;
                                 if (temp2) tempw|=1;
                                 seteaw(tempw);
-                                if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG;
-                                else                            flags&=~V_FLAG;
+                                if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG;
+                                else                                        cpu_state.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;
+                                temp2 = cpu_state.flags & C_FLAG;
+                                if (tempw&1) cpu_state.flags |= C_FLAG;
+                                else         cpu_state.flags &= ~C_FLAG;
                                 tempw>>=1;
                                 if (temp2) tempw|=0x8000;
                                 seteaw(tempw);
 //                                setznp16(tempw);
-                                if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG;
-                                else                           flags&=~V_FLAG;
+                                if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG;
+                                else                           cpu_state.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;
+                                if (tempw&0x8000) cpu_state.flags |= C_FLAG;
+                                else              cpu_state.flags &= ~C_FLAG;
+                                if ((tempw^(tempw<<1))&0x8000) cpu_state.flags |= V_FLAG;
+                                else                           cpu_state.flags &= ~V_FLAG;
                                 tempw<<=1;
                                 seteaw(tempw);
                                 setznp16(tempw);
                                 cycles-=((cpu_mod==3)?2:23);
-                                flags|=A_FLAG;
+                                cpu_state.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;
+                                if (tempw&1) cpu_state.flags |= C_FLAG;
+                                else         cpu_state.flags &= ~C_FLAG;
+                                if (tempw&0x8000) cpu_state.flags |= V_FLAG;
+                                else              cpu_state.flags &= ~V_FLAG;
                                 tempw>>=1;
                                 seteaw(tempw);
                                 setznp16(tempw);
                                 cycles-=((cpu_mod==3)?2:23);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
 
                                 case 0x38: /*SAR w,1*/
-                                if (tempw&1) flags|=C_FLAG;
-                                else         flags&=~C_FLAG;
+                                if (tempw&1) cpu_state.flags |= C_FLAG;
+                                else         cpu_state.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;
+                                cpu_state.flags |= A_FLAG;
+                                cpu_state.flags &= ~V_FLAG;
                                 break;
 
 //                                default:
@@ -2656,12 +2675,12 @@ void execx86(int cycs)
                                         c--;
                                         cycles-=4;
                                 }
-                                if (temp2) flags|=C_FLAG;
-                                else       flags&=~C_FLAG;
+                                if (temp2) cpu_state.flags |= C_FLAG;
+                                else       cpu_state.flags &= ~C_FLAG;
                                 seteab(temp);
 //                                setznp8(temp);
-                                if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG;
-                                else                          flags&=~V_FLAG;
+                                if ((cpu_state.flags & C_FLAG)^(temp>>7)) cpu_state.flags |= V_FLAG;
+                                else                                      cpu_state.flags &= ~V_FLAG;
                                 cycles-=((cpu_mod==3)?8:28);
                                 break;
                                 case 0x08: /*ROR b,CL*/
@@ -2673,40 +2692,40 @@ void execx86(int cycs)
                                         c--;
                                         cycles-=4;
                                 }
-                                if (temp2) flags|=C_FLAG;
-                                else       flags&=~C_FLAG;
+                                if (temp2) cpu_state.flags |= C_FLAG;
+                                else       cpu_state.flags &= ~C_FLAG;
                                 seteab(temp);
-                                if ((temp^(temp>>1))&0x40) flags|=V_FLAG;
-                                else                       flags&=~V_FLAG;
+                                if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG;
+                                else                       cpu_state.flags &= ~V_FLAG;
                                 cycles-=((cpu_mod==3)?8:28);
                                 break;
                                 case 0x10: /*RCL b,CL*/
 //                                printf("RCL %i %02X %02X\n",c,CL,temp);
                                 while (c>0)
                                 {
-                                        templ=flags&C_FLAG;
+                                        templ=cpu_state.flags & C_FLAG;
                                         temp2=temp&0x80;
                                         temp<<=1;
-                                        if (temp2) flags|=C_FLAG;
-                                        else       flags&=~C_FLAG;
+                                        if (temp2) cpu_state.flags |= C_FLAG;
+                                        else       cpu_state.flags &= ~C_FLAG;
                                         if (templ) temp|=1;
                                         c--;
                                         cycles-=4;
                                 }
 //                                printf("Now %02X\n",temp);
                                 seteab(temp);
-                                if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG;
-                                else                          flags&=~V_FLAG;
+                                if ((cpu_state.flags & C_FLAG)^(temp>>7)) cpu_state.flags |= V_FLAG;
+                                else                                      cpu_state.flags &= ~V_FLAG;
                                 cycles-=((cpu_mod==3)?8:28);
                                 break;
                                 case 0x18: /*RCR b,CL*/
                                 while (c>0)
                                 {
-                                        templ=flags&C_FLAG;
+                                        templ=cpu_state.flags & C_FLAG;
                                         temp2=temp&1;
                                         temp>>=1;
-                                        if (temp2) flags|=C_FLAG;
-                                        else       flags&=~C_FLAG;
+                                        if (temp2) cpu_state.flags |= C_FLAG;
+                                        else       cpu_state.flags &= ~C_FLAG;
                                         if (templ) temp|=0x80;
                                         c--;
                                         cycles-=4;
@@ -2714,49 +2733,49 @@ void execx86(int cycs)
 //                                if (temp2) flags|=C_FLAG;
 //                                else       flags&=~C_FLAG;
                                 seteab(temp);
-                                if ((temp^(temp>>1))&0x40) flags|=V_FLAG;
-                                else                       flags&=~V_FLAG;
+                                if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG;
+                                else                       cpu_state.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;
+                                        cpu_state.flags &= ~C_FLAG;
                                 }
                                 else
                                 {
-                                        if ((temp<<(c-1))&0x80) flags|=C_FLAG;
-                                        else                    flags&=~C_FLAG;
+                                        if ((temp<<(c-1))&0x80) cpu_state.flags |= C_FLAG;
+                                        else                    cpu_state.flags &= ~C_FLAG;
                                         temp<<=c;
                                 }
                                 seteab(temp);
                                 setznp8(temp);
                                 cycles-=(c*4);
                                 cycles-=((cpu_mod==3)?8:28);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
                                 case 0x28: /*SHR b,CL*/
                                 if (c > 8)
                                 {
                                         temp = 0;
-                                        flags &= ~C_FLAG;
+                                        cpu_state.flags &= ~C_FLAG;
                                 }
                                 else
                                 {
-                                        if ((temp>>(c-1))&1) flags|=C_FLAG;
-                                        else                 flags&=~C_FLAG;
+                                        if ((temp>>(c-1))&1) cpu_state.flags |= C_FLAG;
+                                        else                 cpu_state.flags &= ~C_FLAG;
                                         temp>>=c;
                                 }
                                 seteab(temp);
                                 setznp8(temp);
                                 cycles-=(c*4);
                                 cycles-=((cpu_mod==3)?8:28);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
                                 case 0x38: /*SAR b,CL*/
-                                if ((temp>>(c-1))&1) flags|=C_FLAG;
-                                else                 flags&=~C_FLAG;
+                                if ((temp>>(c-1))&1) cpu_state.flags |= C_FLAG;
+                                else                 cpu_state.flags &= ~C_FLAG;
                                 while (c>0)
                                 {
                                         temp>>=1;
@@ -2767,7 +2786,7 @@ void execx86(int cycs)
                                 seteab(temp);
                                 setznp8(temp);
                                 cycles-=((cpu_mod==3)?8:28);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
 
 //                                default:
@@ -2794,11 +2813,11 @@ void execx86(int cycs)
                                         c--;
                                         cycles-=4;
                                 }
-                                if (temp) flags|=C_FLAG;
-                                else      flags&=~C_FLAG;
+                                if (temp) cpu_state.flags |= C_FLAG;
+                                else      cpu_state.flags &= ~C_FLAG;
                                 seteaw(tempw);
-                                if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG;
-                                else                            flags&=~V_FLAG;
+                                if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG;
+                                else                                        cpu_state.flags &= ~V_FLAG;
                                 cycles-=((cpu_mod==3)?8:28);
                                 break;
                                 case 0x08: /*ROR w,CL*/
@@ -2809,46 +2828,46 @@ void execx86(int cycs)
                                         c--;
                                         cycles-=4;
                                 }
-                                if (tempw2) flags|=C_FLAG;
-                                else        flags&=~C_FLAG;
+                                if (tempw2) cpu_state.flags |= C_FLAG;
+                                else        cpu_state.flags &= ~C_FLAG;
                                 seteaw(tempw);
-                                if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG;
-                                else                           flags&=~V_FLAG;
+                                if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG;
+                                else                           cpu_state.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;
+                                        templ = cpu_state.flags & C_FLAG;
+                                        if (tempw&0x8000) cpu_state.flags |= C_FLAG;
+                                        else              cpu_state.flags &= ~C_FLAG;
                                         tempw=(tempw<<1)|templ;
                                         c--;
                                         cycles-=4;
                                 }
-                                if (templ) flags|=C_FLAG;
-                                else       flags&=~C_FLAG;
+                                if (templ) cpu_state.flags |= C_FLAG;
+                                else       cpu_state.flags &= ~C_FLAG;
                                 seteaw(tempw);
-                                if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG;
-                                else                            flags&=~V_FLAG;
+                                if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG;
+                                else                                        cpu_state.flags &= ~V_FLAG;
                                 cycles-=((cpu_mod==3)?8:28);
                                 break;
                                 case 0x18: /*RCR w,CL*/
                                 while (c>0)
                                 {
-                                        templ=flags&C_FLAG;
+                                        templ = cpu_state.flags & C_FLAG;
                                         tempw2=(templ&1)?0x8000:0;
-                                        if (tempw&1) flags|=C_FLAG;
-                                        else         flags&=~C_FLAG;
+                                        if (tempw&1) cpu_state.flags |= C_FLAG;
+                                        else         cpu_state.flags &= ~C_FLAG;
                                         tempw=(tempw>>1)|tempw2;
                                         c--;
                                         cycles-=4;
                                 }
-                                if (tempw2) flags|=C_FLAG;
-                                else        flags&=~C_FLAG;
+                                if (tempw2) cpu_state.flags |= C_FLAG;
+                                else        cpu_state.flags &= ~C_FLAG;
                                 seteaw(tempw);
-                                if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG;
-                                else                           flags&=~V_FLAG;
+                                if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG;
+                                else                           cpu_state.flags &= ~V_FLAG;
                                 cycles-=((cpu_mod==3)?8:28);
                                 break;
 
@@ -2856,44 +2875,44 @@ void execx86(int cycs)
                                 if (c>16)
                                 {
                                         tempw=0;
-                                        flags&=~C_FLAG;
+                                        cpu_state.flags &= ~C_FLAG;
                                 }
                                 else
                                 {
-                                        if ((tempw<<(c-1))&0x8000) flags|=C_FLAG;
-                                        else                       flags&=~C_FLAG;
+                                        if ((tempw<<(c-1))&0x8000) cpu_state.flags |= C_FLAG;
+                                        else                       cpu_state.flags &= ~C_FLAG;
                                         tempw<<=c;
                                 }
                                 seteaw(tempw);
                                 setznp16(tempw);
                                 cycles-=(c*4);
                                 cycles-=((cpu_mod==3)?8:28);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
 
                                 case 0x28:            /*SHR w,CL*/
                                 if (c > 16)
                                 {
                                         tempw = 0;
-                                        flags &= ~C_FLAG;
+                                        cpu_state.flags &= ~C_FLAG;
                                 }
                                 else
                                 {
-                                        if ((tempw>>(c-1))&1) flags|=C_FLAG;
-                                        else                  flags&=~C_FLAG;
+                                        if ((tempw>>(c-1))&1) cpu_state.flags |= C_FLAG;
+                                        else                  cpu_state.flags &= ~C_FLAG;
                                         tempw>>=c;
                                 }
                                 seteaw(tempw);
                                 setznp16(tempw);
                                 cycles-=(c*4);
                                 cycles-=((cpu_mod==3)?8:28);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
 
                                 case 0x38:            /*SAR w,CL*/
                                 tempw2=tempw&0x8000;
-                                if ((tempw>>(c-1))&1) flags|=C_FLAG;
-                                else                  flags&=~C_FLAG;
+                                if ((tempw>>(c-1))&1) cpu_state.flags |= C_FLAG;
+                                else                  cpu_state.flags &= ~C_FLAG;
                                 while (c>0)
                                 {
                                         tempw=(tempw>>1)|tempw2;
@@ -2903,7 +2922,7 @@ void execx86(int cycs)
                                 seteaw(tempw);
                                 setznp16(tempw);
                                 cycles-=((cpu_mod==3)?8:28);
-                                flags|=A_FLAG;
+                                cpu_state.flags |= A_FLAG;
                                 break;
 
 //                                default:
@@ -2928,7 +2947,7 @@ void execx86(int cycs)
                         cycles-=60;
                         break;
                         case 0xD6: /*SETALC*/
-                        AL = (flags & C_FLAG) ? 0xff : 0;
+                        AL = (cpu_state.flags & C_FLAG) ? 0xff : 0;
                         cycles -= 4;
                         break;
                         case 0xD7: /*XLAT*/
@@ -2936,22 +2955,90 @@ void execx86(int cycs)
                         AL=readmemb(ds+addr);
                         cycles-=11;
                         break;
-                        case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/
-                        case 0xDC: case 0xDE: case 0xDF: case 0xD8:
+                        
+                        case 0xd8:
+                        fetchea();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_d8_a16[rmdat >> 3](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
+                        break;
+                        case 0xd9:
                         fetchea();
-                        geteab();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_d9_a16[rmdat](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
+                        break;
+                        case 0xda:
+                        fetchea();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_da_a16[rmdat](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
+                        break;
+                        case 0xdb:
+                        fetchea();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_db_a16[rmdat](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
+                        break;
+                        case 0xdc:
+                        fetchea();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_dc_a16[rmdat >> 3](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
+                        break;
+                        case 0xdd:
+                        fetchea();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_dd_a16[rmdat](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
+                        break;
+                        case 0xde:
+                        fetchea();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_de_a16[rmdat](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
+                        break;
+                        case 0xdf:
+                        fetchea();
+                        if (hasfpu)
+                        {
+                                uint16_t save_pc = cpu_state.pc;
+                                ops_808x_fpu_df_a16[rmdat](rmdat);
+                                cpu_state.pc = save_pc;
+                        }
                         break;
 
                         case 0xE0: /*LOOPNE*/
                         offset=(int8_t)FETCH();
                         CX--;
-                        if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); }
+                        if (CX && !(cpu_state.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(); }
+                        if (CX && (cpu_state.flags & Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); }
                         cycles-=6;
                         break;
                         case 0xE2: /*LOOP*/
@@ -3058,7 +3145,7 @@ void execx86(int cycs)
                         break;
 
                         case 0xF4: /*HLT*/
-//                        printf("IN HLT!!!! %04X:%04X %08X %08X %08X\n",oldcs,oldpc,old8,old82,old83);
+//                        printf("IN HLT!!!! %04X %08X %08X %08X\n",oldpc,old8,old82,old83);
 /*                        if (!(flags & I_FLAG))
                         {
                                 pclog("HLT\n");
@@ -3071,7 +3158,7 @@ void execx86(int cycs)
                         cycles-=2;
                         break;
                         case 0xF5: /*CMC*/
-                        flags^=C_FLAG;
+                        cpu_state.flags ^= C_FLAG;
                         cycles-=2;
                         break;
 
@@ -3085,7 +3172,7 @@ void execx86(int cycs)
                                 temp2=FETCH();
                                 temp&=temp2;
                                 setznp8(temp);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 cycles-=((cpu_mod==3)?5:11);
                                 break;
                                 case 0x10: /*NOT b*/
@@ -3102,20 +3189,20 @@ void execx86(int cycs)
                                 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);
+                                if (AX) cpu_state.flags &= ~Z_FLAG;
+                                else    cpu_state.flags |= Z_FLAG;
+                                if (AH) cpu_state.flags |= (C_FLAG|V_FLAG);
+                                else    cpu_state.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);
+                                if (AX) cpu_state.flags &= ~Z_FLAG;
+                                else    cpu_state.flags |= Z_FLAG;
+                                if (AH) cpu_state.flags |= (C_FLAG|V_FLAG);
+                                else    cpu_state.flags &= ~(C_FLAG|V_FLAG);
                                 cycles-=80;
                                 break;
                                 case 0x30: /*DIV AL,b*/
@@ -3146,12 +3233,12 @@ void execx86(int cycs)
                                 else
                                 {
                                         printf("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc);
-                                        writememw(ss,(SP-2)&0xFFFF,flags|0xF000);
+                                        writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG;
+                                        cpu_state.flags &= ~T_FLAG;
                                         cpu_state.pc=readmemw(0,0);
 //                        printf("F6 30\n");
                                         loadcs(readmemw(0,2));
@@ -3190,12 +3277,12 @@ void execx86(int cycs)
                                 else
                                 {
                                         printf("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc);
-                                        writememw(ss,(SP-2)&0xFFFF,flags|0xF000);
+                                        writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG;
+                                        cpu_state.flags &= ~T_FLAG;
                                         cpu_state.pc=readmemw(0,0);
 //                        printf("F6 38\n");
                                         loadcs(readmemw(0,2));
@@ -3223,7 +3310,7 @@ void execx86(int cycs)
                                 case 0x08:
                                 tempw2=getword();
                                 setznp16(tempw&tempw2);
-                                flags&=~(C_FLAG|V_FLAG|A_FLAG);
+                                cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG);
                                 cycles-=((cpu_mod==3)?5:11);
                                 break;
                                 case 0x10: /*NOT w*/
@@ -3242,18 +3329,18 @@ void execx86(int cycs)
 //                                if (output) printf("%04X*%04X=%08X\n",AX,tempw,templ);
                                 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);
+                                if (AX|DX) cpu_state.flags &= ~Z_FLAG;
+                                else       cpu_state.flags |= Z_FLAG;
+                                if (DX)    cpu_state.flags |= (C_FLAG|V_FLAG);
+                                else       cpu_state.flags &= ~(C_FLAG|V_FLAG);
                                 cycles-=118;
                                 break;
                                 case 0x28: /*IMUL AX,w*/
                                 setznp16(AX);
 //                                printf("IMUL %i %i ",(int)((int16_t)AX),(int)((int16_t)tempw));
                                 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);
+                                if ((tempws>>15) && ((tempws>>15)!=-1)) cpu_state.flags |= (C_FLAG|V_FLAG);
+                                else                                    cpu_state.flags &= ~(C_FLAG|V_FLAG);
 //                                printf("%i ",tempws);
                                 AX=tempws&0xFFFF;
                                 tempws=(uint16_t)(tempws>>16);
@@ -3261,8 +3348,8 @@ void execx86(int cycs)
 //                                printf("%04X %04X\n",AX,DX);
 //                                dumpregs();
 //                                exit(-1);
-                                if (AX|DX) flags&=~Z_FLAG;
-                                else       flags|=Z_FLAG;
+                                if (AX|DX) cpu_state.flags &= ~Z_FLAG;
+                                else       cpu_state.flags |= Z_FLAG;
                                 cycles-=128;
                                 break;
                                 case 0x30: /*DIV AX,w*/
@@ -3278,12 +3365,12 @@ void execx86(int cycs)
                                 else
                                 {
                                         printf("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc);
-                                        writememw(ss,(SP-2)&0xFFFF,flags|0xF000);
+                                        writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG;
+                                        cpu_state.flags &= ~T_FLAG;
                                         cpu_state.pc=readmemw(0,0);
 //                        printf("F7 30\n");
                                         loadcs(readmemw(0,2));
@@ -3305,12 +3392,12 @@ void execx86(int cycs)
                                 else
                                 {
                                         printf("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc);
-                                        writememw(ss,(SP-2)&0xFFFF,flags|0xF000);
+                                        writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG;
+                                        cpu_state.flags &= ~T_FLAG;
                                         cpu_state.pc=readmemw(0,0);
 //                        printf("F7 38\n");
                                         loadcs(readmemw(0,2));
@@ -3327,48 +3414,48 @@ void execx86(int cycs)
                         break;
 
                         case 0xF8: /*CLC*/
-                        flags&=~C_FLAG;
+                        cpu_state.flags &= ~C_FLAG;
                         cycles-=2;
                         break;
                         case 0xF9: /*STC*/
 //                        printf("STC %04X\n",pc);
-                        flags|=C_FLAG;
+                        cpu_state.flags |= C_FLAG;
                         cycles-=2;
                         break;
                         case 0xFA: /*CLI*/
-                        flags&=~I_FLAG;
+                        cpu_state.flags &= ~I_FLAG;
 //                        printf("CLI at %04X:%04X\n",cs>>4,pc);
                         cycles-=3;
                         break;
                         case 0xFB: /*STI*/
-                        flags|=I_FLAG;
+                        cpu_state.flags |= I_FLAG;
 //                        printf("STI at %04X:%04X\n",cs>>4,pc);
                         cycles-=2;
                         break;
                         case 0xFC: /*CLD*/
-                        flags&=~D_FLAG;
+                        cpu_state.flags &= ~D_FLAG;
                         cycles-=2;
                         break;
                         case 0xFD: /*STD*/
-                        flags|=D_FLAG;
+                        cpu_state.flags |= D_FLAG;
                         cycles-=2;
                         break;
 
                         case 0xFE: /*INC/DEC b*/
                         fetchea();
                         temp=geteab();
-                        flags&=~V_FLAG;
+                        cpu_state.flags &= ~V_FLAG;
                         if (rmdat&0x38)
                         {
                                 setsub8nc(temp,1);
                                 temp2=temp-1;
-                                if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG;
+                                if ((temp&0x80) && !(temp2&0x80)) cpu_state.flags |= V_FLAG;
                         }
                         else
                         {
                                 setadd8nc(temp,1);
                                 temp2=temp+1;
-                                if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG;
+                                if ((temp2&0x80) && !(temp&0x80)) cpu_state.flags |= V_FLAG;
                         }
 //                        setznp8(temp2);
                         seteab(temp2);
@@ -3485,14 +3572,6 @@ void execx86(int cycs)
                // if (instime) printf("%i %i %i %i\n",cycdiff,cycles,memcycs,fetchclocks);
                 FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks);
                 if ((cycdiff-cycles)<memcycs) cycles-=(memcycs-(cycdiff-cycles));
-                if (romset==ROM_IBMPC)
-                {
-                        if ((cs+cpu_state.pc)==0xFE4A7) /*You didn't seriously think I was going to emulate the cassette, did you?*/
-                        {
-                                CX=1;
-                                BX=0x500;
-                        }
-                }
                 memcycs=0;
 
                 insc++;
@@ -3500,16 +3579,16 @@ void execx86(int cycs)
                 clockhardware();
 
 
-                if (trap && (flags&T_FLAG) && !noint)
+                if (trap && (cpu_state.flags & T_FLAG) && !noint)
                 {
 //                        printf("TRAP!!! %04X:%04X\n",CS,pc);
-                        writememw(ss,(SP-2)&0xFFFF,flags|0xF000);
+                        writememw(ss,(SP-2)&0xFFFF,cpu_state.flags | 0xF000);
                         writememw(ss,(SP-4)&0xFFFF,CS);
                         writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
                         SP-=6;
                         addr=1<<2;
-                        flags&=~I_FLAG;
-                        flags&=~T_FLAG;
+                        cpu_state.flags &= ~I_FLAG;
+                        cpu_state.flags &= ~T_FLAG;
                         cpu_state.pc=readmemw(0,addr);
                         loadcs(readmemw(0,addr+2));
                         FETCHCLEAR();
@@ -3517,13 +3596,13 @@ void execx86(int cycs)
                 else if (nmi && nmi_enable && nmi_mask)
                 {
 //                        output = 3;
-                        writememw(ss,(SP-2)&0xFFFF,flags|0xF000);
+                        writememw(ss,(SP-2)&0xFFFF,cpu_state.flags | 0xF000);
                         writememw(ss,(SP-4)&0xFFFF,CS);
                         writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
                         SP-=6;
                         addr=2<<2;
-                        flags&=~I_FLAG;
-                        flags&=~T_FLAG;
+                        cpu_state.flags &= ~I_FLAG;
+                        cpu_state.flags &= ~T_FLAG;
                         cpu_state.pc=readmemw(0,addr);
                         loadcs(readmemw(0,addr+2));
                         FETCHCLEAR();
@@ -3535,13 +3614,13 @@ void execx86(int cycs)
                         if (temp!=0xFF)
                         {
                                 if (inhlt) cpu_state.pc++;
-                                writememw(ss,(SP-2)&0xFFFF,flags|0xF000);
+                                writememw(ss,(SP-2)&0xFFFF,cpu_state.flags | 0xF000);
                                 writememw(ss,(SP-4)&0xFFFF,CS);
                                 writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
                                 SP-=6;
                                 addr=temp<<2;
-                                flags&=~I_FLAG;
-                                flags&=~T_FLAG;
+                                cpu_state.flags &= ~I_FLAG;
+                                cpu_state.flags &= ~T_FLAG;
                                 cpu_state.pc=readmemw(0,addr);
 //                        printf("INT INT INT\n");
                                 loadcs(readmemw(0,addr+2));
@@ -3549,7 +3628,7 @@ void execx86(int cycs)
 //                                printf("INTERRUPT\n");
                         }
                 }
-                takeint = (flags&I_FLAG) && (pic.pend&~pic.mask);
+                takeint = (cpu_state.flags & I_FLAG) && (pic.pend&~pic.mask);
 
                 if (noint) noint=0;
                 ins++;
index d3f9b48e7530d86db6778a09b778ddfb620235d5..d4f2563f65c40b4de4765bb0f843ff7179dcd6e1 100644 (file)
@@ -4,14 +4,6 @@
 #include "mem.h"
 #include "x86_ops.h"
 
-#ifdef __amd64__
-#include "codegen_x86-64.h"
-#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32
-#include "codegen_x86.h"
-#else
-#error Dynamic recompiler not implemented on your platform
-#endif
-
 /*Handling self-modifying code (of which there is a lot on x86) :
 
   PCem tracks a 'dirty mask' for each physical page, in which each bit
 
 typedef struct codeblock_t
 {
+        uint32_t pc;
+        uint32_t _cs;
+        uint32_t phys, phys_2;
+        uint16_t status;
+        uint16_t flags;
+        uint8_t ins;
+        uint8_t TOP;
+
+        /*Pointers for codeblock tree, used to search for blocks when hash lookup
+          fails.*/
+        uint16_t parent, left, right;
+
+        uint8_t *data;
+        
         uint64_t page_mask, page_mask2;
         uint64_t *dirty_mask, *dirty_mask2;
-        uint64_t cmp;
-        
+
         /*Previous and next pointers, for the codeblock list associated with
           each physical page. Two sets of pointers, as a codeblock can be
           present in two pages.*/
-        struct codeblock_t *prev, *next;
-        struct codeblock_t *prev_2, *next_2;
-        
-        /*Pointers for codeblock tree, used to search for blocks when hash lookup
-          fails.*/
-        struct codeblock_t *parent, *left, *right;
-        
-        int pnt;
-        int ins;
-        
-        int was_recompiled;
-        int TOP;
-
-        uint32_t pc;
-        uint32_t _cs;
-        uint32_t endpc;
-        uint32_t phys, phys_2;
-        uint32_t status;
-        uint32_t flags;
+        uint16_t prev, next;
+        uint16_t prev_2, next_2;
 
-        uint8_t data[2048];
+        /*First mem_block_t used by this block. Any subsequent mem_block_ts
+          will be in the list starting at head_mem_block->next.*/
+        struct mem_block_t *head_mem_block;
 } codeblock_t;
 
+extern codeblock_t *codeblock;
+
+extern uint16_t *codeblock_hash;
+
+extern uint8_t *block_write_data;
+
 /*Code block uses FPU*/
 #define CODEBLOCK_HAS_FPU 1
 /*Code block is always entered with the same FPU top-of-stack*/
 #define CODEBLOCK_STATIC_TOP 2
+/*Code block has been compiled*/
+#define CODEBLOCK_WAS_RECOMPILED 4
+/*Code block is in free list and is not valid*/
+#define CODEBLOCK_IN_FREE_LIST 8
+/*Code block spans two pages, page_mask2 and dirty_mask2 are valid*/
+#define CODEBLOCK_HAS_PAGE2 0x10
+/*Code block is using a byte mask for code present and dirty*/
+#define CODEBLOCK_BYTE_MASK 0x20
+/*Code block is in dirty list*/
+#define CODEBLOCK_IN_DIRTY_LIST 0x40
+/*Code block is not inlining immediate parameters, parameters must be fetched from memory*/
+#define CODEBLOCK_NO_IMMEDIATES 0x80
 
 #define BLOCK_PC_INVALID 0xffffffff
 
+#define BLOCK_INVALID 0
+
+static inline int get_block_nr(codeblock_t *block)
+{
+        return ((uintptr_t)block - (uintptr_t)codeblock) / sizeof(codeblock_t);
+}
+
 static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs)
 {
-        codeblock_t *block = pages[phys >> 12].head;
+        codeblock_t *block;
         uint64_t a = _cs | ((uint64_t)phys << 32);
         
+        if (!pages[phys >> 12].head)
+                return NULL;
+                
+        block = &codeblock[pages[phys >> 12].head];
         while (block)
         {
-                if (a == block->cmp)
+                uint64_t block_cmp = block->_cs | ((uint64_t)block->phys << 32);
+                if (a == block_cmp)
                 {
                         if (!((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) &&
                              ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)))
                                 break;
                 }
-                if (a < block->cmp)
-                        block = block->left;
+                if (a < block_cmp)
+                        block = block->left ? &codeblock[block->left] : NULL;
                 else
-                        block = block->right;
+                        block = block->right ? &codeblock[block->right] : NULL;
         }
         
         return block;
@@ -100,75 +120,87 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs)
 
 static inline void codeblock_tree_add(codeblock_t *new_block)
 {
-        codeblock_t *block = pages[new_block->phys >> 12].head;
+        codeblock_t *block = &codeblock[pages[new_block->phys >> 12].head];
         uint64_t a = new_block->_cs | ((uint64_t)new_block->phys << 32);
-        new_block->cmp = a;
-                
-        if (!block)
+
+        if (!pages[new_block->phys >> 12].head)
         {
-                pages[new_block->phys >> 12].head = new_block;
-                new_block->parent = new_block->left = new_block->right = NULL;
+                pages[new_block->phys >> 12].head = get_block_nr(new_block);
+                new_block->parent = new_block->left = new_block->right = BLOCK_INVALID;
         }
         else
         {
                 codeblock_t *old_block = NULL;
+                uint64_t old_block_cmp = 0;
                 
                 while (block)
                 {
                         old_block = block;
-                        if (a < old_block->cmp)
-                                block = block->left;
+                        old_block_cmp = old_block->_cs | ((uint64_t)old_block->phys << 32);
+                        
+                        if (a < old_block_cmp)
+                                block = block->left ? &codeblock[block->left] : NULL;
                         else
-                                block = block->right;
+                                block = block->right ? &codeblock[block->right] : NULL;
                 }
                 
-                if (a < old_block->cmp)
-                        old_block->left = new_block;
+                if (a < old_block_cmp)
+                        old_block->left = get_block_nr(new_block);
                 else
-                        old_block->right = new_block;
+                        old_block->right = get_block_nr(new_block);
                 
-                new_block->parent = old_block;
-                new_block->left = new_block->right = NULL;
+                new_block->parent = get_block_nr(old_block);
+                new_block->left = new_block->right = BLOCK_INVALID;
         }
 }
 
 static inline void codeblock_tree_delete(codeblock_t *block)
 {
-        codeblock_t *parent = block->parent;
+        uint16_t parent_nr = block->parent;
+        codeblock_t *parent;
+
+        if (block->parent)
+                parent = &codeblock[block->parent];
+        else
+                parent = NULL;
 
         if (!block->left && !block->right)
         {
                 /*Easy case - remove from parent*/
                 if (!parent)
-                        pages[block->phys >> 12].head = NULL;
+                        pages[block->phys >> 12].head = BLOCK_INVALID;
                 else
                 {
-                        if (parent->left == block)
-                                parent->left = NULL;
-                        if (parent->right == block)
-                                parent->right = NULL;
+                        uint16_t block_nr = get_block_nr(block);
+                        
+                        if (parent->left == block_nr)
+                                parent->left = BLOCK_INVALID;
+                        if (parent->right == block_nr)
+                                parent->right = BLOCK_INVALID;
                 }
                 return;
         }
         else if (!block->left)
         {
                 /*Only right node*/
-                if (!parent)
+                if (!parent_nr)
                 {
                         pages[block->phys >> 12].head = block->right;
-                        pages[block->phys >> 12].head->parent = NULL;
+                        codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID;
                 }
                 else
                 {
-                        if (parent->left == block)
+                        uint16_t block_nr = get_block_nr(block);
+
+                        if (parent->left == block_nr)
                         {
                                 parent->left = block->right;
-                                parent->left->parent = parent;
+                                codeblock[parent->left].parent = parent_nr;
                         }
-                        if (parent->right == block)
+                        if (parent->right == block_nr)
                         {
                                 parent->right = block->right;
-                                parent->right->parent = parent;
+                                codeblock[parent->right].parent = parent_nr;
                         }
                 }
                 return;
@@ -176,22 +208,24 @@ static inline void codeblock_tree_delete(codeblock_t *block)
         else if (!block->right)
         {
                 /*Only left node*/
-                if (!parent)
+                if (!parent_nr)
                 {
                         pages[block->phys >> 12].head = block->left;
-                        pages[block->phys >> 12].head->parent = NULL;
+                        codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID;
                 }
                 else
                 {
-                        if (parent->left == block)
+                        uint16_t block_nr = get_block_nr(block);
+
+                        if (parent->left == block_nr)
                         {
                                 parent->left = block->left;
-                                parent->left->parent = parent;
+                                codeblock[parent->left].parent = parent_nr;
                         }
-                        if (parent->right == block)
+                        if (parent->right == block_nr)
                         {
                                 parent->right = block->left;
-                                parent->right->parent = parent;
+                                codeblock[parent->right].parent = parent_nr;
                         }
                 }
                 return;
@@ -199,75 +233,109 @@ static inline void codeblock_tree_delete(codeblock_t *block)
         else
         {
                 /*Difficult case - node has two children. Walk right child to find lowest node*/
-                codeblock_t *lowest = block->right, *highest;
+                codeblock_t *lowest = &codeblock[block->right], *highest;
                 codeblock_t *old_parent;
+                uint16_t lowest_nr;
                         
                 while (lowest->left)
-                        lowest = lowest->left;
-
-                old_parent = lowest->parent;
+                        lowest = &codeblock[lowest->left];
+                lowest_nr = get_block_nr(lowest);
+                
+                old_parent = &codeblock[lowest->parent];
 
                 /*Replace deleted node with lowest node*/
-                if (!parent)
-                        pages[block->phys >> 12].head = lowest;
+                if (!parent_nr)
+                        pages[block->phys >> 12].head = lowest_nr;
                 else
                 {
-                        if (parent->left == block)
-                                parent->left = lowest;
-                        if (parent->right == block)
-                                parent->right = lowest;
+                        uint16_t block_nr = get_block_nr(block);
+
+                        if (parent->left == block_nr)
+                                parent->left = lowest_nr;
+                        if (parent->right == block_nr)
+                                parent->right = lowest_nr;
                 }
 
-                lowest->parent = parent;
+                lowest->parent = parent_nr;
                 lowest->left = block->left;
                 if (lowest->left)
-                        lowest->left->parent = lowest;
+                        codeblock[lowest->left].parent = lowest_nr;
 
-                old_parent->left = NULL;
+                old_parent->left = BLOCK_INVALID;
                                 
-                highest = lowest->right;
-                if (!highest)
+                highest = &codeblock[lowest->right];
+                if (!lowest->right)
                 {
-                        if (lowest != block->right)
+                        if (lowest_nr != block->right)
                         {
                                 lowest->right = block->right;
-                                block->right->parent = lowest;
+                                codeblock[block->right].parent = lowest_nr;
                         }
                         return;
                 }
 
                 while (highest->right)
-                        highest = highest->right;
+                        highest = &codeblock[highest->right];
 
-                if (block->right && block->right != lowest)
+                if (block->right && block->right != lowest_nr)
                 {
                         highest->right = block->right;
-                        block->right->parent = highest;
+                        codeblock[block->right].parent = get_block_nr(highest);
                 }
         }
 }
 
-#define PAGE_MASK_INDEX_MASK 3
-#define PAGE_MASK_INDEX_SHIFT 10
 #define PAGE_MASK_MASK 63
-#define PAGE_MASK_SHIFT 4
+#define PAGE_MASK_SHIFT 6
 
-extern codeblock_t *codeblock;
+void codegen_mark_code_present_multibyte(codeblock_t *block, uint32_t start_pc, int len);
 
-extern codeblock_t **codeblock_hash;
+static inline void codegen_mark_code_present(codeblock_t *block, uint32_t start_pc, int len)
+{
+        if (len == 1)
+        {
+                if (block->flags & CODEBLOCK_BYTE_MASK)
+                {
+                        if (!((start_pc ^ block->pc) & ~0x3f)) /*Starts in second page*/
+                                block->page_mask |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK));
+                        else
+                                block->page_mask2 |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK));
+                }
+                else
+                {
+                        if (!((start_pc ^ block->pc) & ~0xfff)) /*Starts in second page*/
+                                block->page_mask |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK));
+                        else
+                                block->page_mask2 |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK));
+                }
+        }
+        else
+                codegen_mark_code_present_multibyte(block, start_pc, len);
+}
 
 void codegen_init();
+void codegen_close();
 void codegen_reset();
 void codegen_block_init(uint32_t phys_addr);
 void codegen_block_remove();
 void codegen_block_start_recompile(codeblock_t *block);
 void codegen_block_end_recompile(codeblock_t *block);
 void codegen_block_end();
+void codegen_delete_block(codeblock_t *block);
 void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc);
 void codegen_generate_seg_restore();
 void codegen_set_op32();
 void codegen_flush();
 void codegen_check_flush(struct page_t *page, uint64_t mask, uint32_t phys_addr);
+struct ir_data_t;
+x86seg *codegen_generate_ea(struct ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32, int stack_offset);
+void codegen_check_seg_read(codeblock_t *block, struct ir_data_t *ir, x86seg *seg);
+void codegen_check_seg_write(codeblock_t *block, struct ir_data_t *ir, x86seg *seg);
+
+int codegen_purge_purgable_list();
+/*Delete a random code block to free memory. This is obviously quite expensive, and
+  will only be called when the allocator is out of memory*/
+void codegen_delete_random_block(int required_mem_block);
 
 extern int cpu_block_end;
 extern uint32_t codegen_endpc;
@@ -286,23 +354,27 @@ extern int codegen_block_cycles;
 
 extern void (*codegen_timing_start)();
 extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat);
-extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32);
+extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc);
 extern void (*codegen_timing_block_start)();
 extern void (*codegen_timing_block_end)();
+extern int (*codegen_timing_jump_cycles)();
 
 typedef struct codegen_timing_t
 {
         void (*start)();
         void (*prefix)(uint8_t prefix, uint32_t fetchdat);
-        void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32);
+        void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc);
         void (*block_start)();
         void (*block_end)();
+        int (*jump_cycles)();
 } codegen_timing_t;
 
 extern codegen_timing_t codegen_timing_pentium;
 extern codegen_timing_t codegen_timing_686;
 extern codegen_timing_t codegen_timing_486;
 extern codegen_timing_t codegen_timing_winchip;
+extern codegen_timing_t codegen_timing_winchip2;
+extern codegen_timing_t codegen_timing_k6;
 
 void codegen_timing_set(codegen_timing_t *timing);
 
@@ -311,45 +383,6 @@ extern int block_pos;
 
 #define CPU_BLOCK_END() cpu_block_end = 1
 
-static inline void addbyte(uint8_t val)
-{
-        codeblock[block_current].data[block_pos++] = val;
-        if (block_pos >= BLOCK_MAX)
-        {
-                CPU_BLOCK_END();
-        }
-}
-
-static inline void addword(uint16_t val)
-{
-        *(uint16_t *)(void *)&codeblock[block_current].data[block_pos] = val;
-        block_pos += 2;
-        if (block_pos >= BLOCK_MAX)
-        {
-                CPU_BLOCK_END();
-        }
-}
-
-static inline void addlong(uint32_t val)
-{
-        *(uint32_t *)&codeblock[block_current].data[block_pos] = val;
-        block_pos += 4;
-        if (block_pos >= BLOCK_MAX)
-        {
-                CPU_BLOCK_END();
-        }
-}
-
-static inline void addquad(uint64_t val)
-{
-        *(uint64_t *)&codeblock[block_current].data[block_pos] = val;
-        block_pos += 8;
-        if (block_pos >= BLOCK_MAX)
-        {
-                CPU_BLOCK_END();
-        }
-}
-
 /*Current physical page of block being recompiled. -1 if no recompilation taking place */
 extern uint32_t recomp_page;
 
@@ -369,4 +402,13 @@ extern int codegen_reg_loaded[8];
 
 extern int codegen_in_recompile;
 
+void codegen_generate_reset();
+
+int codegen_get_instruction_uop(codeblock_t *block, uint32_t pc, int *first_instruction, int *TOP);
+void codegen_set_loop_start(struct ir_data_t *ir, int first_instruction);
+
+#ifdef DEBUG_EXTRA
+extern uint32_t instr_counts[256*256];
+#endif
+
 #endif
diff --git a/pcem/codegen_backend.h b/pcem/codegen_backend.h
new file mode 100644 (file)
index 0000000..afe2768
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _CODEGEN_BACKEND_H_
+#define _CODEGEN_BACKEND_H_
+
+//#ifdef __amd64__
+//#include "codegen_x86-64.h"
+#if defined __amd64__
+#include "codegen_backend_x86-64.h"
+#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32
+#include "codegen_backend_x86.h"
+#elif defined __ARM_EABI__
+#include "codegen_backend_arm.h"
+#elif defined __aarch64__
+#include "codegen_backend_arm64.h"
+#else
+#error Dynamic recompiler not implemented on your platform
+#endif
+
+void codegen_backend_init();
+void codegen_backend_prologue(codeblock_t *block);
+void codegen_backend_epilogue(codeblock_t *block);
+
+struct ir_data_t;
+struct uop_t;
+
+struct ir_data_t *codegen_get_ir_data();
+
+typedef int (*uOpFn)(codeblock_t *codeblock, struct uop_t *uop);
+
+extern const uOpFn uop_handlers[];
+
+/*Register will not be preserved across function calls*/
+#define HOST_REG_FLAG_VOLATILE (1 << 0)
+
+typedef struct host_reg_def_t
+{
+        int reg;
+        int flags;
+} host_reg_def_t;
+
+extern host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS];
+extern host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS];
+
+#endif
diff --git a/pcem/codegen_backend_x86-64.h b/pcem/codegen_backend_x86-64.h
new file mode 100644 (file)
index 0000000..70e953a
--- /dev/null
@@ -0,0 +1,12 @@
+#include "codegen_backend_x86-64_defs.h"
+
+#define BLOCK_SIZE 0x4000
+#define BLOCK_MASK 0x3fff
+#define BLOCK_START 0
+
+#define HASH_SIZE 0x20000
+#define HASH_MASK 0x1ffff
+
+#define HASH(l) ((l) & 0x1ffff)
+
+#define BLOCK_MAX 0x3c0
diff --git a/pcem/codegen_backend_x86-64_defs.h b/pcem/codegen_backend_x86-64_defs.h
new file mode 100644 (file)
index 0000000..8955773
--- /dev/null
@@ -0,0 +1,67 @@
+/*RBP = cpu_state + 128
+  R12 = ram (if block->flags & CODEBLOCK_NO_IMMEDIATES)*/
+#define REG_AX 0
+#define REG_CX 1
+#define REG_DX 2
+#define REG_BX 3
+#define REG_SP 4
+#define REG_BP 5
+#define REG_SI 6
+#define REG_DI 7
+
+#define REG_EAX 0
+#define REG_ECX 1
+#define REG_EDX 2
+#define REG_EBX 3
+#define REG_ESP 4
+#define REG_EBP 5
+#define REG_ESI 6
+#define REG_EDI 7
+
+#define REG_RAX 0
+#define REG_RCX 1
+#define REG_RDX 2
+#define REG_RBX 3
+#define REG_RSP 4
+#define REG_RBP 5
+#define REG_RSI 6
+#define REG_RDI 7
+#define REG_R8  8
+#define REG_R9  9
+#define REG_R10 10
+#define REG_R11 11
+#define REG_R12 12
+#define REG_R13 13
+#define REG_R14 14
+#define REG_R15 15
+
+#define REG_XMM0 0
+#define REG_XMM1 1
+#define REG_XMM2 2
+#define REG_XMM3 3
+#define REG_XMM4 4
+#define REG_XMM5 5
+#define REG_XMM6 6
+#define REG_XMM7 7
+
+#define REG_XMM_TEMP REG_XMM0
+
+#define CODEGEN_HOST_REGS 3
+#define CODEGEN_HOST_FP_REGS 7
+
+extern void *codegen_mem_load_byte;
+extern void *codegen_mem_load_word;
+extern void *codegen_mem_load_long;
+extern void *codegen_mem_load_quad;
+extern void *codegen_mem_load_single;
+extern void *codegen_mem_load_double;
+
+extern void *codegen_mem_store_byte;
+extern void *codegen_mem_store_word;
+extern void *codegen_mem_store_long;
+extern void *codegen_mem_store_quad;
+extern void *codegen_mem_store_single;
+extern void *codegen_mem_store_double;
+
+extern void *codegen_gpf_rout;
+extern void *codegen_exit_rout;
diff --git a/pcem/codegen_backend_x86.h b/pcem/codegen_backend_x86.h
new file mode 100644 (file)
index 0000000..a5aec72
--- /dev/null
@@ -0,0 +1,12 @@
+#include "codegen_backend_x86_defs.h"
+
+#define BLOCK_SIZE 0x10000
+#define BLOCK_MASK 0xffff
+#define BLOCK_START 0
+
+#define HASH_SIZE 0x20000
+#define HASH_MASK 0x1ffff
+
+#define HASH(l) ((l) & 0x1ffff)
+
+#define BLOCK_MAX 0x3c0
diff --git a/pcem/codegen_backend_x86_defs.h b/pcem/codegen_backend_x86_defs.h
new file mode 100644 (file)
index 0000000..25964ba
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _CODEGEN_BACKEND_X86_DEFS_H_
+#define _CODEGEN_BACKEND_X86_DEFS_H_
+
+#define REG_EAX 0
+#define REG_ECX 1
+#define REG_EDX 2
+#define REG_EBX 3
+#define REG_ESP 4
+#define REG_EBP 5
+#define REG_ESI 6
+#define REG_EDI 7
+
+#define REG_XMM0 0
+#define REG_XMM1 1
+#define REG_XMM2 2
+#define REG_XMM3 3
+#define REG_XMM4 4
+#define REG_XMM5 5
+#define REG_XMM6 6
+#define REG_XMM7 7
+
+#define REG_XMM_TEMP  REG_XMM7
+#define REG_XMM_TEMP2 REG_XMM6
+
+#define CODEGEN_HOST_REGS 3
+#define CODEGEN_HOST_FP_REGS 6
+
+extern void *codegen_mem_load_byte;
+extern void *codegen_mem_load_word;
+extern void *codegen_mem_load_long;
+extern void *codegen_mem_load_quad;
+extern void *codegen_mem_load_single;
+extern void *codegen_mem_load_double;
+
+extern void *codegen_mem_store_byte;
+extern void *codegen_mem_store_word;
+extern void *codegen_mem_store_long;
+extern void *codegen_mem_store_quad;
+extern void *codegen_mem_store_single;
+extern void *codegen_mem_store_double;
+
+extern void *codegen_gpf_rout;
+extern void *codegen_exit_rout;
+
+#define STACK_ARG0 (0)
+#define STACK_ARG1 (4)
+#define STACK_ARG2 (8)
+#define STACK_ARG3 (12)
+
+#endif
diff --git a/pcem/codegen_x86-64.h b/pcem/codegen_x86-64.h
deleted file mode 100644 (file)
index f0c22e4..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#define BLOCK_SIZE 0x4000
-#define BLOCK_MASK 0x3fff
-#define BLOCK_START 0
-
-#define HASH_SIZE 0x20000
-#define HASH_MASK 0x1ffff
-
-#define HASH(l) ((l) & 0x1ffff)
-
-#define BLOCK_EXIT_OFFSET 0x7e0
-#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20)
-
-#define BLOCK_MAX 1620
-
-enum
-{
-        OP_RET = 0xc3
-};
-
-#define NR_HOST_REGS 4
-extern int host_reg_mapping[NR_HOST_REGS];
-#define NR_HOST_XMM_REGS 7
-extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS];
diff --git a/pcem/codegen_x86.h b/pcem/codegen_x86.h
deleted file mode 100644 (file)
index 92e3591..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#define BLOCK_SIZE 0x4000
-#define BLOCK_MASK 0x3fff
-#define BLOCK_START 0
-
-#define HASH_SIZE 0x20000
-#define HASH_MASK 0x1ffff
-
-#define HASH(l) ((l) & 0x1ffff)
-
-#define BLOCK_EXIT_OFFSET 0x7f0
-#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20)
-
-#define BLOCK_MAX 1720
-
-enum
-{
-        OP_RET = 0xc3
-};
-
-#define NR_HOST_REGS 4
-extern int host_reg_mapping[NR_HOST_REGS];
-#define NR_HOST_XMM_REGS 7
-extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS];
-
-extern uint32_t mem_load_addr_ea_b;
-extern uint32_t mem_load_addr_ea_w;
-extern uint32_t mem_load_addr_ea_l;
-extern uint32_t mem_load_addr_ea_q;
-extern uint32_t mem_store_addr_ea_b;
-extern uint32_t mem_store_addr_ea_w;
-extern uint32_t mem_store_addr_ea_l;
-extern uint32_t mem_store_addr_ea_q;
-
-extern uint32_t mem_load_addr_ea_b_no_abrt;
-extern uint32_t mem_store_addr_ea_b_no_abrt;
-extern uint32_t mem_load_addr_ea_w_no_abrt;
-extern uint32_t mem_store_addr_ea_w_no_abrt;
-extern uint32_t mem_load_addr_ea_l_no_abrt;
-extern uint32_t mem_store_addr_ea_l_no_abrt;
-extern uint32_t mem_check_write;
-extern uint32_t mem_check_write_w;
-extern uint32_t mem_check_write_l;
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5913377af841d9fe15226a77c922020af050bb06 100644 (file)
@@ -0,0 +1,27 @@
+float config_get_float(int is_global, char *head, char *name, float def);
+int config_get_int(int is_global, char *head, char *name, int def);
+char *config_get_string(int is_global, char *head, char *name, char *def);
+void config_set_float(int is_global, char *head, char *name, float val);
+void config_set_int(int is_global, char *head, char *name, int val);
+void config_set_string(int is_global, char *head, char *name, char *val);
+
+int config_free_section(int is_global, char *head);
+
+void add_config_callback(void(*loadconfig)(), void(*saveconfig)(), void(*onloaded)());
+
+char *get_filename(char *s);
+void append_filename(char *dest, char *s1, char *s2, int size);
+void append_slash(char *s, int size);
+void put_backslash(char *s);
+char *get_extension(char *s);
+
+void config_load(int is_global, char *fn);
+void config_save(int is_global, char *fn);
+void config_dump(int is_global);
+void config_free(int is_global);
+
+extern char config_file_default[256];
+extern char config_name[256];
+
+#define CFG_MACHINE 0
+#define CFG_GLOBAL  1
index 5619bb53c5a213741eed1bc8d203ba0044f5b172..7490db11abc9d59fefd07b811ea34e87d0df7ed1 100644 (file)
@@ -6,6 +6,10 @@
 #include "mem.h"
 #include "pci.h"
 #include "codegen.h"
+#include "x87_timings.h"
+
+int fpu_type;
+uint32_t cpu_features;
 
 static int cpu_turbo_speed, cpu_nonturbo_speed;
 static int cpu_turbo = 1;
@@ -34,6 +38,7 @@ OpFn *x86_dynarec_opcodes_df_a16;
 OpFn *x86_dynarec_opcodes_df_a32;
 OpFn *x86_dynarec_opcodes_REPE;
 OpFn *x86_dynarec_opcodes_REPNE;
+OpFn *x86_dynarec_opcodes_3DNOW;
 
 OpFn *x86_opcodes;
 OpFn *x86_opcodes_0f;
@@ -55,6 +60,7 @@ OpFn *x86_opcodes_df_a16;
 OpFn *x86_opcodes_df_a32;
 OpFn *x86_opcodes_REPE;
 OpFn *x86_opcodes_REPNE;
+OpFn *x86_opcodes_3DNOW;
 
 enum
 {
@@ -68,17 +74,18 @@ enum
         CPUID_MMX = (1 << 23)
 };
 
+/*Addition flags returned by CPUID function 0x80000001*/
+enum
+{
+        CPUID_3DNOW = (1 << 31)
+};
+
 int cpu = 3, cpu_manufacturer = 0;
 CPU *cpu_s;
 int cpu_multi;
 int cpu_iscyrix;
 int cpu_16bitbus;
 int cpu_busspeed;
-int cpu_hasrdtsc;
-int cpu_hasMMX, cpu_hasMSR;
-int cpu_hasCR4;
-int cpu_hasCX8;
-int cpu_hasVME;
 int cpu_use_dynarec;
 int cpu_cyrix_alignment;
 
@@ -90,6 +97,8 @@ int cpu_waitstates;
 int cpu_cache_int_enabled, cpu_cache_ext_enabled;
 
 int is386;
+int is486;
+int CPUID;
 
 uint64_t tsc = 0;
 
@@ -113,375 +122,64 @@ static struct
         uint64_t fcr2, fcr3;
 } msr;
 
-/*Available cpuspeeds :
-        0 = 16 MHz
-        1 = 20 MHz
-        2 = 25 MHz
-        3 = 33 MHz
-        4 = 40 MHz
-        5 = 50 MHz
-        6 = 66 MHz
-        7 = 75 MHz
-        8 = 80 MHz
-        9 = 90 MHz
-        10 = 100 MHz
-        11 = 120 MHz
-        12 = 133 MHz
-        13 = 150 MHz
-        14 = 160 MHz
-        15 = 166 MHz
-        16 = 180 MHz
-        17 = 200 MHz
-*/
-
-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/8",       CPU_8088,  1,  8000000,   1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8088/10",      CPU_8088,  2, 10000000,   1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8088/12",      CPU_8088,  3, 12000000,   1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8088/16",      CPU_8088,  4, 16000000,   1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_pcjr[] =
-{
-        /*8088 PCjr*/
-        {"8088/4.77",    CPU_8088,  0,  4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_europc[] =
-{
-         /*8088 EuroPC*/
-         {"8088/4.77",    CPU_8088,  0,  4772728,   1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-         {"8088/7.16",    CPU_8088,  1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-         {"8088/9.54",    CPU_8088,  1,  4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-         {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_8086[] =
-{
-        /*8086 standard*/
-        {"8086/7.16",    CPU_8086,  1, 14318184/2,     1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8086/8",       CPU_8086,  1,  8000000,       1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8086/9.54",    CPU_8086,  1,  4772728*2,     1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8086/10",      CPU_8086,  2, 10000000,       1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8086/12",      CPU_8086,  3, 12000000,       1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"8086/16",      CPU_8086,  4, 16000000,       1, 0, 0, 0, 0, 0, 0,0,0,0, 2},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_pc1512[] =
-{
-        /*8086 Amstrad*/
-        {"8086/8",       CPU_8086,  1,  8000000,       1, 0, 0, 0, 0, 0, 0,0,0,0, 1},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_286[] =
-{
-        /*286*/
-        {"286/6",        CPU_286,   0,  6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1},
-        {"286/8",        CPU_286,   1,  8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1},
-        {"286/10",       CPU_286,   2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1},
-        {"286/12",       CPU_286,   3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2},
-        {"286/16",       CPU_286,   4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2},
-        {"286/20",       CPU_286,   5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3},
-        {"286/25",       CPU_286,   6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_ibmat[] =
-{
-        /*286*/
-        {"286/6",        CPU_286,   0,  6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1},
-        {"286/8",        CPU_286,   0,  8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_ibmxt286[] =
-{
-        /*286*/
-        {"286/6",        CPU_286,   0,  6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_ps1_m2011[] =
-{
-        /*286*/
-        {"286/10",       CPU_286,   2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_ps2_m30_286[] =
-{
-        /*286*/
-        {"286/10",       CPU_286,   2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1},
-        {"286/12",       CPU_286,   3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2},
-        {"286/16",       CPU_286,   4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2},
-        {"286/20",       CPU_286,   5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3},
-        {"286/25",       CPU_286,   6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3},
-        {"",             -1,        0, 0, 0, 0}
-};
-
-CPU cpus_i386SX[] =
-{
-        /*i386SX*/
-        {"i386SX/16",    CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2},
-        {"i386SX/20",    CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3},
-        {"i386SX/25",    CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3},
-        {"i386SX/33",    CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4},
-        {"",             -1,        0, 0, 0}
-};
-
-CPU cpus_i386DX[] =
-{
-        /*i386DX*/
-        {"i386DX/16",    CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2},
-        {"i386DX/20",    CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3},
-        {"i386DX/25",    CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3},
-        {"i386DX/33",    CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4},
-        {"",             -1,        0, 0, 0}
-};
-
-CPU cpus_acer[] =
-{
-        /*i386SX*/
-        {"i386SX/25",    CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,4,4, 3},
-        {"",             -1,        0, 0, 0}
-};
-
-CPU cpus_Am386SX[] =
-{
-        /*Am386*/
-        {"Am386SX/16",   CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2},
-        {"Am386SX/20",   CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3},
-        {"Am386SX/25",   CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3},
-        {"Am386SX/33",   CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4},
-        {"Am386SX/40",   CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5},
-        {"",             -1,        0, 0, 0}
-};
-
-CPU cpus_Am386DX[] =
-{
-        /*Am386*/
-        {"Am386DX/25",   CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3},
-        {"Am386DX/33",   CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4},
-        {"Am386DX/40",   CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5},
-        {"",             -1,        0, 0, 0}
-};
-
-CPU cpus_486SLC[] =
-{
-        /*Cx486SLC*/
-        {"Cx486SLC/20",  CPU_486SLC, 1, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3},
-        {"Cx486SLC/25",  CPU_486SLC, 2, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3},
-        {"Cx486SLC/33",  CPU_486SLC, 3, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4},
-        {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 2*2},
-        {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 2*3},
-        {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 2*3},
-        {"",             -1,        0, 0, 0}
-};
-
-CPU cpus_486DLC[] =
-{
-        /*Cx486DLC*/
-        {"Cx486DLC/25",  CPU_486DLC, 2, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4,4,3,3, 3},
-        {"Cx486DLC/33",  CPU_486DLC, 3, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6,6,3,3, 4},
-        {"Cx486DLC/40",  CPU_486DLC, 4, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7,7,3,3, 5},
-        {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6,6,6,6, 2*2},
-        {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 2*3},
-        {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 2*3},
-        {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 2*4},
-        {"",             -1,        0, 0, 0}
-};
-
-CPU cpus_i486[] =
+void cpu_set_edx()
 {
-        /*i486*/
-        {"i486SX/16",    CPU_i486SX, 0,  16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3,3,3,3, 2},
-        {"i486SX/20",    CPU_i486SX, 1,  20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3},
-        {"i486SX/25",    CPU_i486SX, 2,  25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3},
-        {"i486SX/33",    CPU_i486SX, 3,  33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4},
-        {"i486SX2/50",   CPU_i486SX, 5,  50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3},
-        {"i486DX/25",    CPU_i486DX, 2,  25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3},
-        {"i486DX/33",    CPU_i486DX, 3,  33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4},
-        {"i486DX/50",    CPU_i486DX, 5,  50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 6},
-        {"i486DX2/40",   CPU_i486DX, 4,  40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3},
-        {"i486DX2/50",   CPU_i486DX, 5,  50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3},
-        {"i486DX2/66",   CPU_i486DX, 6,  66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4},
-        {"iDX4/75",      CPU_iDX4,   7,  75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 3*3}, /*CPUID available on DX4, >= 75 MHz*/
-        {"iDX4/100",     CPU_iDX4,  10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*4}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/
-        {"Pentium OverDrive/63",       CPU_PENTIUM,     6,  62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, (5*3)/2},
-        {"Pentium OverDrive/83",       CPU_PENTIUM,     8,  83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, (5*4)/2},
-        {"",             -1,        0, 0, 0}
-};
+        EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset;
+}
 
-CPU cpus_Am486[] =
+int fpu_get_type(int model, int manu, int cpu, const char *internal_name)
 {
-        /*Am486/5x86*/
-        {"Am486SX/33",   CPU_Am486SX,  3,  33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4},
-        {"Am486SX/40",   CPU_Am486SX,  4,  40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5},
-        {"Am486SX2/50",  CPU_Am486SX,  5,  50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/
-        {"Am486SX2/66",  CPU_Am486SX,  6,  66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/
-        {"Am486DX/33",   CPU_Am486DX,  3,  33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4},
-        {"Am486DX/40",   CPU_Am486DX,  4,  40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5},
-        {"Am486DX2/50",  CPU_Am486DX,  5,  50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3},
-        {"Am486DX2/66",  CPU_Am486DX,  6,  66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4},
-        {"Am486DX2/80",  CPU_Am486DX,  8,  80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14,6,6, 2*5},
-        {"Am486DX4/75",  CPU_Am486DX,  7,  75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 3*3},
-        {"Am486DX4/90",  CPU_Am486DX,  9,  90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4},
-        {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4},
-        {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 3*5},
-        {"Am5x86/P75",   CPU_Am486DX, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 4*4},
-        {"Am5x86/P75+",  CPU_Am486DX, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 4*5},
-        {"",             -1,        0, 0, 0}
-};
+        CPU *cpu_s = &models[model].cpu[manu].cpus[cpu];
+        const FPU *fpus = cpu_s->fpus;
+        int fpu_type = fpus[0].type;
+        int c = 0;
+        
+        while (fpus[c].internal_name)
+        {
+                if (!strcmp(internal_name, fpus[c].internal_name))
+                        fpu_type = fpus[c].type;
+                c++;
+        }
+        
+        return fpu_type;
+}
 
-CPU cpus_Cx486[] =
+const char *fpu_get_internal_name(int model, int manu, int cpu, int type)
 {
-        /*Cx486/5x86*/
-        {"Cx486S/25",    CPU_Cx486S,   2,  25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3},
-        {"Cx486S/33",    CPU_Cx486S,   3,  33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4},
-        {"Cx486S/40",    CPU_Cx486S,   4,  40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5},
-        {"Cx486DX/33",   CPU_Cx486DX,  3,  33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4},
-        {"Cx486DX/40",   CPU_Cx486DX,  4,  40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5},
-        {"Cx486DX2/50",  CPU_Cx486DX,  5,  50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3},
-        {"Cx486DX2/66",  CPU_Cx486DX,  6,  66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4},
-        {"Cx486DX2/80",  CPU_Cx486DX,  8,  80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16, 2*5},
-        {"Cx486DX4/75",  CPU_Cx486DX,  7,  75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 3*3},
-        {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4},
-        {"Cx5x86/100",   CPU_Cx5x86,  10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4},
-        {"Cx5x86/120",   CPU_Cx5x86,  11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 3*5},
-        {"Cx5x86/133",   CPU_Cx5x86,  12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 4*4},
-        {"",             -1,        0, 0, 0}
-};
+        CPU *cpu_s = &models[model].cpu[manu].cpus[cpu];
+        const FPU *fpus = cpu_s->fpus;
+        int c = 0;
 
-#if 0
- CPU cpus_6x86[] =
- {
-          /*Cyrix 6x86*/
-          {"6x86-P90",  CPU_Cx6x86, 17,     80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 2*5},
-          {"6x86-PR120+",  CPU_Cx6x86, 17,   100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*6},
-          {"6x86-PR133+",  CPU_Cx6x86, 17,   110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*7},
-          {"6x86-PR150+",  CPU_Cx6x86, 17,   120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7},
-          {"6x86-PR166+",  CPU_Cx6x86, 17,   133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8},
-          {"6x86-PR200+",  CPU_Cx6x86, 17,   150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*9},
-
-          /*Cyrix 6x86L*/
-          {"6x86L-PR133+",  CPU_Cx6x86L, 19,   110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*7},
-          {"6x86L-PR150+",  CPU_Cx6x86L, 19,   120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7},
-          {"6x86L-PR166+",  CPU_Cx6x86L, 19,   133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8},
-          {"6x86L-PR200+",  CPU_Cx6x86L, 19,   150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*9},
-          
-          /*Cyrix 6x86MX*/
-          {"6x86MX-PR166",  CPU_Cx6x86MX, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8},
-          {"6x86MX-PR200",  CPU_Cx6x86MX, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-          {"6x86MX-PR233",  CPU_Cx6x86MX, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*9)/2},
-          {"6x86MX-PR266",  CPU_Cx6x86MX, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, (5*10)/2},
-          {"6x86MX-PR300",  CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7, (7*8)/2},
-          {"6x86MX-PR333",  CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9, 3*10},
-          {"6x86MX-PR366",  CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 3*10},
-          {"6x86MX-PR400",  CPU_Cx6x86MX, 18, 285000000, 3, 31666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*11},
-          {"",             -1,        0, 0, 0}
- };
-
-CPU cpus_WinChip[] =
-{
-        /*IDT WinChip*/
-        {"WinChip 75",   CPU_WINCHIP,  7,  75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, (3*6)/2},
-        {"WinChip 90",   CPU_WINCHIP,  9,  90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, (3*7)/2},
-        {"WinChip 100",  CPU_WINCHIP, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, (3*8)/2},
-        {"WinChip 120",  CPU_WINCHIP, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*7},
-        {"WinChip 133",  CPU_WINCHIP, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*8},
-        {"WinChip 150",  CPU_WINCHIP, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, (5*7)/2},
-        {"WinChip 166",  CPU_WINCHIP, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"WinChip 180",  CPU_WINCHIP, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*7},
-        {"WinChip 200",  CPU_WINCHIP, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*8},
-        {"WinChip 225",  CPU_WINCHIP, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*9},
-        {"WinChip 240",  CPU_WINCHIP, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 4*7},
-        {"",             -1,        0, 0, 0}
-};
+        while (fpus[c].internal_name)
+        {
+                if (fpus[c].type == type)
+                        return fpus[c].internal_name;
+                c++;
+        }
 
-CPU cpus_Pentium5V[] =
-{
-        /*Intel Pentium (5V, socket 4)*/
-        {"Pentium 60",       CPU_PENTIUM,     6,  60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7},
-        {"Pentium 66",       CPU_PENTIUM,     6,  66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8},
-        {"Pentium OverDrive 120",CPU_PENTIUM,    14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7},
-        {"Pentium OverDrive 133",CPU_PENTIUM,    16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8},
-        {"",             -1,        0, 0, 0}
-};
+        return fpus[0].internal_name;
+}
 
-CPU cpus_PentiumS5[] =
+const char *fpu_get_name_from_index(int model, int manu, int cpu, int c)
 {
-        /*Intel Pentium (Socket 5)*/
-        {"Pentium 75",       CPU_PENTIUM,     9,  75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, (3*6)/2},
-        {"Pentium 90",       CPU_PENTIUM,    12,  90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*7)/2},
-        {"Pentium 100/50",   CPU_PENTIUM,    13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*6},
-        {"Pentium 100/66",   CPU_PENTIUM,    13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*8)/2},
-        {"Pentium 120",      CPU_PENTIUM,    14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7},
-        {"Pentium 133",      CPU_PENTIUM,    16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8},
-        {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2},
-        {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2},
-        {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"Pentium OverDrive MMX 125",       CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2},
-        {"Pentium OverDrive MMX 150/60",    CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2},
-        {"Pentium OverDrive MMX 166",       CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"Pentium OverDrive MMX 180",       CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*7},
-        {"Pentium OverDrive MMX 200",       CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8},
-        {"",             -1,        0, 0, 0}
-};
+        CPU *cpu_s = &models[model].cpu[manu].cpus[cpu];
+        const FPU *fpus = cpu_s->fpus;
+        
+        return fpus[c].name;
+}
 
-CPU cpus_Pentium[] =
+int fpu_get_type_from_index(int model, int manu, int cpu, int c)
 {
-        /*Intel Pentium*/
-        {"Pentium 75",       CPU_PENTIUM,     9,  75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, (3*6)/2},
-        {"Pentium 90",       CPU_PENTIUM,    12,  90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*7)/2},
-        {"Pentium 100/50",   CPU_PENTIUM,    13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*6},
-        {"Pentium 100/66",   CPU_PENTIUM,    13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*8)/2},
-        {"Pentium 120",      CPU_PENTIUM,    14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7},
-        {"Pentium 133",      CPU_PENTIUM,    16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8},
-        {"Pentium 150",      CPU_PENTIUM,    17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2},
-        {"Pentium 166",      CPU_PENTIUM,    19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"Pentium 200",      CPU_PENTIUM,    21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8},
-        {"Pentium MMX 166",  CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"Pentium MMX 200",  CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8},
-        {"Pentium MMX 233",  CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, (7*8)/2},
-        {"Mobile Pentium MMX 120",  CPU_PENTIUMMMX, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7},
-        {"Mobile Pentium MMX 133",  CPU_PENTIUMMMX, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8},
-        {"Mobile Pentium MMX 150",  CPU_PENTIUMMMX, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2},
-        {"Mobile Pentium MMX 166",  CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"Mobile Pentium MMX 200",  CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8},
-        {"Mobile Pentium MMX 233",  CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, (7*8)/2},
-        {"Mobile Pentium MMX 266",  CPU_PENTIUMMMX, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 4*8},
-        {"Mobile Pentium MMX 300",  CPU_PENTIUMMMX, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, (9*8)/2},
-        {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2},
-        {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2},
-        {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"Pentium OverDrive MMX 125",       CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2},
-        {"Pentium OverDrive MMX 150/60",    CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2},
-        {"Pentium OverDrive MMX 166",       CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2},
-        {"Pentium OverDrive MMX 180",       CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*7},
-        {"Pentium OverDrive MMX 200",       CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8},
-        {"",             -1,        0, 0, 0}
-};
-#endif
+        CPU *cpu_s = &models[model].cpu[manu].cpus[cpu];
+        const FPU *fpus = cpu_s->fpus;
 
-void cpu_set_edx()
-{
-        EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset;
+        return fpus[c].type;
 }
 
-void cpu_set(int speedmultiplier)
+void cpu_set()
 {
         CPU *cpu_s;
-        
+
         if (!models[model].cpu[cpu_manufacturer].cpus)
         {
                 /*CPU is invalid, set to default*/
@@ -491,36 +189,26 @@ void cpu_set(int speedmultiplier)
         
         cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu];
 
-               int rspeed = cpu_s->rspeed;
-               cpu_multi = cpu_s->multi;
-               if (speedmultiplier > 0) {
-                       rspeed = rspeed + (int32_t)(rspeed * (int64_t)speedmultiplier / 1000);
-                       cpu_multi += speedmultiplier / 1000;
-               }
-
         CPUID    = cpu_s->cpuid_model;
         cpuspeed = cpu_s->speed;
         is8086   = (cpu_s->cpu_type > CPU_8088);
         is386    = (cpu_s->cpu_type >= CPU_386SX);
         is486    = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC);
-        hasfpu   = (cpu_s->cpu_type >= CPU_i486DX);
+        hasfpu   = (fpu_type != FPU_NONE);
+
          cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1);
         cpu_16bitbus = (cpu_s->cpu_type == CPU_286 || cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC);
-        if (cpu_multi)
-           cpu_busspeed = rspeed / cpu_multi;
-        cpu_hasrdtsc = 0;
-        cpu_hasMMX = 0;
-        cpu_hasMSR = 0;
-        cpu_hasCR4 = 0;
-        cpu_hasCX8 = 0;
+        if (cpu_s->multi) 
+           cpu_busspeed = cpu_s->rspeed / cpu_s->multi;
+        cpu_multi = cpu_s->multi;
         ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0;
         has_vlb = (cpu_s->cpu_type >= CPU_i486SX) && (cpu_s->cpu_type <= CPU_Cx5x86);
 
-        cpu_turbo_speed = rspeed;
+        cpu_turbo_speed = cpu_s->rspeed;
         if (cpu_s->cpu_type < CPU_286)
                 cpu_nonturbo_speed = 4772728;
-        else if (rspeed < 8000000)
-                cpu_nonturbo_speed = rspeed;
+        else if (cpu_s->rspeed < 8000000)
+                cpu_nonturbo_speed = cpu_s->rspeed;
         else
                 cpu_nonturbo_speed = 8000000;
 
@@ -528,12 +216,11 @@ void cpu_set(int speedmultiplier)
   
         isa_cycles = cpu_s->atclk_div;      
         
-        if (rspeed <= 8000000)
+        if (cpu_s->rspeed <= 8000000)
                 cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles;
         else
-                cpu_rom_prefetch_cycles = rspeed / 1000000;
+                cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000;
 
-#if 0
         if (cpu_s->pci_speed)
         {
                 pci_nonburst_time = 4*cpu_s->rspeed / cpu_s->pci_speed;
@@ -545,7 +232,6 @@ void cpu_set(int speedmultiplier)
                 pci_burst_time = 1;
         }
         pclog("PCI burst=%i nonburst=%i\n", pci_burst_time, pci_nonburst_time);
-#endif
 
         if (cpu_iscyrix)
            io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL);
@@ -555,15 +241,15 @@ void cpu_set(int speedmultiplier)
         pclog("hasfpu - %i\n",hasfpu);
         pclog("is486 - %i  %i\n",is486,cpu_s->cpu_type);
 
-               x86_setopcodes(ops_386, ops_386_0f, NULL, NULL);// dynarec_ops_386, dynarec_ops_386_0f);
+        x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f);
         x86_opcodes_REPE = ops_REPE;
         x86_opcodes_REPNE = ops_REPNE;
-
-#if 0
-               x86_dynarec_opcodes_REPE = dynarec_ops_REPE;
+        x86_opcodes_3DNOW = ops_3DNOW;
+        x86_dynarec_opcodes_REPE = dynarec_ops_REPE;
         x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE;
+        x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOW;
 
-               if (hasfpu)
+        if (hasfpu)
         {
                 x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16;
                 x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32;
@@ -602,7 +288,7 @@ void cpu_set(int speedmultiplier)
                 x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32;
         }
         codegen_timing_set(&codegen_timing_486);
-#endif
+
         if (hasfpu)
         {
                 x86_opcodes_d8_a16 = ops_fpu_d8_a16;
@@ -652,9 +338,9 @@ void cpu_set(int speedmultiplier)
                 case CPU_8088:
                 case CPU_8086:
                 break;
-
-                               case CPU_286:
-                               x86_setopcodes(ops_286, ops_286_0f, NULL, NULL); // dynarec_ops_286, dynarec_ops_286_0f);
+                
+                case CPU_286:
+                x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f);
                 timing_rr  = 2;   /*register dest - register src*/
                 timing_rm  = 7;   /*register dest - memory src*/
                 timing_mr  = 7;   /*memory dest   - register src*/
@@ -747,7 +433,7 @@ void cpu_set(int speedmultiplier)
                 timing_jmp_pm_gate = 45;
                 break;
                 
-                               case CPU_486SLC:
+                case CPU_486SLC:
                 timing_rr  = 1; /*register dest - register src*/
                 timing_rm  = 3; /*register dest - memory src*/
                 timing_mr  = 5; /*memory dest   - register src*/
@@ -814,8 +500,7 @@ void cpu_set(int speedmultiplier)
                 break;
 
                 case CPU_iDX4:
-                cpu_hasCR4 = 1;
-                cpu_hasVME = 1;
+                cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME;
                 cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME;
                 case CPU_i486SX:
                 case CPU_i486DX:
@@ -916,7 +601,7 @@ void cpu_set(int speedmultiplier)
                 timing_jmp_pm_gate = 37;
                 timing_misaligned = 3;
                 break;
-#if 0               
+                
                 case CPU_Cx5x86:
                 timing_rr  = 1; /*register dest - register src*/
                 timing_rm  = 1; /*register dest - memory src*/
@@ -961,10 +646,8 @@ void cpu_set(int speedmultiplier)
                 timing_mml = 3;
                 timing_bt  = 3-1; /*branch taken*/
                 timing_bnt = 1; /*branch not taken*/
-                cpu_hasrdtsc = 1;
-                msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
-                cpu_hasMMX = cpu_hasMSR = 1;
-                cpu_hasCR4 = 1;
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4;
+                msr.fcr = (1 << 8) | (1 << 16);
                 cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE;
                 /*unknown*/
                 timing_int_rm       = 26;
@@ -990,6 +673,44 @@ void cpu_set(int speedmultiplier)
                 codegen_timing_set(&codegen_timing_winchip);
                 break;
 
+                case CPU_WINCHIP2:
+                x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f);
+                timing_rr  = 1; /*register dest - register src*/
+                timing_rm  = 2; /*register dest - memory src*/
+                timing_mr  = 2; /*memory dest   - register src*/
+                timing_mm  = 3;
+                timing_rml = 2; /*register dest - memory src long*/
+                timing_mrl = 2; /*memory dest   - register src long*/
+                timing_mml = 3;
+                timing_bt  = 3-1; /*branch taken*/
+                timing_bnt = 1; /*branch not taken*/
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW;
+                msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21);
+                cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE;
+                /*unknown*/
+                timing_int_rm       = 26;
+                timing_int_v86      = 82;
+                timing_int_pm       = 44;
+                timing_int_pm_outer = 71;
+                timing_iret_rm       = 7;
+                timing_iret_v86      = 26;
+                timing_iret_pm       = 10;
+                timing_iret_pm_outer = 26;
+                timing_call_rm = 4;
+                timing_call_pm = 15;
+                timing_call_pm_gate = 26;
+                timing_call_pm_gate_inner = 35;
+                timing_retf_rm       = 4;
+                timing_retf_pm       = 7;
+                timing_retf_pm_outer = 23;
+                timing_jmp_rm      = 5;
+                timing_jmp_pm      = 7;
+                timing_jmp_pm_gate = 17;
+                timing_misaligned = 2;
+                cpu_cyrix_alignment = 1;
+                codegen_timing_set(&codegen_timing_winchip2);
+                break;
+
                 case CPU_PENTIUM:
                 x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f);
                 timing_rr  = 1; /*register dest - register src*/
@@ -1021,12 +742,8 @@ void cpu_set(int speedmultiplier)
                 timing_jmp_pm      = 3;
                 timing_jmp_pm_gate = 18;
                 timing_misaligned = 3;
-                cpu_hasrdtsc = 1;
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME;
                 msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
-                cpu_hasMMX = 0;
-                cpu_hasMSR = 1;
-                cpu_hasCR4 = 1;
-                cpu_hasVME = 1;
                 cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE;
                 codegen_timing_set(&codegen_timing_pentium);
                 break;
@@ -1062,12 +779,8 @@ void cpu_set(int speedmultiplier)
                 timing_jmp_pm      = 3;
                 timing_jmp_pm_gate = 18;
                 timing_misaligned = 3;
-                cpu_hasrdtsc = 1;
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX;
                 msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
-                cpu_hasMMX = 1;
-                cpu_hasMSR = 1;
-                cpu_hasCR4 = 1;
-                cpu_hasVME = 1;
                 cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE;
                 codegen_timing_set(&codegen_timing_pentium);
                 break;
@@ -1103,11 +816,8 @@ void cpu_set(int speedmultiplier)
                 timing_jmp_pm_gate = 14;
                 timing_misaligned = 2;
                 cpu_cyrix_alignment = 1;
-                cpu_hasrdtsc = 1;
+                cpu_features = CPU_FEATURE_RDTSC;
                 msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
-                cpu_hasMMX = 0;
-                cpu_hasMSR = 0;
-                cpu_hasCR4 = 0;
                codegen_timing_set(&codegen_timing_686);
                CPUID = 0; /*Disabled on powerup by default*/
                 break;
@@ -1143,11 +853,8 @@ void cpu_set(int speedmultiplier)
                 timing_jmp_pm_gate = 14;
                 timing_misaligned = 2;
                 cpu_cyrix_alignment = 1;
-                cpu_hasrdtsc = 1;
+                cpu_features = CPU_FEATURE_RDTSC;
                 msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
-                cpu_hasMMX = 0;
-                cpu_hasMSR = 0;
-                cpu_hasCR4 = 0;
                codegen_timing_set(&codegen_timing_686);
                ccr4 = 0x80;
                 break;
@@ -1164,11 +871,8 @@ void cpu_set(int speedmultiplier)
                 timing_mml = 2;
                 timing_bt  = 5-1; /*branch taken*/
                 timing_bnt = 1; /*branch not taken*/
-                cpu_hasrdtsc = 1;
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4;
                 msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
-                cpu_hasMMX = 0;
-                cpu_hasMSR = 1;
-                cpu_hasCR4 = 1;
                 cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE;
                codegen_timing_set(&codegen_timing_686);
                 break;
@@ -1217,19 +921,116 @@ void cpu_set(int speedmultiplier)
                 timing_jmp_pm_gate = 14;
                 timing_misaligned = 2;
                 cpu_cyrix_alignment = 1;
-                cpu_hasrdtsc = 1;
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_MMX;
                 msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
-                cpu_hasMMX = 1;
-                cpu_hasMSR = 1;
-                cpu_hasCR4 = 1;
                 cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE;
                codegen_timing_set(&codegen_timing_686);
                ccr4 = 0x80;
                 break;
-#endif
+
+                case CPU_K6:
+                x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f);
+                timing_rr  = 1; /*register dest - register src*/
+                timing_rm  = 2; /*register dest - memory src*/
+                timing_mr  = 3; /*memory dest   - register src*/
+                timing_mm  = 3;
+                timing_rml = 2; /*register dest - memory src long*/
+                timing_mrl = 3; /*memory dest   - register src long*/
+                timing_mml = 3;
+                timing_bt  = 0; /*branch taken*/
+                timing_bnt = 1; /*branch not taken*/
+                timing_int = 6;
+                timing_int_rm       = 11;
+                timing_int_v86      = 54;
+                timing_int_pm       = 25;
+                timing_int_pm_outer = 42;
+                timing_iret_rm       = 7;
+                timing_iret_v86      = 27; /*unknown*/
+                timing_iret_pm       = 10;
+                timing_iret_pm_outer = 27;
+                timing_call_rm = 4;
+                timing_call_pm = 4;
+                timing_call_pm_gate = 22;
+                timing_call_pm_gate_inner = 44;
+                timing_retf_rm       = 4;
+                timing_retf_pm       = 4;
+                timing_retf_pm_outer = 23;
+                timing_jmp_rm      = 3;
+                timing_jmp_pm      = 3;
+                timing_jmp_pm_gate = 18;
+                timing_misaligned = 3;
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX;
+                msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
+                cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE;
+                codegen_timing_set(&codegen_timing_k6);
+                break;
+
+                case CPU_K6_2:
+                case CPU_K6_3:
+                case CPU_K6_2P:
+                case CPU_K6_3P:
+                x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f);
+                timing_rr  = 1; /*register dest - register src*/
+                timing_rm  = 2; /*register dest - memory src*/
+                timing_mr  = 3; /*memory dest   - register src*/
+                timing_mm  = 3;
+                timing_rml = 2; /*register dest - memory src long*/
+                timing_mrl = 3; /*memory dest   - register src long*/
+                timing_mml = 3;
+                timing_bt  = 0; /*branch taken*/
+                timing_bnt = 1; /*branch not taken*/
+                timing_int = 6;
+                timing_int_rm       = 11;
+                timing_int_v86      = 54;
+                timing_int_pm       = 25;
+                timing_int_pm_outer = 42;
+                timing_iret_rm       = 7;
+                timing_iret_v86      = 27; /*unknown*/
+                timing_iret_pm       = 10;
+                timing_iret_pm_outer = 27;
+                timing_call_rm = 4;
+                timing_call_pm = 4;
+                timing_call_pm_gate = 22;
+                timing_call_pm_gate_inner = 44;
+                timing_retf_rm       = 4;
+                timing_retf_pm       = 4;
+                timing_retf_pm_outer = 23;
+                timing_jmp_rm      = 3;
+                timing_jmp_pm      = 3;
+                timing_jmp_pm_gate = 18;
+                timing_misaligned = 3;
+                cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX | CPU_FEATURE_3DNOW;
+                msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) |  (1 << 16) | (1 << 19) | (1 << 21);
+                cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE;
+                codegen_timing_set(&codegen_timing_k6);
+                break;
+
                 default:
                 fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type);
         }
+        
+        switch (fpu_type)
+        {
+                case FPU_NONE:
+                break;
+
+                case FPU_8087:
+                x87_timings = x87_timings_8087;
+                break;
+
+                case FPU_287:
+                x87_timings = x87_timings_287;
+                break;
+
+                case FPU_287XL:
+                case FPU_387:
+                x87_timings = x87_timings_387;
+                break;
+                
+                default:
+                x87_timings = x87_timings_486;
+                break;
+        }
 }
 
 void cpu_CPUID()
@@ -1320,7 +1121,7 @@ void cpu_CPUID()
                         else
                         {
                                 EBX = 0x746e6543; /*CentaurHauls*/
-                                ECX = 0x736c7561;                        
+                                ECX = 0x736c7561;
                                 EDX = 0x48727561;
                         }
                 }
@@ -1329,14 +1130,74 @@ void cpu_CPUID()
                         EAX = 0x540;
                         EBX = ECX = 0;
                         EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
-                       if (cpu_hasCX8) 
-                               EDX |= CPUID_CMPXCHG8B;                                                 
+                       if (cpu_has_feature(CPU_FEATURE_CX8))
+                               EDX |= CPUID_CMPXCHG8B;
                         if (msr.fcr & (1 << 9))
                                 EDX |= CPUID_MMX;
                 }
                 else
                         EAX = EBX = ECX = EDX = 0;
                 break;
+                
+                case CPU_WINCHIP2:
+                switch (EAX)
+                {
+                        case 0:
+                        EAX = 1;
+                        if (msr.fcr2 & (1 << 14))
+                        {
+                                EBX = msr.fcr3 >> 32;
+                                ECX = msr.fcr3 & 0xffffffff;
+                                EDX = msr.fcr2 >> 32;
+                        }
+                        else
+                        {
+                                EBX = 0x746e6543; /*CentaurHauls*/
+                                ECX = 0x736c7561;                        
+                                EDX = 0x48727561;
+                        }
+                        break;
+                        case 1:
+                        EAX = 0x580;
+                        EBX = ECX = 0;
+                        EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
+                       if (cpu_has_feature(CPU_FEATURE_CX8))
+                               EDX |= CPUID_CMPXCHG8B;                                                 
+                        if (msr.fcr & (1 << 9))
+                                EDX |= CPUID_MMX;
+                        break;
+                        case 0x80000000:
+                        EAX = 0x80000005;
+                        break;
+                        case 0x80000001:
+                        EAX = 0x580;
+                        EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR;
+                       if (cpu_has_feature(CPU_FEATURE_CX8))
+                               EDX |= CPUID_CMPXCHG8B;
+                        if (msr.fcr & (1 << 9))
+                                EDX |= CPUID_MMX;
+                       if (cpu_has_feature(CPU_FEATURE_3DNOW))
+                                EDX |= CPUID_3DNOW;
+                        break;
+                                
+                        case 0x80000002: /*Processor name string*/
+                        EAX = 0x20544449; /*IDT WinChip 2-3D*/
+                        EBX = 0x436e6957;
+                        ECX = 0x20706968;
+                        EDX = 0x44332d32;
+                        break;
+                        
+                        case 0x80000005: /*Cache information*/
+                        EBX = 0x08800880; /*TLBs*/
+                        ECX = 0x20040120; /*L1 data cache*/
+                        EDX = 0x20020120; /*L1 instruction cache*/
+                        break;
+                        
+                        default:
+                        EAX = EBX = ECX = EDX = 0;
+                        break;
+                }
+                break;
 
                 case CPU_PENTIUM:
                 if (!EAX)
@@ -1451,6 +1312,220 @@ void cpu_CPUID()
                         EAX = EBX = ECX = EDX = 0;
                 break;
 
+                case CPU_K6:
+                switch (EAX)
+                {
+                        case 0:
+                        EAX = 1;
+                        EBX = 0x68747541; /*AuthenticAMD*/
+                        ECX = 0x444d4163;
+                        EDX = 0x69746e65;
+                        break;
+                        case 1:
+                        EAX = CPUID;
+                        EBX = ECX = 0;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX;
+                        break;
+                        case 0x80000000:
+                        EAX = 0x80000005;
+                        break;
+                        case 0x80000001:
+                        EAX = CPUID+0x100;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX;
+                        break;
+
+                        case 0x80000002: /*Processor name string*/
+                        EAX = 0x2d444d41; /*AMD-K6tm w/ mult*/
+                        EBX = 0x6d74364b;
+                        ECX = 0x202f7720;
+                        EDX = 0x746c756d;
+                        break;
+
+                        case 0x80000003: /*Processor name string*/
+                        EAX = 0x64656d69; /*imedia extension*/
+                        EBX = 0x65206169;
+                        ECX = 0x6e657478;
+                        EDX = 0x6e6f6973;
+                        break;
+
+                        case 0x80000004: /*Processor name string*/
+                        EAX = 0x00000073; /*s*/
+                        EBX = 0x00000000;
+                        ECX = 0x00000000;
+                        EDX = 0x00000000;
+                        break;
+
+                        case 0x80000005: /*Cache information*/
+                        EBX = 0x02800140; /*TLBs*/
+                        ECX = 0x20020220; /*L1 data cache*/
+                        EDX = 0x20020220; /*L1 instruction cache*/
+                        break;
+
+                        default:
+                        EAX = EBX = ECX = EDX = 0;
+                        break;
+                }
+                break;
+
+                case CPU_K6_2:
+                switch (EAX)
+                {
+                        case 0:
+                        EAX = 1;
+                        EBX = 0x68747541; /*AuthenticAMD*/
+                        ECX = 0x444d4163;
+                        EDX = 0x69746e65;
+                        break;
+                        case 1:
+                        EAX = CPUID;
+                        EBX = ECX = 0;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX;
+                        break;
+                        case 0x80000000:
+                        EAX = 0x80000005;
+                        break;
+                        case 0x80000001:
+                        EAX = CPUID+0x100;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW;
+                        break;
+
+                        case 0x80000002: /*Processor name string*/
+                        EAX = 0x2d444d41; /*AMD-K6(tm) 3D pr*/
+                        EBX = 0x7428364b;
+                        ECX = 0x3320296d;
+                        EDX = 0x72702044;
+                        break;
+
+                        case 0x80000003: /*Processor name string*/
+                        EAX = 0x7365636f; /*ocessor*/
+                        EBX = 0x00726f73;
+                        ECX = 0x00000000;
+                        EDX = 0x00000000;
+                        break;
+
+                        case 0x80000005: /*Cache information*/
+                        EBX = 0x02800140; /*TLBs*/
+                        ECX = 0x20020220; /*L1 data cache*/
+                        EDX = 0x20020220; /*L1 instruction cache*/
+                        break;
+
+                        default:
+                        EAX = EBX = ECX = EDX = 0;
+                        break;
+                }
+                break;
+
+                case CPU_K6_3:
+                switch (EAX)
+                {
+                        case 0:
+                        EAX = 1;
+                        EBX = 0x68747541; /*AuthenticAMD*/
+                        ECX = 0x444d4163;
+                        EDX = 0x69746e65;
+                        break;
+                        case 1:
+                        EAX = CPUID;
+                        EBX = ECX = 0;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX;
+                        break;
+                        case 0x80000000:
+                        EAX = 0x80000006;
+                        break;
+                        case 0x80000001:
+                        EAX = CPUID+0x100;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW;
+                        break;
+
+                        case 0x80000002: /*Processor name string*/
+                        EAX = 0x2d444d41; /*AMD-K6(tm) 3D+ P*/
+                        EBX = 0x7428364b;
+                        ECX = 0x3320296d;
+                        EDX = 0x50202b44;
+                        break;
+
+                        case 0x80000003: /*Processor name string*/
+                        EAX = 0x65636f72; /*rocessor*/
+                        EBX = 0x726f7373;
+                        ECX = 0x00000000;
+                        EDX = 0x00000000;
+                        break;
+
+                        case 0x80000005: /*Cache information*/
+                        EBX = 0x02800140; /*TLBs*/
+                        ECX = 0x20020220; /*L1 data cache*/
+                        EDX = 0x20020220; /*L1 instruction cache*/
+                        break;
+
+                        case 0x80000006: /*L2 Cache information*/
+                        ECX = 0x01004220;
+                        break;
+                        
+                        default:
+                        EAX = EBX = ECX = EDX = 0;
+                        break;
+                }
+                break;
+
+                case CPU_K6_2P:
+                case CPU_K6_3P:
+                switch (EAX)
+                {
+                        case 0:
+                        EAX = 1;
+                        EBX = 0x68747541; /*AuthenticAMD*/
+                        ECX = 0x444d4163;
+                        EDX = 0x69746e65;
+                        break;
+                        case 1:
+                        EAX = CPUID;
+                        EBX = ECX = 0;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX;
+                        break;
+                        case 0x80000000:
+                        EAX = 0x80000007;
+                        break;
+                        case 0x80000001:
+                        EAX = CPUID+0x100;
+                        EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW;
+                        break;
+
+                        case 0x80000002: /*Processor name string*/
+                        EAX = 0x2d444d41; /*AMD-K6(tm)-III P*/
+                        EBX = 0x7428364b;
+                        ECX = 0x492d296d;
+                        EDX = 0x50204949;
+                        break;
+
+                        case 0x80000003: /*Processor name string*/
+                        EAX = 0x65636f72; /*rocessor*/
+                        EBX = 0x726f7373;
+                        ECX = 0x00000000;
+                        EDX = 0x00000000;
+                        break;
+
+                        case 0x80000005: /*Cache information*/
+                        EBX = 0x02800140; /*TLBs*/
+                        ECX = 0x20020220; /*L1 data cache*/
+                        EDX = 0x20020220; /*L1 instruction cache*/
+                        break;
+
+                        case 0x80000006: /*L2 Cache information*/
+                        if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_K6_3P)
+                                ECX = 0x01004220;
+                        else
+                                ECX = 0x00804220;
+                        break;
+
+                        case 0x80000007: /*PowerNow information*/
+                        EDX = 7;
+                        break;
+
+                        default:
+                        EAX = EBX = ECX = EDX = 0;
+                        break;
+                }
+                break;
         }
 }
 
@@ -1459,6 +1534,7 @@ void cpu_RDMSR()
         switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type)
         {
                 case CPU_WINCHIP:
+                case CPU_WINCHIP2:
                 EAX = EDX = 0;
                 switch (ECX)
                 {
@@ -1511,6 +1587,20 @@ void cpu_RDMSR()
                         break;
                 }
                break;
+                case CPU_K6:
+                case CPU_K6_2:
+                case CPU_K6_3:
+                case CPU_K6_2P:
+                case CPU_K6_3P:
+                EAX = EDX = 0;
+                switch (ECX)
+                {
+                        case 0x10:
+                        EAX = tsc & 0xffffffff;
+                        EDX = tsc >> 32;
+                        break;
+                }
+                break;
         }
 }
 
@@ -1519,6 +1609,7 @@ void cpu_WRMSR()
         switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type)
         {
                 case CPU_WINCHIP:
+                case CPU_WINCHIP2:
                 switch (ECX)
                 {
                         case 0x02:
@@ -1535,11 +1626,18 @@ void cpu_WRMSR()
                         break;
                         case 0x107:
                         msr.fcr = EAX;
-                        cpu_hasMMX = EAX & (1 << 9);
+                        if (EAX & (1 << 9))
+                                cpu_features |= CPU_FEATURE_MMX;
+                        else
+                                cpu_features &= ~CPU_FEATURE_MMX;
                        if (EAX & (1 << 1))
-                               cpu_hasCX8 = 1;                                                 
+                                cpu_features |= CPU_FEATURE_CX8;
+                       else
+                                cpu_features &= ~CPU_FEATURE_CX8;
+                       if ((EAX & (1 << 20)) && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type >= CPU_WINCHIP2)
+                                cpu_features |= CPU_FEATURE_3DNOW;
                        else
-                               cpu_hasCX8 = 0;                                                                         
+                                cpu_features &= ~CPU_FEATURE_3DNOW;
                         if (EAX & (1 << 29))
                                 CPUID = 0;
                         else
@@ -1574,6 +1672,18 @@ void cpu_WRMSR()
                         break;
                 }
                 break;
+                case CPU_K6:
+                case CPU_K6_2:
+                case CPU_K6_3:
+                case CPU_K6_2P:
+                case CPU_K6_3P:
+                switch (ECX)
+                {
+                        case 0x10:
+                        tsc = EAX | ((uint64_t)EDX << 32);
+                        break;
+                }
+                break;
         }
 }
 
@@ -1647,8 +1757,8 @@ void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f, OpFn *dynarec_opcodes, OpFn
 {
         x86_opcodes = opcodes;
         x86_opcodes_0f = opcodes_0f;
-        //x86_dynarec_opcodes = dynarec_opcodes;
-        //x86_dynarec_opcodes_0f = dynarec_opcodes_0f;
+        x86_dynarec_opcodes = dynarec_opcodes;
+        x86_dynarec_opcodes_0f = dynarec_opcodes_0f;
 }
 
 void cpu_update_waitstates()
index cd31b4837a68271c3b01e90abaf7a4625f86bf1a..b4dc2b66004239c0274e19a16f1e7ab6b1680bbc 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef _CPU_H_
 #define _CPU_H_
 
-//extern int cpu;
-extern int cpu_manufacturer;
+extern int cpu, cpu_manufacturer;
+extern int fpu_type;
 
 /*808x class CPUs*/
 #define CPU_8088 0
@@ -29,12 +29,18 @@ extern int cpu_manufacturer;
 
 /*586 class CPUs*/
 #define CPU_WINCHIP 15
-#define CPU_PENTIUM 16
-#define CPU_PENTIUMMMX 17
-#define CPU_Cx6x86     18
-#define CPU_Cx6x86MX   19
-#define CPU_Cx6x86L    20
-#define CPU_CxGX1      21
+#define CPU_WINCHIP2 16
+#define CPU_PENTIUM 17
+#define CPU_PENTIUMMMX 18
+#define CPU_Cx6x86     19
+#define CPU_Cx6x86MX    20
+#define CPU_Cx6x86L    21
+#define CPU_CxGX1      22
+#define CPU_K6          23
+#define CPU_K6_2        24
+#define CPU_K6_3        25
+#define CPU_K6_2P       26
+#define CPU_K6_3P       27
 
 #define MANU_INTEL 0
 #define MANU_AMD   1
@@ -55,10 +61,28 @@ extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate;
 
 extern int timing_misaligned;
 
+enum
+{
+        FPU_NONE,
+        FPU_8087,
+        FPU_287,
+        FPU_287XL,
+        FPU_387,
+        FPU_BUILTIN
+};
+
+typedef struct
+{
+        const char *name;
+        const char *internal_name;
+        const int type;
+} FPU;
+
 typedef struct
 {
         char name[32];
         int cpu_type;
+        const FPU *fpus;
         int speed;
         int rspeed;
         int multi;
@@ -85,14 +109,19 @@ extern CPU cpus_i486[];
 extern CPU cpus_Am486[];
 extern CPU cpus_Cx486[];
 extern CPU cpus_WinChip[];
+extern CPU cpus_WinChip_SS7[];
 extern CPU cpus_Pentium5V[];
 extern CPU cpus_PentiumS5[];
 extern CPU cpus_Pentium[];
 extern CPU cpus_6x86[];
+extern CPU cpus_6x86_SS7[];
+extern CPU cpus_K6_S7[];
+extern CPU cpus_K6_SS7[];
 
 extern CPU cpus_pcjr[];
 extern CPU cpus_europc[];
 extern CPU cpus_pc1512[];
+extern CPU cpus_super286tr[];
 extern CPU cpus_ibmat[];
 extern CPU cpus_ibmxt286[];
 extern CPU cpus_ps1_m2011[];
@@ -106,12 +135,19 @@ extern int cpu_multi;
 /*Cyrix 5x86/6x86 only has data misalignment penalties when crossing 8-byte boundaries*/
 extern int cpu_cyrix_alignment;
 
-extern int cpu_hasrdtsc;
-extern int cpu_hasMSR;
-extern int cpu_hasMMX;
-extern int cpu_hasCR4;
-extern int cpu_hasVME;
-extern int cpu_hasCX8;
+#define CPU_FEATURE_RDTSC (1 << 0)
+#define CPU_FEATURE_MSR   (1 << 1)
+#define CPU_FEATURE_MMX   (1 << 2)
+#define CPU_FEATURE_CR4   (1 << 3)
+#define CPU_FEATURE_VME   (1 << 4)
+#define CPU_FEATURE_CX8   (1 << 5)
+#define CPU_FEATURE_3DNOW (1 << 6)
+
+extern uint32_t cpu_features;
+static inline int cpu_has_feature(int feature)
+{
+        return cpu_features & feature;
+}
 
 #define CR4_TSD  (1 << 2)
 #define CR4_DE   (1 << 3)
@@ -134,6 +170,8 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv);
 uint8_t cyrix_read(uint16_t addr, void *priv);
 
 extern int is8086;
+extern int is486;
+extern int CPUID;
 
 void cpu_CPUID();
 void cpu_RDMSR();
@@ -141,17 +179,22 @@ void cpu_WRMSR();
 
 extern int cpu_use_dynarec;
 
-extern int xt_cpu_multi;
+extern uint64_t xt_cpu_multi;
 
 extern int isa_cycles;
 #define ISA_CYCLES(x) (x * isa_cycles)
 
 void cpu_update_waitstates();
-void cpu_set(int);
+void cpu_set();
 void cpu_set_edx();
 void cpu_set_turbo(int turbo);
 int cpu_get_speed();
 
 extern int has_vlb;
 
+int fpu_get_type(int model, int manu, int cpu, const char *internal_name);
+const char *fpu_get_internal_name(int model, int manu, int cpu, int type);
+const char *fpu_get_name_from_index(int model, int manu, int cpu, int c);
+int fpu_get_type_from_index(int model, int manu, int cpu, int c);
+
 #endif
index 85d6d7e143bf715087bafa0d49a6209854802301..8d804aa325c4806a89433b8888eaf98c2cf167c7 100644 (file)
@@ -7,6 +7,7 @@ void fdc_reset();
 void fdc_poll();
 void fdc_abort();
 void fdc_discchange_clear(int drive);
+int fdc_discchange_read();
 void fdc_set_dskchg_activelow();
 void fdc_3f1_enable(int enable);
 void fdc_set_ps1();
@@ -23,3 +24,13 @@ void fdc_update_boot_drive(int boot_drive);
 void fdc_update_densel_polarity(int densel_polarity);
 void fdc_update_densel_force(int densel_force);
 void fdc_update_drvrate(int drive, int drvrate);
+
+
+
+enum
+{
+        FDC_STATUS_AM_NOT_FOUND,
+        FDC_STATUS_NOT_FOUND,
+        FDC_STATUS_WRONG_CYLINDER,
+        FDC_STATUS_BAD_CYLINDER
+};
index 1a5ed65ac229202840282cbe0db4c339ce41cd3c..da0f39fec600db8d6085fd182fb276c047453a1a 100644 (file)
@@ -2,6 +2,8 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "timer.h"
+
 #ifdef ABS
 #undef ABS
 #endif
 #define readflash_get(offset, drive) ((readflash&(1<<((offset)+(drive)))) != 0)
 
 /*Memory*/
-extern uint8_t *ram;
+uint8_t *ram;
 
-extern uint32_t rammask;
+uint32_t rammask;
 
-extern int readlookup[256],readlookupp[256];
-extern uintptr_t *readlookup2;
-extern int readlnext;
-extern int writelookup[256],writelookupp[256];
-extern uintptr_t *writelookup2;
-extern int writelnext;
+int readlookup[256],readlookupp[256];
+uintptr_t *readlookup2;
+int readlnext;
+int writelookup[256],writelookupp[256];
+uintptr_t *writelookup2;
+int writelnext;
 
 extern int mmu_perm;
 
-#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a)))
-#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
-#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
-
-//#define writememb(a,v) if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v
-//#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v
-//#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v
-//#define readmemb(a) ((isram[((a)>>16)&255] && !(cr0>>31))?ram[a&0xFFFFFF]:readmembl(a))
-//#define writememb(a,v) if (isram[((a)>>16)&255] && !(cr0>>31)) ram[a&0xFFFFFF]=v; else writemembl(a,v)
-
-//void writememb(uint32_t addr, uint8_t val);
 uint8_t readmembl(uint32_t addr);
 void writemembl(uint32_t addr, uint8_t val);
-uint8_t readmemb386l(uint32_t seg, uint32_t addr);
-void writememb386l(uint32_t seg, 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);
-uint64_t readmemql(uint32_t seg, uint32_t addr);
-void writememql(uint32_t seg, uint32_t addr, uint64_t val);
+uint16_t readmemwl(uint32_t addr);
+void writememwl(uint32_t addr, uint16_t val);
+uint32_t readmemll(uint32_t addr);
+void writememll(uint32_t addr, uint32_t val);
+uint64_t readmemql(uint32_t addr);
+void writememql(uint32_t addr, uint64_t val);
 
 uint8_t *getpccache(uint32_t a);
 
@@ -69,225 +58,14 @@ uint32_t inl(uint16_t port);
 void outl(uint16_t port, uint32_t val);
 
 FILE *romfopen(char *fn, char *mode);
-extern int shadowbios,shadowbios_write;
 extern int mem_size;
 extern int readlnum,writelnum;
 
 
 /*Processor*/
-#define EAX cpu_state.regs[0].l
-#define ECX cpu_state.regs[1].l
-#define EDX cpu_state.regs[2].l
-#define EBX cpu_state.regs[3].l
-#define ESP cpu_state.regs[4].l
-#define EBP cpu_state.regs[5].l
-#define ESI cpu_state.regs[6].l
-#define EDI cpu_state.regs[7].l
-#define AX cpu_state.regs[0].w
-#define CX cpu_state.regs[1].w
-#define DX cpu_state.regs[2].w
-#define BX cpu_state.regs[3].w
-#define SP cpu_state.regs[4].w
-#define BP cpu_state.regs[5].w
-#define SI cpu_state.regs[6].w
-#define DI cpu_state.regs[7].w
-#define AL cpu_state.regs[0].b.l
-#define AH cpu_state.regs[0].b.h
-#define CL cpu_state.regs[1].b.l
-#define CH cpu_state.regs[1].b.h
-#define DL cpu_state.regs[2].b.l
-#define DH cpu_state.regs[2].b.h
-#define BL cpu_state.regs[3].b.l
-#define BH cpu_state.regs[3].b.h
-
-typedef union
-{
-        uint32_t l;
-        uint16_t w;
-        struct
-        {
-                uint8_t l,h;
-        } b;
-} x86reg;
-
-typedef struct
-{
-        uint32_t base;
-        uint32_t limit;
-        uint8_t access;
-        uint16_t seg;
-        uint32_t limit_low, limit_high;
-        int checked; /*Non-zero if selector is known to be valid*/
-} x86seg;
-
-typedef union MMX_REG
-{
-        uint64_t q;
-        int64_t  sq;
-        uint32_t l[2];
-        int32_t  sl[2];
-        uint16_t w[4];
-        int16_t  sw[4];
-        uint8_t  b[8];
-        int8_t   sb[8];
-} MMX_REG;
+extern int ins, output, timetolive;
 
-typedef struct
-{
-        x86reg regs[8];
-        
-        uint8_t tag[8];
-
-        x86seg *ea_seg;
-        uint32_t eaaddr;
-        
-        int flags_op;
-        uint32_t flags_res;
-        uint32_t flags_op1, flags_op2;
-        
-        uint32_t pc;
-        uint32_t oldpc;
-        uint32_t op32;
-        
-        int TOP;
-        
-        union
-        {
-                struct
-                {
-                        int8_t rm, mod, reg;
-                } rm_mod_reg;
-                uint32_t rm_mod_reg_data;
-        } rm_data;
-        
-        int8_t ssegs;
-        int8_t ismmx;
-        int8_t abrt;
-        
-        int _cycles;
-        int cpu_recomp_ins;
-        
-        uint16_t npxs, npxc;
-
-        double ST[8];        
-        
-        uint16_t MM_w4[8];
-        
-        MMX_REG MM[8];
-        
-        uint16_t old_npxc, new_npxc;
-} cpu_state_s;
-
-extern cpu_state_s cpu_state;
-
-#define cycles cpu_state._cycles
-
-extern uint32_t cpu_cur_status;
-
-/*The flags below must match in both cpu_cur_status and block->status for a block
-  to be valid*/
-#define CPU_STATUS_USE32   (1 << 0)
-#define CPU_STATUS_STACK32 (1 << 1)
-#define CPU_STATUS_PMODE   (1 << 2)
-#define CPU_STATUS_V86     (1 << 3)
-#define CPU_STATUS_FLAGS 0xffff
-
-/*If the flags below are set in cpu_cur_status, they must be set in block->status.
-  Otherwise they are ignored*/
-#define CPU_STATUS_NOTFLATDS  (1 << 16)
-#define CPU_STATUS_NOTFLATSS  (1 << 17)
-#define CPU_STATUS_MASK 0xffff0000
-
-#define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0];
-
-//COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128);
-
-#define cpu_state_offset(MEMBER) ((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128)
-
-extern uint16_t flags,eflags;
-extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw;
-
-extern int ins,output;
-extern int cycdiff;
-
-extern x86seg gdt,ldt,idt,tr;
-extern x86seg _cs,_ds,_es,_ss,_fs,_gs;
-extern x86seg _oldds;
-
-extern int32_t pccache;
-extern uint8_t *pccache2;
-/*Segments -
-  _cs,_ds,_es,_ss are the segment structures
-  CS,DS,ES,SS is the 16-bit data
-  cs,ds,es,ss are defines to the bases*/
-#define CS _cs.seg
-#define DS _ds.seg
-#define ES _es.seg
-#define SS _ss.seg
-#define FS _fs.seg
-#define GS _gs.seg
-#define cs _cs.base
-#define ds _ds.base
-#define es _es.base
-#define ss _ss.base
-#define seg_fs _fs.base
-#define gs _gs.base
-
-#define CPL ((_cs.access>>5)&3)
-
-void loadseg(uint16_t seg, x86seg *s);
-void loadcs(uint16_t seg);
-
-union CR0_s
-{
-        uint32_t l;
-        uint16_t w;
-};
-
-extern union CR0_s CR0;
-
-#define cr0 CR0.l
-#define msw CR0.w
-
-extern uint32_t cr2, cr3, cr4;
-extern uint32_t dr[8];
-
-#define C_FLAG  0x0001
-#define P_FLAG  0x0004
-#define A_FLAG  0x0010
-#define Z_FLAG  0x0040
-#define N_FLAG  0x0080
-#define T_FLAG  0x0100
-#define I_FLAG  0x0200
-#define D_FLAG  0x0400
-#define V_FLAG  0x0800
-#define NT_FLAG 0x4000
-#define VM_FLAG 0x0002 /*In EFLAGS*/
-#define VIF_FLAG 0x0008 /*In EFLAGS*/
-#define VIP_FLAG 0x0010 /*In EFLAGS*/
-
-#define WP_FLAG 0x10000 /*In CR0*/
-
-#define CR4_VME (1 << 0)
-#define CR4_PVI (1 << 1)
-#define CR4_PSE (1 << 4)
-
-#define IOPL ((flags>>12)&3)
-
-#define IOPLp ((!(msw&1)) || (CPL<=IOPL))
-//#define IOPLp 1
-
-//#define IOPLV86 ((!(msw&1)) || (CPL<=IOPL))
 extern int cycles_lost;
-extern int is486;
-extern uint8_t opcode;
-extern int insc;
-extern int fpucount;
-extern float mips,flops;
-extern int cgate16;
-extern int CPUID;
-
-extern int cpl_override;
 
 /*Timer*/
 typedef struct PIT_nr
@@ -299,7 +77,7 @@ typedef struct PIT_nr
 typedef struct PIT
 {
         uint32_t l[3];
-        int c[3];
+       pc_timer_t timer[3];
         uint8_t m[3];
         uint8_t ctrl,ctrls[3];
         int wp,rm[3],wm[3];
@@ -326,7 +104,7 @@ typedef struct PIT
         void (*set_out_funcs[3])(int new_out, int old_out);
 } PIT;
 
-extern PIT pit, pit2;
+PIT pit, pit2;
 void setpitclock(float clock);
 
 float pit_timer0_freq();
@@ -355,7 +133,7 @@ typedef struct dma_t
         uint16_t io_addr;
 } dma_t;
 
-extern dma_t dma[8];
+dma_t dma[8];
 
 /*PPI*/
 typedef struct PPI
@@ -364,7 +142,7 @@ typedef struct PPI
         uint8_t pa,pb;
 } PPI;
 
-extern PPI ppi;
+PPI ppi;
 
 
 /*PIC*/
@@ -377,23 +155,22 @@ typedef struct PIC
         uint8_t level_sensitive;
 } PIC;
 
-extern PIC pic,pic2;
+PIC pic,pic2;
 extern int pic_intpending;
 
 
-extern int disctime;
-extern char discfns[2][256];
-extern int driveempty[2];
+char discfns[2][256];
+int driveempty[2];
 
 #define PCJR (romset == ROM_IBMPCJR)
 
-extern int GAMEBLASTER, GUS, SSI2001, voodoo_enabled;
-extern int AMSTRAD, AT, is386, PCI, TANDY;
+int GAMEBLASTER, GUS, SSI2001, voodoo_enabled;
+extern int AMSTRAD, AT, is386, PCI, TANDY, MCA;
 
 enum
 {
-        ROM_IBMPC = 0,  /*301 keyboard error, 131 cassette (!!!) error*/
-        ROM_IBMXT,      /*301 keyboard error*/
+        ROM_IBMPC = 0,
+        ROM_IBMXT,
         ROM_IBMPCJR,
         ROM_GENXT,      /*'Generic XT BIOS'*/
         ROM_DTKXT,
@@ -417,21 +194,27 @@ enum
         ROM_IBMAT,
         ROM_CMDPC30,
         ROM_AMI286,
+        ROM_TG286M,
         ROM_AWARD286,
+        ROM_GDC212M,
         ROM_GW286CT,
         ROM_SPC4200P,
         ROM_SPC4216P,
+        ROM_SPC4620P,
         ROM_DELL200,
         ROM_MISC286,
         ROM_IBMAT386,
         ROM_ACER386,
         ROM_KMXC02,
         ROM_MEGAPC,
+        ROM_AMA932J,
         ROM_AMI386SX,
         ROM_AMI486,
         ROM_WIN486,
         ROM_PCI486,
         ROM_SIS496,
+        ROM_P55VA,   /* Epox P55-VA/430VX/Award/SMC FDC37C932FR*/
+        ROM_P55TVP4, /* ASUS P/I-P55TVP4/430VX/Award/Winbond W8387F*/
         ROM_430VX,
         ROM_ENDEAVOR,
         ROM_REVENGE,
@@ -440,6 +223,7 @@ enum
         ROM_IBMPS1_2121,
         ROM_AMI386DX_OPTI495,
         ROM_MR386DX_OPTI495,
+        ROM_P55T2P4, /* ASUS P/I-P55T2P4/430HX/Award/Winbond W8387F*/
        ROM_IBMPS2_M30_286,
        ROM_IBMPS2_M50,
        ROM_IBMPS2_M55SX,
@@ -464,14 +248,26 @@ enum
        ROM_XI8088,
        ROM_IBMPS2_M70_TYPE3,
        ROM_IBMPS2_M70_TYPE4,
-                       
+       ROM_TULIP_TC7,
+       ROM_ZD_SUPERS,   /* [8088] Zenith Data Systems SupersPort */
+       ROM_PB410A,
+        ROM_PPC512,
+       ROM_BULL_MICRAL_45,
+       ROM_FIC_VA503P,
+        ROM_CBM_SL386SX25,
+        ROM_IBMPS1_2133_451,
+        ROM_ECS_386_32,
+        ROM_LEDGE_MODELM,
+        ROM_HYUNDAI_SUPER286TR,
+        ROM_ITAUTEC_INFOWAYM,
+
         ROM_MAX
 };
 
 extern int romspresent[ROM_MAX];
 
-extern int hasfpu;
-extern int romset;
+int hasfpu;
+int romset;
 
 enum
 {
@@ -482,6 +278,7 @@ enum
         GFX_EGA,        /*Using IBM EGA BIOS*/
         GFX_TVGA,       /*Using Trident TVGA8900D BIOS*/
         GFX_ET4000,     /*Tseng ET4000*/
+        GFX_TGKOREANVGA, /*Trigem Korean VGA(Tseng ET4000AX)*/
         GFX_ET4000W32,  /*Tseng ET4000/W32p (Diamond Stealth 32)*/
         GFX_BAHAMAS64,  /*S3 Vision864 (Paradise Bahamas 64)*/
         GFX_N9_9FX,     /*S3 764/Trio64 (Number Nine 9FX)*/
@@ -508,18 +305,27 @@ enum
         GFX_CL_GD5434,  /*Cirrus Logic CL-GD5434*/
         GFX_OTI037,     /*Oak OTI-037*/
         GFX_COMPAQ_CGA,        /*Compaq CGA*/
+       GFX_SIGMA400,   /*Sigma Designs Color 400 */
+       GFX_PGC,        /*Professional Graphics Controller */
+       GFX_IM1024,     /*Vermont Microsystems IM1024 */
+       GFX_EGAWONDER800, /*ATI EGA Wonder 800+*/
+       GFX_MYSTIQUE,   /*Matrox Mystique*/
+       GFX_AVGA2,      /*Acumos AVGA2 / Cirrus Logic CL-GD5402*/
+        GFX_CL_GD5428,  /*Cirrus Logic CL-GD5428*/
+        GFX_IBM_GD5428, /*IBM 1MB SVGA Adapter/A*/
+
         GFX_MAX
 };
 
 extern int gfx_present[GFX_MAX];
 
-extern int gfxcard;
+int gfxcard;
 
-extern int cpuspeed;
+int cpuspeed;
 
 
 /*Video*/
-extern int readflash;
+int readflash;
 extern int egareads,egawrites;
 extern int vid_resize;
 extern int vid_api;
@@ -529,12 +335,12 @@ extern int changeframecount;
 
 
 /*Sound*/
-extern int ppispeakon;
-extern float CGACONST;
-extern float MDACONST;
-extern float VGACONST1,VGACONST2;
-extern float RTCCONST;
-extern int gated,speakval,speakon;
+int ppispeakon;
+extern uint64_t CGACONST;
+extern uint64_t MDACONST;
+extern uint64_t VGACONST1,VGACONST2;
+extern uint64_t RTCCONST;
+int gated,speakval,speakon;
 
 
 /*Sound Blaster*/
@@ -559,10 +365,10 @@ typedef struct
         int tracks;
 } PcemHDC;
 
-extern PcemHDC hdc[7];
+PcemHDC hdc[7];
 
 /*Keyboard*/
-extern int keybsenddelay;
+int keybsenddelay;
 
 
 /*CD-ROM*/
index a346a4a225b7f67c98d06b392b4797890f72f184..7c2c63c792feaa2cc0aa8a2f33f9e1a332afc873 100644 (file)
@@ -6,243 +6,413 @@ int keybsendcallback = 0;
 
 typedef struct
 {
-        int scancodes_make[8];
-        int scancodes_break[8];        
+        uint8_t scancodes_make[8];
+        uint8_t scancodes_break[8];        
 } scancode;
 
 /*272 = 256 + 16 fake interim scancodes for disambiguation purposes.*/
 static scancode scancode_set1[272] =
 {
-        { {-1},       {-1} },       { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
-        { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
-        { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
-        { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
-        { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
-        { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
-        { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
-        { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
-        { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
-        { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
-        { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
-        { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
-        { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
-        { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
-        { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
-        { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
-        { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
-        { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
-        { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
-        { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
-        { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
-        { {0x54, -1}, {0xd4, -1} }, { {0x55, -1}, {0xd5, -1} }, { {0x56, -1}, {0xd6, -1} }, { {0x57, -1}, {0xd7, -1} },
-        { {0x58, -1}, {0xd8, -1} }, { {0x59, -1}, {0xd9, -1} }, { {0x5a, -1}, {0xda, -1} }, { {0x5b, -1}, {0xdb, -1} },
-        { {0x5c, -1}, {0xdc, -1} }, { {0x5d, -1}, {0xdd, -1} }, { {0x5e, -1}, {0xde, -1} }, { {0x5f, -1}, {0xdf, -1} },
-        { {0x60, -1}, {0xe0, -1} }, { {0x61, -1}, {0xe1, -1} }, { {0x62, -1}, {0xe2, -1} }, { {0x63, -1}, {0xe3, -1} },
-        { {0x64, -1}, {0xe4, -1} }, { {0x65, -1}, {0xe5, -1} }, { {0x66, -1}, {0xe6, -1} }, { {0x67, -1}, {0xe7, -1} },
-        { {0x68, -1}, {0xe8, -1} }, { {0x69, -1}, {0xe9, -1} }, { {0x6a, -1}, {0xea, -1} }, { {0x6b, -1}, {0xeb, -1} },
-        { {0x6c, -1}, {0xec, -1} }, { {0x6d, -1}, {0xed, -1} }, { {0x6e, -1}, {0xee, -1} }, { {0x6f, -1}, {0xef, -1} },
-        { {0x70, -1}, {0xf0, -1} }, { {0x71, -1}, {0xf1, -1} }, { {0x72, -1}, {0xf2, -1} }, { {0x73, -1}, {0xf3, -1} },
-        { {0x74, -1}, {0xf4, -1} }, { {0x75, -1}, {0xf5, -1} }, { {0x76, -1}, {0xf6, -1} }, { {0x77, -1}, {0xf7, -1} },
-        { {0x78, -1}, {0xf8, -1} }, { {0x79, -1}, {0xf9, -1} }, { {0x7a, -1}, {0xfa, -1} }, { {0x7b, -1}, {0xfb, -1} },
-        { {0x7c, -1}, {0xfc, -1} }, { {0x7d, -1}, {0xfd, -1} }, { {0x7e, -1}, {0xfe, -1} }, { {0x7f, -1}, {0xff, -1} },
+        { {0},       {0} },       { {0x01, 0}, {0x81, 0} }, { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} },
+        { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} },
+        { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} },
+        { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} },
+        { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} },
+        { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} },
+        { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} },
+        { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} },
+        { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} },
+        { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} },
+        { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, { {0x2a, 0}, {0xaa, 0} }, { {0x2b, 0}, {0xab, 0} },
+        { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} },
+        { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} },
+        { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} },
+        { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} },
+        { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} },
+        { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} },
+        { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} },
+        { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} },
+        { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} },
+        { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} },
+        { {0x54, 0}, {0xd4, 0} }, { {0x55, 0}, {0xd5, 0} }, { {0x56, 0}, {0xd6, 0} }, { {0x57, 0}, {0xd7, 0} },
+        { {0x58, 0}, {0xd8, 0} }, { {0x59, 0}, {0xd9, 0} }, { {0x5a, 0}, {0xda, 0} }, { {0x5b, 0}, {0xdb, 0} },
+        { {0x5c, 0}, {0xdc, 0} }, { {0x5d, 0}, {0xdd, 0} }, { {0x5e, 0}, {0xde, 0} }, { {0x5f, 0}, {0xdf, 0} },
+        { {0x60, 0}, {0xe0, 0} }, { {0x61, 0}, {0xe1, 0} }, { {0x62, 0}, {0xe2, 0} }, { {0x63, 0}, {0xe3, 0} },
+        { {0x64, 0}, {0xe4, 0} }, { {0x65, 0}, {0xe5, 0} }, { {0x66, 0}, {0xe6, 0} }, { {0x67, 0}, {0xe7, 0} },
+        { {0x68, 0}, {0xe8, 0} }, { {0x69, 0}, {0xe9, 0} }, { {0x6a, 0}, {0xea, 0} }, { {0x6b, 0}, {0xeb, 0} },
+        { {0x6c, 0}, {0xec, 0} }, { {0x6d, 0}, {0xed, 0} }, { {0x6e, 0}, {0xee, 0} }, { {0x6f, 0}, {0xef, 0} },
+        { {0x70, 0}, {0xf0, 0} }, { {0x71, 0}, {0xf1, 0} }, { {0x72, 0}, {0xf2, 0} }, { {0x73, 0}, {0xf3, 0} },
+        { {0x74, 0}, {0xf4, 0} }, { {0x75, 0}, {0xf5, 0} }, { {0x76, 0}, {0xf6, 0} }, { {0x77, 0}, {0xf7, 0} },
+        { {0x78, 0}, {0xf8, 0} }, { {0x79, 0}, {0xf9, 0} }, { {0x7a, 0}, {0xfa, 0} }, { {0x7b, 0}, {0xfb, 0} },
+        { {0x7c, 0}, {0xfc, 0} }, { {0x7d, 0}, {0xfd, 0} }, { {0x7e, 0}, {0xfe, 0} }, { {0x7f, 0}, {0xff, 0} },
 
-        { {0x80, -1},       {-1} },             { {0x81, -1},       {-1} },             { {0x82, -1},       {-1} },             { {0xe0, 0x03, -1}, {0xe0, 0x83, -1} }, /*80*/
-        { {0xe0, 0x04, -1}, {0xe0, 0x84, -1} }, { {0x85, -1},       {-1} },             { {0x86, -1},       {-1} },             { {0x87, -1},       {-1} },             /*84*/
-        { {0xe0, 0x08, -1}, {0xe0, 0x88, -1} }, { {0xe0, 0x09, -1}, {0xe0, 0x89, -1} }, { {0xe0, 0x0a, -1}, {0xe0, 0x8a, -1} }, { {0xe0, 0x0b, -1}, {0xe0, 0x8b, -1} }, /*88*/
-        { {0xe0, 0x0c, -1}, {0xe0, 0x8c, -1} }, { {-1},             {-1} },             { {0xe0, 0x0e, -1}, {0xe0, 0x8e, -1} }, { {0xe0, 0x0f, -1}, {0xe0, 0x8f, -1} }, /*8c*/
-        { {0xe0, 0x10, -1}, {0xe0, 0x90, -1} }, { {0xe0, 0x11, -1}, {0xe0, 0x91, -1} }, { {0xe0, 0x12, -1}, {0xe0, 0x92, -1} }, { {0xe0, 0x13, -1}, {0xe0, 0x93, -1} }, /*90*/
-        { {0xe0, 0x14, -1}, {0xe0, 0x94, -1} }, { {0xe0, 0x15, -1}, {0xe0, 0x95, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0x96, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0x97, -1} }, /*94*/
-        { {0xe0, 0x18, -1}, {0xe0, 0x98, -1} }, { {0xe0, 0x19, -1}, {0xe0, 0x99, -1} }, { {0xe0, 0x1a, -1}, {0xe0, 0x9a, -1} }, { {0xe0, 0x1b, -1}, {0xe0, 0x9b, -1} }, /*98*/
-        { {0xe0, 0x1c, -1}, {0xe0, 0x9c, -1} }, { {0xe0, 0x1d, -1}, {0xe0, 0x9d, -1} }, { {0xe0, 0x1e, -1}, {0xe0, 0x9e, -1} }, { {0xe0, 0x1f, -1}, {0xe0, 0x9f, -1} }, /*9c*/
-        { {0xe0, 0x20, -1}, {0xe0, 0xa0, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xa1, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xa2, -1} }, { {0xe0, 0x23, -1}, {0xe0, 0xa3, -1} }, /*a0*/
-        { {0xe0, 0x24, -1}, {0xe0, 0xa4, -1} }, { {0xe0, 0x25, -1}, {0xe0, 0xa5, -1} }, { {0xe0, 0x26, -1}, {0xe0, 0xa6, -1} }, { {-1},             {-1} },             /*a4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {0xe0, 0x2a, -1}, {0xe0, 0xaa, -1} }, { {-1},             {-1} },             /*a8*/
-        { {0xe0, 0x2c, -1}, {0xe0, 0xac, -1} }, { {0xe0, 0x2d, -1}, {0xe0, 0xad, -1} }, { {0xe0, 0x2e, -1}, {0xe0, 0xae, -1} }, { {0xe0, 0x2f, -1}, {0xe0, 0xaf, -1} }, /*ac*/
-        { {0xe0, 0x30, -1}, {0xe0, 0xb0, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xb1, -1} }, { {0xe0, 0x32, -1}, {0xe0, 0xb2, -1} }, { {-1},             {-1} },             /*b0*/
-        { {0xe0, 0x34, -1}, {0xe0, 0xb4, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xb5, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xb6, -1} }, { {0xe0, 0x37, -1}, {0xe0, 0xb7, -1} }, /*b4*/
-        { {0xe0, 0x38, -1}, {0xe0, 0xb8, -1} }, { {-1},             {-1} },             { {0xe0, 0x3a, -1}, {0xe0, 0xba, -1} }, { {0xe0, 0x3b, -1}, {0xe0, 0xbb, -1} }, /*b8*/
-        { {0xe0, 0x3c, -1}, {0xe0, 0xbc, -1} }, { {0xe0, 0x3d, -1}, {0xe0, 0xbd, -1} }, { {0xe0, 0x3e, -1}, {0xe0, 0xbe, -1} }, { {0xe0, 0x3f, -1}, {0xe0, 0xbf, -1} }, /*bc*/
-        { {0xe0, 0x40, -1}, {0xe0, 0xc0, -1} }, { {0xe0, 0x41, -1}, {0xe0, 0xc1, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xc2, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xc3, -1} }, /*c0*/
-        { {0xe0, 0x44, -1}, {0xe0, 0xc4, -1} }, { {-1},             {-1} },             { {0xe0, 0x46, -1}, {0xe0, 0xc6, -1} }, { {0xe0, 0x47, -1}, {0xe0, 0xc7, -1} }, /*c4*/
-        { {0xe0, 0x48, -1}, {0xe0, 0xc8, -1} }, { {0xe0, 0x49, -1}, {0xe0, 0xc9, -1} }, { {-1},             {-1} },             { {0xe0, 0x4b, -1}, {0xe0, 0xcb, -1} }, /*c8*/
-        { {0xe0, 0x4c, -1}, {0xe0, 0xcc, -1} }, { {0xe0, 0x4d, -1}, {0xe0, 0xcd, -1} }, { {0xe0, 0x4e, -1}, {0xe0, 0xce, -1} }, { {0xe0, 0x4f, -1}, {0xe0, 0xcf, -1} }, /*cc*/
-        { {0xe0, 0x50, -1}, {0xe0, 0xd0, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xd1, -1} }, { {0xe0, 0x52, -1}, {0xe0, 0xd2, -1} }, { {0xe0, 0x53, -1}, {0xe0, 0xd3, -1} }, /*d0*/
-        { {0xd4, -1},       {-1} },             { {0xe0, 0x55, -1}, {0xe0, 0xd5, -1} }, { {-1},             {-1} },             { {0xe0, 0x57, -1}, {0xe0, 0xd7, -1} }, /*d4*/
-        { {0xe0, 0x58, -1}, {0xe0, 0xd8, -1} }, { {0xe0, 0x59, -1}, {0xe0, 0xd9, -1} }, { {0xe0, 0x5a, -1}, {0xe0, 0xaa, -1} }, { {0xe0, 0x5b, -1}, {0xe0, 0xdb, -1} }, /*d8*/
-        { {0xe0, 0x5c, -1}, {0xe0, 0xdc, -1} }, { {0xe0, 0x5d, -1}, {0xe0, 0xdd, -1} }, { {0xe0, 0x5e, -1}, {0xe0, 0xee, -1} }, { {0xe0, 0x5f, -1}, {0xe0, 0xdf, -1} }, /*dc*/
-        { {-1},             {-1} },             { {0xe0, 0x61, -1}, {0xe0, 0xe1, -1} }, { {0xe0, 0x62, -1}, {0xe0, 0xe2, -1} }, { {0xe0, 0x63, -1}, {0xe0, 0xe3, -1} }, /*e0*/
-        { {0xe0, 0x64, -1}, {0xe0, 0xe4, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xe5, -1} }, { {0xe0, 0x66, -1}, {0xe0, 0xe6, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xe7, -1} }, /*e4*/
-        { {0xe0, 0x68, -1}, {0xe0, 0xe8, -1} }, { {0xe0, 0x69, -1}, {0xe0, 0xe9, -1} }, { {0xe0, 0x6a, -1}, {0xe0, 0xea, -1} }, { {0xe0, 0x6b, -1}, {0xe0, 0xeb, -1} }, /*e8*/
-        { {0xe0, 0x6c, -1}, {0xe0, 0xec, -1} }, { {0xe0, 0x6d, -1}, {0xe0, 0xed, -1} }, { {0xe0, 0x6e, -1}, {0xe0, 0xee, -1} }, { {-1},             {-1} },             /*ec*/
-        { {0xe0, 0x70, -1}, {0xe0, 0xf0, -1} }, { {0xf1, -1},       {-1} },             { {0xf2, -1},       {-1} },             { {0xe0, 0x73, -1}, {0xe0, 0xf3, -1} }, /*f0*/
-        { {0xe0, 0x74, -1}, {0xe0, 0xf4, -1} }, { {0xe0, 0x75, -1}, {0xe0, 0xf5, -1} }, { {-1},             {-1} },             { {0xe0, 0x77, -1}, {0xe0, 0xf7, -1} }, /*f4*/
-        { {0xe0, 0x78, -1}, {0xe0, 0xf8, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xf9, -1} }, { {0xe0, 0x7a, -1}, {0xe0, 0xfa, -1} }, { {0xe0, 0x7b, -1}, {0xe0, 0xfb, -1} }, /*f8*/
-        { {0xe0, 0x7c, -1}, {0xe0, 0xfc, -1} }, { {0xe0, 0x7d, -1}, {0xe0, 0xfd, -1} }, { {0xe0, 0x7e, -1}, {0xe0, 0xfe, -1} }, { {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5, -1},             {-1} },  /*fc*/
-        { {-1},             {-1} },             { {0xe0, 0x01, -1}, {0xe0, 0x81, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0x82, -1} }, { {-1},             {-1} },             /*100*/
-        { {-1},             {-1} },             { {0xe0, 0x05, -1}, {0xe0, 0x85, -1} }, { {0xe0, 0x06, -1}, {0xe0, 0x86, -1} }, { {0xe0, 0x07, -1}, {0xe0, 0x87, -1} }, /*104*/
-        { {0xe0, 0x71, -1}, {0xe0, 0xf1, -1} }, { {0xe0, 0x72, -1}, {0xe0, 0xf2, -1} }, { {0xe0, 0x7f, -1}, {0xe0, 0xff, -1} }, { {0xe0, 0xe1, -1}, {-1} },             /*108*/
-        { {0xe0, 0xee, -1}, {-1} },             { {0xe0, 0xf1, -1}, {-1} },             { {0xe0, 0xfe, -1}, {-1} },             { {0xe0, 0xff, -1}, {-1} }              /*10c*/
+        { {0x80, 0},       {0} },             { {0x81, 0},       {0} },             { {0x82, 0},       {0} },             { {0xe0, 0x03, 0}, {0xe0, 0x83, 0} }, /*80*/
+        { {0xe0, 0x04, 0}, {0xe0, 0x84, 0} }, { {0x85, 0},       {0} },             { {0x86, 0},       {0} },             { {0x87, 0},       {0} },             /*84*/
+        { {0xe0, 0x08, 0}, {0xe0, 0x88, 0} }, { {0xe0, 0x09, 0}, {0xe0, 0x89, 0} }, { {0xe0, 0x0a, 0}, {0xe0, 0x8a, 0} }, { {0xe0, 0x0b, 0}, {0xe0, 0x8b, 0} }, /*88*/
+        { {0xe0, 0x0c, 0}, {0xe0, 0x8c, 0} }, { {0},             {0} },             { {0xe0, 0x0e, 0}, {0xe0, 0x8e, 0} }, { {0xe0, 0x0f, 0}, {0xe0, 0x8f, 0} }, /*8c*/
+        { {0xe0, 0x10, 0}, {0xe0, 0x90, 0} }, { {0xe0, 0x11, 0}, {0xe0, 0x91, 0} }, { {0xe0, 0x12, 0}, {0xe0, 0x92, 0} }, { {0xe0, 0x13, 0}, {0xe0, 0x93, 0} }, /*90*/
+        { {0xe0, 0x14, 0}, {0xe0, 0x94, 0} }, { {0xe0, 0x15, 0}, {0xe0, 0x95, 0} }, { {0xe0, 0x16, 0}, {0xe0, 0x96, 0} }, { {0xe0, 0x17, 0}, {0xe0, 0x97, 0} }, /*94*/
+        { {0xe0, 0x18, 0}, {0xe0, 0x98, 0} }, { {0xe0, 0x19, 0}, {0xe0, 0x99, 0} }, { {0xe0, 0x1a, 0}, {0xe0, 0x9a, 0} }, { {0xe0, 0x1b, 0}, {0xe0, 0x9b, 0} }, /*98*/
+        { {0xe0, 0x1c, 0}, {0xe0, 0x9c, 0} }, { {0xe0, 0x1d, 0}, {0xe0, 0x9d, 0} }, { {0xe0, 0x1e, 0}, {0xe0, 0x9e, 0} }, { {0xe0, 0x1f, 0}, {0xe0, 0x9f, 0} }, /*9c*/
+        { {0xe0, 0x20, 0}, {0xe0, 0xa0, 0} }, { {0xe0, 0x21, 0}, {0xe0, 0xa1, 0} }, { {0xe0, 0x22, 0}, {0xe0, 0xa2, 0} }, { {0xe0, 0x23, 0}, {0xe0, 0xa3, 0} }, /*a0*/
+        { {0xe0, 0x24, 0}, {0xe0, 0xa4, 0} }, { {0xe0, 0x25, 0}, {0xe0, 0xa5, 0} }, { {0xe0, 0x26, 0}, {0xe0, 0xa6, 0} }, { {0},             {0} },             /*a4*/
+        { {0},             {0} },             { {0},             {0} },             { {0xe0, 0x2a, 0}, {0xe0, 0xaa, 0} }, { {0},             {0} },             /*a8*/
+        { {0xe0, 0x2c, 0}, {0xe0, 0xac, 0} }, { {0xe0, 0x2d, 0}, {0xe0, 0xad, 0} }, { {0xe0, 0x2e, 0}, {0xe0, 0xae, 0} }, { {0xe0, 0x2f, 0}, {0xe0, 0xaf, 0} }, /*ac*/
+        { {0xe0, 0x30, 0}, {0xe0, 0xb0, 0} }, { {0xe0, 0x31, 0}, {0xe0, 0xb1, 0} }, { {0xe0, 0x32, 0}, {0xe0, 0xb2, 0} }, { {0},             {0} },             /*b0*/
+        { {0xe0, 0x34, 0}, {0xe0, 0xb4, 0} }, { {0xe0, 0x35, 0}, {0xe0, 0xb5, 0} }, { {0xe0, 0x36, 0}, {0xe0, 0xb6, 0} }, { {0xe0, 0x37, 0}, {0xe0, 0xb7, 0} }, /*b4*/
+        { {0xe0, 0x38, 0}, {0xe0, 0xb8, 0} }, { {0},             {0} },             { {0xe0, 0x3a, 0}, {0xe0, 0xba, 0} }, { {0xe0, 0x3b, 0}, {0xe0, 0xbb, 0} }, /*b8*/
+        { {0xe0, 0x3c, 0}, {0xe0, 0xbc, 0} }, { {0xe0, 0x3d, 0}, {0xe0, 0xbd, 0} }, { {0xe0, 0x3e, 0}, {0xe0, 0xbe, 0} }, { {0xe0, 0x3f, 0}, {0xe0, 0xbf, 0} }, /*bc*/
+        { {0xe0, 0x40, 0}, {0xe0, 0xc0, 0} }, { {0xe0, 0x41, 0}, {0xe0, 0xc1, 0} }, { {0xe0, 0x42, 0}, {0xe0, 0xc2, 0} }, { {0xe0, 0x43, 0}, {0xe0, 0xc3, 0} }, /*c0*/
+        { {0xe0, 0x44, 0}, {0xe0, 0xc4, 0} }, { {0},             {0} },             { {0xe0, 0x46, 0}, {0xe0, 0xc6, 0} }, { {0xe0, 0x47, 0}, {0xe0, 0xc7, 0} }, /*c4*/
+        { {0xe0, 0x48, 0}, {0xe0, 0xc8, 0} }, { {0xe0, 0x49, 0}, {0xe0, 0xc9, 0} }, { {0},             {0} },             { {0xe0, 0x4b, 0}, {0xe0, 0xcb, 0} }, /*c8*/
+        { {0xe0, 0x4c, 0}, {0xe0, 0xcc, 0} }, { {0xe0, 0x4d, 0}, {0xe0, 0xcd, 0} }, { {0xe0, 0x4e, 0}, {0xe0, 0xce, 0} }, { {0xe0, 0x4f, 0}, {0xe0, 0xcf, 0} }, /*cc*/
+        { {0xe0, 0x50, 0}, {0xe0, 0xd0, 0} }, { {0xe0, 0x51, 0}, {0xe0, 0xd1, 0} }, { {0xe0, 0x52, 0}, {0xe0, 0xd2, 0} }, { {0xe0, 0x53, 0}, {0xe0, 0xd3, 0} }, /*d0*/
+        { {0xd4, 0},       {0} },             { {0xe0, 0x55, 0}, {0xe0, 0xd5, 0} }, { {0},             {0} },             { {0xe0, 0x57, 0}, {0xe0, 0xd7, 0} }, /*d4*/
+        { {0xe0, 0x58, 0}, {0xe0, 0xd8, 0} }, { {0xe0, 0x59, 0}, {0xe0, 0xd9, 0} }, { {0xe0, 0x5a, 0}, {0xe0, 0xaa, 0} }, { {0xe0, 0x5b, 0}, {0xe0, 0xdb, 0} }, /*d8*/
+        { {0xe0, 0x5c, 0}, {0xe0, 0xdc, 0} }, { {0xe0, 0x5d, 0}, {0xe0, 0xdd, 0} }, { {0xe0, 0x5e, 0}, {0xe0, 0xee, 0} }, { {0xe0, 0x5f, 0}, {0xe0, 0xdf, 0} }, /*dc*/
+        { {0},             {0} },             { {0xe0, 0x61, 0}, {0xe0, 0xe1, 0} }, { {0xe0, 0x62, 0}, {0xe0, 0xe2, 0} }, { {0xe0, 0x63, 0}, {0xe0, 0xe3, 0} }, /*e0*/
+        { {0xe0, 0x64, 0}, {0xe0, 0xe4, 0} }, { {0xe0, 0x65, 0}, {0xe0, 0xe5, 0} }, { {0xe0, 0x66, 0}, {0xe0, 0xe6, 0} }, { {0xe0, 0x67, 0}, {0xe0, 0xe7, 0} }, /*e4*/
+        { {0xe0, 0x68, 0}, {0xe0, 0xe8, 0} }, { {0xe0, 0x69, 0}, {0xe0, 0xe9, 0} }, { {0xe0, 0x6a, 0}, {0xe0, 0xea, 0} }, { {0xe0, 0x6b, 0}, {0xe0, 0xeb, 0} }, /*e8*/
+        { {0xe0, 0x6c, 0}, {0xe0, 0xec, 0} }, { {0xe0, 0x6d, 0}, {0xe0, 0xed, 0} }, { {0xe0, 0x6e, 0}, {0xe0, 0xee, 0} }, { {0},             {0} },             /*ec*/
+        { {0xe0, 0x70, 0}, {0xe0, 0xf0, 0} }, { {0xf1, 0},       {0} },             { {0xf2, 0},       {0} },             { {0xe0, 0x73, 0}, {0xe0, 0xf3, 0} }, /*f0*/
+        { {0xe0, 0x74, 0}, {0xe0, 0xf4, 0} }, { {0xe0, 0x75, 0}, {0xe0, 0xf5, 0} }, { {0},             {0} },             { {0xe0, 0x77, 0}, {0xe0, 0xf7, 0} }, /*f4*/
+        { {0xe0, 0x78, 0}, {0xe0, 0xf8, 0} }, { {0xe0, 0x79, 0}, {0xe0, 0xf9, 0} }, { {0xe0, 0x7a, 0}, {0xe0, 0xfa, 0} }, { {0xe0, 0x7b, 0}, {0xe0, 0xfb, 0} }, /*f8*/
+        { {0xe0, 0x7c, 0}, {0xe0, 0xfc, 0} }, { {0xe0, 0x7d, 0}, {0xe0, 0xfd, 0} }, { {0xe0, 0x7e, 0}, {0xe0, 0xfe, 0} }, { {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5, 0},             {0} },  /*fc*/
+        { {0},             {0} },             { {0xe0, 0x01, 0}, {0xe0, 0x81, 0} }, { {0xe0, 0x02, 0}, {0xe0, 0x82, 0} }, { {0},             {0} },             /*100*/
+        { {0},             {0} },             { {0xe0, 0x05, 0}, {0xe0, 0x85, 0} }, { {0xe0, 0x06, 0}, {0xe0, 0x86, 0} }, { {0xe0, 0x07, 0}, {0xe0, 0x87, 0} }, /*104*/
+        { {0xe0, 0x71, 0}, {0xe0, 0xf1, 0} }, { {0xe0, 0x72, 0}, {0xe0, 0xf2, 0} }, { {0xe0, 0x7f, 0}, {0xe0, 0xff, 0} }, { {0xe0, 0xe1, 0}, {0} },             /*108*/
+        { {0xe0, 0xee, 0}, {0} },             { {0xe0, 0xf1, 0}, {0} },             { {0xe0, 0xfe, 0}, {0} },             { {0xe0, 0xff, 0}, {0} }              /*10c*/
+};
+
+/*272 = 256 + 16 fake interim scancodes for disambiguation purposes.*/
+static scancode scancode_set2[272] =
+{
+        { {0},       {0} },             { {0x76, 0}, {0xf0, 0x76, 0} }, { {0x16, 0}, {0xf0, 0x16, 0} }, { {0x1e, 0}, {0xf0, 0x1e, 0} },
+        { {0x26, 0}, {0xf0, 0x26, 0} }, { {0x25, 0}, {0xf0, 0x25, 0} }, { {0x2e, 0}, {0xf0, 0x2e, 0} }, { {0x36, 0}, {0xf0, 0x36, 0} },
+        { {0x3d, 0}, {0xf0, 0x3d, 0} }, { {0x3e, 0}, {0xf0, 0x3e, 0} }, { {0x46, 0}, {0xf0, 0x46, 0} }, { {0x45, 0}, {0xf0, 0x45, 0} },
+        { {0x4e, 0}, {0xf0, 0x4e, 0} }, { {0x55, 0}, {0xf0, 0x55, 0} }, { {0x66, 0}, {0xf0, 0x66, 0} }, { {0x0d, 0}, {0xf0, 0x0d, 0} },
+        { {0x15, 0}, {0xf0, 0x15, 0} }, { {0x1d, 0}, {0xf0, 0x1d, 0} }, { {0x24, 0}, {0xf0, 0x24, 0} }, { {0x2d, 0}, {0xf0, 0x2d, 0} },
+        { {0x2c, 0}, {0xf0, 0x2c, 0} }, { {0x35, 0}, {0xf0, 0x35, 0} }, { {0x3c, 0}, {0xf0, 0x3c, 0} }, { {0x43, 0}, {0xf0, 0x43, 0} },
+        { {0x44, 0}, {0xf0, 0x44, 0} }, { {0x4d, 0}, {0xf0, 0x4d, 0} }, { {0x54, 0}, {0xf0, 0x54, 0} }, { {0x5b, 0}, {0xf0, 0x5b, 0} },
+        { {0x5a, 0}, {0xf0, 0x5a, 0} }, { {0x14, 0}, {0xf0, 0x14, 0} }, { {0x1c, 0}, {0xf0, 0x1c, 0} }, { {0x1b, 0}, {0xf0, 0x1b, 0} },
+        { {0x23, 0}, {0xf0, 0x23, 0} }, { {0x2b, 0}, {0xf0, 0x2b, 0} }, { {0x34, 0}, {0xf0, 0x34, 0} }, { {0x33, 0}, {0xf0, 0x33, 0} },
+        { {0x3b, 0}, {0xf0, 0x3b, 0} }, { {0x42, 0}, {0xf0, 0x42, 0} }, { {0x4b, 0}, {0xf0, 0x4b, 0} }, { {0x4c, 0}, {0xf0, 0x4c, 0} },
+        { {0x52, 0}, {0xf0, 0x52, 0} }, { {0x0e, 0}, {0xf0, 0x0e, 0} }, { {0x12, 0}, {0xf0, 0x12, 0} }, { {0x5d, 0}, {0xf0, 0x5d, 0} },
+        { {0x1a, 0}, {0xf0, 0x1a, 0} }, { {0x22, 0}, {0xf0, 0x22, 0} }, { {0x21, 0}, {0xf0, 0x21, 0} }, { {0x2a, 0}, {0xf0, 0x2a, 0} },
+        { {0x32, 0}, {0xf0, 0x32, 0} }, { {0x31, 0}, {0xf0, 0x31, 0} }, { {0x3a, 0}, {0xf0, 0x3a, 0} }, { {0x41, 0}, {0xf0, 0x41, 0} },
+        { {0x49, 0}, {0xf0, 0x49, 0} }, { {0x4a, 0}, {0xf0, 0x4a, 0} }, { {0x59, 0}, {0xf0, 0x59, 0} }, { {0x7c, 0}, {0xf0, 0x7c, 0} },
+        { {0x11, 0}, {0xf0, 0x11, 0} }, { {0x29, 0}, {0xf0, 0x29, 0} }, { {0x58, 0}, {0xf0, 0x58, 0} }, { {0x05, 0}, {0xf0, 0x05, 0} },
+        { {0x06, 0}, {0xf0, 0x06, 0} }, { {0x04, 0}, {0xf0, 0x04, 0} }, { {0x0c, 0}, {0xf0, 0x0c, 0} }, { {0x03, 0}, {0xf0, 0x03, 0} },
+        { {0x0b, 0}, {0xf0, 0x0b, 0} }, { {0x83, 0}, {0xf0, 0x83, 0} }, { {0x0a, 0}, {0xf0, 0x0a, 0} }, { {0x01, 0}, {0xf0, 0x01, 0} },
+        { {0x09, 0}, {0xf0, 0x09, 0} }, { {0x77, 0}, {0xf0, 0x77, 0} }, { {0x7e, 0}, {0xf0, 0x7e, 0} }, { {0x6c, 0}, {0xf0, 0x6c, 0} },
+        { {0x75, 0}, {0xf0, 0x75, 0} }, { {0x7d, 0}, {0xf0, 0x7d, 0} }, { {0x7b, 0}, {0xf0, 0x7b, 0} }, { {0x6b, 0}, {0xf0, 0x6b, 0} },
+        { {0x73, 0}, {0xf0, 0x73, 0} }, { {0x74, 0}, {0xf0, 0x74, 0} }, { {0x79, 0}, {0xf0, 0x79, 0} }, { {0x69, 0}, {0xf0, 0x69, 0} },
+        { {0x72, 0}, {0xf0, 0x72, 0} }, { {0x7a, 0}, {0xf0, 0x7a, 0} }, { {0x70, 0}, {0xf0, 0x70, 0} }, { {0x71, 0}, {0xf0, 0x71, 0} },
+        { {0x84, 0}, {0xf0, 0x84, 0} }, { {0, 0}, {0, 0} },             { {0x61, 0}, {0xf0, 0x61, 0} }, { {0x78, 0}, {0xf0, 0x78, 0} },
+        { {0x07, 0}, {0xf0, 0x07, 0} }, { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0xe0, 0x5a, 0}, {0xe0, 0xf0, 0x5a, 0} }, { {0xe0, 0x14, 0}, {0xe0, 0xf0, 0x14, 0} }, { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0xe0, 0x4a, 0}, {0xe0, 0xf0, 0x4a, 0} }, { {0, 0}, {0, 0} },                         { {0xe0, 0x7c, 0}, {0xe0, 0xf0, 0x7c, 0} },
+        { {0xe0, 0x11, 0}, {0xe0, 0xf0, 0x11, 0} }, { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0xe0, 0x6c, 0}, {0xe0, 0xf0, 0x6c, 0} },
+        { {0xe0, 0x75, 0}, {0xe0, 0xf0, 0x75, 0} }, { {0xe0, 0x7d, 0}, {0xe0, 0xf0, 0x7d, 0} }, { {0, 0}, {0, 0} },                         { {0xe0, 0x6b, 0}, {0xe0, 0xf0, 0x6b, 0} },
+        { {0, 0}, {0, 0} },                         { {0xe0, 0x74, 0}, {0xe0, 0xf0, 0x74, 0} }, { {0, 0}, {0, 0} },                         { {0xe0, 0x69, 0}, {0xe0, 0xf0, 0x69, 0} },
+        { {0xe0, 0x72, 0}, {0xe0, 0xf0, 0x72, 0} }, { {0xe0, 0x7a, 0}, {0xe0, 0xf0, 0x7a, 0} }, { {0xe0, 0x70, 0}, {0xe0, 0xf0, 0x70, 0} }, { {0xe0, 0x71, 0}, {0xe0, 0xf0, 0x71, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0xe0, 0x1f, 0}, {0xe0, 0xf0, 0x1f, 0} },
+        { {0xe0, 0x27, 0}, {0xe0, 0xf0, 0x27, 0} }, { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },                         { {0, 0}, {0, 0} },
+
+        { {0},             {0} },                   { {0xe0, 0x01, 0}, {0xe0, 0xf0, 0x01, 0} }, { {0xe0, 0x02, 0}, {0xe0, 0xf0, 0x02, 0} }, { {0},             {0} },             /*100*/
+        { {0},             {0} },                   { {0xe0, 0x05, 0}, {0xe0, 0xf0, 0x15, 0} }, { {0xe0, 0x06, 0}, {0xe0, 0xf0, 0x06, 0} }, { {0xe0, 0x07, 0}, {0xe0, 0xf0, 0x07, 0} }, /*104*/
+        { {0xe0, 0x71, 0}, {0xe0, 0xf0, 0x71, 0} }, { {0xe0, 0x72, 0}, {0xe0, 0xf0, 0x72, 0} }, { {0xe0, 0x7f, 0}, {0xe0, 0xf0, 0x7f, 0} }, { {0xe0, 0xe1, 0}, {0} },             /*108*/
+        { {0xe0, 0xee, 0}, {0} },                   { {0xe0, 0xf1, 0}, {0} },                   { {0xe0, 0xfe, 0}, {0} },                   { {0xe0, 0xff, 0}, {0} }              /*10c*/
+};
+
+/*272 = 256 + 16 fake interim scancodes for disambiguation purposes.*/
+static scancode scancode_set3[272] =
+{
+        { {0},       {0} },             { {0x76, 0}, {0xf0, 0x76, 0} }, { {0x16, 0}, {0xf0, 0x16, 0} }, { {0x1e, 0}, {0xf0, 0x1e, 0} },
+        { {0x26, 0}, {0xf0, 0x26, 0} }, { {0x25, 0}, {0xf0, 0x25, 0} }, { {0x2e, 0}, {0xf0, 0x2e, 0} }, { {0x36, 0}, {0xf0, 0x36, 0} },
+        { {0x3d, 0}, {0xf0, 0x3d, 0} }, { {0x3e, 0}, {0xf0, 0x3e, 0} }, { {0x46, 0}, {0xf0, 0x46, 0} }, { {0x45, 0}, {0xf0, 0x45, 0} },
+        { {0x4e, 0}, {0xf0, 0x4e, 0} }, { {0x55, 0}, {0xf0, 0x55, 0} }, { {0x66, 0}, {0xf0, 0x66, 0} }, { {0x0d, 0}, {0xf0, 0x0d, 0} },
+        { {0x15, 0}, {0xf0, 0x15, 0} }, { {0x1d, 0}, {0xf0, 0x1d, 0} }, { {0x24, 0}, {0xf0, 0x24, 0} }, { {0x2d, 0}, {0xf0, 0x2d, 0} },
+        { {0x2c, 0}, {0xf0, 0x2c, 0} }, { {0x35, 0}, {0xf0, 0x35, 0} }, { {0x3c, 0}, {0xf0, 0x3c, 0} }, { {0x43, 0}, {0xf0, 0x43, 0} },
+        { {0x44, 0}, {0xf0, 0x44, 0} }, { {0x4d, 0}, {0xf0, 0x4d, 0} }, { {0x54, 0}, {0xf0, 0x54, 0} }, { {0x5b, 0}, {0xf0, 0x5b, 0} },
+        { {0x5a, 0}, {0xf0, 0x5a, 0} }, { {0x19, 0}, {0xf0, 0x19, 0} }, { {0x1c, 0}, {0xf0, 0x1c, 0} }, { {0x1b, 0}, {0xf0, 0x1b, 0} },
+        { {0x23, 0}, {0xf0, 0x23, 0} }, { {0x2b, 0}, {0xf0, 0x2b, 0} }, { {0x34, 0}, {0xf0, 0x34, 0} }, { {0x33, 0}, {0xf0, 0x33, 0} },
+        { {0x3b, 0}, {0xf0, 0x3b, 0} }, { {0x42, 0}, {0xf0, 0x42, 0} }, { {0x4b, 0}, {0xf0, 0x4b, 0} }, { {0x4c, 0}, {0xf0, 0x4c, 0} },
+        { {0x52, 0}, {0xf0, 0x52, 0} }, { {0x0e, 0}, {0xf0, 0x0e, 0} }, { {0x12, 0}, {0xf0, 0x12, 0} }, { {0x5c, 0}, {0xf0, 0x5c, 0} },
+        { {0x1a, 0}, {0xf0, 0x1a, 0} }, { {0x22, 0}, {0xf0, 0x22, 0} }, { {0x21, 0}, {0xf0, 0x21, 0} }, { {0x2a, 0}, {0xf0, 0x2a, 0} },
+        { {0x32, 0}, {0xf0, 0x32, 0} }, { {0x31, 0}, {0xf0, 0x31, 0} }, { {0x3a, 0}, {0xf0, 0x3a, 0} }, { {0x41, 0}, {0xf0, 0x41, 0} },
+        { {0x49, 0}, {0xf0, 0x49, 0} }, { {0x4a, 0}, {0xf0, 0x4a, 0} }, { {0x59, 0}, {0xf0, 0x59, 0} }, { {0x7c, 0}, {0xf0, 0x7c, 0} },
+        { {0x11, 0}, {0xf0, 0x11, 0} }, { {0x29, 0}, {0xf0, 0x29, 0} }, { {0x14, 0}, {0xf0, 0x14, 0} }, { {0x05, 0}, {0xf0, 0x05, 0} },
+        { {0x06, 0}, {0xf0, 0x06, 0} }, { {0x04, 0}, {0xf0, 0x04, 0} }, { {0x0c, 0}, {0xf0, 0x0c, 0} }, { {0x03, 0}, {0xf0, 0x03, 0} },
+        { {0x0b, 0}, {0xf0, 0x0b, 0} }, { {0x83, 0}, {0xf0, 0x83, 0} }, { {0x0a, 0}, {0xf0, 0x0a, 0} }, { {0x01, 0}, {0xf0, 0x01, 0} },
+        { {0x09, 0}, {0xf0, 0x09, 0} }, { {0x77, 0}, {0xf0, 0x77, 0} }, { {0x7e, 0}, {0xf0, 0x7e, 0} }, { {0x6c, 0}, {0xf0, 0x6c, 0} },
+        { {0x75, 0}, {0xf0, 0x75, 0} }, { {0x7d, 0}, {0xf0, 0x7d, 0} }, { {0x7b, 0}, {0xf0, 0x7b, 0} }, { {0x6b, 0}, {0xf0, 0x6b, 0} },
+        { {0x73, 0}, {0xf0, 0x73, 0} }, { {0x74, 0}, {0xf0, 0x74, 0} }, { {0x79, 0}, {0xf0, 0x79, 0} }, { {0x69, 0}, {0xf0, 0x69, 0} },
+        { {0x72, 0}, {0xf0, 0x72, 0} }, { {0x7a, 0}, {0xf0, 0x7a, 0} }, { {0x70, 0}, {0xf0, 0x70, 0} }, { {0x71, 0}, {0xf0, 0x71, 0} },
+        { {0x84, 0}, {0xf0, 0x84, 0} }, { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0x78, 0}, {0xf0, 0x78, 0} },
+        { {0x07, 0}, {0xf0, 0x07, 0} }, { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0x79, 0}, {0xf0, 0x79, 0} }, { {0x58, 0}, {0xf0, 0x58, 0} }, { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0x77, 0}, {0xf0, 0x77, 0} }, { {0, 0}, {0, 0} },             { {0x57, 0}, {0xf0, 0x57, 0} },
+        { {0x39, 0}, {0xf0, 0x39, 0} }, { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0x6e, 0}, {0xf0, 0x6e, 0} },
+        { {0x63, 0}, {0xf0, 0x63, 0} }, { {0x6f, 0}, {0xf0, 0x6f, 0} }, { {0, 0}, {0, 0} },             { {0x61, 0}, {0xf0, 0x61, 0} },
+        { {0, 0}, {0, 0} },             { {0x6a, 0}, {0xf0, 0x6a, 0} }, { {0, 0}, {0, 0} },             { {0x65, 0}, {0xf0, 0x65, 0} },
+        { {0x60, 0}, {0xf0, 0x60, 0} }, { {0x6d, 0}, {0xf0, 0x6d, 0} }, { {0x67, 0}, {0xf0, 0x67, 0} }, { {0x64, 0}, {0xf0, 0x64, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0x8b, 0}, {0xf0, 0x8b, 0} },
+        { {0x8c, 0}, {0xf0, 0x8c, 0} }, { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
+        { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },             { {0, 0}, {0, 0} },
 };
 
 /*XT keyboard has no escape scancodes, and no scancodes beyond 53*/
 static scancode scancode_xt[272] =
 {
-        { {-1},       {-1} },       { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
-        { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
-        { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
-        { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
-        { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
-        { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
-        { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
-        { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
-        { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
-        { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
-        { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
-        { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
-        { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
-        { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
-        { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
-        { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
-        { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
-        { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
-        { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
-        { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
-        { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*54*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*58*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*5c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*60*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*64*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*68*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*6c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*70*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*74*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*78*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*7c*/
+        { {0},       {0} },       { {0x01, 0}, {0x81, 0} }, { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} },
+        { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} },
+        { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} },
+        { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} },
+        { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} },
+        { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} },
+        { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} },
+        { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} },
+        { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} },
+        { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} },
+        { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, { {0x2a, 0}, {0xaa, 0} }, { {0x2b, 0}, {0xab, 0} },
+        { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} },
+        { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} },
+        { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} },
+        { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} },
+        { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} },
+        { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} },
+        { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} },
+        { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} },
+        { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} },
+        { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} },
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*54*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*58*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*5c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*60*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*64*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*68*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*6c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*70*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*74*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*78*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*7c*/
 
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*80*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*84*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*88*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*8c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*90*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*94*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*98*/
-        { {0x1c, -1}, {0x9c, -1} },             { {0x1d, -1}, {0x9d, -1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*9c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*a0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*a4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {0x2a, -1}, {0xaa, -1} },             { {-1},             {-1} },             /*a8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*ac*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*b0*/
-        { {-1},             {-1} },             { {0x35, -1}, {0xb5, -1} },             { {0x36, -1}, {0xb6, -1} },             { {0x37, -1}, {0xb7, -1} }, /*b4*/
-        { {0x38, -1}, {0xb8, -1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*b8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*bc*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*c0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {0x46, -1}, {0xc6, -1} },             { {0x47, -1}, {0xc7, -1} }, /*c4*/
-        { {0x48, -1}, {0xc8, -1} },             { {0x49, -1}, {0xc9, -1} },             { {-1},             {-1} },             { {0x4b, -1}, {0xcb, -1} }, /*c8*/
-        { {-1},             {-1} },             { {0x4d, -1}, {0xcd, -1} },             { {-1},             {-1} },             { {0x4f, -1}, {0xcf, -1} }, /*cc*/
-        { {0x50, -1}, {0xd0, -1} },             { {0x51, -1}, {0xd1, -1} },             { {0x52, -1}, {0xd2, -1} },             { {0x53, -1}, {0xd3, -1} }, /*d0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*d4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*d8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*dc*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*e0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*e4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*e8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*ec*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*f0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*f4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*f8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*fc*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*100*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*104*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*108*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*10c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*80*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*84*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*88*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*8c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*90*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*94*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*98*/
+        { {0x1c, 0}, {0x9c, 0} },             { {0x1d, 0}, {0x9d, 0} },             { {0},             {0} },             { {0},             {0} },             /*9c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*a0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*a4*/
+        { {0},             {0} },             { {0},             {0} },             { {0x2a, 0}, {0xaa, 0} },             { {0},             {0} },             /*a8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*ac*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*b0*/
+        { {0},             {0} },             { {0x35, 0}, {0xb5, 0} },             { {0x36, 0}, {0xb6, 0} },             { {0x37, 0}, {0xb7, 0} }, /*b4*/
+        { {0x38, 0}, {0xb8, 0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*b8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*bc*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*c0*/
+        { {0},             {0} },             { {0},             {0} },             { {0x46, 0}, {0xc6, 0} },             { {0x47, 0}, {0xc7, 0} }, /*c4*/
+        { {0x48, 0}, {0xc8, 0} },             { {0x49, 0}, {0xc9, 0} },             { {0},             {0} },             { {0x4b, 0}, {0xcb, 0} }, /*c8*/
+        { {0},             {0} },             { {0x4d, 0}, {0xcd, 0} },             { {0},             {0} },             { {0x4f, 0}, {0xcf, 0} }, /*cc*/
+        { {0x50, 0}, {0xd0, 0} },             { {0x51, 0}, {0xd1, 0} },             { {0x52, 0}, {0xd2, 0} },             { {0x53, 0}, {0xd3, 0} }, /*d0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*d4*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*d8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*dc*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*e0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*e4*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*e8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*ec*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*f0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*f4*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*f8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*fc*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*100*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*104*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*108*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*10c*/
 };
 
 /*Tandy keyboard has slightly different scancodes to XT*/
 static scancode scancode_tandy[272] =
 {
-        { {-1},       {-1} },       { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
-        { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
-        { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
-        { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
-        { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
-        { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
-        { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
-        { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
-        { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
-        { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
-        { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x47, -1}, {0xc7, -1} },
-        { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
-        { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
-        { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
-        { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
-        { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
-        { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
-        { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
-        { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
-        { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
-        { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} },
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*54*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*58*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*5c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*60*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*64*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*68*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*6c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*70*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*74*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*78*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*7c*/
+        { {0},       {0} },       { {0x01, 0}, {0x81, 0} }, { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} },
+        { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} },
+        { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} },
+        { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} },
+        { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} },
+        { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} },
+        { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} },
+        { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} },
+        { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} },
+        { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} },
+        { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, { {0x2a, 0}, {0xaa, 0} }, { {0x47, 0}, {0xc7, 0} },
+        { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} },
+        { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} },
+        { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} },
+        { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} },
+        { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} },
+        { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} },
+        { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} },
+        { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} },
+        { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} },
+        { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x56, 0}, {0xd6, 0} },
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*54*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*58*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*5c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*60*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*64*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*68*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*6c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*70*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*74*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*78*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*7c*/
 
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*80*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*84*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*88*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*8c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*90*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*94*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*98*/
-        { {0x57, -1}, {0xd7, -1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*9c*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*a0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*a4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {0x2a, -1}, {0xaa, -1} },             { {-1},             {-1} },             /*a8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*ac*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*b0*/
-        { {-1},             {-1} },             { {0x35, -1}, {0xb5, -1} },             { {0x36, -1}, {0xb6, -1} },             { {0x37, -1}, {0xb7, -1} }, /*b4*/
-        { {0x38, -1}, {0xb8, -1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*b8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*bc*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*c0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {0x46, -1}, {0xc6, -1} },             { {0x47, -1}, {0xc7, -1} }, /*c4*/
-        { {0x29, -1}, {0xa9, -1} },             { {0x49, -1}, {0xc9, -1} },             { {-1},             {-1} },             { {0x2b, -1}, {0xab, -1} }, /*c8*/
-        { {-1},             {-1} },             { {0x4e, -1}, {0xce, -1} },             { {-1},             {-1} },             { {0x4f, -1}, {0xcf, -1} }, /*cc*/
-        { {0x4a, -1}, {0xca, -1} },             { {0x51, -1}, {0xd1, -1} },             { {0x52, -1}, {0xd2, -1} },             { {0x53, -1}, {0xd3, -1} }, /*d0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*d4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*d8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*dc*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*e0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*e4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*e8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*ec*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*f0*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*f4*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*f8*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*fc*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*100*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*104*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*108*/
-        { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             { {-1},             {-1} },             /*10c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*80*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*84*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*88*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*8c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*90*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*94*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*98*/
+        { {0x57, 0}, {0xd7, 0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*9c*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*a0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*a4*/
+        { {0},             {0} },             { {0},             {0} },             { {0x2a, 0}, {0xaa, 0} },             { {0},             {0} },             /*a8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*ac*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*b0*/
+        { {0},             {0} },             { {0x35, 0}, {0xb5, 0} },             { {0x36, 0}, {0xb6, 0} },             { {0x37, 0}, {0xb7, 0} }, /*b4*/
+        { {0x38, 0}, {0xb8, 0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*b8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*bc*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*c0*/
+        { {0},             {0} },             { {0},             {0} },             { {0x46, 0}, {0xc6, 0} },             { {0x47, 0}, {0xc7, 0} }, /*c4*/
+        { {0x29, 0}, {0xa9, 0} },             { {0x49, 0}, {0xc9, 0} },             { {0},             {0} },             { {0x2b, 0}, {0xab, 0} }, /*c8*/
+        { {0},             {0} },             { {0x4e, 0}, {0xce, 0} },             { {0},             {0} },             { {0x4f, 0}, {0xcf, 0} }, /*cc*/
+        { {0x4a, 0}, {0xca, 0} },             { {0x51, 0}, {0xd1, 0} },             { {0x52, 0}, {0xd2, 0} },             { {0x53, 0}, {0xd3, 0} }, /*d0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*d4*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*d8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*dc*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*e0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*e4*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*e8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*ec*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*f0*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*f4*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*f8*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*fc*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*100*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*104*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*108*/
+        { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             { {0},             {0} },             /*10c*/
 };
-static int oldkey[272];
-static int keydelay[272];
+static uint8_t oldkey[272];
+static uint8_t keydelay[272];
 
 void (*keyboard_send)(uint8_t val);
 void (*keyboard_poll)();
 int keyboard_scan = 1;
 
+static scancode *at_scancodes;
+
+void keyboard_set_scancode_set(int set)
+{
+        switch (set)
+        {
+                case SCANCODE_SET_1:
+                at_scancodes = scancode_set1;
+                break;
+                case SCANCODE_SET_2:
+                at_scancodes = scancode_set2;
+                break;
+                case SCANCODE_SET_3:
+                at_scancodes = scancode_set3;
+                break;
+                default:
+                pclog("Invalid scancode set: %i\n", set);
+        }
+}
+
 void keyboard_process()
 {
         int c;
         int d;
-        scancode *scancodes = (AT) ? scancode_set1 : scancode_xt;
+        scancode *scancodes = (AT || romset == ROM_XI8088) ? at_scancodes : scancode_xt;
         if (!keyboard_scan) return;
         if (TANDY) scancodes = scancode_tandy;
                 
@@ -259,20 +429,20 @@ void keyboard_process()
                 if (pcem_key[c] != oldkey[c])
                 {
                         oldkey[c] = pcem_key[c];
-                        if ( pcem_key[c] && scancodes[c].scancodes_make[0]  == -1)
+                        if ( pcem_key[c] && scancodes[c].scancodes_make[0]  == 0)
                            continue;
-                        if (!pcem_key[c] && scancodes[c].scancodes_break[0] == -1)
+                        if (!pcem_key[c] && scancodes[c].scancodes_break[0] == 0)
                            continue;
 //                        pclog("Key %02X start\n", c);
                         d = 0;
                         if (pcem_key[c])
                         {
-                                while (scancodes[c].scancodes_make[d] != -1)
+                                while (scancodes[c].scancodes_make[d] != 0)
                                       keyboard_send(scancodes[c].scancodes_make[d++]);
                         }
                         else
                         {
-                                while (scancodes[c].scancodes_break[d] != -1)
+                                while (scancodes[c].scancodes_break[d] != 0)
                                       keyboard_send(scancodes[c].scancodes_break[d++]);
                         }
                 }
@@ -283,13 +453,32 @@ void keyboard_process()
                 if (keydelay[c] >= 30)
                 {
                         keydelay[c] -= 10;
-                        if (scancode_set1[c].scancodes_make[0] == -1)
+                        if (scancodes[c].scancodes_make[0] == 0)
                            continue;
                            
                         d = 0;
 
-                        while (scancode_set1[c].scancodes_make[d] != -1)
-                              keyboard_send(scancode_set1[c].scancodes_make[d++]);
+                        while (scancodes[c].scancodes_make[d] != 0)
+                              keyboard_send(scancodes[c].scancodes_make[d++]);
                 }
         }
 }
+
+void keyboard_send_scancode(int code, int is_break)
+{
+        scancode *scancodes = (AT || romset == ROM_XI8088) ? at_scancodes : scancode_xt;
+        int d = 0;
+
+        if (!keyboard_scan) return;
+
+        if (!is_break)
+        {
+                while (scancodes[code].scancodes_make[d] != 0)
+                        keyboard_send(scancodes[code].scancodes_make[d++]);
+        }
+        else
+        {
+                while (scancodes[code].scancodes_break[d] != 0)
+                        keyboard_send(scancodes[code].scancodes_break[d++]);
+        }
+}
index 9430617c7c31b576b2b2b46dc000e5c846532705..fb47b314de4e0fe933b85aedd384541e9649e177 100644 (file)
@@ -3,4 +3,14 @@ extern void (*keyboard_poll)();
 void keyboard_process();
 extern int keyboard_scan;
 
-extern int pcem_key[272];
+extern uint8_t pcem_key[272];
+
+enum
+{
+        SCANCODE_SET_1,
+        SCANCODE_SET_2,
+        SCANCODE_SET_3
+};
+
+void keyboard_set_scancode_set(int set);
+void keyboard_send_scancode(int code, int is_break);
index c56c14e02f6c99cd3261a72ac2b6705763d77519..b2fd23b350e36acadf067db20852101df0d9af20 100644 (file)
@@ -14,8 +14,6 @@
 #include "keyboard.h"
 #include "keyboard_at.h"
 
-extern bool ps2_mouse_supported;
-
 #define STAT_PARITY     0x80
 #define STAT_RTIMEOUT   0x40
 #define STAT_TTIMEOUT   0x20
@@ -28,6 +26,8 @@ extern bool ps2_mouse_supported;
 
 #define PS2_REFRESH_TIME (16 * TIMER_USEC)
 
+#define RESET_DELAY_TIME (100 * 10) /*600ms*/
+
 struct
 {
         int initialised;
@@ -38,6 +38,10 @@ struct
         uint8_t mem[0x20];
         uint8_t out;
         int out_new, out_delayed;
+
+        int scancode_set;
+        int translate;
+        int next_is_release;
         
         uint8_t input_port;
         uint8_t output_port;
@@ -50,12 +54,36 @@ struct
         void (*mouse_write)(uint8_t val, void *p);
         void *mouse_p;
         
-        int refresh_time;
+        pc_timer_t refresh_timer;
         int refresh;
         
         int is_ps2;
+
+       pc_timer_t send_delay_timer;
+       
+       int reset_delay;
 } keyboard_at;
 
+/*Translation table taken from https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#ss10.3*/
+static uint8_t at_translation[256] =
+{
+        0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
+        0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
+        0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
+        0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
+        0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
+        0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
+        0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
+        0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
+        0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+        0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
 static uint8_t key_ctrl_queue[16];
 static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0;
 
@@ -65,24 +93,34 @@ static int key_queue_start = 0, key_queue_end = 0;
 static uint8_t mouse_queue[16];
 int mouse_queue_start = 0, mouse_queue_end = 0;
 
-void keyboard_at_poll(void *priv)
+void keyboard_at_adddata_keyboard(uint8_t val);
+
+void keyboard_at_poll()
 {
-       keybsenddelay += (100 * TIMER_USEC);
+       timer_advance_u64(&keyboard_at.send_delay_timer, (100 * TIMER_USEC));
 
         if (keyboard_at.out_new != -1 && !keyboard_at.last_irq)
         {
                 keyboard_at.wantirq = 0;
                 if (keyboard_at.out_new & 0x100)
                 {
-                        if (keyboard_at.mem[0] & 0x02)
-                                picint(0x1000);
-                        keyboard_at.out = keyboard_at.out_new & 0xff;
-                        keyboard_at.out_new = -1;
-                        keyboard_at.status |=  STAT_OFULL;
-                        keyboard_at.status &= ~STAT_IFULL;
-                        keyboard_at.status |=  STAT_MFULL;
-//                        pclog("keyboard_at : take IRQ12\n");
-                        keyboard_at.last_irq = 0x1000;
+                        if (mouse_scan)
+                        {
+//                                pclog("keyboard_at : take IRQ12\n");
+                                if (keyboard_at.mem[0] & 0x02)
+                                        picint(0x1000);
+                                keyboard_at.out = keyboard_at.out_new & 0xff;
+                                keyboard_at.out_new = -1;
+                                keyboard_at.status |=  STAT_OFULL;
+                                keyboard_at.status &= ~STAT_IFULL;
+                                keyboard_at.status |=  STAT_MFULL;
+                                keyboard_at.last_irq = 0x1000;
+                        }
+                        else
+                        {
+//                                pclog("keyboard_at: suppressing IRQ12\n");
+                                keyboard_at.out_new = -1;
+                        }
                 }
                 else
                 {
@@ -121,19 +159,21 @@ void keyboard_at_poll(void *priv)
         {
                 keyboard_at.out_new = mouse_queue[mouse_queue_start] | 0x100;
                 mouse_queue_start = (mouse_queue_start + 1) & 0xf;
-        }                
+        }
         else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 &&
                  !(keyboard_at.mem[0] & 0x10) && key_queue_start != key_queue_end)
         {
                 keyboard_at.out_new = key_queue[key_queue_start];
                 key_queue_start = (key_queue_start + 1) & 0xf;
-        }                
-}
-void keyboard_at_poll()
-{
-       keyboard_at_poll(NULL);
-}
+        }
 
+        if (keyboard_at.reset_delay)
+        {
+                keyboard_at.reset_delay--;
+                if (!keyboard_at.reset_delay)
+                        keyboard_at_adddata_keyboard(0xaa);
+        }
+}
 
 void keyboard_at_adddata(uint8_t val)
 {
@@ -149,6 +189,8 @@ void keyboard_at_adddata(uint8_t val)
 
 void keyboard_at_adddata_keyboard(uint8_t val)
 {
+        if (keyboard_at.reset_delay)
+                return;
 /*        if (val == 0x1c)
         {
                 key_1c++;
@@ -178,6 +220,21 @@ void keyboard_at_adddata_keyboard(uint8_t val)
                        case 0x4D: t3100e_notify_set(0x0F); break; /* Right */
                }
        }
+       if (keyboard_at.translate)
+       {
+                if (val == 0xf0)
+                {
+                        keyboard_at.next_is_release = 1;
+                        return;
+                }
+                else
+                {
+                        val = at_translation[val];
+                        if (keyboard_at.next_is_release)
+                                val |= 0x80;
+                        keyboard_at.next_is_release = 0;
+                }
+        }
         key_queue[key_queue_end] = val;
         key_queue_end = (key_queue_end + 1) & 0xf;
 //        pclog("keyboard_at : %02X added to key queue\n", val);
@@ -192,11 +249,9 @@ void keyboard_at_adddata_mouse(uint8_t val)
         return;
 }
 
-uint8_t x86_get_jumpers(void);
-
 void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
 {
-        //pclog("keyboard_at : write %04X %02X %i  %02X\n", port, val, keyboard_at.key_wantdata, ram[8]);
+//        pclog("keyboard_at : write %04X %02X %i  %02X\n", port, val, keyboard_at.key_wantdata, ram[8]);
         if (romset == ROM_XI8088 && port == 0x63)
                 port = 0x61;
 /*        if (ram[8] == 0xc3) 
@@ -228,6 +283,7 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                                         if (!(val & 1) && keyboard_at.wantirq)
                                            keyboard_at.wantirq = 0;
                                         mouse_scan = !(val & 0x20);
+                                        keyboard_at.translate = val & 0x40;
                                 }                                           
                                 break;
 
@@ -255,13 +311,17 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                                 break;
                                 
                                 case 0xd3: /*Write to mouse output buffer*/
-                                                               if (ps2_mouse_supported)
-                                       keyboard_at_adddata_mouse(val);
+                                keyboard_at_adddata_mouse(val);
                                 break;
                                 
                                 case 0xd4: /*Write to mouse*/
-                                if (keyboard_at.mouse_write && ps2_mouse_supported)
+                                if (keyboard_at.mouse_write)
+                                {
                                         keyboard_at.mouse_write(val, keyboard_at.mouse_p);
+                                        /*Implicitly enable mouse*/
+                                        mouse_scan = 1;
+                                        keyboard_at.mem[0] &= ~0x20;
+                                }
                                 break;     
                                 
                                 default:
@@ -282,6 +342,45 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                                         case 0xed: /*Set/reset LEDs*/
                                         keyboard_at_adddata_keyboard(0xfa);
                                         break;
+                                        
+                                        case 0xf0: /*Set scancode set*/
+                                        switch (val)
+                                        {
+                                                case 0: /*Read current set*/
+                                                keyboard_at_adddata_keyboard(0xfa);
+                                                switch (keyboard_at.scancode_set)
+                                                {
+                                                        case SCANCODE_SET_1:
+                                                        keyboard_at_adddata_keyboard(0x01);
+                                                        break;
+                                                        case SCANCODE_SET_2:
+                                                        keyboard_at_adddata_keyboard(0x02);
+                                                        break;
+                                                        case SCANCODE_SET_3:
+                                                        keyboard_at_adddata_keyboard(0x03);
+                                                        break;
+                                                }
+                                                break;
+                                                case 1:
+                                                keyboard_at.scancode_set = SCANCODE_SET_1;
+                                                keyboard_set_scancode_set(SCANCODE_SET_1);
+                                                keyboard_at_adddata_keyboard(0xfa);
+                                                break;
+                                                case 2:
+                                                keyboard_at.scancode_set = SCANCODE_SET_2;
+                                                keyboard_set_scancode_set(SCANCODE_SET_2);
+                                                keyboard_at_adddata_keyboard(0xfa);
+                                                break;
+                                                case 3:
+                                                keyboard_at.scancode_set = SCANCODE_SET_3;
+                                                keyboard_set_scancode_set(SCANCODE_SET_3);
+                                                keyboard_at_adddata_keyboard(0xfa);
+                                                break;
+                                                default:
+                                                keyboard_at_adddata_keyboard(0xfe);
+                                                break;
+                                        }
+                                        break;
 
                                         case 0xf3: /*Set typematic rate/delay*/
                                         keyboard_at_adddata_keyboard(0xfa);
@@ -307,11 +406,19 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                                         keyboard_at_adddata_keyboard(0xfa);
                                         break;
                                         
+                                        case 0xee: /*Diagnostic echo*/
+                                        keyboard_at_adddata_keyboard(0xee);
+                                        break;
+
+                                        case 0xf0: /*Set scancode set*/
+                                        keyboard_at.key_wantdata = 1;
+                                        keyboard_at_adddata_keyboard(0xfa);
+                                        break;
+
                                         case 0xf2: /*Read ID*/
                                         keyboard_at_adddata_keyboard(0xfa);
-                                                                               // A2286/A2386 does not want these
-                                        //keyboard_at_adddata_keyboard(0xab);
-                                        //keyboard_at_adddata_keyboard(0x41);
+                                        keyboard_at_adddata_keyboard(0xab);
+                                        keyboard_at_adddata_keyboard(0x83);
                                         break;
                                         
                                         case 0xf3: /*Set typematic rate/delay*/
@@ -331,7 +438,7 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                                         case 0xff: /*Reset*/
                                         key_queue_start = key_queue_end = 0; /*Clear key queue*/
                                         keyboard_at_adddata_keyboard(0xfa);
-                                        keyboard_at_adddata_keyboard(0xaa);
+                                        keyboard_at.reset_delay = RESET_DELAY_TIME;
                                         break;
                                         
                                         default:
@@ -347,9 +454,6 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                 case 0x61:
                 ppi.pb = val;
 
-                timer_process();
-                timer_update_outstanding();
-
                 speaker_update();
                 speaker_gated = val & 1;
                 speaker_enable = val & 2;
@@ -399,16 +503,16 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                                 
                         case 0xa7: /*Disable mouse port*/
                         mouse_scan = 0;
+                        keyboard_at.mem[0] |= 0x20;
                         break;
 
                         case 0xa8: /*Enable mouse port*/
-                                               if (ps2_mouse_supported)
-                               mouse_scan = 1;
+                        mouse_scan = 1;
+                        keyboard_at.mem[0] &= ~0x20;
                         break;
                         
                         case 0xa9: /*Test mouse port*/
-                                               if (ps2_mouse_supported)
-                               keyboard_at_adddata(0x00); /*no error*/
+                        keyboard_at_adddata(0x00); /*no error*/
                         break;
                         
                         case 0xaa: /*Self-test*/
@@ -445,8 +549,6 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
 
                         case 0xae: /*Enable keyboard*/
                         keyboard_at.mem[0] &= ~0x10;
-                                               if (!keyboard_at.initialised)
-                                                       keyboard_at_adddata(0x00); // A2286 bios requires data in output buffer after enable keyboard.
                         break;
 
                        case 0xb0:      /* T3100e: Turbo on */
@@ -514,8 +616,7 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                        if (romset == ROM_T3100E)
                                keyboard_at.input_port = (t3100e_mono_get() & 1) ? 0xFF : 0xBF;
 
-                        keyboard_at_adddata(x86_get_jumpers());
-                        //keyboard_at_adddata(keyboard_at.input_port | 4);
+                        keyboard_at_adddata(keyboard_at.input_port | 4);
                         keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc);
                         break;
                         
@@ -543,18 +644,28 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
                         break;
                         
                         case 0xd3: /*Write mouse output buffer*/
-                                               if (ps2_mouse_supported)
-                               keyboard_at.want60 = 1;
+                        keyboard_at.want60 = 1;
                         break;
                         
                         case 0xd4: /*Write to mouse*/
-                                               if (ps2_mouse_supported)
-                                                       keyboard_at.want60 = 1;
+                        keyboard_at.want60 = 1;
                         break;
                         
                         case 0xe0: /*Read test inputs*/
                         keyboard_at_adddata(0x00);
                         break;
+
+                        case 0xe8: /* Super-286TR: turbo ON */
+                        // TODO: 0xe8 is always followed by 0xba
+                        // TODO: I don't know where to call cpu_set_turbo(1) to avoid slow POST after ctrl-alt-del when on low speed (if this is the real behavior!)
+                        if (romset == ROM_HYUNDAI_SUPER286TR)
+                                cpu_set_turbo(1); // 12 MHz
+                        break;
+
+                        case 0xe9: /* Super-286TR: turbo OFF */
+                        if (romset == ROM_HYUNDAI_SUPER286TR)
+                                cpu_set_turbo(0); // 8 MHz
+                        break;
                         
                         case 0xef: /*??? - sent by AMI486*/
                         break;
@@ -579,6 +690,9 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv)
 uint8_t keyboard_at_read(uint16_t port, void *priv)
 {
         uint8_t temp = 0xff;
+
+        if (romset != ROM_IBMAT && romset != ROM_IBMXT286)
+                cycles -= ISA_CYCLES(8);
 //        if (port != 0x61) pclog("keyboard_at : read %04X ", port);
         if (romset == ROM_XI8088 && port == 0x63)
                 port = 0x61;
@@ -633,9 +747,9 @@ void keyboard_at_reset()
                 keyboard_at.input_port = (video_is_mda()) ? 0xb0 : 0xf0;
         else
                 keyboard_at.input_port = (video_is_mda()) ? 0xf0 : 0xb0;
-               keyboard_at.out_new = -1;
-               keyboard_at.out_delayed = -1;
-               keyboard_at.last_irq = 0;
+        keyboard_at.out_new = -1;
+        keyboard_at.out_delayed = -1;
+        keyboard_at.last_irq = 0;
         
         keyboard_at.key_wantdata = 0;
         
@@ -645,7 +759,7 @@ void keyboard_at_reset()
 static void at_refresh(void *p)
 {
         keyboard_at.refresh = !keyboard_at.refresh;
-        keyboard_at.refresh_time += PS2_REFRESH_TIME;
+        timer_advance_u64(&keyboard_at.refresh_timer, PS2_REFRESH_TIME);
 }
 
 void keyboard_at_init()
@@ -659,8 +773,10 @@ void keyboard_at_init()
         keyboard_at.mouse_write = NULL;
         keyboard_at.mouse_p = NULL;
         keyboard_at.is_ps2 = 0;
+        keyboard_set_scancode_set(SCANCODE_SET_2);
+        keyboard_at.scancode_set = SCANCODE_SET_2;
         
-        timer_add(keyboard_at_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED,  NULL);
+        timer_add(&keyboard_at.send_delay_timer, keyboard_at_poll, NULL, 1);
 }
 
 void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p)
@@ -671,6 +787,6 @@ void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p)
 
 void keyboard_at_init_ps2()
 {
-        timer_add(at_refresh, &keyboard_at.refresh_time, TIMER_ALWAYS_ENABLED,  NULL);
+        timer_add(&keyboard_at.refresh_timer, at_refresh, NULL, 1);
         keyboard_at.is_ps2 = 1;
 }
index 90d7f07ef5d15ccf3a01218a3bd5b345a2e3e42e..0f1e6aef962f18d2612dcd0beaefbcf8989df323 100644 (file)
@@ -1,5 +1,6 @@
 void mca_init(int nr_cards);
-void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv);
+void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void (*reset)(void *priv), void *priv);
 void mca_set_index(int index);
 uint8_t mca_read(uint16_t port);
 void mca_write(uint16_t port, uint8_t val);
+void mca_reset(void);
index 425500a6f3e4379c42c3ea88d50907a2e8bd116f..89bbff8d68ca55c9817898a08120a53e4ac3f75a 100644 (file)
 page_t *pages;
 page_t **page_lookup;
 
-static uint8_t         (*_mem_read_b[0x40000])(uint32_t addr, void *priv);
-static uint16_t        (*_mem_read_w[0x40000])(uint32_t addr, void *priv);
-static uint32_t        (*_mem_read_l[0x40000])(uint32_t addr, void *priv);
-static void           (*_mem_write_b[0x40000])(uint32_t addr, uint8_t  val, void *priv);
-static void           (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv);
-static void           (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv);
-static uint8_t            *_mem_exec[0x40000];
-static void             *_mem_priv_r[0x40000];
-static void             *_mem_priv_w[0x40000];
-static mem_mapping_t *_mem_mapping_r[0x40000];
-static mem_mapping_t *_mem_mapping_w[0x40000];
-static int                _mem_state[0x40000];
+static mem_mapping_t  *read_mapping[0x40000];
+static mem_mapping_t *write_mapping[0x40000];
+static uint8_t           *_mem_exec[0x40000];
+static uint8_t           _mem_state[0x40000];
 
 static mem_mapping_t base_mapping;
 mem_mapping_t ram_low_mapping;
@@ -44,10 +36,6 @@ mem_mapping_t bios_mapping[8];
 mem_mapping_t bios_high_mapping[8];
 static mem_mapping_t romext_mapping;
 
-int shadowbios,shadowbios_write;
-
-unsigned char isram[0x10000];
-
 static uint8_t ff_array[0x1000];
 
 int mem_size;
@@ -58,7 +46,20 @@ int cachesize=256;
 uint8_t *ram, *rom = NULL;
 uint8_t romext[32768];
 
-//int abrt=0;
+uint64_t *byte_dirty_mask;
+uint64_t *byte_code_present_mask;
+
+uint32_t mem_logical_addr;
+
+int mmuflush=0;
+int mmu_perm=4;
+
+int mem_addr_is_ram(uint32_t addr)
+{
+        mem_mapping_t *mapping = read_mapping[addr >> 14];
+        
+        return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || (mapping == &ram_remapped_mapping);
+}
 
 void resetreadlookup()
 {
@@ -76,9 +77,6 @@ void resetreadlookup()
 
 }
 
-int mmuflush=0;
-int mmu_perm=4;
-
 void flushmmucache()
 {
         int c;
@@ -210,15 +208,9 @@ void mem_flush_write_page(uint32_t addr, uint32_t virt)
         }
 }
 
-extern int output;
-
 #define mmutranslate_read(addr) mmutranslatereal(addr,0)
 #define mmutranslate_write(addr) mmutranslatereal(addr,1)
 
-int pctrans=0;
-
-extern uint32_t testr[9];
-
 static inline uint32_t mmu_readl(uint32_t addr)
 {
         return *(uint32_t *)&_mem_exec[addr >> 14][addr & 0x3fff];
@@ -295,7 +287,6 @@ uint32_t mmutranslatereal(uint32_t addr, int rw)
         if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || cr0&WP_FLAG)))
         {
 //                if (!nopageerrors) pclog("Page not present!  %08X   %08X   %02X %02X  %i  %08X  %04X:%08X  %04X:%08X %i  %i %i\n",addr,temp,opcode,opcode2,frame,rmdat32, CS,pc,SS,ESP,ins,CPL,rw);
-
 //                dumpregs();
 //                exit(-1);
 //                if (addr == 0x815F6E90) output = 3;
@@ -420,7 +411,7 @@ void addwritelookup(uint32_t virt, uint32_t phys)
 //        if (page_lookup[virt >> 12] && (writelookup2[virt>>12] != 0xffffffff))
 //                fatal("Bad write mapping\n");
 
-        if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page)
+        if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page)
                 page_lookup[virt >> 12] = &pages[phys >> 12];//(uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)];
         else
                 writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)];
@@ -432,16 +423,13 @@ void addwritelookup(uint32_t virt, uint32_t phys)
         cycles -= 9;
 }
 
-#undef printf
 uint8_t *getpccache(uint32_t a)
 {
         uint32_t a2=a;
 
         if (cr0>>31)
         {
-               pctrans=1;
                 a = mmutranslate_read(a);
-                pctrans=0;
 
                 if (a==0xFFFFFFFF) return ram;
         }
@@ -449,7 +437,7 @@ uint8_t *getpccache(uint32_t a)
 
         if (_mem_exec[a >> 14])
         {
-                if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM)
+                if (read_mapping[a >> 14]->flags & MEM_MAPPING_ROM)
                         cpu_prefetch_cycles = cpu_rom_prefetch_cycles;
                 else
                         cpu_prefetch_cycles = cpu_mem_prefetch_cycles;
@@ -460,11 +448,11 @@ uint8_t *getpccache(uint32_t a)
         pclog("Bad getpccache %08X\n", a);
         return &ff_array[0-(uintptr_t)(a2 & ~0xFFF)];
 }
-#define printf pclog
 
-uint32_t mem_logical_addr;
 uint8_t readmembl(uint32_t addr)
 {
+        mem_mapping_t *map;
+        
         mem_logical_addr = addr;
         if (cr0 >> 31)
         {
@@ -473,13 +461,17 @@ uint8_t readmembl(uint32_t addr)
         }
         addr &= rammask;
 
-        if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]);
+        map = read_mapping[addr >> 14];
+        if (map && map->read_b)
+                return map->read_b(addr, map->p);
 //        pclog("Bad readmembl %08X %04X:%08X\n", addr, CS, pc);
         return 0xFF;
 }
 
 void writemembl(uint32_t addr, uint8_t val)
 {
+        mem_mapping_t *map;
+
         mem_logical_addr = addr;
 
         if (page_lookup[addr>>12])
@@ -494,456 +486,380 @@ void writemembl(uint32_t addr, uint8_t val)
         }
         addr &= rammask;
 
-        if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
+        map = write_mapping[addr >> 14];
+        if (map && map->write_b)
+                return map->write_b(addr, val, map->p);
 //        else                          pclog("Bad writemembl %08X %02X  %04X:%08X\n", addr, val, CS, pc);
 }
 
-uint8_t readmemb386l(uint32_t seg, uint32_t addr)
-{
-        if (seg==-1)
-        {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! rb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return -1;
-        }
-        mem_logical_addr = addr = addr + seg;
-/*        if (readlookup2[mem_logical_addr >> 12] != 0xFFFFFFFF)
-        {
-                return ram[readlookup2[mem_logical_addr >> 12] + (mem_logical_addr & 0xFFF)];
-        }*/
-        
-        if (cr0 >> 31)
-        {
-                addr = mmutranslate_read(addr);
-                if (addr == 0xFFFFFFFF) return 0xFF;
-        }
-
-        addr &= rammask;
-
-        if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]);
-//        pclog("Bad readmemb386l %08X %04X:%08X\n", addr, CS, pc);
-        return 0xFF;
-}
-
-void writememb386l(uint32_t seg, uint32_t addr, uint8_t val)
+uint16_t readmemwl(uint32_t addr)
 {
-        if (seg==-1)
-        {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! wb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return;
-        }
-        
-        mem_logical_addr = addr = addr + seg;
-        if (page_lookup[addr>>12])
-        {
-                page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]);
-                return;
-        }
-        if (cr0 >> 31)
-        {
-                addr = mmutranslate_write(addr);
-                if (addr == 0xFFFFFFFF) return;
-        }
-
-        addr &= rammask;
-
-/*        if (addr >= 0xa0000 && addr < 0xc0000)
-           pclog("writemembl %08X %02X\n", addr, val);*/
+        mem_mapping_t *map;
 
-        if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
-//        else                          pclog("Bad writememb386l %08X %02X %04X:%08X\n", addr, val, CS, pc);
-}
-
-uint16_t readmemwl(uint32_t seg, uint32_t addr)
-{
-        uint32_t addr2 = mem_logical_addr = seg + addr;
+        mem_logical_addr = addr;
 
-        if (seg==-1)
+        if (addr & 1)
         {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! rw %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return -1;
-        }
-        if (addr2 & 1)
-        {
-                if (!cpu_cyrix_alignment || (addr2 & 7) == 7)
+                if (!cpu_cyrix_alignment || (addr & 7) == 7)
                         cycles -= timing_misaligned;
-                if ((addr2 & 0xFFF) > 0xFFE)
+                if ((addr & 0xFFF) > 0xFFE)
                 {
                         if (cr0 >> 31)
                         {
-                                if (mmutranslate_read(addr2)   == 0xffffffff) return 0xffff;
-                                if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff;
+                                if (mmutranslate_read(addr)   == 0xffffffff) return 0xffff;
+                                if (mmutranslate_read(addr+1) == 0xffffffff) return 0xffff;
                         }
-                        if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8);
-                        else       return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8);
+                        return readmembl(addr)|(readmembl(addr+1)<<8);
                 }
-                else if (readlookup2[addr2 >> 12] != -1)
-                        return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2);
+                else if (readlookup2[addr >> 12] != -1)
+                        return *(uint16_t *)(readlookup2[addr >> 12] + addr);
         }
         if (cr0>>31)
         {
-                addr2 = mmutranslate_read(addr2);
-                if (addr2==0xFFFFFFFF) return 0xFFFF;
+                addr = mmutranslate_read(addr);
+                if (addr==0xFFFFFFFF) return 0xFFFF;
         }
 
-        addr2 &= rammask;
-
-        if (_mem_read_w[addr2 >> 14]) return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]);
+        addr &= rammask;
 
-        if (_mem_read_b[addr2 >> 14])
+        map = read_mapping[addr >> 14];
+        if (map)
         {
-                if (AT) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8);
-                else    return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14]) << 8);
+                if (map->read_w)
+                        return map->read_w(addr, map->p);
+
+                if (map->read_b)
+                        return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8);
         }
-//        pclog("Bad readmemwl %08X\n", addr2);
+
+//        pclog("Bad readmemwl %08X\n", addr);
         return 0xffff;
 }
 
-void writememwl(uint32_t seg, uint32_t addr, uint16_t val)
+void writememwl(uint32_t addr, uint16_t val)
 {
-        uint32_t addr2 = mem_logical_addr = seg + addr;
+        mem_mapping_t *map;
 
-        if (seg==-1)
-        {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! ww %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return;
-        }
+        mem_logical_addr = addr;
 
-        if (addr2 & 1)
+        if (addr & 1)
         {
-                if (!cpu_cyrix_alignment || (addr2 & 7) == 7)
+                if (!cpu_cyrix_alignment || (addr & 7) == 7)
                         cycles -= timing_misaligned;
-                if ((addr2 & 0xFFF) > 0xFFE)
+                if ((addr & 0xFFF) > 0xFFE)
                 {
                         if (cr0 >> 31)
                         {
-                                if (mmutranslate_write(addr2)   == 0xffffffff) return;
-                                if (mmutranslate_write(addr2+1) == 0xffffffff) return;
-                        }
-                        if (is386)
-                        {
-                                writememb386l(seg,addr,val);
-                                writememb386l(seg,addr+1,val>>8);
-                        }
-                        else
-                        {
-                                writemembl(seg+addr,val);
-                                writemembl(seg+addr+1,val>>8);
+                                if (mmutranslate_write(addr)   == 0xffffffff) return;
+                                if (mmutranslate_write(addr+1) == 0xffffffff) return;
                         }
+                        writemembl(addr,val);
+                        writemembl(addr+1,val>>8);
                         return;
                 }
-                else if (writelookup2[addr2 >> 12] != -1)
+                else if (writelookup2[addr >> 12] != -1)
                 {
-                        *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val;
+                        *(uint16_t *)(writelookup2[addr >> 12] + addr) = val;
                         return;
                 }
         }
 
-        if (page_lookup[addr2>>12])
+        if (page_lookup[addr>>12])
         {
-                page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]);
+                page_lookup[addr>>12]->write_w(addr, val, page_lookup[addr>>12]);
                 return;
         }
         if (cr0>>31)
         {
-                addr2 = mmutranslate_write(addr2);
-                if (addr2==0xFFFFFFFF) return;
+                addr = mmutranslate_write(addr);
+                if (addr==0xFFFFFFFF) return;
         }
         
-        addr2 &= rammask;
+        addr &= rammask;
 
-/*        if (addr2 >= 0xa0000 && addr2 < 0xc0000)
-           pclog("writememwl %08X %02X\n", addr2, val);*/
-        
-        if (_mem_write_w[addr2 >> 14]) 
+        map = write_mapping[addr >> 14];
+        if (map)
         {
-                _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]);
-                return;
+                if (map->write_w)
+                        map->write_w(addr, val, map->p);
+                else if (map->write_b)
+                {
+                        map->write_b(addr, val, map->p);
+                        map->write_b(addr + 1, val >> 8, map->p);
+                }
         }
 
-        if (_mem_write_b[addr2 >> 14]) 
-        {
-                _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]);
-                return;
-        }
-//        pclog("Bad writememwl %08X %04X\n", addr2, val);
+//        pclog("Bad writememwl %08X %04X\n", addr, val);
 }
 
-uint32_t readmemll(uint32_t seg, uint32_t addr)
+uint32_t readmemll(uint32_t addr)
 {
-        uint32_t addr2 = mem_logical_addr = seg + addr;
+        mem_mapping_t *map;
 
-        if (seg==-1)
-        {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return -1;
-        }
+        mem_logical_addr = addr;
 
-        if (addr2 & 3)
+        if (addr & 3)
         {
-                if (!cpu_cyrix_alignment || (addr2 & 7) > 4)
+                if (!cpu_cyrix_alignment || (addr & 7) > 4)
                         cycles -= timing_misaligned;
-                if ((addr2&0xFFF)>0xFFC)
+                if ((addr&0xFFF)>0xFFC)
                 {
                         if (cr0>>31)
                         {
-                                if (mmutranslate_read(addr2)   == 0xffffffff) return 0xffffffff;
-                                if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff;
+                                if (mmutranslate_read(addr)   == 0xffffffff) return 0xffffffff;
+                                if (mmutranslate_read(addr+3) == 0xffffffff) return 0xffffffff;
                         }
-                        return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16);
+                        return readmemwl(addr)|(readmemwl(addr+2)<<16);
                 }
-                else if (readlookup2[addr2 >> 12] != -1)
-                        return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2);
+                else if (readlookup2[addr >> 12] != -1)
+                        return *(uint32_t *)(readlookup2[addr >> 12] + addr);
         }
 
         if (cr0>>31)
         {
-                addr2 = mmutranslate_read(addr2);
-                if (addr2==0xFFFFFFFF) return 0xFFFFFFFF;
+                addr = mmutranslate_read(addr);
+                if (addr==0xFFFFFFFF) return 0xFFFFFFFF;
         }
 
-        addr2&=rammask;
+        addr&=rammask;
+
+        map = read_mapping[addr >> 14];
+        if (map)
+        {
+                if (map->read_l)
+                        return map->read_l(addr, map->p);
 
-        if (_mem_read_l[addr2 >> 14]) return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]);
+                if (map->read_w)
+                        return map->read_w(addr, map->p) | (map->read_w(addr + 2, map->p) << 16);
 
-        if (_mem_read_w[addr2 >> 14]) return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16);
-        
-        if (_mem_read_b[addr2 >> 14]) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8) | (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16) | (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14]) << 24);
+                if (map->read_b)
+                        return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8) |
+                                (map->read_b(addr + 2, map->p) << 16) | (map->read_b(addr + 3, map->p) << 24);
+        }
 
-//        pclog("Bad readmemll %08X\n", addr2);
+//        pclog("Bad readmemll %08X\n", addr);
         return 0xffffffff;
 }
 
-void writememll(uint32_t seg, uint32_t addr, uint32_t val)
+void writememll(uint32_t addr, uint32_t val)
 {
-        uint32_t addr2 = mem_logical_addr = seg + addr;
+        mem_mapping_t *map;
 
-        if (seg==-1)
-        {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return;
-        }
-        if (addr2 & 3)
+        mem_logical_addr = addr;
+
+        if (addr & 3)
         {
-                if (!cpu_cyrix_alignment || (addr2 & 7) > 4)
+                if (!cpu_cyrix_alignment || (addr & 7) > 4)
                         cycles -= timing_misaligned;
-                if ((addr2 & 0xFFF) > 0xFFC)
+                if ((addr & 0xFFF) > 0xFFC)
                 {
                         if (cr0>>31)
                         {
-                                if (mmutranslate_write(addr2)   == 0xffffffff) return;
-                                if (mmutranslate_write(addr2+3) == 0xffffffff) return;
+                                if (mmutranslate_write(addr)   == 0xffffffff) return;
+                                if (mmutranslate_write(addr+3) == 0xffffffff) return;
                         }
-                        writememwl(seg,addr,val);
-                        writememwl(seg,addr+2,val>>16);
+                        writememwl(addr,val);
+                        writememwl(addr+2,val>>16);
                         return;
                 }
-                else if (writelookup2[addr2 >> 12] != -1)
+                else if (writelookup2[addr >> 12] != -1)
                 {
-                        *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val;
+                        *(uint32_t *)(writelookup2[addr >> 12] + addr) = val;
                         return;
                 }
         }
-        if (page_lookup[addr2>>12])
+        if (page_lookup[addr>>12])
         {
-                page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]);
+                page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]);
                 return;
         }
         if (cr0>>31)
         {
-                addr2 = mmutranslate_write(addr2);
-                if (addr2==0xFFFFFFFF) return;
+                addr = mmutranslate_write(addr);
+                if (addr==0xFFFFFFFF) return;
         }
         
-        addr2&=rammask;
+        addr&=rammask;
 
-/*        if (addr >= 0xa0000 && addr < 0xc0000)
-           pclog("writememll %08X %08X\n", addr, val);*/
-
-        if (_mem_write_l[addr2 >> 14]) 
-        {
-                _mem_write_l[addr2 >> 14](addr2, val,           _mem_priv_w[addr2 >> 14]);
-                return;
-        }
-        if (_mem_write_w[addr2 >> 14]) 
-        {
-                _mem_write_w[addr2 >> 14](addr2,     val,       _mem_priv_w[addr2 >> 14]);
-                _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]);
-                return;
-        }
-        if (_mem_write_b[addr2 >> 14]) 
+        map = write_mapping[addr >> 14];
+        if (map)
         {
-                _mem_write_b[addr2 >> 14](addr2,     val,       _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8,  _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]);
-                return;
+                if (map->write_l)
+                        map->write_l(addr, val, map->p);
+                else if (map->write_w)
+                {
+                        map->write_w(addr, val, map->p);
+                        map->write_w(addr + 2, val >> 16, map->p);
+                }
+                else if (map->write_b)
+                {
+                        map->write_b(addr, val, map->p);
+                        map->write_b(addr + 1, val >> 8, map->p);
+                        map->write_b(addr + 2, val >> 16, map->p);
+                        map->write_b(addr + 3, val >> 24, map->p);
+                }
         }
-//        pclog("Bad writememll %08X %08X\n", addr2, val);
+//        pclog("Bad writememll %08X %08X\n", addr, val);
 }
 
-uint64_t readmemql(uint32_t seg, uint32_t addr)
+uint64_t readmemql(uint32_t addr)
 {
-        uint32_t addr2 = mem_logical_addr = seg + addr;
+        mem_mapping_t *map;
 
-        if (seg==-1)
-        {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return -1;
-        }
+        mem_logical_addr = addr;
 
-        if (addr2 & 7)
+        if (addr & 7)
         {
                 cycles -= timing_misaligned;
-                if ((addr2 & 0xFFF) > 0xFF8)
+                if ((addr & 0xFFF) > 0xFF8)
                 {
                         if (cr0>>31)
                         {
-                                if (mmutranslate_read(addr2)   == 0xffffffff) return 0xffffffff;
-                                if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff;
+                                if (mmutranslate_read(addr)   == 0xffffffff) return 0xffffffff;
+                                if (mmutranslate_read(addr+7) == 0xffffffff) return 0xffffffff;
                         }
-                        return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32);
+                        return readmemll(addr)|((uint64_t)readmemll(addr+4)<<32);
                 }
-                else if (readlookup2[addr2 >> 12] != -1)
-                        return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2);
+                else if (readlookup2[addr >> 12] != -1)
+                        return *(uint64_t *)(readlookup2[addr >> 12] + addr);
         }
         
         if (cr0>>31)
         {
-                addr2 = mmutranslate_read(addr2);
-                if (addr2==0xFFFFFFFF) return 0xFFFFFFFF;
+                addr = mmutranslate_read(addr);
+                if (addr==0xFFFFFFFF) return 0xFFFFFFFF;
         }
 
-        addr2&=rammask;
+        addr&=rammask;
 
-        if (_mem_read_l[addr2 >> 14])
-                return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) |
-                                 ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32);
+        map = read_mapping[addr >> 14];
+        if (map && map->read_l)
+                return map->read_l(addr, map->p) | ((uint64_t)map->read_l(addr + 4, map->p) << 32);
 
-        return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32);
+        return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32);
 }
 
-void writememql(uint32_t seg, uint32_t addr, uint64_t val)
+void writememql(uint32_t addr, uint64_t val)
 {
-        uint32_t addr2 = mem_logical_addr = seg + addr;
+        mem_mapping_t *map;
 
-        if (seg==-1)
-        {
-                x86gpf("NULL segment", 0);
-                printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr);
-                return;
-        }
-        if (addr2 & 7)
+        mem_logical_addr = addr;
+
+        if (addr & 7)
         {
                 cycles -= timing_misaligned;
-                if ((addr2 & 0xFFF) > 0xFF8)
+                if ((addr & 0xFFF) > 0xFF8)
                 {
                         if (cr0>>31)
                         {
-                                if (mmutranslate_write(addr2)   == 0xffffffff) return;
-                                if (mmutranslate_write(addr2+7) == 0xffffffff) return;
+                                if (mmutranslate_write(addr)   == 0xffffffff) return;
+                                if (mmutranslate_write(addr+7) == 0xffffffff) return;
                         }
-                        writememll(seg, addr, val);
-                        writememll(seg, addr+4, val >> 32);
+                        writememll(addr, val);
+                        writememll(addr+4, val >> 32);
                         return;
                 }
-                else if (writelookup2[addr2 >> 12] != -1)
+                else if (writelookup2[addr >> 12] != -1)
                 {
-                        *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val;
+                        *(uint64_t *)(writelookup2[addr >> 12] + addr) = val;
                         return;
                 }
         }
-        if (page_lookup[addr2>>12])
+        if (page_lookup[addr>>12])
         {
-                page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]);
-                page_lookup[addr2>>12]->write_l(addr2 + 4, val >> 32, page_lookup[addr2>>12]);
+                page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]);
+                page_lookup[addr>>12]->write_l(addr + 4, val >> 32, page_lookup[addr>>12]);
                 return;
         }
         if (cr0>>31)
         {
-                addr2 = mmutranslate_write(addr2);
-                if (addr2==0xFFFFFFFF) return;
+                addr = mmutranslate_write(addr);
+                if (addr==0xFFFFFFFF) return;
         }
         
-        addr2&=rammask;
+        addr&=rammask;
 
-        if (_mem_write_l[addr2 >> 14]) 
-        {
-                _mem_write_l[addr2 >> 14](addr2,   val,       _mem_priv_w[addr2 >> 14]);
-                _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]);
-                return;
-        }
-        if (_mem_write_w[addr2 >> 14]) 
-        {
-                _mem_write_w[addr2 >> 14](addr2,     val,       _mem_priv_w[addr2 >> 14]);
-                _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]);
-                _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]);
-                _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]);
-                return;
-        }
-        if (_mem_write_b[addr2 >> 14]) 
+        map = write_mapping[addr >> 14];
+        if (map)
         {
-                _mem_write_b[addr2 >> 14](addr2,     val,       _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8,  _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 5, val >> 40, _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]);
-                _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]);
-                return;
+                if (map->write_l)
+                {
+                        map->write_l(addr, val, map->p);
+                        map->write_l(addr + 4, val >> 32, map->p);
+                }
+                else if (map->write_w)
+                {
+                        map->write_w(addr, val, map->p);
+                        map->write_w(addr + 2, val >> 16, map->p);
+                        map->write_w(addr + 4, val >> 32, map->p);
+                        map->write_w(addr + 6, val >> 48, map->p);
+                }
+                else if (map->write_b)
+                {
+                        map->write_b(addr, val, map->p);
+                        map->write_b(addr + 1, val >> 8, map->p);
+                        map->write_b(addr + 2, val >> 16, map->p);
+                        map->write_b(addr + 3, val >> 24, map->p);
+                        map->write_b(addr + 4, val >> 32, map->p);
+                        map->write_b(addr + 5, val >> 40, map->p);
+                        map->write_b(addr + 6, val >> 48, map->p);
+                        map->write_b(addr + 7, val >> 56, map->p);
+                }
         }
-//        pclog("Bad writememql %08X %08X\n", addr2, val);
+//        pclog("Bad writememql %08X %08X\n", addr, val);
 }
 
 uint8_t mem_readb_phys(uint32_t addr)
 {
+        mem_mapping_t *map = read_mapping[addr >> 14];
+
         mem_logical_addr = 0xffffffff;
         
-        if (_mem_read_b[addr >> 14]) 
-                return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]);
+        if (map && map->read_b)
+                return map->read_b(addr, map->p);
                 
         return 0xff;
 }
 uint16_t mem_readw_phys(uint32_t addr)
 {
+        mem_mapping_t *map = read_mapping[addr >> 14];
+        
         mem_logical_addr = 0xffffffff;
         
-        if (_mem_read_w[addr >> 14] && !(addr & 1)) 
-                return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]);
+        if (map && map->read_w)
+                return map->read_w(addr, map->p);
                 
         return mem_readb_phys(addr) | (mem_readb_phys(addr + 1) << 8);
 }
 uint32_t mem_readl_phys(uint32_t addr)
 {
+        mem_mapping_t *map = read_mapping[addr >> 14];
+        
         mem_logical_addr = 0xffffffff;
         
-        if (_mem_read_l[addr >> 14] && !(addr & 3)) 
-                return _mem_read_l[addr >> 14](addr, _mem_priv_r[addr >> 14]);
+        if (map && map->read_l)
+                return map->read_l(addr, map->p);
                 
         return mem_readw_phys(addr) | (mem_readw_phys(addr + 2) << 16);
 }
 
 void mem_writeb_phys(uint32_t addr, uint8_t val)
 {
+        mem_mapping_t *map = write_mapping[addr >> 14];
+
         mem_logical_addr = 0xffffffff;
 
-        if (_mem_write_b[addr >> 14]) 
-                _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
+        if (map && map->write_b)
+                map->write_b(addr, val, map->p);
 }
 void mem_writew_phys(uint32_t addr, uint16_t val)
 {
+        mem_mapping_t *map = write_mapping[addr >> 14];
+        
         mem_logical_addr = 0xffffffff;
 
-        if (_mem_write_w[addr >> 14] && !(addr & 1)) 
-                _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
+        if (map && map->write_w && !(addr & 1))
+                map->write_w(addr, val, map->p);
         else
         {
                 mem_writeb_phys(addr, val);
@@ -952,10 +868,12 @@ void mem_writew_phys(uint32_t addr, uint16_t val)
 }
 void mem_writel_phys(uint32_t addr, uint32_t val)
 {
+        mem_mapping_t *map = write_mapping[addr >> 14];
+        
         mem_logical_addr = 0xffffffff;
 
-        if (_mem_write_l[addr >> 14] && !(addr & 3)) 
-                _mem_write_l[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
+        if (map && map->write_l && !(addr & 3))
+                map->write_l(addr, val, map->p);
         else
         {
                 mem_writew_phys(addr, val);
@@ -982,14 +900,59 @@ uint32_t mem_read_raml(uint32_t addr, void *priv)
         return *(uint32_t *)&ram[addr];
 }
 
+uint32_t purgable_page_list_head = 0;
+int purgeable_page_count = 0;
+
+static inline int page_index(page_t *p)
+{
+        return ((uintptr_t)p - (uintptr_t)pages) / sizeof(page_t);
+}
+void page_add_to_evict_list(page_t *p)
+{
+//        pclog("page_add_to_evict_list: %08x %i\n", page_index(p), purgeable_page_count);
+        pages[purgable_page_list_head].evict_prev = page_index(p);
+        p->evict_next = purgable_page_list_head;
+        p->evict_prev = 0;
+        purgable_page_list_head = pages[purgable_page_list_head].evict_prev;
+        purgeable_page_count++;
+}
+void page_remove_from_evict_list(page_t *p)
+{
+//        pclog("page_remove_from_evict_list: %08x %i\n", page_index(p), purgeable_page_count);
+        if (!page_in_evict_list(p))
+                fatal("page_remove_from_evict_list: not in evict list!\n");
+        if (p->evict_prev)
+                pages[p->evict_prev].evict_next = p->evict_next;
+        else
+                purgable_page_list_head = p->evict_next;
+        if (p->evict_next)
+                pages[p->evict_next].evict_prev = p->evict_prev;
+        p->evict_prev = EVICT_NOT_IN_LIST;
+        purgeable_page_count--;
+}
+
 void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p)
 {      
         if (val != p->mem[addr & 0xfff] || codegen_in_recompile)
         {
                 uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
-//        pclog("mem_write_ramb_page: %08x %02x %08x %llx %llx\n", addr, val, cs+pc, p->dirty_mask, mask);
-                p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
+                int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
+                uint64_t byte_mask = (uint64_t)1 << (addr & PAGE_BYTE_MASK_MASK);
+                
+//        pclog("mem_write_ramb_page: %08x %02x %08x %llx %llx\n", addr, val, cs+cpu_state.pc, p->dirty_mask, mask);
                 p->mem[addr & 0xfff] = val;
+                p->dirty_mask |= mask;
+                if ((p->code_present_mask & mask) && !page_in_evict_list(p))
+                {
+//                        pclog("ramb add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask);
+                        page_add_to_evict_list(p);
+                }
+                p->byte_dirty_mask[byte_offset] |= byte_mask;
+                if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p))
+                {
+//                        pclog("   ramb add %08x %016llx %016llx\n", addr, p->byte_code_present_mask[byte_offset], byte_mask);
+                        page_add_to_evict_list(p);
+                }
         }
 }
 void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p)
@@ -997,11 +960,38 @@ void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p)
         if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile)
         {
                 uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+                int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
+                uint64_t byte_mask = (uint64_t)1 << (addr & PAGE_BYTE_MASK_MASK);
+
                 if ((addr & 0xf) == 0xf)
                         mask |= (mask << 1);
-//        pclog("mem_write_ramw_page: %08x %04x %08x\n", addr, val, cs+pc);
-                p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
+//        pclog("mem_write_ramw_page: %08x %04x %08x  %016llx %016llx %016llx  %08x %08x  %p\n", addr, val, cs+cpu_state.pc, p->dirty_mask[index], p->code_present_mask[index], mask, p->evict_prev, p->evict_next,  p);
                 *(uint16_t *)&p->mem[addr & 0xfff] = val;
+                p->dirty_mask |= mask;
+                if ((p->code_present_mask & mask) && !page_in_evict_list(p))
+                {
+//                        pclog("ramw add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask);
+                        page_add_to_evict_list(p);
+                }
+                if ((addr & PAGE_BYTE_MASK_MASK) == PAGE_BYTE_MASK_MASK)
+                {
+                        p->byte_dirty_mask[byte_offset+1] |= 1;
+                        if ((p->byte_code_present_mask[byte_offset+1] & 1) && !page_in_evict_list(p))
+                        {
+//                                pclog("ramw add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask);
+                                page_add_to_evict_list(p);
+                        }
+                }
+                else
+                        byte_mask |= (byte_mask << 1);
+                        
+                p->byte_dirty_mask[byte_offset] |= byte_mask;
+
+                if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p))
+                {
+//                        pclog("ramw add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask);
+                        page_add_to_evict_list(p);
+                }
         }
 }
 void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p)
@@ -1009,11 +999,31 @@ void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p)
         if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile)
         {
                 uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+                int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
+                uint64_t byte_mask = (uint64_t)0xf << (addr & PAGE_BYTE_MASK_MASK);
+
                 if ((addr & 0xf) >= 0xd)
                         mask |= (mask << 1);
-//        pclog("mem_write_raml_page: %08x %08x %08x\n", addr, val, cs+pc);
-                p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
+//        pclog("mem_write_raml_page: %08x %08x %08x   %016llx %016llx %016llx\n", addr, val, cs+cpu_state.pc, p->dirty_mask[index], p->code_present_mask[index], mask);
                 *(uint32_t *)&p->mem[addr & 0xfff] = val;
+                p->dirty_mask |= mask;
+                p->byte_dirty_mask[byte_offset] |= byte_mask;
+                if (!page_in_evict_list(p) && ((p->code_present_mask & mask) || (p->byte_code_present_mask[byte_offset] & byte_mask)))
+                {
+//                        pclog("raml add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask);
+                        page_add_to_evict_list(p);
+                }
+                if ((addr & PAGE_BYTE_MASK_MASK) > (PAGE_BYTE_MASK_MASK-3))
+                {
+                        uint32_t byte_mask_2 = 0xf >> (4 - (addr & 3));
+
+                        p->byte_dirty_mask[byte_offset+1] |= byte_mask_2;
+                        if ((p->byte_code_present_mask[byte_offset+1] & byte_mask_2) && !page_in_evict_list(p))
+                        {
+//                                pclog("raml add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask);
+                                page_add_to_evict_list(p);
+                        }
+                }
         }
 }
 
@@ -1124,8 +1134,15 @@ void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr)
         for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT))
         {
                 uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
-                
-                pages[start_addr >> 12].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
+                page_t *p = &pages[start_addr >> 12];
+
+//pclog("mem_invalidate: %08x\n", start_addr);
+                p->dirty_mask |= mask;
+                if ((p->code_present_mask & mask) && !page_in_evict_list(p))
+                {
+//                        pclog("invalidate add %08x %016llx %016llx\n", start_addr, p->code_present_mask[index], mask);
+                        page_add_to_evict_list(p);
+                }
         }
 }
 
@@ -1174,17 +1191,9 @@ static void mem_mapping_recalc(uint64_t base, uint64_t size)
         /*Clear out old mappings*/
         for (c = base; c < base + size; c += 0x4000)
         {
-                _mem_read_b[c >> 14] = NULL;
-                _mem_read_w[c >> 14] = NULL;
-                _mem_read_l[c >> 14] = NULL;
-                _mem_priv_r[c >> 14] = NULL;
-                _mem_mapping_r[c >> 14] = NULL;
+                read_mapping[c >> 14] = NULL;
+                write_mapping[c >> 14] = NULL;
                 _mem_exec[c >> 14] = NULL;
-                _mem_write_b[c >> 14] = NULL;
-                _mem_write_w[c >> 14] = NULL;
-                _mem_write_l[c >> 14] = NULL;
-                _mem_priv_w[c >> 14] = NULL;
-                _mem_mapping_w[c >> 14] = NULL;
         }
 
         /*Walk mapping list*/
@@ -1203,24 +1212,16 @@ static void mem_mapping_recalc(uint64_t base, uint64_t size)
                                 if ((mapping->read_b || mapping->read_w || mapping->read_l) &&
                                      mem_mapping_read_allowed(mapping->flags, _mem_state[c >> 14]))
                                 {
-                                        _mem_read_b[c >> 14] = mapping->read_b;
-                                        _mem_read_w[c >> 14] = mapping->read_w;
-                                        _mem_read_l[c >> 14] = mapping->read_l;
+                                        read_mapping[c >> 14] = mapping;
                                         if (mapping->exec)
                                                 _mem_exec[c >> 14] = mapping->exec + (c - mapping->base);
                                         else
                                                 _mem_exec[c >> 14] = NULL;
-                                        _mem_priv_r[c >> 14] = mapping->p;
-                                        _mem_mapping_r[c >> 14] = mapping;
                                 }
                                 if ((mapping->write_b || mapping->write_w || mapping->write_l) &&
                                      mem_mapping_write_allowed(mapping->flags, _mem_state[c >> 14]))
                                 {
-                                        _mem_write_b[c >> 14] = mapping->write_b;
-                                        _mem_write_w[c >> 14] = mapping->write_w;
-                                        _mem_write_l[c >> 14] = mapping->write_l;
-                                        _mem_priv_w[c >> 14] = mapping->p;
-                                        _mem_mapping_w[c >> 14] = mapping;
+                                        write_mapping[c >> 14] = mapping;
                                 }
                         }
                 }
@@ -1365,94 +1366,6 @@ void mem_add_bios()
 int mem_a20_key = 0, mem_a20_alt = 0;
 static int mem_a20_state = 2;
 
-void mem_free()
-{
-       free(ram);
-       ram = NULL;
-       free(readlookup2);
-       readlookup2 = NULL;
-       free(writelookup2);
-       writelookup2 = NULL;
-       free(pages);
-       pages = NULL;
-       free(page_lookup);
-       page_lookup = NULL;
-}
-
-void mem_init()
-{
-        int c;
-
-        ram = (uint8_t*)malloc(mem_size * 1024);
-//        rom = malloc(0x20000);
-        readlookup2  = (uintptr_t*)malloc(1024 * 1024 * sizeof(uintptr_t));
-        writelookup2 = (uintptr_t*)malloc(1024 * 1024 * sizeof(uintptr_t));
-        biosmask = 0xffff;
-        pages = (page_t*)malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t));
-        page_lookup = (page_t**)malloc((1 << 20) * sizeof(page_t *));
-
-        memset(ram, 0, mem_size * 1024);
-        memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t));
-        
-        memset(page_lookup, 0, (1 << 20) * sizeof(page_t *));
-        
-        for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++)
-        {
-                pages[c].mem = &ram[c << 12];
-                pages[c].write_b = mem_write_ramb_page;
-                pages[c].write_w = mem_write_ramw_page;
-                pages[c].write_l = mem_write_raml_page;
-        }
-
-        memset(isram, 0, sizeof(isram));
-        for (c = 0; c < (mem_size / 64); c++)
-        {
-                isram[c] = 1;
-                if ((c >= 0xa && c <= 0xf) || (cpu_16bitbus && c >= 0xfe && c <= 0xff))
-                        isram[c] = 0;
-        }
-
-        memset(_mem_read_b,  0, sizeof(_mem_read_b));
-        memset(_mem_read_w,  0, sizeof(_mem_read_w));
-        memset(_mem_read_l,  0, sizeof(_mem_read_l));
-        memset(_mem_write_b, 0, sizeof(_mem_write_b));
-        memset(_mem_write_w, 0, sizeof(_mem_write_w));
-        memset(_mem_write_l, 0, sizeof(_mem_write_l));
-        memset(_mem_exec, 0, sizeof(_mem_exec));
-        
-        memset(ff_array, 0xff, sizeof(ff_array));
-
-        memset(&base_mapping, 0, sizeof(base_mapping));
-
-        memset(_mem_state, 0, sizeof(_mem_state));
-
-        mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
-        mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
-
-        mem_mapping_add(&ram_low_mapping, 0x00000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, mem_read_ram,    mem_read_ramw,    mem_read_raml,    mem_write_ram, mem_write_ramw, mem_write_raml,   ram,  MEM_MAPPING_INTERNAL, NULL);
-        if (mem_size > 1024)
-        {
-                if (cpu_16bitbus && mem_size > 16256)
-                {
-                        mem_set_mem_state(0x100000, (16256 - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
-                        mem_mapping_add(&ram_high_mapping, 0x100000, ((16256 - 1024) * 1024), mem_read_ram,    mem_read_ramw,    mem_read_raml,    mem_write_ram, mem_write_ramw, mem_write_raml,   ram + 0x100000, MEM_MAPPING_INTERNAL, NULL);
-                }
-                else
-                {
-                        mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
-                        mem_mapping_add(&ram_high_mapping, 0x100000, ((mem_size - 1024) * 1024), mem_read_ram,    mem_read_ramw,    mem_read_raml,    mem_write_ram, mem_write_ramw, mem_write_raml,   ram + 0x100000, MEM_MAPPING_INTERNAL, NULL);
-                }
-        }
-       if (mem_size > 768)
-               mem_mapping_add(&ram_mid_mapping,   0xc0000, 0x40000, mem_read_ram,    mem_read_ramw,    mem_read_raml,    mem_write_ram, mem_write_ramw, mem_write_raml,   ram + 0xc0000,  MEM_MAPPING_INTERNAL, NULL);
-
-        if (romset == ROM_IBMPS1_2011)
-                mem_mapping_add(&romext_mapping,  0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL,   romext, 0, NULL);
-//        pclog("Mem resize %i %i\n",mem_size,c);
-        mem_a20_key = 2;
-        mem_a20_alt = 0;
-}
-
 static void mem_remap_top(int max_size)
 {
         int c;
@@ -1468,10 +1381,14 @@ static void mem_remap_top(int max_size)
                         
                 for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++)
                 {
-                        pages[c].mem = &ram[0xA0000 + ((c - ((start * 1024) >> 12)) << 12)];
+                        int offset = c - ((start * 1024) >> 12);
+                        pages[c].mem = &ram[0xA0000 + (offset << 12)];
                         pages[c].write_b = mem_write_ramb_page;
                         pages[c].write_w = mem_write_ramw_page;
                         pages[c].write_l = mem_write_raml_page;
+                        pages[c].evict_prev = EVICT_NOT_IN_LIST;
+                        pages[c].byte_dirty_mask = &byte_dirty_mask[offset * 64];
+                        pages[c].byte_code_present_mask = &byte_code_present_mask[offset * 64];
                 }
 
                 mem_set_mem_state(start * 1024, size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
@@ -1494,16 +1411,32 @@ void mem_set_704kb()
         mem_mapping_set_addr(&ram_low_mapping, 0x00000, (mem_size > 704) ? 0xb0000 : mem_size * 1024);
 }
 
-void mem_resize()
+void mem_init()
+{
+        readlookup2  = malloc(1024 * 1024 * sizeof(uintptr_t));
+        writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t));
+        page_lookup = malloc((1 << 20) * sizeof(page_t *));
+
+        memset(ff_array, 0xff, sizeof(ff_array));
+}
+
+void mem_alloc()
 {
         int c;
         
         free(ram);
-        ram = (uint8_t*)malloc(mem_size * 1024);
+        ram = malloc(mem_size * 1024);
         memset(ram, 0, mem_size * 1024);
         
+        free(byte_dirty_mask);
+        byte_dirty_mask = malloc((mem_size * 1024) / 8);
+        memset(byte_dirty_mask, 0, (mem_size * 1024) / 8);
+        free(byte_code_present_mask);
+        byte_code_present_mask = malloc((mem_size * 1024) / 8);
+        memset(byte_code_present_mask, 0, (mem_size * 1024) / 8);
+        
         free(pages);
-        pages = (page_t*)malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t));
+        pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t));
         memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t));
         for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++)
         {
@@ -1511,22 +1444,15 @@ void mem_resize()
                 pages[c].write_b = mem_write_ramb_page;
                 pages[c].write_w = mem_write_ramw_page;
                 pages[c].write_l = mem_write_raml_page;
-        }
-        
-        memset(isram, 0, sizeof(isram));
-        for (c = 0; c < (mem_size / 64); c++)
-        {
-                isram[c] = 1;
-                if ((c >= 0xa && c <= 0xf) || (cpu_16bitbus && c >= 0xfe && c <= 0xff))
-                        isram[c] = 0;
+                pages[c].evict_prev = EVICT_NOT_IN_LIST;
+                pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64];
+                pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64];
         }
 
-        memset(_mem_read_b,  0, sizeof(_mem_read_b));
-        memset(_mem_read_w,  0, sizeof(_mem_read_w));
-        memset(_mem_read_l,  0, sizeof(_mem_read_l));
-        memset(_mem_write_b, 0, sizeof(_mem_write_b));
-        memset(_mem_write_w, 0, sizeof(_mem_write_w));
-        memset(_mem_write_l, 0, sizeof(_mem_write_l));
+        memset(page_lookup, 0, (1 << 20) * sizeof(page_t *));
+
+        memset(read_mapping, 0, sizeof(read_mapping));
+        memset(write_mapping, 0, sizeof(write_mapping));
         memset(_mem_exec, 0, sizeof(_mem_exec));
         
         memset(&base_mapping, 0, sizeof(base_mapping));
@@ -1560,6 +1486,9 @@ void mem_resize()
         mem_a20_key = 2;
         mem_a20_alt = 0;
         mem_a20_recalc();
+
+        purgable_page_list_head = 0;
+        purgeable_page_count = 0;
 }
 
 void mem_reset_page_blocks()
@@ -1571,8 +1500,8 @@ void mem_reset_page_blocks()
                 pages[c].write_b = mem_write_ramb_page;
                 pages[c].write_w = mem_write_ramw_page;
                 pages[c].write_l = mem_write_raml_page;
-                pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL;
-                pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL;
+                pages[c].block = BLOCK_INVALID;
+                pages[c].block_2 = BLOCK_INVALID;
         }
 }
 
index 7ea6f6f1a7e4f867b9dca4d88fe84d8f6be48ce2..41fe23f368071467ec03c3a589bc249e091077cb 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _MEM_H_
 #define _MEM_H_
 
+#include "x86.h"
+
 typedef struct mem_mapping_t
 {
         struct mem_mapping_t *prev, *next;
@@ -35,7 +37,6 @@ extern uint8_t *ram,*rom;
 extern uint8_t romext[32768];
 extern int readlnum,writelnum;
 extern int memspeed[11];
-extern int nopageerrors;
 extern uint32_t biosmask;
 
 void mem_mapping_add(mem_mapping_t *mapping,
@@ -105,12 +106,20 @@ void mem_write_nulll(uint32_t addr, uint32_t val, void *p);
 
 FILE *romfopen(char *fn, char *mode);
 
-extern mem_mapping_t bios_mapping[8];
-extern mem_mapping_t bios_high_mapping[8];
+mem_mapping_t bios_mapping[8];
+mem_mapping_t bios_high_mapping[8];
 
 extern mem_mapping_t ram_high_mapping;
 extern mem_mapping_t ram_remapped_mapping;
 
+extern uint64_t *byte_dirty_mask;
+extern uint64_t *byte_code_present_mask;
+
+#define PAGE_BYTE_MASK_SHIFT 6
+#define PAGE_BYTE_MASK_OFFSET_MASK 63
+#define PAGE_BYTE_MASK_MASK  63
+
+#define EVICT_NOT_IN_LIST ((uint32_t)-1)
 typedef struct page_t
 {
         void (*write_b)(uint32_t addr, uint8_t val, struct page_t *p);
@@ -119,18 +128,33 @@ typedef struct page_t
         
         uint8_t *mem;
         
-        struct codeblock_t *block[4], *block_2[4];
+        uint16_t block, block_2;
         
         /*Head of codeblock tree associated with this page*/
-        struct codeblock_t *head;
+        uint16_t head;
+        
+        uint64_t code_present_mask, dirty_mask;
         
-        uint64_t code_present_mask[4], dirty_mask[4];
+        uint32_t evict_prev, evict_next;
+        
+        uint64_t *byte_dirty_mask;
+        uint64_t *byte_code_present_mask;
 } page_t;
 
 extern page_t *pages;
 
 extern page_t **page_lookup;
 
+extern uint32_t purgable_page_list_head;
+static inline int page_in_evict_list(page_t *p)
+{
+        return (p->evict_prev != EVICT_NOT_IN_LIST);
+}
+void page_remove_from_evict_list(page_t *p);
+void page_add_to_evict_list(page_t *p);
+
+int mem_addr_is_ram(uint32_t addr);
+
 uint32_t mmutranslate_noabrt(uint32_t addr, int rw);
 extern uint32_t get_phys_virt,get_phys_phys;
 static inline uint32_t get_phys(uint32_t addr)
@@ -146,17 +170,34 @@ static inline uint32_t get_phys(uint32_t addr)
                 return addr & rammask;
         }
         
-        get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff;
+        if (readlookup2[addr >> 12] != -1)
+                get_phys_phys = ((uintptr_t)readlookup2[addr >> 12] + (addr & ~0xfff)) - (uintptr_t)ram;
+        else
+        {
+                get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff;
+                if (!cpu_state.abrt && mem_addr_is_ram(get_phys_phys))
+                        addreadlookup(get_phys_virt, get_phys_phys);
+        }
+                
         return get_phys_phys | (addr & 0xfff);
 //        return mmutranslatereal(addr, 0) & rammask;
 }
 
 static inline uint32_t get_phys_noabrt(uint32_t addr)
 {
+        uint32_t phys_addr;
+        
         if (!(cr0 >> 31))
                 return addr & rammask;
         
-        return mmutranslate_noabrt(addr, 0) & rammask;
+        if (readlookup2[addr >> 12] != -1)
+                return ((uintptr_t)readlookup2[addr >> 12] + addr) - (uintptr_t)ram;
+
+        phys_addr = mmutranslate_noabrt(addr, 0) & rammask;
+        if (phys_addr != 0xffffffff && mem_addr_is_ram(phys_addr))
+                addreadlookup(addr, phys_addr);
+
+        return phys_addr;
 }
 
 void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr);
@@ -180,8 +221,7 @@ void mem_flush_write_page(uint32_t addr, uint32_t virt);
 void mem_add_bios();
 
 void mem_init();
-void mem_free();
-void mem_resize();
+void mem_alloc();
 
 void mem_set_704kb();
 
@@ -195,5 +235,5 @@ void mmu_invalidate(uint32_t addr);
 
 int loadbios();
 
-extern unsigned char isram[0x10000];
+extern int purgeable_page_count;
 #endif
index e8fab5630b5fef8c7d5218aea4f79109bdae9027..6834e43934212bf0412a31fdfaa1ec894292a55a 100644 (file)
@@ -39,6 +39,7 @@ extern int model;
 
 int model_count();
 int model_getromset();
+int model_getromset_from_model(int model);
 int model_getmodel(int romset);
 char *model_getname();
 char *model_get_internal_name();
index 551d20b0d2040af14d10a52d4c329edd7d137387..b1c219df014a2d253b6aed6e53fe5010b5c64603 100644 (file)
@@ -96,6 +96,27 @@ void mouse_ps2_write(uint8_t val, void *p)
                         keyboard_at_adddata_mouse(mouse->sample_rate);
                         break;
                         
+                        case 0xeb: /*Get mouse data*/
+                        keyboard_at_adddata_mouse(0xfa);
+
+                        temp = 0;
+                        if (mouse->x < 0)
+                                temp |= 0x10;
+                        if (mouse->y < 0)
+                                temp |= 0x20;
+                        if (mouse_buttons & 1)
+                                temp |= 1;
+                        if (mouse_buttons & 2)
+                                temp |= 2;
+                        if ((mouse_buttons & 4) && (mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON))
+                                temp |= 4;
+                        keyboard_at_adddata_mouse(temp);
+                        keyboard_at_adddata_mouse(mouse->x & 0xff);
+                        keyboard_at_adddata_mouse(mouse->y & 0xff);
+                        if (mouse->intellimouse_mode)
+                                keyboard_at_adddata_mouse(mouse->z);
+                        break;
+                        
                         case 0xf2: /*Read ID*/
                         keyboard_at_adddata_mouse(0xfa);
                         if (mouse->intellimouse_mode)
@@ -123,6 +144,7 @@ void mouse_ps2_write(uint8_t val, void *p)
                         mouse->mode  = MOUSE_STREAM;
                         mouse->flags = 0;
                         mouse->intellimouse_mode = 0;
+                        mouse_queue_start = mouse_queue_end = 0;
                         keyboard_at_adddata_mouse(0xfa);
                         keyboard_at_adddata_mouse(0xaa);
                         keyboard_at_adddata_mouse(0x00);
@@ -221,7 +243,7 @@ void *mouse_ps2_init()
 
 void *mouse_intellimouse_init()
 {
-        mouse_ps2_t *mouse = (mouse_ps2_t*)mouse_ps2_init();
+        mouse_ps2_t *mouse = mouse_ps2_init();
 
         mouse->is_intellimouse = 1;
                 
index f975d00e603268827ee334945fcb04000e17daf9..2d81dea4bc540abcae7ed0d302a0b66627889940 100644 (file)
@@ -7,7 +7,8 @@
 
 typedef struct mouse_serial_t
 {
-        int mousepos, mousedelay;
+        int mousepos;
+       pc_timer_t mousedelay_timer;
         int oldb;
         SERIAL *serial;
 } mouse_serial_t;
@@ -52,14 +53,13 @@ void mouse_serial_rcr(struct SERIAL *serial, void *p)
         mouse_serial_t *mouse = (mouse_serial_t *)p;
         
         mouse->mousepos = -1;
-        mouse->mousedelay = 5000 * (1 << TIMER_SHIFT);
+        timer_set_delay_u64(&mouse->mousedelay_timer, TIMER_USEC * 5000);
 }
         
 void mousecallback(void *p)
 {
         mouse_serial_t *mouse = (mouse_serial_t *)p;
 
-       mouse->mousedelay = 0;
         if (mouse->mousepos == -1)
         {
                 mouse->mousepos = 0;
@@ -75,7 +75,7 @@ void *mouse_serial_init()
         mouse->serial = &serial1;
         serial1.rcr_callback = mouse_serial_rcr;
         serial1.rcr_callback_p = mouse;
-        timer_add(mousecallback, &mouse->mousedelay, &mouse->mousedelay, mouse);
+        timer_add(&mouse->mousedelay_timer, mousecallback, mouse, 0);
         
         return mouse;
 }
similarity index 73%
rename from pcem/pcemnvr.cpp
rename to pcem/nvr.cpp
index 406364dbe76630b07ba47687d7603db983285fab..ccb7f9f087c06c6607aa228248260a086fa49b73 100644 (file)
@@ -1,5 +1,7 @@
 #include <stdio.h>
+#include <stdlib.h>
 #include "ibm.h"
+#include "device.h"
 #include "io.h"
 #include "nvr.h"
 #include "nvr_tc8521.h"
 #include "model.h"
 #include "nmi.h"
 #include "t1000.h"
+#include "x86.h"
 
 int oldromset;
 int nvrmask=63;
-uint8_t nvrram[128+64];
+uint8_t nvrram[128];
 int nvraddr;
 
 int nvr_dosave = 0;
 
-static int nvr_onesec_time = 0, nvr_onesec_cnt = 0;
+typedef struct nvr_t
+{
+        pc_timer_t rtc_timer;
+        pc_timer_t onesec_timer;
+        pc_timer_t update_end_timer;
 
-static int rtctime;
+        int onesec_cnt;
+} nvr_t;
 
-#if 0
 FILE *nvrfopen(char *fn, char *mode)
 {
         char s[512];
@@ -54,40 +61,50 @@ FILE *nvrfopen(char *fn, char *mode)
                 return NULL;
         }
 }
-#endif
 
 void getnvrtime()
 {
        time_get(nvrram);
 }
 
-void nvr_recalc()
+static void nvr_speed_changed(void *p)
 {
-        int c;
-        int newrtctime;
-        c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
-        newrtctime=(int)(RTCCONST * c * (1 << TIMER_SHIFT));
-        if (rtctime>newrtctime) rtctime=newrtctime;
+        nvr_t *nvr = (nvr_t *)p;
+
+        if (!(nvrram[RTC_REGA] & RTC_RS))
+        {
+               timer_disable(&nvr->rtc_timer);
+                return;
+        }
+        else
+        {
+                int c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
+               timer_set_delay_u64(&nvr->rtc_timer, (uint64_t)(RTCCONST * c));
+        }
 }
 
-void nvr_rtc(void *p)
+static void nvr_rtc(void *p)
 {
-        int c;
+        nvr_t *nvr = (nvr_t *)p;
+
         if (!(nvrram[RTC_REGA] & RTC_RS))
         {
-                rtctime=0x7fffffff;
+               timer_disable(&nvr->rtc_timer);
                 return;
         }
-        c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
-        rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
-//        pclog("RTCtime now %f\n",rtctime);
-        nvrram[RTC_REGC] |= RTC_PF;
-        if (nvrram[RTC_REGB] & RTC_PIE)
+        else
         {
-                nvrram[RTC_REGC] |= RTC_IRQF;
-                if (AMSTRAD) picint(2);
-                else         picint(0x100);
-//                pclog("RTC int\n");
+                int c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
+                timer_advance_u64(&nvr->rtc_timer, (uint64_t)(RTCCONST * c));
+//                pclog("RTCtime now %f\n",rtctime);
+                nvrram[RTC_REGC] |= RTC_PF;
+                if (nvrram[RTC_REGB] & RTC_PIE)
+                {
+                        nvrram[RTC_REGC] |= RTC_IRQF;
+                        if (AMSTRAD) picint(2);
+                        else         picint(0x100);
+//                        pclog("RTC int\n");
+                }
         }
 }
 
@@ -100,10 +117,11 @@ int nvr_check_alarm(int nvraddr)
         return (nvrram[nvraddr + 1] == nvrram[nvraddr] || (nvrram[nvraddr + 1] & ALARM_DONTCARE) == ALARM_DONTCARE);
 }
 
-int nvr_update_end_count = 0;
 
-void nvr_update_end(void *p)
+static void nvr_update_end(void *p)
 {
+//        nvr_t *nvr = (nvr_t *)p;
+
         if (!(nvrram[RTC_REGB] & RTC_SET))
         {
                 getnvrtime();
@@ -132,29 +150,30 @@ void nvr_update_end(void *p)
         }
         
 //                pclog("RTC onesec\n");
-
-        nvr_update_end_count = 0;
 }
 
-void nvr_onesec(void *p)
+static void nvr_onesec(void *p)
 {
-        nvr_onesec_cnt++;
-        if (nvr_onesec_cnt >= 100)
+        nvr_t *nvr = (nvr_t *)p;
+
+        nvr->onesec_cnt++;
+        if (nvr->onesec_cnt >= 100)
         {
                 if (!(nvrram[RTC_REGB] & RTC_SET))
                 {
                         nvr_update_status = RTC_UIP;
                         rtc_tick();
 
-                        nvr_update_end_count = (int)((244.0 + 1984.0) * TIMER_USEC);
+                        timer_set_delay_u64(&nvr->update_end_timer, (uint64_t)((244.0 + 1984.0) * TIMER_USEC));
                 }
-                nvr_onesec_cnt = 0;
+                nvr->onesec_cnt = 0;
         }
-        nvr_onesec_time += (int)(10000 * TIMER_USEC);
+        timer_advance_u64(&nvr->onesec_timer, (uint64_t)(10000 * TIMER_USEC));
 }
 
-void writenvr(uint16_t addr, uint8_t val, void *priv)
+static void writenvr(uint16_t addr, uint8_t val, void *p)
 {
+        nvr_t *nvr = (nvr_t *)p;
         int c, old;
         
         cycles -= ISA_CYCLES(8);
@@ -176,10 +195,10 @@ void writenvr(uint16_t addr, uint8_t val, void *priv)
                         if (val & RTC_RS)
                         {
                                 c = 1 << ((val & RTC_RS) - 1);
-                                rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
+                               timer_set_delay_u64(&nvr->rtc_timer, (uint64_t)(RTCCONST * c));
                         }
                         else
-                           rtctime = 0x7fffffff;
+                               timer_disable(&nvr->rtc_timer);
                 }
                else
                {
@@ -208,24 +227,26 @@ void writenvr(uint16_t addr, uint8_t val, void *priv)
         else
         {
                 nvraddr=val&nvrmask;
-                               
-                               // A2386SX extra 64 byte bank
-                               extern int x86_cmos_bank;
-                               if (nvraddr >= 64 && x86_cmos_bank)
-                                       nvraddr += 64;
-
-                               /*PS/2 BIOSes will disable NMIs and expect the watchdog timer to still be able
+                /*PS/2 BIOSes will disable NMIs and expect the watchdog timer to still be able
                   to fire them. I suspect the watchdog is exempt from NMI masking. Currently NMIs
                   are always enabled for PS/2 machines - this would mean that other peripherals
                   could fire NMIs regardless of the mask state, but as there aren't any emulated
                   MCA peripherals that do this it's currently a moot point.*/
-                if (!(models[model].flags & MODEL_MCA))
+
+               /* Also don't update the NMI mask on Amstrad PCs - actually
+                * ought not to do it for any XT because their NMI mask 
+                * register is at 0xA0. But particularly important on the 
+                * PC200 and PPC because their video subsystem issues NMIs */
+                if (!(models[model].flags & (MODEL_MCA | MODEL_AMSTRAD)))
+               {
                         nmi_mask = ~val & 0x80;
+               }
         }
 }
 
-uint8_t readnvr(uint16_t addr, void *priv)
+uint8_t readnvr(uint16_t addr, void *p)
 {
+//        nvr_t *nvr = (nvr_t *)p;
         uint8_t temp;
 //        printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc);
         cycles -= ISA_CYCLES(8);
@@ -252,18 +273,18 @@ uint8_t readnvr(uint16_t addr, void *priv)
 
 void loadnvr()
 {
-        int c;
+        FILE *f;
+
         nvrmask=63;
         oldromset=romset;
-#if 0
-               FILE *f;
-               switch (romset)
+        switch (romset)
         {
                 case ROM_PC1512:      f = nvrfopen("pc1512.nvr",      "rb"); break;
                 case ROM_PC1640:      f = nvrfopen("pc1640.nvr",      "rb"); break;
                 case ROM_PC200:       f = nvrfopen("pc200.nvr",       "rb"); break;
                 case ROM_PC2086:      f = nvrfopen("pc2086.nvr",      "rb"); break;
                 case ROM_PC3086:      f = nvrfopen("pc3086.nvr",      "rb"); break;
+                case ROM_PPC512:      f = nvrfopen("ppc512.nvr",      "rb"); break;
                 case ROM_IBMAT:       f = nvrfopen("at.nvr",          "rb"); break;
                 case ROM_IBMXT286:    f = nvrfopen("ibmxt286.nvr",    "rb"); break;
                 case ROM_IBMPS1_2011: f = nvrfopen("ibmps1_2011.nvr", "rb"); /*nvrmask = 127; */break;
@@ -274,24 +295,32 @@ void loadnvr()
                 case ROM_IBMPS2_M80:  f = nvrfopen("ibmps2_m80.nvr",  "rb"); break;
                 case ROM_CMDPC30:     f = nvrfopen("cmdpc30.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_AMI286:      f = nvrfopen("ami286.nvr",      "rb"); nvrmask = 127; break;
+                case ROM_TG286M:      f = nvrfopen("tg286m.nvr",      "rb"); nvrmask = 127; break;
                 case ROM_AWARD286:    f = nvrfopen("award286.nvr",    "rb"); nvrmask = 127; break;
+                case ROM_GDC212M:     f = nvrfopen("gdc212m.nvr",     "rb"); nvrmask = 127; break;
+                case ROM_HYUNDAI_SUPER286TR: f = nvrfopen("super286tr.nvr", "rb"); nvrmask = 127; break;
                 case ROM_GW286CT:     f = nvrfopen("gw286ct.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_SPC4200P:    f = nvrfopen("spc4200p.nvr",    "rb"); nvrmask = 127; break;
                 case ROM_SPC4216P:    f = nvrfopen("spc4216p.nvr",    "rb"); nvrmask = 127; break;
+                case ROM_SPC4620P:    f = nvrfopen("spc4620p.nvr",    "rb"); nvrmask = 127; break;
                 case ROM_DELL200:     f = nvrfopen("dell200.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_IBMAT386:    f = nvrfopen("at386.nvr",       "rb"); nvrmask = 127; break;
                 case ROM_DESKPRO_386: f = nvrfopen("deskpro386.nvr",  "rb"); break;
                 case ROM_ACER386:     f = nvrfopen("acer386.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_KMXC02:      f = nvrfopen("kmxc02.nvr",      "rb"); nvrmask = 127; break;
                 case ROM_MEGAPC:      f = nvrfopen("megapc.nvr",      "rb"); nvrmask = 127; break;
+                case ROM_AMA932J:     f = nvrfopen("ama932j.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_AMI386SX:    f = nvrfopen("ami386.nvr",      "rb"); nvrmask = 127; break;
                 case ROM_AMI486:      f = nvrfopen("ami486.nvr",      "rb"); nvrmask = 127; break;
                 case ROM_WIN486:      f = nvrfopen("win486.nvr",      "rb"); nvrmask = 127; break;
                 case ROM_PCI486:      f = nvrfopen("hot-433.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_SIS496:      f = nvrfopen("sis496.nvr",      "rb"); nvrmask = 127; break;
+                case ROM_P55VA:       f = nvrfopen("p55va.nvr",       "rb"); nvrmask = 127; break;
+                case ROM_P55TVP4:     f = nvrfopen("p55tvp4.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_430VX:       f = nvrfopen("430vx.nvr",       "rb"); nvrmask = 127; break;
                 case ROM_REVENGE:     f = nvrfopen("revenge.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_ENDEAVOR:    f = nvrfopen("endeavor.nvr",    "rb"); nvrmask = 127; break;
+                case ROM_P55T2P4:     f = nvrfopen("p55t2p4.nvr",     "rb"); nvrmask = 127; break;
                 case ROM_PX386:       f = nvrfopen("px386.nvr",       "rb"); nvrmask = 127; break;
                 case ROM_DTK386:      f = nvrfopen("dtk386.nvr",      "rb"); nvrmask = 127; break;
                 case ROM_MR386DX_OPTI495:  f = nvrfopen("mr386dx_opti495.nvr",  "rb"); nvrmask = 127; break;
@@ -313,11 +342,19 @@ void loadnvr()
                case ROM_ELX_PC425X:       f = nvrfopen("elx_pc425.nvr",       "rb"); nvrmask = 127; break;
                case ROM_PB570:            f = nvrfopen("pb570.nvr",           "rb"); nvrmask = 127; break;
                case ROM_ZAPPA:            f = nvrfopen("zappa.nvr",           "rb"); nvrmask = 127; break;
+               case ROM_ITAUTEC_INFOWAYM: f = nvrfopen("infowaym.nvr",        "rb"); nvrmask = 127; break;
                case ROM_PB520R:           f = nvrfopen("pb520r.nvr",          "rb"); nvrmask = 127; break;
                case ROM_XI8088:           f = nvrfopen("xi8088.nvr",          "rb"); nvrmask = 127; break;
                 case ROM_IBMPS2_M70_TYPE3: f = nvrfopen("ibmps2_m70_type3.nvr","rb"); break;
                 case ROM_IBMPS2_M70_TYPE4: f = nvrfopen("ibmps2_m70_type4.nvr","rb"); break;
-                                                               
+               case ROM_TULIP_TC7:        f = nvrfopen("tulip_tc7.nvr",       "rb"); break;
+               case ROM_PB410A:           f = nvrfopen("pb410a.nvr",          "rb"); nvrmask = 127; break;
+               case ROM_BULL_MICRAL_45:   f = nvrfopen("bull_micral_45.nvr",  "rb"); break;
+                case ROM_FIC_VA503P:       f = nvrfopen("fic_va503p.nvr",      "rb"); nvrmask = 127; break;
+                case ROM_CBM_SL386SX25:    f = nvrfopen("cbm_sl386sx25.nvr",   "rb"); nvrmask = 127; break;
+                case ROM_IBMPS1_2133_451:  f = nvrfopen("ibmps1_2133.nvr",     "rb"); nvrmask = 127; break;
+                case ROM_ECS_386_32:       f = nvrfopen("ecs_386_32.nvr",      "rb"); nvrmask = 127; break;
+                
                 default: return;
         }
         if (!f)
@@ -334,18 +371,14 @@ void loadnvr()
                 return;
         }
         fread(nvrram,128,1,f);
-               fclose(f);
-#endif
-               if (enable_sync)
+        if (enable_sync)
                 time_internal_sync(nvrram);
         else
                 time_internal_set_nvrram(nvrram); /* Update the internal clock state based on the NVR registers. */
+        fclose(f);
         nvrram[RTC_REGA] = 6;
         nvrram[RTC_REGB] = RTC_2412;
-        c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
-        rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
 }
-#if 0
 void savenvr()
 {
         FILE *f;
@@ -356,6 +389,7 @@ void savenvr()
                 case ROM_PC200:       f = nvrfopen("pc200.nvr",       "wb"); break;
                 case ROM_PC2086:      f = nvrfopen("pc2086.nvr",      "wb"); break;
                 case ROM_PC3086:      f = nvrfopen("pc3086.nvr",      "wb"); break;
+                case ROM_PPC512:      f = nvrfopen("ppc512.nvr",      "wb"); break;
                 case ROM_IBMAT:       f = nvrfopen("at.nvr",          "wb"); break;
                 case ROM_IBMXT286:    f = nvrfopen("ibmxt286.nvr",    "wb"); break;
                 case ROM_IBMPS1_2011: f = nvrfopen("ibmps1_2011.nvr", "wb"); break;
@@ -366,24 +400,32 @@ void savenvr()
                 case ROM_IBMPS2_M80:  f = nvrfopen("ibmps2_m80.nvr",  "wb"); break;
                 case ROM_CMDPC30:     f = nvrfopen("cmdpc30.nvr",     "wb"); break;
                 case ROM_AMI286:      f = nvrfopen("ami286.nvr",      "wb"); break;
+                case ROM_TG286M:      f = nvrfopen("tg286m.nvr",      "wb"); break;
                 case ROM_AWARD286:    f = nvrfopen("award286.nvr",    "wb"); break;
+                case ROM_GDC212M:     f = nvrfopen("gdc212m.nvr",     "wb"); break;
+                case ROM_HYUNDAI_SUPER286TR: f = nvrfopen("super286tr.nvr", "wb"); break;
                 case ROM_GW286CT:     f = nvrfopen("gw286ct.nvr",     "wb"); break;
                 case ROM_SPC4200P:    f = nvrfopen("spc4200p.nvr",    "wb"); break;
                 case ROM_SPC4216P:    f = nvrfopen("spc4216p.nvr",    "wb"); break;
+                case ROM_SPC4620P:    f = nvrfopen("spc4620p.nvr",    "wb"); break;
                 case ROM_DELL200:     f = nvrfopen("dell200.nvr",     "wb"); break;
                 case ROM_IBMAT386:    f = nvrfopen("at386.nvr",       "wb"); break;
                 case ROM_DESKPRO_386: f = nvrfopen("deskpro386.nvr",  "wb"); break;
                 case ROM_ACER386:     f = nvrfopen("acer386.nvr",     "wb"); break;
                 case ROM_KMXC02:      f = nvrfopen("kmxc02.nvr",      "wb"); break;
                 case ROM_MEGAPC:      f = nvrfopen("megapc.nvr",      "wb"); break;
+                case ROM_AMA932J:     f = nvrfopen("ama932j.nvr",     "wb"); break;
                 case ROM_AMI386SX:    f = nvrfopen("ami386.nvr",      "wb"); break;
                 case ROM_AMI486:      f = nvrfopen("ami486.nvr",      "wb"); break;
                 case ROM_WIN486:      f = nvrfopen("win486.nvr",      "wb"); break;
                 case ROM_PCI486:      f = nvrfopen("hot-433.nvr",     "wb"); break;
                 case ROM_SIS496:      f = nvrfopen("sis496.nvr",      "wb"); break;
+                case ROM_P55VA:       f = nvrfopen("p55va.nvr",       "wb"); break;
+                case ROM_P55TVP4:     f = nvrfopen("p55tvp4.nvr",     "wb"); break;
                 case ROM_430VX:       f = nvrfopen("430vx.nvr",       "wb"); break;
                 case ROM_REVENGE:     f = nvrfopen("revenge.nvr",     "wb"); break;
                 case ROM_ENDEAVOR:    f = nvrfopen("endeavor.nvr",    "wb"); break;
+                case ROM_P55T2P4:     f = nvrfopen("p55t2p4.nvr",     "wb"); break;
                 case ROM_PX386:       f = nvrfopen("px386.nvr",       "wb"); break;
                 case ROM_DTK386:      f = nvrfopen("dtk386.nvr",      "wb"); break;
                 case ROM_MR386DX_OPTI495:  f = nvrfopen("mr386dx_opti495.nvr",  "wb"); break;
@@ -405,23 +447,54 @@ void savenvr()
                case ROM_ELX_PC425X:       f = nvrfopen("elx_pc425.nvr",       "wb"); break;
                case ROM_PB570:            f = nvrfopen("pb570.nvr",           "wb"); break;
                case ROM_ZAPPA:            f = nvrfopen("zappa.nvr",           "wb"); break;
+               case ROM_ITAUTEC_INFOWAYM:  f = nvrfopen("infowaym.nvr",        "wb"); break;
                case ROM_PB520R:           f = nvrfopen("pb520r.nvr",          "wb"); break;
                case ROM_XI8088:           f = nvrfopen("xi8088.nvr",          "wb"); break;
                 case ROM_IBMPS2_M70_TYPE3: f = nvrfopen("ibmps2_m70_type3.nvr","wb"); break;
                 case ROM_IBMPS2_M70_TYPE4: f = nvrfopen("ibmps2_m70_type4.nvr","wb"); break;
-                               
+               case ROM_TULIP_TC7:        f = nvrfopen("tulip_tc7.nvr",       "wb"); break;
+               case ROM_PB410A:           f = nvrfopen("pb410a.nvr",          "wb"); break;
+               case ROM_BULL_MICRAL_45:   f = nvrfopen("bull_micral_45.nvr",  "wb"); break;
+                case ROM_FIC_VA503P:       f = nvrfopen("fic_va503p.nvr",      "wb"); break;
+                case ROM_CBM_SL386SX25:    f = nvrfopen("cbm_sl386sx25.nvr",   "wb"); break;
+                case ROM_IBMPS1_2133_451:  f = nvrfopen("ibmps1_2133.nvr",     "wb"); break;
+                case ROM_ECS_386_32:       f = nvrfopen("ecs_386_32.nvr",      "wb"); break;
+                
                 default: return;
         }
         fwrite(nvrram,128,1,f);
         fclose(f);
 }
-#endif
 
-void nvr_init()
+static void *nvr_init()
 {
-        io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL,  NULL);
-        timer_add(nvr_rtc, &rtctime, TIMER_ALWAYS_ENABLED, NULL);
-        timer_add(nvr_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL);
-        timer_add(nvr_update_end, &nvr_update_end_count, &nvr_update_end_count, NULL);
+        nvr_t *nvr = (nvr_t *)malloc(sizeof(nvr_t));
+        memset(nvr, 0, sizeof(nvr_t));
+
+        io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL,  nvr);
+        timer_add(&nvr->rtc_timer, nvr_rtc, nvr, 1);
+        timer_add(&nvr->onesec_timer, nvr_onesec, nvr, 1);
+        timer_add(&nvr->update_end_timer, nvr_update_end, nvr, 0);
+
+        return nvr;
+}
 
+static void nvr_close(void *p)
+{
+        nvr_t *nvr = (nvr_t *)p;
+        
+        free(nvr);
 }
+
+device_t nvr_device =
+{
+        "Motorola MC146818 RTC",
+        0,
+        nvr_init,
+        nvr_close,
+        NULL,
+        nvr_speed_changed,
+        NULL,
+        NULL,
+        NULL
+};
index dd769a8acc7291a6e514805a3e435abc2c7b7e11..c545f8487f3fc76ba5e270a9360e2ccbfa50d33f 100644 (file)
@@ -1,4 +1,6 @@
-void nvr_init();
+#include "device.h"
+
+extern device_t nvr_device;
 
 extern int enable_sync;
 
@@ -7,10 +9,8 @@ extern int nvr_dosave;
 void loadnvr();
 void savenvr();
 
-void nvr_recalc();
-
 FILE *nvrfopen(char *fn, char *mode);
 
-extern uint8_t nvrram[128+64];
+extern uint8_t nvrram[128];
 extern int nvrmask;
 extern int oldromset;
index a8161bcdfaa88af68b93317b3c5b40a22b92351c..fe33dc26e9905e0aa34a2640a457405fe9b391fc 100644 (file)
@@ -10,7 +10,8 @@
 #include "codegen.h"
 #include "timer.h"
 #include "sound.h"
-#include "sound_mpu401_uart.h"
+#include "rom.h"
+#include "thread.h"
 
 #ifdef _WIN32
 #include <windows.h>
 
 #include "sysconfig.h"
 #include "sysdeps.h"
+#include "threaddep/thread.h"
+#include "machdep/maccess.h"
+#include "gfxboard.h"
+#include "uae/time.h"
+
+#include "video.h"
+#include "vid_svga.h"
+
+CPU_STATE cpu_state;
 
 PIT pit, pit2;
 PIC pic, pic2;
@@ -28,23 +38,17 @@ dma_t dma[8];
 int AT;
 
 int ppispeakon;
-float CGACONST;
-float MDACONST;
-float VGACONST1, VGACONST2;
-float RTCCONST;
 int gated, speakval, speakon;
 
 PPI ppi;
 
-cpu_state_s cpu_state;
-
-
 int codegen_flags_changed;
 uint32_t codegen_endpc;
 int codegen_in_recompile;
 int codegen_flat_ds, codegen_flat_ss;
 uint32_t recomp_page;
-codeblock_t **codeblock_hash;
+uint16_t *codeblock_hash;
+codeblock_t *codeblock;
 
 void codegen_reset(void)
 {
@@ -109,44 +113,31 @@ void device_speed_changed(void)
        write_log(_T("device_speed_changed\n"));
 }
 
-union CR0_s CR0;
-
 int model;
 int cpuspeed;
-int CPUID;
 int insc;
 int hasfpu;
 int romset;
 int nmi_mask;
-int use32;
-int stack32;
-uint32_t cr2, cr3, cr4;
 uint32_t rammask;
 uintptr_t *readlookup2;
 uintptr_t *writelookup2;
 uint16_t flags, eflags;
-x86seg gdt, ldt, idt, tr;
-x86seg _cs, _ds, _es, _ss, _fs, _gs;
-x86seg _oldds;
 int writelookup[256], writelookupp[256];
 int readlookup[256], readlookupp[256];
 int readlnext;
 int writelnext;
-int pccache;
-unsigned char *pccache2;
-int cpl_override;
-uint32_t oldds, oldss, olddslimit, oldsslimit, olddslimitw, oldsslimitw;
+uint32_t olddslimit, oldsslimit, olddslimitw, oldsslimitw;
 int pci_burst_time, pci_nonburst_time;
-int optype;
 uint32_t oxpc;
 char logs_path[512];
 uint32_t ealimit, ealimitw;
+int MCA;
+struct svga_t *mb_vga;
 
 uint32_t x87_pc_off, x87_op_off;
 uint16_t x87_pc_seg, x87_op_seg;
 
-uint32_t dr[8];
-
 int xi8088_bios_128kb(void)
 {
        return 0;
@@ -195,7 +186,7 @@ int TANDY;
 int keybsenddelay;
 int mouse_buttons;
 int mouse_type;
-int pcem_key[272];
+uint8_t pcem_key[272];
 
 int mouse_get_type(int mouse_type)
 {
@@ -249,6 +240,99 @@ int video_is_mda()
        return 0;
 }
 
+static FPU fpus_none[] =
+{
+       { "None", "none", FPU_NONE },
+       { NULL, NULL, 0 }
+};
+static FPU fpus_8088[] =
+{
+       { "None", "none", FPU_NONE },
+       { "8087", "8087", FPU_8087 },
+       { NULL, NULL, 0 }
+};
+static FPU fpus_80286[] =
+{
+       { "None", "none", FPU_NONE },
+       { "287", "287", FPU_287 },
+       { "287XL", "287xl", FPU_287XL },
+       { NULL, NULL, 0 }
+};
+static FPU fpus_80386[] =
+{
+       { "None", "none", FPU_NONE },
+       { "387", "387", FPU_387 },
+       { NULL, NULL, 0 }
+};
+static FPU fpus_builtin[] =
+{
+       { "Built-in", "builtin", FPU_BUILTIN },
+       { NULL, NULL, 0 }
+};
+
+static CPU cpus_8088[] =
+{
+       /*8088 standard*/
+       { "8088/4.77", CPU_8088, fpus_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+       { "8088/7.16", CPU_8088, fpus_8088, 1, 14318184 / 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+       { "8088/8", CPU_8088, fpus_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+       { "8088/10", CPU_8088, fpus_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+       { "8088/12", CPU_8088, fpus_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+       { "8088/16", CPU_8088, fpus_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+       { "", -1, 0, 0, 0, 0 }
+};
+
+static CPU cpus_286[] =
+{
+       /*286*/
+       { "286/6", CPU_286, fpus_80286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1 },
+       { "286/8", CPU_286, fpus_80286, 1, 8000000, 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1 },
+       { "286/10", CPU_286, fpus_80286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1 },
+       { "286/12", CPU_286, fpus_80286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 2 },
+       { "286/16", CPU_286, fpus_80286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 2 },
+       { "286/20", CPU_286, fpus_80286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4, 4, 4, 4, 3 },
+       { "286/25", CPU_286, fpus_80286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4, 4, 4, 4, 3 },
+       { "", -1, 0, 0, 0, 0 }
+};
+
+static CPU cpus_i386SX[] =
+{
+       /*i386SX*/
+       { "i386SX/16", CPU_386SX, fpus_80386, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3, 3, 3, 3, 2 },
+       { "i386SX/20", CPU_386SX, fpus_80386, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4, 4, 3, 3, 3 },
+       { "i386SX/25", CPU_386SX, fpus_80386, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4, 4, 3, 3, 3 },
+       { "i386SX/33", CPU_386SX, fpus_80386, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6, 6, 3, 3, 4 },
+       { "", -1, 0, 0, 0 }
+};
+
+static CPU cpus_i386DX[] =
+{
+       /*i386DX*/
+       { "i386DX/16", CPU_386DX, fpus_80386, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3, 3, 3, 3, 2 },
+       { "i386DX/20", CPU_386DX, fpus_80386, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4, 4, 3, 3, 3 },
+       { "i386DX/25", CPU_386DX, fpus_80386, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4, 4, 3, 3, 3 },
+       { "i386DX/33", CPU_386DX, fpus_80386, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6, 6, 3, 3, 4 },
+       { "", -1, 0, 0, 0 }
+};
+
+static CPU cpus_i486[] =
+{
+       /*i486*/
+       { "i486SX/16", CPU_i486SX, fpus_none, 0, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3, 3, 3, 3, 2 },
+       { "i486SX/20", CPU_i486SX, fpus_none, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3 },
+       { "i486SX/25", CPU_i486SX, fpus_none, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3 },
+       { "i486SX/33", CPU_i486SX, fpus_none, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4 },
+       { "i486SX2/50", CPU_i486SX, fpus_none, 5, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 2 * 3 },
+       { "i486DX/25", CPU_i486DX, fpus_builtin, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3 },
+       { "i486DX/33", CPU_i486DX, fpus_builtin, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4 },
+       { "i486DX/50", CPU_i486DX, fpus_builtin, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 6 },
+       { "i486DX2/40", CPU_i486DX, fpus_builtin, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 2 * 3 },
+       { "i486DX2/50", CPU_i486DX, fpus_builtin, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 2 * 3 },
+       { "i486DX2/66", CPU_i486DX, fpus_builtin, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 2 * 4 },
+       { "", -1, 0, 0, 0 }
+};
+
+
 MODEL models[] =
 {
        { "[8088] Generic XT clone", ROM_GENXT, "genxt", { { "", cpus_8088 }, { "", NULL }, { "", NULL } }, MODEL_GFX_NONE, 32, 704, 16, model_init, NULL },
@@ -277,4 +361,598 @@ void pcem_close(void)
        midi_open = 0;
 }
 
-// void (*code)() = (void(*)(void))&block->data[BLOCK_START];
+#ifdef CPU_i386
+void codegen_set_rounding_mode(int mode)
+{
+       /*SSE*/
+       cpu_state.new_fp_control = (cpu_state.old_fp_control & ~0x6000) | (mode << 13);
+       /*x87 - used for double -> i64 conversions*/
+       cpu_state.new_fp_control2 = (cpu_state.old_fp_control2 & ~0x0c00) | (mode << 10);
+}
+#else
+void codegen_set_rounding_mode(int mode)
+{
+       /*SSE*/
+       cpu_state.new_fp_control = (cpu_state.old_fp_control & ~0x6000) | (mode << 13);
+       /*x87 - used for double -> i64 conversions*/
+       cpu_state.new_fp_control2 = (cpu_state.old_fp_control2 & ~0x0c00) | (mode << 10);
+}
+#endif
+
+// VIDEO STUFF
+
+int video_timing_read_b;
+int video_timing_read_w;
+int video_timing_read_l;
+
+int video_timing_write_b;
+int video_timing_write_w;
+int video_timing_write_l;
+
+int cycles_lost;
+
+uint8_t fontdat[2048][8];
+uint8_t fontdatm[2048][16];
+uint8_t fontdatw[512][32];     /* Wyse700 font */
+uint8_t fontdat8x12[256][16];  /* MDSI Genius font */
+uint8_t fontdat12x18[256][36]; /* IM1024 font */
+uint8_t fontdatksc5601[16384][32]; /* Korean KSC-5601 font */
+uint8_t fontdatksc5601_user[192][32]; /* Korean KSC-5601 user defined font */
+
+int PCI;
+int readflash;
+int egareads;
+int egawrites;
+int changeframecount;
+PCBITMAP *buffer32;
+static int buffer32size;
+static uae_u8 *tempbuf;
+int vid_resize;
+int xsize, ysize;
+uint64_t timer_freq;
+
+uint8_t edatlookup[4][4];
+uint8_t rotatevga[8][256];
+uint32_t *video_15to32, *video_16to32;
+
+static void *gfxboard_priv;
+
+static mem_mapping_t *pcem_mapping_linear;
+void *pcem_mapping_linear_priv;
+uae_u32 pcem_mapping_linear_offset;
+uint8_t(*pcem_linear_read_b)(uint32_t addr, void *priv);
+uint16_t(*pcem_linear_read_w)(uint32_t addr, void *priv);
+uint32_t(*pcem_linear_read_l)(uint32_t addr, void *priv);
+void (*pcem_linear_write_b)(uint32_t addr, uint8_t  val, void *priv);
+void (*pcem_linear_write_w)(uint32_t addr, uint16_t val, void *priv);
+void (*pcem_linear_write_l)(uint32_t addr, uint32_t val, void *priv);
+
+static uint8_t dummy_bread(uint32_t addr, void *p)
+{
+       return 0;
+}
+static uint16_t dummy_wread(uint32_t addr, void *p)
+{
+       return 0;
+}
+static uint32_t dummy_lread(uint32_t addr, void *p)
+{
+       return 0;
+}
+static void dummy_bwrite(uint32_t addr, uint8_t v, void *p)
+{
+
+}
+static void dummy_wwrite(uint32_t addr, uint16_t v, void *p)
+{
+
+}
+static void dummy_lwrite(uint32_t addr, uint32_t v, void *p)
+{
+
+}
+
+uint64_t timer_read(void)
+{
+       return read_processor_time();
+}
+
+void initpcemvideo(void *p, bool swapped)
+{
+       int c, d, e;
+
+       gfxboard_priv = p;
+       has_vlb = 0;
+       timer_freq = syncbase;
+
+       for (c = 0; c < 256; c++)
+       {
+               e = c;
+               for (d = 0; d < 8; d++)
+               {
+                       rotatevga[d][c] = e;
+                       e = (e >> 1) | ((e & 1) ? 0x80 : 0);
+               }
+       }
+       for (c = 0; c < 4; c++)
+       {
+               for (d = 0; d < 4; d++)
+               {
+                       edatlookup[c][d] = 0;
+                       if (c & 1) edatlookup[c][d] |= 1;
+                       if (d & 1) edatlookup[c][d] |= 2;
+                       if (c & 2) edatlookup[c][d] |= 0x10;
+                       if (d & 2) edatlookup[c][d] |= 0x20;
+                       //                        printf("Edat %i,%i now %02X\n",c,d,edatlookup[c][d]);
+               }
+       }
+
+       if (!video_15to32)
+               video_15to32 = (uint32_t*)malloc(4 * 65536);
+       for (c = 0; c < 65536; c++) {
+               if (swapped) {
+                       video_15to32[c] = (((c >> 10) & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 0) & 31) << 19);
+               } else {
+                       video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19);
+               }
+       }
+
+       if (!video_16to32)
+               video_16to32 = (uint32_t*)malloc(4 * 65536);
+       for (c = 0; c < 65536; c++) {
+               if (swapped) {
+                       video_16to32[c] = (((c >> 11) & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 0) & 31) << 19);
+               } else {
+                       video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19);
+               }
+       }
+
+       if (!buffer32) {
+               buffer32 = (PCBITMAP *)calloc(sizeof(PCBITMAP) + sizeof(uint8_t *) * 2048, 1);
+               buffer32->dat = xcalloc(uae_u8, 2048 * 2048 * 4);
+               buffer32->w = 2048;
+               buffer32->h = 2048;
+               for (int i = 0; i < buffer32->h; i++) {
+                       buffer32->line[i] = buffer32->dat + buffer32->w * 4 * i;
+               }
+       }
+
+       pcem_linear_read_b = dummy_bread;
+       pcem_linear_read_w = dummy_wread;
+       pcem_linear_read_l = dummy_lread;
+       pcem_linear_write_b = dummy_bwrite;
+       pcem_linear_write_w = dummy_wwrite;
+       pcem_linear_write_l = dummy_lwrite;
+       pcem_mapping_linear = NULL;
+       pcem_mapping_linear_offset = 0;
+
+}
+
+extern void *svga_get_object(void);
+
+uae_u8 pcem_read_io(int port, int index)
+{
+       svga_t *svga = (svga_t*)svga_get_object();
+       if (port == 0x3d5) {
+               return svga->crtc[index];
+       } else {
+               write_log("unknown port %04x!\n", port);
+               abort();
+       }
+}
+
+#if 0
+void update_pcembuffer32(void *buf, int w, int h, int bytesperline)
+{
+       if (!buf) {
+               w = 2048;
+               h = 2048;
+               if (!tempbuf) {
+                       tempbuf = xmalloc(uae_u8, w * 4);
+               }
+               buf = tempbuf;
+               bytesperline = 0;
+       }
+       if (!buffer32 || h > buffer32->h) {
+               free(buffer32);
+               buffer32 = (PCBITMAP *)calloc(sizeof(PCBITMAP) + sizeof(uint8_t *) * h, 1);
+       }
+       if (buffer32->w == w && buffer32->h == h && buffer32->line[0] == buf)
+               return;
+       buffer32->w = w;
+       buffer32->h = h;
+       uae_u8 *b = (uae_u8*)buf;
+       for (int i = 0; i < h; i++) {
+               buffer32->line[i] = b;
+               b += bytesperline;
+       }
+}
+#endif
+
+uae_u8 *getpcembuffer32(int x, int y, int yy)
+{
+       return buffer32->line[y + yy] + x * 4;
+}
+
+
+void video_wait_for_buffer(void)
+{
+       //write_log(_T("video_wait_for_buffer\n"));
+}
+void updatewindowsize(int x, int y)
+{
+       gfxboard_resize(x, y, gfxboard_priv);
+}
+
+static void (*pci_card_write)(int func, int addr, uint8_t val, void *priv);
+static uint8_t(*pci_card_read)(int func, int addr, void *priv);
+static void *pci_card_priv;
+
+void put_pci_pcem(uaecptr addr, uae_u8 v)
+{
+       if (pci_card_write) {
+               pci_card_write(0, addr, v, pci_card_priv);
+       }
+}
+uae_u8 get_pci_pcem(uaecptr addr)
+{
+       uae_u8 v = 0;
+       if (pci_card_read) {
+               v = pci_card_read(0, addr, pci_card_priv);
+       }
+       return v;
+}
+
+int pci_add(uint8_t(*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv)
+{
+       pci_card_read = read;
+       pci_card_write = write;
+       pci_card_priv = priv;
+       return 0;
+}
+extern void gfxboard_intreq(void *, int);
+void pci_set_irq_routing(int card, int irq)
+{
+       write_log(_T("pci_set_irq_routing %d %d\n"), card, irq);
+}
+void pci_set_irq(int card, int pci_int)
+{
+       //write_log(_T("pci_set_irq %d %d\n"), card, pci_int);
+       gfxboard_intreq(gfxboard_priv, 1);
+}
+void pci_clear_irq(int card, int pci_int)
+{
+       //write_log(_T("pci_clear_irq %d %d\n"), card, pci_int);
+       gfxboard_intreq(gfxboard_priv, 0);
+}
+int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags)
+{
+       return 0;
+}
+
+thread_t *thread_create(void (*thread_rout)(void *param), void *param)
+{
+       uae_thread_id tid;
+       uae_start_thread(_T("PCem helper"), thread_rout, param, &tid);
+       return tid;
+}
+void thread_kill(thread_t *handle)
+{
+       uae_end_thread((uae_thread_id*)handle);
+}
+event_t *thread_create_event(void)
+{
+       uae_sem_t sem = { 0 };
+       uae_sem_init(&sem, 1, 0);
+       return sem;
+}
+void thread_set_event(event_t *event)
+{
+       uae_sem_post((uae_sem_t*)&event);
+}
+void thread_reset_event(event_t *_event)
+{
+       uae_sem_init((uae_sem_t*)&_event, 1, 0);
+}
+int thread_wait_event(event_t *event, int timeout)
+{
+       uae_sem_trywait_delay((uae_sem_t*)&event, timeout);
+       return 0;
+}
+void thread_destroy_event(event_t *_event)
+{
+       uae_sem_destroy((uae_sem_t*)&_event);
+}
+
+#define MAX_PCEMMAPPINGS 10
+static mem_mapping_t *pcemmappings[MAX_PCEMMAPPINGS];
+#define PCEMMAPBLOCKSIZE 0x10000
+#define MAX_PCEMMAPBLOCKS (0x10000000 / PCEMMAPBLOCKSIZE)
+mem_mapping_t *pcemmap[MAX_PCEMMAPBLOCKS];
+
+static mem_mapping_t *getmm(uaecptr *addrp)
+{
+       uaecptr addr = *addrp;
+       addr &= 0x0fffffff;
+       int index = addr / PCEMMAPBLOCKSIZE;
+       mem_mapping_t *m = pcemmap[index];
+       if (!m) {
+               write_log(_T("%08x no mapping\n"), addr);
+       }
+       return m;
+}
+
+void put_mem_pcem(uaecptr addr, uae_u32 v, int size)
+{
+       mem_mapping_t *m = getmm(&addr);
+       if (m) {
+               if (size == 0) {
+                       m->write_b(addr, v, m->p);
+               } else if (size == 1) {
+                       m->write_w(addr, v, m->p);
+               } else if (size == 2) {
+                       m->write_l(addr, v, m->p);
+               }
+       }
+}
+uae_u32 get_mem_pcem(uaecptr addr, int size)
+{
+       uae_u32 v = 0;
+       mem_mapping_t *m = getmm(&addr);
+       if (m) {
+               if (size == 0) {
+                       v = m->read_b(addr, m->p);
+               } else if (size == 1) {
+                       v = m->read_w(addr, m->p);
+               } else if (size == 2) {
+                       v = m->read_l(addr, m->p);
+               }
+       }
+       return v;
+}
+
+static void mapping_recalc(mem_mapping_t *mapping)
+{
+       if (mapping->read_b == NULL)
+               mapping->read_b = dummy_bread;
+       if (mapping->read_w == NULL)
+               mapping->read_w = dummy_wread;
+       if (mapping->read_l == NULL)
+               mapping->read_l = dummy_lread;
+       if (mapping->write_b == NULL)
+               mapping->write_b = dummy_bwrite;
+       if (mapping->write_w == NULL)
+               mapping->write_w = dummy_wwrite;
+       if (mapping->write_l == NULL)
+               mapping->write_l = dummy_lwrite;
+
+
+       if (mapping == pcem_mapping_linear || (!pcem_mapping_linear && mapping->size >= 1024 * 1024)) {
+               pcem_mapping_linear = mapping;
+               pcem_mapping_linear_priv = mapping->p;
+               pcem_mapping_linear_offset = mapping->base;
+               if (!mapping->enable) {
+                       pcem_linear_read_b = dummy_bread;
+                       pcem_linear_read_w = dummy_wread;
+                       pcem_linear_read_l = dummy_lread;
+                       pcem_linear_write_b = dummy_bwrite;
+                       pcem_linear_write_w = dummy_wwrite;
+                       pcem_linear_write_l = dummy_lwrite;
+               } else {
+                       pcem_linear_read_b = mapping->read_b;
+                       pcem_linear_read_w = mapping->read_w;
+                       pcem_linear_read_l = mapping->read_l;
+                       pcem_linear_write_b = mapping->write_b;
+                       pcem_linear_write_w = mapping->write_w;
+                       pcem_linear_write_l = mapping->write_l;
+               }
+       }
+
+       for (uae_u32 i = 0; i < mapping->size; i += PCEMMAPBLOCKSIZE) {
+               uae_u32 addr = i + mapping->base;
+               addr &= 0x0fffffff;
+               int offset = addr / PCEMMAPBLOCKSIZE;
+               if (offset >= 0 && offset < MAX_PCEMMAPBLOCKS) {
+                       if (mapping->enable) {
+                               pcemmap[offset] = mapping;
+                       } else {
+                               pcemmap[offset] = NULL;
+                       }
+               }
+       }
+}
+
+void mem_mapping_addx(mem_mapping_t *mapping,
+       uint32_t base,
+       uint32_t size,
+       uint8_t(*read_b)(uint32_t addr, void *p),
+       uint16_t(*read_w)(uint32_t addr, void *p),
+       uint32_t(*read_l)(uint32_t addr, void *p),
+       void (*write_b)(uint32_t addr, uint8_t  val, void *p),
+       void (*write_w)(uint32_t addr, uint16_t val, void *p),
+       void (*write_l)(uint32_t addr, uint32_t val, void *p),
+       uint8_t *exec,
+       uint32_t flags,
+       void *p)
+{
+       mapping->enable = 0;
+       for (int i = 0; i < MAX_PCEMMAPPINGS; i++) {
+               if (pcemmappings[i] == mapping)
+                       return;
+       }
+       for (int i = 0; i < MAX_PCEMMAPPINGS; i++) {
+               if (pcemmappings[i] == NULL) {
+                       pcemmappings[i] = mapping;
+                       mapping->base = base;
+                       mapping->size = size;
+                       mapping->read_b = read_b;
+                       mapping->read_w = read_w;
+                       mapping->read_l = read_l;
+                       mapping->write_b = write_b;
+                       mapping->write_w = write_w;
+                       mapping->write_l = write_l;
+                       mapping->exec = exec;
+                       mapping->flags = flags;
+                       mapping->p = p;
+                       mapping->next = NULL;
+                       mapping_recalc(mapping);
+                       return;
+               }
+       }
+}
+
+void mem_mapping_set_handlerx(mem_mapping_t *mapping,
+       uint8_t(*read_b)(uint32_t addr, void *p),
+       uint16_t(*read_w)(uint32_t addr, void *p),
+       uint32_t(*read_l)(uint32_t addr, void *p),
+       void (*write_b)(uint32_t addr, uint8_t  val, void *p),
+       void (*write_w)(uint32_t addr, uint16_t val, void *p),
+       void (*write_l)(uint32_t addr, uint32_t val, void *p))
+{
+       mapping->read_b = read_b;
+       mapping->read_w = read_w;
+       mapping->read_l = read_l;
+       mapping->write_b = write_b;
+       mapping->write_w = write_w;
+       mapping->write_l = write_l;
+       mapping_recalc(mapping);
+}
+
+void mem_mapping_set_px(mem_mapping_t *mapping, void *p)
+{
+       mapping->p = p;
+}
+
+void pci_add_specific(int card, uint8_t(*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv)
+{
+}
+
+void mca_add(uint8_t(*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void (*reset)(void *priv), void *priv)
+{
+}
+
+#define MAX_IO_PORT 0x10000
+static uint8_t(*port_inb[MAX_IO_PORT])(uint16_t addr, void *priv);
+static uint16_t(*port_inw[MAX_IO_PORT])(uint16_t addr, void *priv);
+static uint32_t(*port_inl[MAX_IO_PORT])(uint16_t addr, void *priv);
+static void(*port_outb[MAX_IO_PORT])(uint16_t addr, uint8_t  val, void *priv);
+static void(*port_outw[MAX_IO_PORT])(uint16_t addr, uint16_t val, void *priv);
+static void(*port_outl[MAX_IO_PORT])(uint16_t addr, uint32_t val, void *priv);
+static void *port_priv[MAX_IO_PORT];
+
+void put_io_pcem(uaecptr addr, uae_u32 v, int size)
+{
+       addr &= MAX_IO_PORT - 1;
+       if (size == 0) {
+               if (port_outb[addr])
+                       port_outb[addr](addr, v, port_priv[addr]);
+       } else if (size == 1) {
+               if (port_outw[addr]) {
+                       port_outw[addr](addr, v, port_priv[addr]);
+               } else {
+                       put_io_pcem(addr + 0, v >> 0, 0);
+                       put_io_pcem(addr + 1, v >> 8, 0);
+               }
+       } else if (size == 2) {
+               if (port_outl[addr]) {
+                       port_outl[addr](addr, v, port_priv[addr]);
+               } else {
+                       put_io_pcem(addr + 0, v >> 16, 1);
+                       put_io_pcem(addr + 2, v >> 0, 1);
+               }
+       }
+}
+uae_u32 get_io_pcem(uaecptr addr, int size)
+{
+       uae_u32 v = 0;
+       addr &= MAX_IO_PORT - 1;
+       if (size == 0) {
+               if (port_inb[addr])
+                       v = port_inb[addr](addr, port_priv[addr]);
+       } else if (size == 1) {
+               if (port_inw[addr]) {
+                       v = port_inw[addr](addr, port_priv[addr]);
+               } else {
+                       v = get_io_pcem(addr + 0, 0) << 0;
+                       v |= get_io_pcem(addr + 1, 0) << 8;
+               }
+       } else if (size == 2) {
+               if (port_inl[addr]) {
+                       v = port_inl[addr](addr, port_priv[addr]);
+               } else {
+                       v = get_io_pcem(addr + 0, 1) << 16;
+                       v |= get_io_pcem(addr + 2, 1) << 0;
+               }
+       }
+       return v;
+}
+
+void io_sethandlerx(uint16_t base, int size,
+       uint8_t(*inb)(uint16_t addr, void *priv),
+       uint16_t(*inw)(uint16_t addr, void *priv),
+       uint32_t(*inl)(uint16_t addr, void *priv),
+       void (*outb)(uint16_t addr, uint8_t  val, void *priv),
+       void (*outw)(uint16_t addr, uint16_t val, void *priv),
+       void (*outl)(uint16_t addr, uint32_t val, void *priv),
+       void *priv)
+{
+       if (base + size > MAX_IO_PORT)
+               return;
+
+       for (int i = 0; i < size; i++) {
+               int io = base + i;
+               port_inb[io] = inb;
+               port_inw[io] = inw;
+               port_inl[io] = inl;
+               port_outb[io] = outb;
+               port_outw[io] = outw;
+               port_outl[io] = outl;
+               port_priv[io] = priv;
+       }
+}
+
+void io_removehandlerx(uint16_t base, int size,
+       uint8_t(*inb)(uint16_t addr, void *priv),
+       uint16_t(*inw)(uint16_t addr, void *priv),
+       uint32_t(*inl)(uint16_t addr, void *priv),
+       void (*outb)(uint16_t addr, uint8_t  val, void *priv),
+       void (*outw)(uint16_t addr, uint16_t val, void *priv),
+       void (*outl)(uint16_t addr, uint32_t val, void *priv),
+       void *priv)
+{
+       if (base + size > MAX_IO_PORT)
+               return;
+
+       for (int i = 0; i < size; i++) {
+               int io = base + i;
+               port_inb[io] = NULL;
+               port_inw[io] = NULL;
+               port_inl[io] = NULL;
+               port_outb[io] = NULL;
+               port_outw[io] = NULL;
+               port_outl[io] = NULL;
+       }
+}
+
+void mem_mapping_set_addrx(mem_mapping_t *mapping, uint32_t base, uint32_t size)
+{
+       mapping->enable = 0;
+       mapping_recalc(mapping);
+       mapping->enable = 1;
+       mapping->base = base;
+       mapping->size = size;
+       mapping_recalc(mapping);
+}
+
+void mem_mapping_disablex(mem_mapping_t *mapping)
+{
+       mapping->enable = 0;
+       mapping_recalc(mapping);
+}
+
+void mem_mapping_enablex(mem_mapping_t *mapping)
+{
+       mapping->enable = 1;
+       mapping_recalc(mapping);
+}
+
index 41cea2c9242017698082ae500a079e954ee1f865..8c5ed7aa78c1d6089e53e70f88ea6caa0c4258a7 100644 (file)
@@ -6,7 +6,6 @@ uint8_t mem_read_romext(uint32_t addr, void *priv);
 uint16_t mem_read_romextw(uint32_t addr, void *priv);
 uint32_t mem_read_romextl(uint32_t addr, void *priv);
 
-void sound_speed_changed(void);
 extern int SOUNDBUFLEN;
 extern int32_t *x86_sndbuffer[2];
 extern bool x86_sndbuffer_filled[2];
index e21d065052f36b6aa4f2f7dcd0604ac310422419..e6bf6791d2d375efe356e4624dfe6932fafd27e7 100644 (file)
@@ -4,7 +4,6 @@
 #include "pit.h"
 #include "video.h"
 
-extern int output;
 int intclear;
 int keywaiting=0;
 int pic_intpending;
@@ -74,8 +73,6 @@ static void pic_autoeoi()
         }
 }
 
-void x86_ack_keyboard(void);
-
 void pic_write(uint16_t addr, uint8_t val, void *priv)
 {
         int c;
@@ -124,12 +121,7 @@ void pic_write(uint16_t addr, uint8_t val, void *priv)
                         if ((val&0xE0)==0x60)
                         {
 //                                pclog("Specific EOI - %02X %i\n",pic.ins,1<<(val&7));
-
-                                                               if ((pic.ins & (1 << 1)) && ((val & 7) == 1)) {
-                                                                       x86_ack_keyboard();
-                                                               }
-                                                       
-                                                               pic.ins&=~(1<<(val&7));
+                                pic.ins&=~(1<<(val&7));
                                 pic_update_mask(&pic.mask2, pic.ins);
                                 if (val == 2 && (pic2.pend&~pic2.mask)&~pic2.mask2)
                                         pic.pend |= (1 << 2);
@@ -149,10 +141,6 @@ void pic_write(uint16_t addr, uint8_t val, void *priv)
                                                 if (c == 2 && (pic2.pend&~pic2.mask)&~pic2.mask2)
                                                         pic.pend |= (1 << 2);
 
-                                                                                               if (c == 1) {
-                                                                                                       x86_ack_keyboard();
-                                                                                               }
-
                                                 if (c==1 && keywaiting)
                                                 {
                                                         intclear&=~1;
@@ -335,7 +323,7 @@ int pic_current[16];
 
 void picint(uint16_t num)
 {
-        if (AT && num == (1 << 2))
+        if ((AT || romset == ROM_XI8088) && num == (1 << 2))
                 num = 1 << 9;
 //        pclog("picint : %04X\n", num);
 //        if (num == 0x10) pclog("PICINT 10\n");
@@ -357,7 +345,7 @@ void picintlevel(uint16_t num)
 {
         int c = 0;
         while (!(num & (1 << c))) c++;
-        if (AT && c == 2)
+        if ((AT || romset == ROM_XI8088) && num == (1 << 2))
         {
                 c = 9;
                 num = 1 << 9;
@@ -383,7 +371,7 @@ void picintc(uint16_t num)
         if (!num)
                 return;
         while (!(num & (1 << c))) c++;
-        if (AT && c == 2)
+        if ((AT || romset == ROM_XI8088) && num == (1 << 2))
         {
                 c = 9;
                 num = 1 << 9;
index 078f1c010d6d11c85ce2722384f36c5db279d5f3..6e7ef6ed0b492838aaa4d319a362e7d146b2aeb5 100644 (file)
 //Tyrian writes 4300 or 17512
 int displine;
 
-double PITCONST;
+uint64_t PITCONST;
+uint64_t CGACONST;
+uint64_t MDACONST;
+uint64_t VGACONST1, VGACONST2;
+uint64_t RTCCONST;
+
 float cpuclock;
 float isa_timing, bus_timing;
 
@@ -30,23 +35,23 @@ void setpitclock(float clock)
 {
 //        printf("PIT clock %f\n",clock);
         cpuclock=clock;
-        PITCONST=clock/1193182.0;
-        CGACONST=(clock/(19687503.0/11.0));
-        MDACONST=(clock/2032125.0);
-        VGACONST1=(clock/25175000.0);
-        VGACONST2=(clock/28322000.0);
+        PITCONST = (uint64_t)(clock / 1193182.0 * (float)(1ull << 32));
+        CGACONST = (uint64_t)((clock / (19687503.0/11.0)) * (float)(1ull << 32));
+        MDACONST = (uint64_t)((clock / 2032125.0) * (float)(1ull << 32));
+        VGACONST1 = (uint64_t)((clock / 25175000.0) * (float)(1ull << 32));
+        VGACONST2 = (uint64_t)((clock / 28322000.0) * (float)(1ull << 32));
         isa_timing = clock/8000000.0;
         bus_timing = clock/(double)cpu_busspeed;
         video_updatetiming();
 //        pclog("PITCONST=%f CGACONST=%f\n", PITCONST, CGACONST);
 //        pclog("CPUMULTI=%g\n", ((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed));
         
-        xt_cpu_multi = (int)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)cpu_get_speed());
+        xt_cpu_multi = (uint64_t)((14318184.0*(double)(1ull << 32)) / (double)cpu_get_speed());
 //        pclog("egacycles %i egacycles2 %i temp %f clock %f\n",egacycles,egacycles2,temp,clock);
 /*        if (video_recalctimings)
                 video_recalctimings();*/
-        RTCCONST=clock/32768.0;
-        TIMER_USEC = (int)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT));
+        RTCCONST = (uint64_t)((clock / 32768.0) * (float)(1ull << 32));
+        TIMER_USEC = (uint64_t)((clock / 1000000.0) * (float)(1ull << 32));
         device_speed_changed();
 }
 
@@ -55,9 +60,9 @@ void setpitclock(float clock)
 void pit_reset(PIT *pit)
 {
         memset(pit, 0, sizeof(PIT));
-        pit->l[0] = 0xFFFF; pit->c[0] = 0xFFFF*PITCONST;
-        pit->l[1] = 0xFFFF; pit->c[1] = 0xFFFF*PITCONST;
-        pit->l[2] = 0xFFFF; pit->c[2] = 0xFFFF*PITCONST;
+        pit->l[0] = 0xFFFF;
+        pit->l[1] = 0xFFFF;
+        pit->l[2] = 0xFFFF;
         pit->m[0] = pit->m[1] = pit->m[2] = 0;
         pit->ctrls[0] = pit->ctrls[1] = pit->ctrls[2] = 0;
         pit->thit[0]=1;
@@ -66,11 +71,6 @@ void pit_reset(PIT *pit)
         pit->using_timer[0] = pit->using_timer[1] = pit->using_timer[2] = 1;
 }
 
-void clearpit()
-{
-        pit.c[0]=(pit.l[0]<<2);
-}
-
 float pit_timer0_freq()
 {
         if (pit.l[0])
@@ -85,18 +85,52 @@ static void pit_set_out(PIT *pit, int t, int out)
         pit->out[t] = out;
 }
 
+static int pit_read_timer(PIT *pit, int t)
+{
+//        pclog("pit_read_timer: t=%i using_timer=%i m=%i enabled=%i\n", t, pit->using_timer[t], pit->m[t], timer_is_enabled(&pit->timer[t]));
+        if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t]) && timer_is_enabled(&pit->timer[t]))
+        {
+                int read = (int)((timer_get_remaining_u64(&pit->timer[t])) / PITCONST);
+//             pclog(" read %i %08x %016llx\n", t, read, timer_get_remaining_u64(&pit->timer[t]));
+                if (pit->m[t] == 2)
+                        read++;
+                if (read < 0)
+                        read = 0;
+                if (read > 0x10000)
+                        read = 0x10000;
+                if (pit->m[t] == 3)
+                        read <<= 1;
+                return read;
+        }
+        if (pit->m[t] == 2)
+                return pit->count[t] + 1;
+        return pit->count[t];
+}
+
+/*Dump timer count back to pit->count[], and disable timer. This should be used
+  when stopping a PIT timer, to ensure the correct value can be read back.*/
+static void pit_dump_and_disable_timer(PIT *pit, int t)
+{
+       if (pit->using_timer[t] && timer_is_enabled(&pit->timer[t]))
+       {
+               pit->count[t] = pit_read_timer(pit, t);
+               timer_disable(&pit->timer[t]);
+       }
+}
+
 static void pit_load(PIT *pit, int t)
 {
         int l = pit->l[t] ? pit->l[t] : 0x10000;
-        timer_clock();
+
         pit->newcount[t] = 0;
         pit->disabled[t] = 0;
-//        pclog("pit_load: t=%i l=%x\n", t, l);
+//        pclog("pit_load: t=%i l=%x m=%i %016llx\n", t, l, pit->m[t], PITCONST);
         switch (pit->m[t])
         {
                 case 0: /*Interrupt on terminal count*/
                 pit->count[t] = l;
-                pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST);
+               if (pit->using_timer[t])
+                       timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
                 pit_set_out(pit, t, 0);
                 pit->thit[t] = 0;
                 pit->enabled[t] = pit->gate[t];
@@ -108,7 +142,8 @@ static void pit_load(PIT *pit, int t)
                 if (pit->initial[t])
                 {
                         pit->count[t] = l - 1;
-                        pit->c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_set_delay_u64(&pit->timer[t], (uint64_t)((l - 1) * PITCONST));
                         pit_set_out(pit, t, 1);
                         pit->thit[t] = 0;
                 }
@@ -118,12 +153,13 @@ static void pit_load(PIT *pit, int t)
                 if (pit->initial[t])
                 {
                         pit->count[t] = l;
-                        pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST));
                         pit_set_out(pit, t, 1);
                         pit->thit[t] = 0;
                 }
                 pit->enabled[t] = pit->gate[t];
-//                pclog("pit_load: square wave mode c=%x\n", pit->c[t]);
+//                pclog("pit_load: square wave mode c=%x\n", );
                 break;
                 case 4: /*Software triggered stobe*/
                 if (!pit->thit[t] && !pit->initial[t])
@@ -131,7 +167,8 @@ static void pit_load(PIT *pit, int t)
                 else
                 {
                         pit->count[t] = l;
-                        pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
                         pit_set_out(pit, t, 0);
                         pit->thit[t] = 0;
                 }
@@ -143,7 +180,9 @@ static void pit_load(PIT *pit, int t)
         }
         pit->initial[t] = 0;
         pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t];
-        timer_update_outstanding();
+       if (pit->using_timer[t] && !pit->running[t])
+               pit_dump_and_disable_timer(pit, t);
+
 //        pclog("pit_load: t=%i running=%i thit=%i enabled=%i m=%i l=%x c=%g gate=%i\n", t, pit.running[t], pit.thit[t], pit.enabled[t], pit.m[t], pit.l[t], pit.c[t], pit.gate[t]);
 }
 
@@ -161,6 +200,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate)
         {
                 case 0: /*Interrupt on terminal count*/
                 case 4: /*Software triggered stobe*/
+                if (pit->using_timer[t] && !pit->running[t])
+                        timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
                 pit->enabled[t] = gate;
                 break;
                 case 1: /*Hardware retriggerable one-shot*/
@@ -168,7 +209,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate)
                 if (gate && !pit->gate[t])
                 {
                         pit->count[t] = l;
-                        pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
                         pit_set_out(pit, t, 0);
                         pit->thit[t] = 0;
                         pit->enabled[t] = 1;
@@ -178,7 +220,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate)
                 if (gate && !pit->gate[t])
                 {
                         pit->count[t] = l - 1;
-                        pit->c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
                         pit_set_out(pit, t, 1);
                         pit->thit[t] = 0;
                 }                
@@ -188,7 +231,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate)
                 if (gate && !pit->gate[t])
                 {
                         pit->count[t] = l;
-                        pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST));
                         pit_set_out(pit, t, 1);
                         pit->thit[t] = 0;
                 }
@@ -197,23 +241,21 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate)
         }
         pit->gate[t] = gate;
         pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t];
+       if (pit->using_timer[t] && !pit->running[t])
+               pit_dump_and_disable_timer(pit, t);
 //        pclog("pit_set_gate: t=%i gate=%i\n", t, gate);
 }
 
 void pit_set_gate(PIT *pit, int t, int gate)
 {
+//        pclog("pit_set_gate: t=%i gate=%i\n", t, gate);
         if (pit->disabled[t])
         {
                 pit->gate[t] = gate;
                 return;
         }
                 
-        timer_process();
-
         pit_set_gate_no_timer(pit, t, gate);
-        
-        timer_update_outstanding();
-//        pclog("pit_set_gate: t=%i gate=%i\n", t, gate);
 }
 
 static void pit_over(PIT *pit, int t)
@@ -222,11 +264,12 @@ static void pit_over(PIT *pit, int t)
         if (pit->disabled[t])
         {
                 pit->count[t] += 0xffff;
-                pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST);
+               if (pit->using_timer[t])
+                       timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
                 return;
         }
                 
-//        if (!t) pclog("pit_over: t=%i l=%x c=%x %i hit=%i\n", t, pit->l[t], pit.c[t], pit.c[t] >> TIMER_SHIFT, pit.thit[t]);
+//        if (t == 2) pclog("pit_over: t=%i l=%x c=%llx hit=%i %016llx\n", t, pit->l[t], timer_get_remaining_u64(&pit->timer[t]), pit->thit[t], tsc);
         switch (pit->m[t])
         {
                 case 0: /*Interrupt on terminal count*/
@@ -235,11 +278,13 @@ static void pit_over(PIT *pit, int t)
                         pit_set_out(pit, t, 1);
                 pit->thit[t] = 1;
                 pit->count[t] += 0xffff;
-                pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST);
+               if (pit->using_timer[t])
+                       timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
                 break;
                 case 2: /*Rate generator*/
                 pit->count[t] += l;
-                pit->c[t] += (int)((l << TIMER_SHIFT) * PITCONST);
+               if (pit->using_timer[t])
+                       timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
                 pit_set_out(pit, t, 0);
                 pit_set_out(pit, t, 1);
                 break;
@@ -248,13 +293,15 @@ static void pit_over(PIT *pit, int t)
                 {
                         pit_set_out(pit, t, 0);
                         pit->count[t] += (l >> 1);
-                        pit->c[t] += (int)(((l >> 1) << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_advance_u64(&pit->timer[t], (uint64_t)((l >> 1) * PITCONST));
                 }
                 else
                 {
                         pit_set_out(pit, t, 1);
                         pit->count[t] += ((l + 1) >> 1);
-                        pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_advance_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST));
                 }
 //                if (!t) pclog("pit_over: square wave mode c=%x  %lli  %f\n", pit.c[t], tsc, PITCONST);
                 break;
@@ -268,13 +315,15 @@ static void pit_over(PIT *pit, int t)
                 {
                         pit->newcount[t] = 0;
                         pit->count[t] += l;
-                        pit->c[t] += (int)((l << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST));
                 }
                 else
                 {
                         pit->thit[t] = 1;
                         pit->count[t] += 0xffff;
-                        pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST);
+                       if (pit->using_timer[t])
+                               timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
                 }
                 break;
                 case 5: /*Hardware triggered strove*/
@@ -285,54 +334,20 @@ static void pit_over(PIT *pit, int t)
                 }
                 pit->thit[t] = 1;
                 pit->count[t] += 0xffff;
-                pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST);
+               if (pit->using_timer[t])
+                       timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST));
                 break;
         }
         pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t];
-}
-
-int pit_get_timer_0()
-{
-        int read = (int)((pit.c[0] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT;
-//pclog("pit_get_timer_0: t=%i using_timer=%i m=%i\n", 0, pit.using_timer[0], pit.m[0]);
-        if (pit.m[0] == 2)
-                read++;
-        if (read < 0)
-                read = 0;
-        if (read > 0x10000)
-                read = 0x10000;
-        if (pit.m[0] == 3)
-                read <<= 1;
-        return read;
-}
-        
-static int pit_read_timer(PIT *pit, int t)
-{
-        timer_clock();
-//        pclog("pit_read_timer: t=%i using_timer=%i m=%i\n", t, pit.using_timer[t], pit.m[t]);
-        if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t]))
-        {
-                int read = (int)((pit->c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT;
-                if (pit->m[t] == 2)
-                        read++;
-                if (read < 0)
-                        read = 0;
-                if (read > 0x10000)
-                        read = 0x10000;
-                if (pit->m[t] == 3)
-                        read <<= 1;
-                return read;
-        }
-        if (pit->m[t] == 2)
-                return pit->count[t] + 1;
-        return pit->count[t];
+       if (pit->using_timer[t] && !pit->running[t])
+               pit_dump_and_disable_timer(pit, t);
 }
         
 void pit_write(uint16_t addr, uint8_t val, void *p)
 {
         PIT *pit = (PIT *)p;
         int t;
-//        /*if (val != 0x40) */pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins, pit->gate[0]);
+//        /*if (val != 0x40) */pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,cpu_state.pc,ins, pit->gate[0]);
         
         switch (addr&3)
         {
@@ -456,7 +471,7 @@ uint8_t pit_read(uint16_t addr, void *p)
         PIT *pit = (PIT *)p;
         int t;
         uint8_t temp = 0xff;
-//        printf("Read PIT %04X ",addr);
+//        printf("Read PIT %04X\n",addr);
         switch (addr&3)
         {
                 case 0: case 1: case 2: /*Timers*/
@@ -537,11 +552,12 @@ void pit_set_using_timer(PIT *pit, int t, int using_timer)
         timer_process();
         if (pit->using_timer[t] && !using_timer)
                 pit->count[t] = pit_read_timer(pit, t);
-        if (!pit->using_timer[t] && using_timer)
-                pit->c[t] = (int)((pit->count[t] << TIMER_SHIFT) * PITCONST);
+       pit->running[t] = pit->enabled[t] && using_timer && !pit->disabled[t];
+        if (!pit->using_timer[t] && using_timer && pit->running[t])
+                timer_set_delay_u64(&pit->timer[t], (uint64_t)(pit->count[t] * PITCONST));
+       else if (!pit->running[t])
+               timer_disable(&pit->timer[t]);
         pit->using_timer[t] = using_timer;
-        pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t];
-        timer_update_outstanding();
 }
 
 void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out))
@@ -633,9 +649,9 @@ void pit_init()
         pit.pit_nr[2].nr = 2;
         pit.pit_nr[0].pit = pit.pit_nr[1].pit = pit.pit_nr[2].pit = &pit;
 
-        timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)&pit.pit_nr[0]);
-        timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)&pit.pit_nr[1]);
-        timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)&pit.pit_nr[2]);
+        timer_add(&pit.timer[0], pit_timer_over, (void *)&pit.pit_nr[0], 0);
+        timer_add(&pit.timer[1], pit_timer_over, (void *)&pit.pit_nr[1], 0);
+        timer_add(&pit.timer[2], pit_timer_over, (void *)&pit.pit_nr[2], 0);
                 
         pit_set_out_func(&pit, 0, pit_irq0_timer);
         pit_set_out_func(&pit, 1, pit_null_timer);
@@ -656,7 +672,7 @@ void pit_ps2_init()
         pit2.pit_nr[0].nr = 0;
         pit2.pit_nr[0].pit = &pit2;
 
-        timer_add(pit_timer_over, &pit2.c[0], &pit2.running[0], (void *)&pit2.pit_nr[0]);
+        timer_add(&pit2.timer[0], pit_timer_over, (void *)&pit2.pit_nr[0], 0);
 
         pit_set_out_func(&pit, 0, pit_irq0_ps2);
         pit_set_out_func(&pit2, 0, pit_nmi_ps2);
index 2b54da4b7f4c8ba2c099f6d34b3e970946a92f7c..3bcf2029daa511700d3d26c19bcb974773210b9e 100644 (file)
@@ -1,4 +1,4 @@
-extern double PITCONST;
+extern uint64_t PITCONST;
 void pit_init();
 void pit_ps2_init();
 void pit_reset();
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ad027f994412d97efb4aebd5ae3bbf9f2dc8b5ec 100644 (file)
@@ -0,0 +1,21 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+        #include <stdint.h>
+        
+        void keyboard_init();
+        void keyboard_close();
+        void keyboard_poll_host();
+        extern uint8_t pcem_key[272];
+       extern int rawinputkey[272];
+       
+#ifndef __unix
+        #define KEY_LCONTROL 0x1d
+        #define KEY_RCONTROL (0x1d | 0x80)
+        #define KEY_END      (0x4f | 0x80)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
index befdba90f3b7b239c71ebeb0cde657575bf02dc2..ff7d26407b1c0d173f0ea805eb9e83cdd9fccfc2 100644 (file)
@@ -1,2 +1,5 @@
-
-void midi_write(uint8_t);
+void midi_init();
+void midi_close();
+void midi_write(uint8_t val);
+int midi_get_num_devs();
+void midi_get_dev_name(int num, char *s);
index 79224d6cac2a54639ab5d981f662853bd300685a..e9323027df350878036e2eddc2fb2df3bc84155d 100644 (file)
@@ -1 +1,13 @@
-extern int mouse_buttons;
\ No newline at end of file
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+        void mouse_init();
+        void mouse_close();
+        extern int mouse_buttons;
+        void mouse_poll_host();
+        void mouse_get_mickeys(int *x, int *y, int *z);
+       extern int mousecapture;
+#ifdef __cplusplus
+}
+#endif
index 551acf2445463808fd818180b01462708255cd4a..18e8cf8ec3394e61a15f09965322dc12c817d5bb 100644 (file)
@@ -1 +1,21 @@
+#ifndef _ROM_H_
+#define _ROM_H_
+
+FILE *romfopen(char *fn, char *mode);
 int rom_present(char *fn);
+
+typedef struct rom_t
+{
+        uint8_t *rom;
+        uint32_t mask;
+        mem_mapping_t mapping;
+} rom_t;
+
+int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags);
+int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags);
+
+uint8_t rom_read(uint32_t addr, void *p);
+uint16_t rom_readw(uint32_t addr, void *p);
+uint32_t rom_readl(uint32_t addr, void *p);
+
+#endif
index b8b1c2b2980317f16f44ac94a6868d71cac62a53..8d2947bbfb867f1965afb9b85e59ad6f48357783 100644 (file)
@@ -35,7 +35,7 @@ void serial_update_ints(SERIAL *serial)
                 stat = 1;
                 serial->iir = 6;
         }
-        else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/
+        else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Received data available*/
         {
                 stat = 1;
                 serial->iir = 4;
@@ -111,7 +111,8 @@ void serial_write(uint16_t addr, uint8_t val, void *p)
                 serial_update_ints(serial);
                 break;
                 case 2:
-                serial->fcr = val;
+                if (serial->has_fifo)
+                        serial->fcr = val;
                 break;
                 case 3:
                 serial->lcr = val;
@@ -185,7 +186,7 @@ uint8_t serial_read(uint16_t addr, void *p)
                 serial_update_ints(serial);
                 temp = serial_read_fifo(serial);
                 if (serial->fifo_read != serial->fifo_write)
-                        serial->recieve_delay = 1000 * TIMER_USEC;
+                        timer_set_delay_u64(&serial->receive_timer, 1000 * TIMER_USEC);
                 break;
                 case 1:
                 if (serial->lcr & 0x80)
@@ -234,12 +235,10 @@ uint8_t serial_read(uint16_t addr, void *p)
         return temp;
 }
 
-void serial_recieve_callback(void *p)
+void serial_receive_callback(void *p)
 {
         SERIAL *serial = (SERIAL *)p;
         
-        serial->recieve_delay = 0;
-        
         if (serial->fifo_read != serial->fifo_write)
         {
                 serial->lsr |= 1;
@@ -249,14 +248,15 @@ void serial_recieve_callback(void *p)
 }
 
 /*Tandy might need COM1 at 2f8*/
-void serial1_init(uint16_t addr, int irq)
+void serial1_init(uint16_t addr, int irq, int has_fifo)
 {
         memset(&serial1, 0, sizeof(serial1));
         io_sethandler(addr, 0x0008, serial_read,  NULL, NULL, serial_write,  NULL, NULL, &serial1);
         serial1.irq = irq;
         serial1.addr = addr;
         serial1.rcr_callback = NULL;
-        timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1);
+        timer_add(&serial1.receive_timer, serial_receive_callback, &serial1, 0);
+        serial1.has_fifo = has_fifo;
 }
 void serial1_set(uint16_t addr, int irq)
 {
@@ -270,14 +270,15 @@ void serial1_remove()
         io_removehandler(serial1.addr, 0x0008, serial_read,  NULL, NULL, serial_write,  NULL, NULL, &serial1);
 }
 
-void serial2_init(uint16_t addr, int irq)
+void serial2_init(uint16_t addr, int irq, int has_fifo)
 {
         memset(&serial2, 0, sizeof(serial2));
         io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2);
         serial2.irq = irq;
         serial2.addr = addr;
         serial2.rcr_callback = NULL;
-        timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2);
+        timer_add(&serial2.receive_timer, serial_receive_callback, &serial2, 0);
+        serial2.has_fifo = has_fifo;
 }
 void serial2_set(uint16_t addr, int irq)
 {
index b4261231825c38f0fe478a9f2d57cf24caf45bd5..85ae2592c15b341f3dcb6a9c1bb184093f2b2efa 100644 (file)
@@ -1,12 +1,16 @@
-void serial1_init(uint16_t addr, int irq);
-void serial2_init(uint16_t addr, int irq);
+#include "timer.h"
+
+void serial1_init(uint16_t addr, int irq, int has_fifo);
+void serial2_init(uint16_t addr, int irq, int has_fifo);
 void serial1_set(uint16_t addr, int irq);
 void serial2_set(uint16_t addr, int irq);
 void serial1_remove();
 void serial2_remove();
 void serial_reset();
 
-typedef struct SERIAL
+struct SERIAL;
+
+typedef struct
 {
         uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr;
         uint8_t dlab1,dlab2;
@@ -22,8 +26,9 @@ typedef struct SERIAL
         void *rcr_callback_p;
         uint8_t fifo[256];
         int fifo_read, fifo_write;
+        int has_fifo;
         
-        int recieve_delay;
+        pc_timer_t receive_timer;
 } SERIAL;
 
 void serial_write_fifo(SERIAL *serial, uint8_t dat);
index 9823680483c29010da20e82774eb89e058fb11b6..9d532e9adbabca66fd1a9ca7eb2ecb457a410ffc 100644 (file)
@@ -1,6 +1,37 @@
+#include "timer.h"
+
+void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p);
+
+extern int sound_card_current;
+
+int sound_card_available(int card);
+char *sound_card_getname(int card);
+struct device_t *sound_card_getdevice(int card);
+int sound_card_has_config(int card);
+char *sound_card_get_internal_name(int card);
+int sound_card_get_from_internal_name(char *s);
+void sound_card_init();
+void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r);
+
+#define CD_FREQ 44100
+#define CD_BUFLEN (CD_FREQ / 10)
 
-#define MAXSOUNDBUFLEN (8192)
 extern int sound_pos_global;
-void sound_add_handler(void(*get_buffer)(int32_t *buffer, int len, void *p), void *p);
+void sound_speed_changed();
+
+void sound_init();
 void sound_reset();
-void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r);
\ No newline at end of file
+
+void initalmain(int argc, char *argv[]);
+void inital();
+
+void givealbuffer(int32_t *buf);
+void givealbuffer_cd(int16_t *buf);
+
+extern int sound_buf_len;
+void sound_update_buf_length();
+
+extern int sound_gain;
+
+extern int SOUNDBUFLEN;
+#define MAXSOUNDBUFLEN (48000 / 10)
index 39a4f1d20c3e0d6d164d254c6831e7968633a33c..c649a6255de95aa9c9f9f9b947acf76cc4fd0cbd 100644 (file)
@@ -176,7 +176,7 @@ uint8_t cms_read(uint16_t addr, void *p)
 
 void *cms_init()
 {
-        cms_t *cms = (cms_t*)malloc(sizeof(cms_t));
+        cms_t *cms = malloc(sizeof(cms_t));
         memset(cms, 0, sizeof(cms_t));
 
         pclog("cms_init\n");
@@ -191,7 +191,7 @@ void cms_close(void *p)
         
         free(cms);
 }
-#if 0
+
 device_t cms_device =
 {
         "Creative Music System / Game Blaster",
@@ -203,4 +203,3 @@ device_t cms_device =
         NULL,
         NULL
 };
-#endif
\ No newline at end of file
index 165ed84a0e94c760fa2624633ac7d495ca72eaf0..fd9f6c7e24f76bb2c2d50b6a958b2d6843c0b5cb 100644 (file)
@@ -141,11 +141,10 @@ uint8_t opl_read(int nr, uint16_t addr)
         return opl[nr].is_opl3 ? 0 : 0xff;
 }
 
-static Bit32s buffer_32[8192 * 2];
-
 void opl2_update(int nr, int16_t *buffer, int samples)
 {
         int c;
+        Bit32s buffer_32[samples];
         
         opl[nr].chip.GenerateBlock2(samples, buffer_32);
         
@@ -156,6 +155,7 @@ void opl2_update(int nr, int16_t *buffer, int samples)
 void opl3_update(int nr, int16_t *buffer, int samples)
 {
         int c;
+        Bit32s buffer_32[samples*2];
 
        if (opl[nr].opl_emu)
        {
index b86040b19861a80b3aa87e8c7043257f195f255c..80c15bbd35a9d3f407aa36e8bf7ccfbad5668ecf 100644 (file)
@@ -1,6 +1,12 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
         void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3, int opl_emu);
         void opl_write(int nr, uint16_t addr, uint8_t val);
         uint8_t opl_read(int nr, uint16_t addr);
         void opl_timer_over(int nr, int timer);
         void opl2_update(int nr, int16_t *buffer, int samples);
         void opl3_update(int nr, int16_t *buffer, int samples);
+#ifdef __cplusplus
+}
+#endif
index 97b4528ca10d4e5fc45a431279342dc84f8c0fb8..290a1b53d363cc45a450d3729e1630f2ef000325 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef SOUND_EMU8K_H
+#define SOUND_EMU8K_H
 
 /* All these defines are in samples, not in bytes. */
 #define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF
@@ -773,3 +775,5 @@ Treble Parameters:
 0xD308  0xD308  0xD308  0xD308  0xD308  0xD308  0xD3019 0xD32A  0xD34C  0xD36E  0xD36E  0xD36E
 0x0001  0x0001  0x0001  0x0001  0x0001  0x0002  0x0002  0x0002  0x0002  0x0002  0x0002  0x0002
 */
+
+#endif /* SOUND_EMU8K_H */
index 5d70b542761e10d6450b6936c9c71e6c252a5a0f..99a7f8a9370ea14ba5e0abd734ecd865a075a290 100644 (file)
@@ -1,5 +1,6 @@
 #include "ibm.h"
 #include "io.h"
+#include "pic.h"
 #include "plat-midi.h"
 #include "sound_mpu401_uart.h"
 
@@ -9,6 +10,14 @@ enum
         STATUS_INPUT_NOT_READY  = 0x80
 };
 
+static void mpu401_uart_raise_irq(void *p)
+{
+        mpu401_uart_t *mpu = (mpu401_uart_t *)p;
+
+        if (mpu->irq != -1)
+                picint(1 << mpu->irq);
+}
+
 static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p)
 {
         mpu401_uart_t *mpu = (mpu401_uart_t *)p;
@@ -18,15 +27,30 @@ static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p)
                 switch (val)
                 {
                         case 0xff: /*Reset*/
+                        // From Roland: "An ACK will not be sent back upon sending a SYSTEM RESET to leave the UART MODE ($3F)."
+                        // But actual behaviour is weird. For example, the MPU401 port test in the AZT1605 drivers for Windows NT
+                        // want this to return an Ack but the IRQ test in the same driver wants this to raise no interrupts!
                         mpu->rx_data = 0xfe; /*Acknowledge*/
-                        mpu->status = 0;
                         mpu->uart_mode = 0;
+                        if (mpu->is_aztech)
+                                mpu->status = STATUS_OUTPUT_NOT_READY;
+                        else
+                        {
+                                mpu->status = 0;
+                                mpu401_uart_raise_irq(p);
+                        }
                         break;
                         
                         case 0x3f: /*Enter UART mode*/
                         mpu->rx_data = 0xfe; /*Acknowledge*/
-                        mpu->status = 0;
                         mpu->uart_mode = 1;
+                        if (mpu->is_aztech)
+                        {
+                                mpu->status = STATUS_OUTPUT_NOT_READY;
+                                mpu401_uart_raise_irq(p);
+                        }
+                        else
+                                mpu->status = 0;
                         break;
                 }
                 return;
@@ -45,14 +69,31 @@ static uint8_t mpu401_uart_read(uint16_t addr, void *p)
                 return mpu->status;
         
         /*Data*/
-        mpu->status |= STATUS_INPUT_NOT_READY;
+        mpu->status = STATUS_INPUT_NOT_READY;
         return mpu->rx_data;
 }
 
-void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr)
+void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq, int is_aztech)
 {
         mpu->status = STATUS_INPUT_NOT_READY;
         mpu->uart_mode = 0;
+        mpu->addr = addr;
+        mpu->irq = irq;
+        mpu->is_aztech = is_aztech;
         
         io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu);
 }
+
+void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr)
+{
+        io_removehandler(mpu->addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu);
+        mpu->addr = addr;
+        if (addr != 0)
+                io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu);
+}
+
+void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq)
+{
+        mpu->irq = irq;
+}
+
index 893c53fc40226ce65a45a03ed364b9190a2fb757..dd00612f2e37190613fc57e86893e07014c13819 100644 (file)
@@ -1,9 +1,20 @@
+#ifndef SOUND_MPU401_UART
+#define SOUND_MPU401_UART
+
 typedef struct mpu401_uart_t
 {
         uint8_t status;
         uint8_t rx_data;
 
-        int uart_mode;        
+        int uart_mode;
+        uint16_t addr;
+        int irq;
+        
+        int is_aztech;
 } mpu401_uart_t;
 
-void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr);
+void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq, int is_aztech);
+void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr);
+void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq);
+
+#endif /* SOUND_MPU401_UART */
index 9d4d48d5ed95a202967726d88e7d053074df3184..44c1af7d03d55ac59c118fc51e1904763d475961 100644 (file)
@@ -5,7 +5,7 @@
 #include "sound.h"
 #include "sound_opl.h"
 #include "sound_dbopl.h"
-#include "timer.h"
+#include "x86.h"
 
 /*Interfaces between PCem and the actual OPL emulator*/
 
@@ -107,54 +107,45 @@ void ym3812_timer_set_0(void *param, int timer, int64_t period)
 {
         opl_t *opl = (opl_t *)param;
         
-        opl->timers[0][timer] = period * TIMER_USEC * 20;
-        if (!opl->timers[0][timer]) opl->timers[0][timer] = 1;
-        opl->timers_enable[0][timer] = period ? 1 : 0;
+       if (period)
+               timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20);
+       else
+               timer_disable(&opl->timers[0][timer]);
 }
 void ym3812_timer_set_1(void *param, int timer, int64_t period)
 {
         opl_t *opl = (opl_t *)param;
 
-        opl->timers[1][timer] = period * TIMER_USEC * 20;
-        if (!opl->timers[1][timer]) opl->timers[1][timer] = 1;
-        opl->timers_enable[1][timer] = period ? 1 : 0;
+       if (period)
+               timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20);
+       else
+               timer_disable(&opl->timers[1][timer]);
 }
 
 void ymf262_timer_set(void *param, int timer, int64_t period)
 {
         opl_t *opl = (opl_t *)param;
 
-        opl->timers[0][timer] = period * TIMER_USEC * 20;
-        if (!opl->timers[0][timer]) opl->timers[0][timer] = 1;
-        opl->timers_enable[0][timer] = period ? 1 : 0;
+       if (period)
+               timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20);
+       else
+               timer_disable(&opl->timers[0][timer]);
 }
 
 static void opl_timer_callback00(void *p)
 {
-        opl_t *opl = (opl_t *)p;
-        
-        opl->timers_enable[0][0] = 0;
         opl_timer_over(0, 0);
 }
 static void opl_timer_callback01(void *p)
 {
-        opl_t *opl = (opl_t *)p;
-        
-        opl->timers_enable[0][1] = 0;
         opl_timer_over(0, 1);
 }
 static void opl_timer_callback10(void *p)
 {
-        opl_t *opl = (opl_t *)p;
-        
-        opl->timers_enable[1][0] = 0;
         opl_timer_over(1, 0);
 }
 static void opl_timer_callback11(void *p)
 {
-        opl_t *opl = (opl_t *)p;
-        
-        opl->timers_enable[1][1] = 0;
         opl_timer_over(1, 1);
 }
         
@@ -162,16 +153,16 @@ void opl2_init(opl_t *opl)
 {
         opl_init(ym3812_timer_set_0, opl, 0, 0, 0);
         opl_init(ym3812_timer_set_1, opl, 1, 0, 0);
-        timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl);
-        timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl);
-        timer_add(opl_timer_callback10, &opl->timers[1][0], &opl->timers_enable[1][0], (void *)opl);
-        timer_add(opl_timer_callback11, &opl->timers[1][1], &opl->timers_enable[1][1], (void *)opl);
+        timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0);
+        timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0);
+        timer_add(&opl->timers[1][0], opl_timer_callback10, (void *)opl, 0);
+        timer_add(&opl->timers[1][1], opl_timer_callback11, (void *)opl, 0);
 }
 
 void opl3_init(opl_t *opl, int opl_emu)
 {
         opl_init(ymf262_timer_set, opl, 0, 1, opl_emu);
-        timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl);
-        timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl);
+        timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0);
+        timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0);
 }
 
index d2aa3654ed8f19f444396830330b205f4bdcc01a..7ce62278c8bab75d25c844bc0a3621b01c267b36 100644 (file)
@@ -4,8 +4,7 @@ typedef struct opl_t
 {
         int chip_nr[2];
         
-        int timers[2][2];
-        int timers_enable[2][2];
+        pc_timer_t timers[2][2];
 
         int16_t filtbuf[2];
 
index 2da4d22d9150c38b7ea40c82adcadd5dc3d89d36..2c308c5e3f86f349095bcc29262a902425141a7e 100644 (file)
@@ -21,102 +21,6 @@ FILE* soundfsb = 0/*NULL*/;
 FILE* soundfsbin = 0/*NULL*/;
 #endif
 
-
-
-/* SB 2.0 CD version */
-typedef struct sb_ct1335_mixer_t
-{
-        int32_t master;
-        int32_t voice;
-        int32_t fm;
-        int32_t cd;
-
-        uint8_t index;
-        uint8_t regs[256];
-} sb_ct1335_mixer_t;
-/* SB PRO */
-typedef struct sb_ct1345_mixer_t
-{
-        int32_t master_l, master_r;
-        int32_t voice_l,  voice_r;
-        int32_t fm_l,     fm_r;
-        int32_t cd_l,     cd_r;
-        int32_t line_l,   line_r;
-        int32_t mic;
-        /*see sb_ct1745_mixer for values for input selector*/
-        int32_t input_selector;
-        
-        int input_filter;
-        int in_filter_freq;
-        int output_filter;
-        
-        int stereo;
-        int stereo_isleft;
-        
-        uint8_t index;
-        uint8_t regs[256];
-    
-} sb_ct1345_mixer_t;
-/* SB16 and AWE32 */
-typedef struct sb_ct1745_mixer_t
-{
-        int32_t master_l, master_r;
-        int32_t voice_l,  voice_r;
-        int32_t fm_l,     fm_r;
-        int32_t cd_l,     cd_r;
-        int32_t line_l,   line_r;
-        int32_t mic;
-        int32_t speaker;
-
-        int bass_l,   bass_r;
-        int treble_l, treble_r;
-        
-        int output_selector;
-        #define OUTPUT_MIC 1
-        #define OUTPUT_CD_R 2
-        #define OUTPUT_CD_L 4
-        #define OUTPUT_LINE_R 8
-        #define OUTPUT_LINE_L 16
-
-        int input_selector_left;
-        int input_selector_right;
-        #define INPUT_MIC 1
-        #define INPUT_CD_R 2
-        #define INPUT_CD_L 4
-        #define INPUT_LINE_R 8
-        #define INPUT_LINE_L 16
-        #define INPUT_MIDI_R 32
-        #define INPUT_MIDI_L 64
-
-        int mic_agc;
-        
-        int32_t input_gain_L;
-        int32_t input_gain_R;
-        int32_t output_gain_L;
-        int32_t output_gain_R;
-        
-        uint8_t index;
-        uint8_t regs[256];
-} sb_ct1745_mixer_t;
-
-typedef struct sb_t
-{
-        opl_t           opl;
-        sb_dsp_t        dsp;
-        union {
-                sb_ct1335_mixer_t mixer_sb2;
-                sb_ct1345_mixer_t mixer_sbpro;
-                sb_ct1745_mixer_t mixer_sb16;
-        };
-        mpu401_uart_t   mpu;
-        emu8k_t         emu8k;
-
-        int pos;
-        
-        uint8_t pos_regs[8];
-        
-        int opl_emu;
-} sb_t;
 /* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps.
   Note that for positive dB values, this is not amplitude, it is amplitude-1. */
 const float sb_bass_treble_4bits[]= {
@@ -195,7 +99,7 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p)
         sb->dsp.pos = 0;
 }
 
-static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p)
+void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p)
 {
         sb_t *sb = (sb_t *)p;
         sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro;
@@ -521,7 +425,7 @@ void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p)
                         {
                                 /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */
                                 case 0x02: case 0x06:
-                                mixer->regs[mixer->index+0x20]=((val&0xE) << 4)||(val&0xE) << 4;
+                                mixer->regs[mixer->index+0x20]=((val&0xE) << 4) | (val&0xE);
                                 break;
                                 
                                 case 0x22: case 0x26:
@@ -945,12 +849,12 @@ void *sb_1_init()
           2x0 to 2x3 -> CMS chip
           2x6, 2xA, 2xC, 2xE -> DSP chip
           2x8, 2x9, 388 and 389 FM chip*/
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         uint16_t addr = device_get_config_int("addr");        
         memset(sb, 0, sizeof(sb_t));
         
         opl2_init(&sb->opl);
-        sb_dsp_init(&sb->dsp, SB1);
+        sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, addr);
         sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
         sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@@ -967,12 +871,12 @@ void *sb_15_init()
           2x0 to 2x3 -> CMS chip
           2x6, 2xA, 2xC, 2xE -> DSP chip
           2x8, 2x9, 388 and 389 FM chip*/
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         uint16_t addr = device_get_config_int("addr");
         memset(sb, 0, sizeof(sb_t));
 
         opl2_init(&sb->opl);
-        sb_dsp_init(&sb->dsp, SB15);
+        sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, addr);
         sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
         sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@@ -984,29 +888,26 @@ void *sb_15_init()
         return sb;
 }
 
-#if 0
 void *sb_mcv_init()
 {
         /*sb1/2 port mappings, 210h to 260h in 10h steps
           2x6, 2xA, 2xC, 2xE -> DSP chip
           2x8, 2x9, 388 and 389 FM chip*/
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         memset(sb, 0, sizeof(sb_t));
 
         opl2_init(&sb->opl);
-        sb_dsp_init(&sb->dsp, SB15);
+        sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, 0);//addr);
         sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
         sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
         sound_add_handler(sb_get_buffer_sb2, sb);
         /* I/O handlers activated in sb_mcv_write */
-        mca_add(sb_mcv_read, sb_mcv_write, sb);
+        mca_add(sb_mcv_read, sb_mcv_write, NULL, sb);
         sb->pos_regs[0] = 0x84;
         sb->pos_regs[1] = 0x50;
         return sb;
 }
-#endif
-
 void *sb_2_init()
 {
         /*sb2 port mappings. 220h or 240h.
@@ -1022,12 +923,12 @@ void *sb_2_init()
           test this. It shouldn't exist on SB 1.0 as the CMS chips are always
           present there.
           Syndicate requires this mirror for music to play.*/
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         uint16_t addr = device_get_config_int("addr");
         memset(sb, 0, sizeof(sb_t));
 
         opl2_init(&sb->opl);
-        sb_dsp_init(&sb->dsp, SB2);
+        sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, addr);
         sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
         sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@@ -1059,12 +960,12 @@ void *sb_pro_v1_init()
           2x6, 2xA, 2xC, 2xE -> DSP chip
           2x8, 2x9, 388 and 389 FM chip (9 voices)
           2x0+10 to 2x0+13 CDROM interface.*/
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         uint16_t addr = device_get_config_int("addr");
         memset(sb, 0, sizeof(sb_t));
 
         opl2_init(&sb->opl);
-        sb_dsp_init(&sb->dsp, SBPRO);
+        sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, addr);
         sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
         sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@@ -1088,13 +989,13 @@ void *sb_pro_v2_init()
           2x6, 2xA, 2xC, 2xE -> DSP chip
           2x8, 2x9, 388 and 389 FM chip (9 voices)
           2x0+10 to 2x0+13 CDROM interface.*/
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         memset(sb, 0, sizeof(sb_t));
 
         uint16_t addr = device_get_config_int("addr");
         sb->opl_emu = device_get_config_int("opl_emu");
         opl3_init(&sb->opl, sb->opl_emu);
-        sb_dsp_init(&sb->dsp, SBPRO2);
+        sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, addr);
         sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
         sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@@ -1109,7 +1010,6 @@ void *sb_pro_v2_init()
         return sb;
 }
 
-#if 0
 void *sb_pro_mcv_init()
 {
         /*sbpro port mappings. 220h or 240h.
@@ -1117,34 +1017,33 @@ void *sb_pro_mcv_init()
           2x4 to 2x5 -> Mixer interface
           2x6, 2xA, 2xC, 2xE -> DSP chip
           2x8, 2x9, 388 and 389 FM chip (9 voices)*/
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         memset(sb, 0, sizeof(sb_t));
 
         sb->opl_emu = device_get_config_int("opl_emu");
         opl3_init(&sb->opl, sb->opl_emu);
-        sb_dsp_init(&sb->dsp, SBPRO2);
+        sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb);
         sb_ct1345_mixer_reset(sb);
         /* I/O handlers activated in sb_mcv_write */
         sound_add_handler(sb_get_buffer_sbpro, sb);
 
         /* I/O handlers activated in sb_pro_mcv_write */
-        mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb);
+        mca_add(sb_pro_mcv_read, sb_pro_mcv_write, NULL, sb);
         sb->pos_regs[0] = 0x03;
         sb->pos_regs[1] = 0x51;
 
         return sb;
 }
-#endif
 
 void *sb_16_init()
 {
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         memset(sb, 0, sizeof(sb_t));
 
         uint16_t addr = device_get_config_int("addr");
         sb->opl_emu = device_get_config_int("opl_emu");
         opl3_init(&sb->opl, sb->opl_emu);
-        sb_dsp_init(&sb->dsp, SB16);
+        sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, addr);
         // TODO: irq and dma options too? 
         sb_ct1745_mixer_reset(sb);
@@ -1153,13 +1052,12 @@ void *sb_16_init()
         io_sethandler(0x0388, 0x0004, opl3_read,   NULL, NULL, opl3_write,   NULL, NULL, &sb->opl);
         io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb);
         sound_add_handler(sb_get_buffer_sb16, sb);
-        mpu401_uart_init(&sb->mpu, 0x330);
+        mpu401_uart_init(&sb->mpu, 0x330, -1, 0);
 
 
         return sb;
 }
 
-#if 0
 int sb_awe32_available()
 {
         return rom_present("awe32.raw");
@@ -1167,7 +1065,7 @@ int sb_awe32_available()
 
 void *sb_awe32_init()
 {
-        sb_t *sb = (sb_t*)malloc(sizeof(sb_t));
+        sb_t *sb = malloc(sizeof(sb_t));
         int onboard_ram = device_get_config_int("onboard_ram");
         memset(sb, 0, sizeof(sb_t));
 
@@ -1175,7 +1073,7 @@ void *sb_awe32_init()
         uint16_t emu_addr = device_get_config_int("emu_addr");
         sb->opl_emu = device_get_config_int("opl_emu");
         opl3_init(&sb->opl, sb->opl_emu);
-        sb_dsp_init(&sb->dsp, SB16 + 1);
+        sb_dsp_init(&sb->dsp, SB16 + 1, SB_SUBTYPE_DEFAULT, sb);
         sb_dsp_setaddr(&sb->dsp, addr);
         // TODO: irq and dma options too?
         sb_ct1745_mixer_reset(sb);
@@ -1184,12 +1082,11 @@ void *sb_awe32_init()
         io_sethandler(0x0388, 0x0004, opl3_read,   NULL, NULL, opl3_write,   NULL, NULL, &sb->opl);
         io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb);
         sound_add_handler(sb_get_buffer_emu8k, sb);
-        mpu401_uart_init(&sb->mpu, 0x330);
+        mpu401_uart_init(&sb->mpu, 0x330, -1, 0);
         emu8k_init(&sb->emu8k, emu_addr, onboard_ram);
 
         return sb;
 }
-#endif
 
 void sb_close(void *p)
 {
@@ -1211,7 +1108,6 @@ void sb_close(void *p)
         free(sb);
 }
 
-#if 0
 void sb_awe32_close(void *p)
 {
         sb_t *sb = (sb_t *)p;
@@ -1220,7 +1116,6 @@ void sb_awe32_close(void *p)
 
         sb_close(sb);
 }
-#endif
 
 void sb_speed_changed(void *p)
 {
@@ -1236,7 +1131,6 @@ void sb_add_status_info(char *s, int max_len, void *p)
         sb_dsp_add_status_info(s, max_len, &sb->dsp);
 }
 
-#if 0
 static device_config_t sb_config[] =
 {
         {
@@ -1952,4 +1846,3 @@ device_t sb_awe32_device =
         sb_add_status_info,
         sb_awe32_config
 };
-#endif
index 4a0b974b8ad5e8f9fee698da5bb44a069008fccf..0f0902e5011b1f506948f26249000353ce161201 100644 (file)
@@ -1,3 +1,10 @@
+#ifndef SOUND_SB_H
+#define SOUND_SB_H
+
+#include "sound_emu8k.h"
+#include "sound_mpu401_uart.h"
+#include "sound_sb_dsp.h"
+
 extern device_t sb_1_device;
 extern device_t sb_15_device;
 extern device_t sb_mcv_device;
@@ -7,3 +14,110 @@ extern device_t sb_pro_v2_device;
 extern device_t sb_pro_mcv_device;
 extern device_t sb_16_device;
 extern device_t sb_awe32_device;
+
+/* SB 2.0 CD version */
+typedef struct sb_ct1335_mixer_t
+{
+        int32_t master;
+        int32_t voice;
+        int32_t fm;
+        int32_t cd;
+
+        uint8_t index;
+        uint8_t regs[256];
+} sb_ct1335_mixer_t;
+/* SB PRO */
+typedef struct sb_ct1345_mixer_t
+{
+        int32_t master_l, master_r;
+        int32_t voice_l,  voice_r;
+        int32_t fm_l,     fm_r;
+        int32_t cd_l,     cd_r;
+        int32_t line_l,   line_r;
+        int32_t mic;
+        /*see sb_ct1745_mixer for values for input selector*/
+        int32_t input_selector;
+        
+        int input_filter;
+        int in_filter_freq;
+        int output_filter;
+        
+        int stereo;
+        int stereo_isleft;
+        
+        uint8_t index;
+        uint8_t regs[256];
+    
+} sb_ct1345_mixer_t;
+/* SB16 and AWE32 */
+typedef struct sb_ct1745_mixer_t
+{
+        int32_t master_l, master_r;
+        int32_t voice_l,  voice_r;
+        int32_t fm_l,     fm_r;
+        int32_t cd_l,     cd_r;
+        int32_t line_l,   line_r;
+        int32_t mic;
+        int32_t speaker;
+
+        int bass_l,   bass_r;
+        int treble_l, treble_r;
+        
+        int output_selector;
+        #define OUTPUT_MIC 1
+        #define OUTPUT_CD_R 2
+        #define OUTPUT_CD_L 4
+        #define OUTPUT_LINE_R 8
+        #define OUTPUT_LINE_L 16
+
+        int input_selector_left;
+        int input_selector_right;
+        #define INPUT_MIC 1
+        #define INPUT_CD_R 2
+        #define INPUT_CD_L 4
+        #define INPUT_LINE_R 8
+        #define INPUT_LINE_L 16
+        #define INPUT_MIDI_R 32
+        #define INPUT_MIDI_L 64
+
+        int mic_agc;
+        
+        int32_t input_gain_L;
+        int32_t input_gain_R;
+        int32_t output_gain_L;
+        int32_t output_gain_R;
+        
+        uint8_t index;
+        uint8_t regs[256];
+} sb_ct1745_mixer_t;
+
+typedef struct sb_t
+{
+        opl_t           opl;
+        sb_dsp_t        dsp;
+        union {
+                sb_ct1335_mixer_t mixer_sb2;
+                sb_ct1345_mixer_t mixer_sbpro;
+                sb_ct1745_mixer_t mixer_sb16;
+        };
+        mpu401_uart_t   mpu;
+        emu8k_t         emu8k;
+
+        int pos;
+        
+        uint8_t pos_regs[8];
+        
+        int opl_emu;
+} sb_t;
+
+// exported for clone cards
+void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p);
+void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p);
+uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p);
+void sb_ct1345_mixer_reset(sb_t* sb);
+
+void sb_close(void *p);
+void sb_speed_changed(void *p);
+void sb_add_status_info(char *s, int max_len, void *p);
+
+#endif /* SOUND_SB_H */
index edcad06f670799bf03fb074dcf4e803dcf032f7e..ce88db9134d8d0bc0eb62b46c43c3dfecbb8faaa 100644 (file)
 #include "ibm.h"
 
 
+#include "device.h"
 #include "dma.h"
 #include "filters.h"
 #include "io.h"
 #include "pic.h"
 #include "sound.h"
+#include "sound_azt2316a.h"
 #include "sound_sb_dsp.h"
 #include "timer.h"
+#include "x86.h"
 
 /*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/
 #define SB_DSP_REC_SAFEFTY_MARGIN 4096
@@ -112,8 +115,6 @@ uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x
 
 float low_fir_sb16_coef[SB16_NCoef];
 
-#define M_PI 3.1415927
-
 static inline double sinc(double x)
 {
        return sin(M_PI * x) / (M_PI * x);
@@ -166,7 +167,9 @@ void sb_irqc(sb_dsp_t *dsp, int irq8)
 
 void sb_dsp_reset(sb_dsp_t *dsp)
 {
-        dsp->sbenable = dsp->sb_enable_i = 0;
+       timer_disable(&dsp->output_timer);
+       timer_disable(&dsp->input_timer);
+
         dsp->sb_command = 0;
         
         dsp->sb_8_length = 0xffff;
@@ -183,7 +186,6 @@ void sb_dsp_reset(sb_dsp_t *dsp)
         dsp->sbe2count = 0;
 
         dsp->sbreset = 0;
-        dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0;
 
         dsp->record_pos_read=0;
         dsp->record_pos_write=SB_DSP_REC_SAFEFTY_MARGIN;
@@ -206,10 +208,18 @@ void sb_doreset(sb_dsp_t *dsp)
         int c;
         
         sb_dsp_reset(dsp);
-        
-        if (dsp->sb_type==SB16) sb_commands[8] =  1;
-        else                    sb_commands[8] = -1;
-        
+
+        if (IS_AZTECH(dsp))
+        {
+                sb_commands[8] =  1;
+                sb_commands[9] =  1;
+        }
+        else
+        {
+                if (dsp->sb_type==SB16) sb_commands[8] =  1;
+                else                    sb_commands[8] = -1;
+        }
+
         for (c = 0; c < 256; c++)
             dsp->sb_asp_regs[c] = 0;
         dsp->sb_asp_regs[5] = 0x01;
@@ -221,12 +231,12 @@ void sb_dsp_speed_changed(sb_dsp_t *dsp)
         if (dsp->sb_timeo < 256)
                 dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo);
         else
-                dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256)));
+                dsp->sblatcho = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256)));
 
         if (dsp->sb_timei < 256)
                 dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei);
         else
-                dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256)));
+                dsp->sblatchi = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256)));
 }
 
 void sb_add_data(sb_dsp_t *dsp, uint8_t v)
@@ -251,9 +261,8 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len
                 dsp->sb_8_enable = 1;
                 if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0;
                 dsp->sb_8_output = 1;
-                timer_process();
-                dsp->sbenable = dsp->sb_8_enable;
-                timer_update_outstanding();
+               if (!timer_is_enabled(&dsp->output_timer))
+                       timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho);
                 dsp->sbleftright = 0;
                 dsp->sbdacpos = 0;
 //                pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
@@ -267,9 +276,8 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len
                 dsp->sb_16_enable = 1;
                 if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0;
                 dsp->sb_16_output = 1;
-                timer_process();
-                dsp->sbenable = dsp->sb_16_enable;
-                timer_update_outstanding();
+               if (!timer_is_enabled(&dsp->output_timer))
+                       timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho);
 //                pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len);
         }
 }
@@ -292,9 +300,8 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l
                 dsp->sb_8_enable = 1;
                 if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0;                
                 dsp->sb_8_output = 0;
-                timer_process();
-                dsp->sb_enable_i = dsp->sb_8_enable;
-                timer_update_outstanding();
+               if (!timer_is_enabled(&dsp->input_timer))
+                       timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi);
 //                pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
         }
         else
@@ -313,9 +320,8 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l
                 dsp->sb_16_enable = 1;
                 if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0;
                 dsp->sb_16_output = 0;
-                timer_process();
-                dsp->sb_enable_i = dsp->sb_16_enable;
-                timer_update_outstanding();
+               if (!timer_is_enabled(&dsp->input_timer))
+                       timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi);
 //                pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
         }
         memset(dsp->record_buffer,0,sizeof(dsp->record_buffer));
@@ -415,15 +421,13 @@ void sb_exec_command(sb_dsp_t *dsp)
                 sb_add_data(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80);
                 /*Due to the current implementation, I need to emulate a samplerate, even if this
                  * mode does not imply such samplerate. Position is increased in sb_poll_i*/
-                if (dsp->sb_enable_i==0)
+                if (!timer_is_enabled(&dsp->input_timer))
                 {
                         dsp->sb_timei = 256 - 22;
                         dsp->sblatchi = TIMER_USEC * 22;
                         temp = 1000000 / 22;
                         dsp->sb_freq = temp;
-                        timer_process();
-                        dsp->sb_enable_i = 1;
-                        timer_update_outstanding();
+                       timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi);
                 }
                 break;
                 case 0x24: /*8-bit single cycle DMA input*/
@@ -446,7 +450,7 @@ void sb_exec_command(sb_dsp_t *dsp)
                 case 0x41: /*Set output sampling rate*/
                 case 0x42: /*Set input sampling rate*/
                 if (dsp->sb_type < SB16) break;
-                dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8))));
+                dsp->sblatcho = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8))));
 //                pclog("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho);
                 temp = dsp->sb_freq;
                 dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8);
@@ -496,9 +500,8 @@ void sb_exec_command(sb_dsp_t *dsp)
                 case 0x80: /*Pause DAC*/
                 dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8);
 //                pclog("SB pause %04X\n",sb_pausetime);
-                timer_process();
-                dsp->sbenable = 1;
-                timer_update_outstanding();
+               if (!timer_is_enabled(&dsp->output_timer))
+                       timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho);
                 break;
                 case 0x90: /*High speed 8-bit autoinit DMA output*/
                 if (dsp->sb_type < SB2) break;
@@ -587,6 +590,20 @@ void sb_exec_command(sb_dsp_t *dsp)
                 sb_add_data(dsp, ~dsp->sb_data[0]);
                 break;
                 case 0xE1: /*Get DSP version*/
+                if (IS_AZTECH(dsp))
+                {
+                        if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11)
+                        {
+                                sb_add_data(dsp, 0x3);
+                                sb_add_data(dsp, 0x1);
+                        }
+                        else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C)
+                        {
+                                sb_add_data(dsp, 0x2);
+                                sb_add_data(dsp, 0x1);
+                        }
+                        break;
+                }
                 sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8);
                 sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff);
                 break;
@@ -625,6 +642,32 @@ void sb_exec_command(sb_dsp_t *dsp)
                 case 0xFF:
                 break;
                 case 0x08: /*ASP get version*/
+                if (IS_AZTECH(dsp))
+                {
+                        if ((dsp->sb_data[0] == 0x55 || dsp->sb_data[0] == 0x05) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11)
+                                sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */
+                        else if ((dsp->sb_data[0] == 0x55 || dsp->sb_data[0] == 0x05) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C)
+                                sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */
+                        else if (dsp->sb_data[0] == 0x08)
+                        {
+                                // EEPROM address to write followed by byte
+                                if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE)
+                                        fatal("AZT EEPROM: out of bounds write to %02X\n", dsp->sb_data[1]);
+                                dsp->azt_eeprom[dsp->sb_data[1]] = dsp->sb_data[2];
+                                break;
+                        }
+                        else if (dsp->sb_data[0] == 0x07)
+                        {
+                                // EEPROM address to read
+                                if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE)
+                                        fatal("AZT EEPROM: out of bounds read to %02X\n", dsp->sb_data[1]);
+                                sb_add_data(dsp, dsp->azt_eeprom[dsp->sb_data[1]]);
+                                break;
+                        }
+                        else
+                                pclog("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); // 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen
+                        break;
+                }
                 if (dsp->sb_type < SB16) break;
                 sb_add_data(dsp, 0x18);
                 break;
@@ -652,10 +695,29 @@ void sb_exec_command(sb_dsp_t *dsp)
                 case 0x04:
                 case 0x05:
                 break;
+                case 0x09: /*AZTECH mode set*/
+                if (IS_AZTECH(dsp))
+                {
+                        if (dsp->sb_data[0] == 0x00)
+                        {
+                                pclog("AZT2316A: WSS MODE!\n");
+                                azt2316a_enable_wss(1, dsp->parent);
+                        }
+                        else if (dsp->sb_data[0] == 0x01)
+                        {
+                                pclog("AZT2316A: SB8PROV2 MODE!\n");
+                                azt2316a_enable_wss(0, dsp->parent);
+                        }
+                        else
+                                pclog("AZT2316A: UNKNOWN MODE!\n"); // sequences 0x02->0xFF, 0x04->0xFF seen
+                }
+                break;
+                case 0x38: /*TODO: AZTECH MIDI-related? */
+                break;
 //                default:
-//                fatal("Exec bad SB command %02X\n",sb_command);
-                
-                
+//                fatal("Exec bad SB command %02X\n",dsp->sb_command);
+
+
                 /*TODO: Some more data about the DSP registeres
                  * http://the.earth.li/~tfm/oldpage/sb_dsp.html
                  * http://www.synchrondata.com/pheaven/www/area19.htm
@@ -688,10 +750,7 @@ void sb_write(uint16_t a, uint8_t v, void *priv)
                 dsp->sbreset = v;
                 return;
                 case 0xC: /*Command/data write*/
-                timer_process();
-                dsp->wb_time = TIMER_USEC * 1;
-                dsp->wb_full = 1;
-                timer_update_outstanding();
+                timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1);
                 if (dsp->asp_data_len)
                 {
 //                        pclog("ASP data %i\n", dsp->asp_data_len);
@@ -710,11 +769,27 @@ void sb_write(uint16_t a, uint8_t v, void *priv)
                         dsp->sb_data_stat++;
                 }
                 else
-                   dsp->sb_data[dsp->sb_data_stat++] = v;
+                {
+                        dsp->sb_data[dsp->sb_data_stat++] = v;
+                        if (IS_AZTECH(dsp))
+                        {
+                                // variable length commands
+                                if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08)
+                                        sb_commands[dsp->sb_command] = 3;
+                                else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07)
+                                        sb_commands[dsp->sb_command] = 2;
+                        }
+                }
                 if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1)
                 {
                         sb_exec_command(dsp);
                         dsp->sb_data_stat = -1;
+                        if (IS_AZTECH(dsp))
+                        {
+                                // variable length commands
+                                if (dsp->sb_command == 0x08)
+                                        sb_commands[dsp->sb_command] = 1;
+                        }
                 }
                 break;
         }
@@ -742,14 +817,32 @@ uint8_t sb_read(uint16_t a, void *priv)
                         dsp->busy_count = 0;
                 if (dsp->wb_full || (dsp->busy_count & 2))
                 {
-                        dsp->wb_full = dsp->wb_time;
-                        return 0xff;
+                        dsp->wb_full = timer_is_enabled(&dsp->wb_timer);
+//                        pclog("SB read 0x80\n");
+                        if (IS_AZTECH(dsp))
+                                return 0x80;
+                        else
+                                return 0xFF;
                 }
-                return 0x7f;
+//                pclog("SB read 0x00\n");
+                if (IS_AZTECH(dsp))
+                        return 0x00;
+                else
+                        return 0x7F;
                 case 0xE: /*Read data ready*/
                 picintc(1 << dsp->sb_irqnum);
                 dsp->sb_irq8 = dsp->sb_irq16 = 0;
-                return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff;
+                // Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working.
+                if (IS_AZTECH(dsp))
+                {
+//                        pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80);
+                        return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80;
+                }
+                else
+                {
+//                        pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7F : 0xFF);
+                        return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7F : 0xFF;
+                }
                 case 0xF: /*16-bit ack*/
                 dsp->sb_irq16 = 0;
                 if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum);
@@ -760,14 +853,13 @@ uint8_t sb_read(uint16_t a, void *priv)
 
 static void sb_wb_clear(void *p)
 {
-        sb_dsp_t *dsp = (sb_dsp_t *)p;
-        
-        dsp->wb_time = 0;
 }
 
-void sb_dsp_init(sb_dsp_t *dsp, int type)
+void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent)
 {
         dsp->sb_type = type;
+        dsp->sb_subtype = subtype;
+        dsp->parent = parent;
         
         // Default values. Use sb_dsp_setxxx() methods to change.
         dsp->sb_irqnum = 7;
@@ -776,9 +868,9 @@ void sb_dsp_init(sb_dsp_t *dsp, int type)
         
         sb_doreset(dsp);
 
-        timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp);
-        timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp);
-        timer_add(sb_wb_clear, &dsp->wb_time, &dsp->wb_time, dsp);
+        timer_add(&dsp->output_timer, pollsb, dsp, 0);
+        timer_add(&dsp->input_timer, sb_poll_i, dsp, 0);
+        timer_add(&dsp->wb_timer, sb_wb_clear, dsp, 0);
 
         /*Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when
           a set frequency command is sent.*/
@@ -788,9 +880,9 @@ void sb_dsp_init(sb_dsp_t *dsp, int type)
 void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr)
 {
 //        pclog("sb_dsp_setaddr : %04X\n", addr);
-        dsp->sb_addr = addr;
         io_removehandler(dsp->sb_addr + 6,   0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
         io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);        
+        dsp->sb_addr = addr;
         if (dsp->sb_addr != 0)
         {
                 io_sethandler(dsp->sb_addr + 6,   0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
@@ -808,7 +900,8 @@ void pollsb(void *p)
         sb_dsp_t *dsp = (sb_dsp_t *)p;
         int tempi,ref;
         
-        dsp->sbcount += dsp->sblatcho;
+        timer_advance_u64(&dsp->output_timer, dsp->sblatcho);
+
 //        pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output);
         if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output)
         {
@@ -972,8 +1065,13 @@ void pollsb(void *p)
                 
                 if (dsp->sb_8_length < 0)
                 {
-                        if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen;
-                        else                    dsp->sb_8_enable = dsp->sbenable=0;
+                        if (dsp->sb_8_autoinit)
+                               dsp->sb_8_length = dsp->sb_8_autolen;
+                        else
+                       {
+                               dsp->sb_8_enable = 0;
+                               timer_disable(&dsp->output_timer);
+                       }
                         sb_irq(dsp, 1);
                 }
         }
@@ -1024,8 +1122,13 @@ void pollsb(void *p)
                 if (dsp->sb_16_length < 0)
                 {
 //                        pclog("16DMA over %i\n",dsp->sb_16_autoinit);
-                        if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen;
-                        else                     dsp->sb_16_enable = dsp->sbenable = 0;
+                        if (dsp->sb_16_autoinit)
+                               dsp->sb_16_length = dsp->sb_16_autolen;
+                        else
+                       {
+                               dsp->sb_16_enable = 0;
+                               timer_disable(&dsp->output_timer);
+                       }
                         sb_irq(dsp, 0);
                 }
         }
@@ -1035,7 +1138,8 @@ void pollsb(void *p)
                 if (dsp->sb_pausetime < 0)
                 {
                         sb_irq(dsp, 1);
-                        dsp->sbenable = dsp->sb_8_enable;
+                       if (!dsp->sb_8_enable)
+                               timer_disable(&dsp->output_timer);
 //                        pclog("SB pause over\n");
                 }
         }
@@ -1045,7 +1149,9 @@ void sb_poll_i(void *p)
 {
         sb_dsp_t *dsp = (sb_dsp_t *)p;
         int processed=0;
-        dsp->sb_count_i += dsp->sblatchi;
+
+        timer_advance_u64(&dsp->input_timer, dsp->sblatchi);
+
 //        pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output);        
         if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output)
         {
@@ -1102,8 +1208,13 @@ void sb_poll_i(void *p)
                 if (dsp->sb_8_length < 0)
                 {
 //                        pclog("Input DMA over %i\n",sb_8_autoinit);
-                        if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen;
-                        else                    dsp->sb_8_enable = dsp->sb_enable_i = 0;
+                        if (dsp->sb_8_autoinit)
+                               dsp->sb_8_length = dsp->sb_8_autolen;
+                        else
+                       {
+                               dsp->sb_8_enable = 0;
+                               timer_disable(&dsp->input_timer);
+                       }
                         sb_irq(dsp, 1);
                 }
                 processed=1;
@@ -1169,8 +1280,13 @@ void sb_poll_i(void *p)
                 if (dsp->sb_16_length < 0)
                 {
 //                        pclog("16iDMA over %i\n",sb_16_autoinit);
-                        if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen;
-                        else                     dsp->sb_16_enable = dsp->sb_enable_i = 0;
+                        if (dsp->sb_16_autoinit)
+                               dsp->sb_16_length = dsp->sb_16_autolen;
+                        else
+                       {
+                               dsp->sb_16_enable = 0;
+                               timer_disable(&dsp->input_timer);
+                       }
                         sb_irq(dsp, 0);
                 }
                 processed=1;
@@ -1269,4 +1385,5 @@ void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp)
                 sprintf(temps, "SB playback frequency : %iHz\n", freq);
                 strncat(s, temps, max_len);
         }
+        strncat(s, "\n", max_len);
 }
index cf21e82f856ed61faa1e7d1a0393829d961cb182..f728400ca9ce4b1bc2a06491a3046307f90722b3 100644 (file)
@@ -1,6 +1,20 @@
+#ifndef SOUND_SB_DSP_H
+#define SOUND_SB_DSP_H
+
+/*Sound Blaster Clones, for quirks*/
+#define SB_SUBTYPE_DEFAULT             0 /*Handle as a Creative card*/
+#define SB_SUBTYPE_CLONE_AZT2316A_0X11 1 /*Aztech Sound Galaxy Pro 16 AB, DSP 3.1 - SBPRO2 clone*/
+#define SB_SUBTYPE_CLONE_AZT1605_0X0C  2 /*Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone*/
+
+// aztech-related
+#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) // check for future AZT cards here
+#define AZTECH_EEPROM_SIZE             16
+
 typedef struct sb_dsp_t
 {
         int sb_type;
+        int sb_subtype; // which clone
+        void *parent; // "sb_t *" if default subtype, "azt2316a_t *" if aztech.
 
         int sb_8_length,  sb_8_format,  sb_8_autoinit,  sb_8_pause,  sb_8_enable,  sb_8_autolen,  sb_8_output;
         int sb_8_dmanum;
@@ -47,9 +61,9 @@ typedef struct sb_dsp_t
         
         int sbenable, sb_enable_i;
         
-        int sbcount, sb_count_i;
+        pc_timer_t output_timer, input_timer;
         
-        int sblatcho, sblatchi;
+        uint64_t sblatcho, sblatchi;
         
         uint16_t sb_addr;
         
@@ -57,7 +71,8 @@ typedef struct sb_dsp_t
         
         int asp_data_len;
         
-        int wb_time, wb_full;
+       pc_timer_t wb_timer;
+        int wb_full;
         
         int busy_count;
 
@@ -66,9 +81,11 @@ typedef struct sb_dsp_t
         int16_t record_buffer[0xFFFF];
         int16_t buffer[MAXSOUNDBUFLEN * 2];
         int pos;
+
+        uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; // the eeprom in the Aztech cards is attached to the DSP
 } sb_dsp_t;
 
-void sb_dsp_init(sb_dsp_t *dsp, int type);
+void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent);
 void sb_dsp_close(sb_dsp_t *dsp);
 
 void sb_dsp_setirq(sb_dsp_t *dsp, int irq);
@@ -85,3 +102,5 @@ void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo);
 void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp);
 
 void sb_dsp_update(sb_dsp_t *dsp);
+
+#endif /* SOUND_SB_DSP_H */
diff --git a/pcem/thread.h b/pcem/thread.h
new file mode 100644 (file)
index 0000000..c8bcd0b
--- /dev/null
@@ -0,0 +1,18 @@
+typedef void thread_t;
+thread_t *thread_create(void (*thread_rout)(void *param), void *param);
+void thread_kill(thread_t *handle);
+
+typedef void event_t;
+event_t *thread_create_event();
+void thread_set_event(event_t *event);
+void thread_reset_event(event_t *_event);
+int thread_wait_event(event_t *event, int timeout);
+void thread_destroy_event(event_t *_event);
+
+typedef void mutex_t;
+mutex_t *thread_create_mutex(void);
+void thread_lock_mutex(mutex_t *mutex);
+void thread_unlock_mutex(mutex_t *mutex);
+void thread_destroy_mutex(mutex_t *mutex);
+
+void thread_sleep(int t);
index a8f65ddae195e3f02dcb299ed241f367e8976b26..565e51daadc80b25759dc0a52724a5122715d45c 100644 (file)
 #include "ibm.h"
 
-/*#include "sound_opl.h"
-#include "adlibgold.h"
-#include "sound_pas16.h"
-#include "sound_sb.h"
-#include "sound_sb_dsp.h"
-#include "sound_wss.h"*/
 #include "timer.h"
 
-#define TIMERS_MAX 32
+uint64_t TIMER_USEC;
+uint32_t timer_target;
 
-int TIMER_USEC;
+/*Enabled timers are stored in a linked list, with the first timer to expire at
+  the head.*/
+static pc_timer_t *timer_head = NULL;
 
-static struct
+void timer_enable(pc_timer_t *timer)
 {
-       int present;
-       void (*callback)(void *priv);
-       void *priv;
-       int *enable;
-       int *count;
-} timers[TIMERS_MAX];
-
-int timers_present = 0;
-int timer_one = 1;
-       
-int timer_count = 0, timer_latch = 0;
-int timer_start = 0;
+       pc_timer_t *timer_node = timer_head;
 
-void timer_process()
-{
-       int c;
-       int process = 0;
-       /*Get actual elapsed time*/
-       int diff = timer_latch - timer_count;
-       int enable[TIMERS_MAX];
-
-       timer_latch = 0;
-
-        for (c = 0; c < timers_present; c++)
-        {
-                enable[c] = *timers[c].enable;
-                if (*timers[c].enable)
-                {
-                        *timers[c].count = *timers[c].count - diff;
-                        if (*timers[c].count <= 0)
-                                process = 1;
-                }
-        }
-        
-        if (!process)
-                return;
-
-        while (1)
-        {
-                int lowest = 1, lowest_c;
-                
-                for (c = 0; c < timers_present; c++)
-                {
-                        if (enable[c])
-                        {
-                                if (*timers[c].count < lowest)
-                                {
-                                        lowest = *timers[c].count;
-                                        lowest_c = c;
-                                }
+//     pclog("timer->enable %p %i\n", timer, timer->enabled);
+       if (timer->enabled)
+               timer_disable(timer);
+
+       if (timer->next || timer->prev)
+               fatal("timer_enable - timer->next\n");
+
+       timer->enabled = 1;
+
+       /*List currently empty - add to head*/
+       if (!timer_head)
+       {
+               timer_head = timer;
+               timer->next = timer->prev = NULL;
+               timer_target = timer_head->ts_integer;
+               return;
+       }
+
+       timer_node = timer_head;
+
+       while (1)
+       {
+               /*Timer expires before timer_node. Add to list in front of timer_node*/
+               if (TIMER_LESS_THAN(timer, timer_node))
+               {
+                       timer->next = timer_node;
+                       timer->prev = timer_node->prev;
+                       timer_node->prev = timer;
+                       if (timer->prev)
+                               timer->prev->next = timer;
+                       else
+                       {
+                               timer_head = timer;
+                               timer_target = timer_head->ts_integer;
                         }
-                }
-                
-                if (lowest > 0)
-                        break;
-
-                timers[lowest_c].callback(timers[lowest_c].priv);
-                enable[lowest_c] = *timers[lowest_c].enable;
-        }              
+                       return;
+               }
+
+               /*timer_node is last in the list. Add timer to end of list*/
+               if (!timer_node->next)
+               {
+                       timer_node->next = timer;
+                       timer->prev = timer_node;
+                       return;
+               }
+
+               timer_node = timer_node->next;
+       }
 }
+void timer_disable(pc_timer_t *timer)
+{
+//     pclog("timer->disable %p\n", timer);
+       if (!timer->enabled)
+               return;
+
+       if (!timer->next && !timer->prev && timer != timer_head)
+               fatal("timer_disable - !timer->next\n");
 
-void timer_update_outstanding()
+       timer->enabled = 0;
+
+       if (timer->prev)
+               timer->prev->next = timer->next;
+       else
+               timer_head = timer->next;
+       if (timer->next)
+               timer->next->prev = timer->prev;
+       timer->prev = timer->next = NULL;
+}
+static void timer_remove_head()
 {
-       int c;
-       timer_latch = 0x7fffffff;
-       for (c = 0; c < timers_present; c++)
+       if (timer_head)
        {
-               if (*timers[c].enable && *timers[c].count < timer_latch)
-                       timer_latch = *timers[c].count;
+               pc_timer_t *timer = timer_head;
+//             pclog("timer_remove_head %p %p\n", timer_head, timer_head->next);
+               timer_head = timer->next;
+               timer_head->prev = NULL;
+               timer->next = timer->prev = NULL;
+               timer->enabled = 0;
        }
-       timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1));
 }
 
-void timer_reset()
+void timer_process()
 {
-       pclog("timer_reset\n");
-       timers_present = 0;
-       timer_latch = timer_count = 0;
-//     timer_process();
-}
+       if (!timer_head)
+               return;
 
-int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv)
-{
-       if (timers_present < TIMERS_MAX)
+       while (1)
        {
-//             pclog("timer_add : adding timer %i\n", timers_present);
-               timers[timers_present].present = 1;
-               timers[timers_present].callback = callback;
-               timers[timers_present].priv = priv;
-               timers[timers_present].count = count;
-               timers[timers_present].enable = enable;
-               timers_present++;
-               return timers_present - 1;
+               pc_timer_t *timer = timer_head;
+
+               if (!TIMER_LESS_THAN_VAL(timer, (uint32_t)tsc))
+                       break;
+
+               timer_remove_head();
+               timer->callback(timer->p);
        }
-       return -1;
+
+       timer_target = timer_head->ts_integer;
+}
+
+void timer_reset()
+{
+       pclog("timer_reset\n");
+       timer_target = 0;
+       tsc = 0;
+       timer_head = NULL;
 }
 
-void timer_set_callback(int timer, void (*callback)(void *priv))
+void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer)
 {
-       timers[timer].callback = callback;
+        memset(timer, 0, sizeof(pc_timer_t));
+        
+       timer->callback = callback;
+       timer->p = p;
+       timer->enabled = 0;
+       timer->prev = timer->next = NULL;
+       if (start_timer)
+               timer_set_delay_u64(timer, 0);
 }
index 50c83e55c1b1272506c5427f941d810ff4cdbbcb..ddcd9c004cfe79eba7e2821dc889bbca9b6255c8 100644 (file)
 
 #include "cpu.h"
 
-extern int timer_start;
-
-#define timer_start_period(cycles)                      \
-        timer_start = cycles;
-
-#define timer_end_period(cycles)                       \
-       do                                              \
-       {                                               \
-                int diff = timer_start - (cycles);      \
-               timer_count -= diff;                    \
-                timer_start = cycles;                   \
-               if (timer_count <= 0)                   \
-               {                                       \
-                       timer_process();                \
-                       timer_update_outstanding();     \
-               }                                       \
-       } while (0)
-
-#define timer_clock()                                                   \
-       do                                                              \
-       {                                                               \
-                int diff;                                               \
-                if (AT)                                                 \
-                {                                                       \
-                        diff = timer_start - (cycles << TIMER_SHIFT);   \
-                        timer_start = cycles << TIMER_SHIFT;            \
-                }                                                       \
-                else                                                    \
-                {                                                       \
-                        diff = timer_start - (cycles * xt_cpu_multi);   \
-                        timer_start = cycles * xt_cpu_multi;            \
-                }                                                       \
-               timer_count -= diff;                                    \
-               timer_process();                                        \
-               timer_update_outstanding();                             \
-       } while (0)
+/*Timers are based on the CPU Time Stamp Counter. Timer timestamps are in a
+  32:32 fixed point format, with the integer part compared against the TSC. The
+  fractional part is used when advancing the timestamp to ensure a more accurate
+  period.
+  
+  As the timer only stores 32 bits of integer timestamp, and the TSC is 64 bits,
+  the timer period can only be at most 0x7fffffff CPU cycles. To allow room for
+  (optimistic) CPU frequency growth, timer period must be at most 1 second.
 
+  When a timer callback is called, the timer has been disabled. If the timer is
+  to repeat, the callback must call timer_advance_u64(). This is a change from
+  the old timer API.*/
+typedef struct pc_timer_t
+{
+       uint32_t ts_integer;
+       uint32_t ts_frac;
+       int enabled;
+
+       void (*callback)(void *p);
+       void *p;
+
+       struct pc_timer_t *prev, *next;
+} pc_timer_t;
+
+/*Timestamp of nearest enabled timer. CPU emulation must call timer_process()
+  when TSC matches or exceeds this.*/
+extern uint32_t timer_target;
+
+/*Enable timer, without updating timestamp*/
+void timer_enable(pc_timer_t *timer);
+/*Disable timer*/
+void timer_disable(pc_timer_t *timer);
+
+/*Process any pending timers*/
 void timer_process();
-void timer_update_outstanding();
+
+/*Reset timer system*/
 void timer_reset();
-int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv);
-void timer_set_callback(int timer, void (*callback)(void *priv));
 
-#define TIMER_ALWAYS_ENABLED &timer_one
+/*Add new timer. If start_timer is set, timer will be enabled with a zero
+  timestamp - this is useful for permanently enabled timers*/
+void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer);
+
+/*1us in 32:32 format*/
+extern uint64_t TIMER_USEC;
+
+/*True if timer a expires before timer b*/
+#define TIMER_LESS_THAN(a, b) ((int32_t)((a)->ts_integer - (b)->ts_integer) <= 0)
+/*True if timer a expires before 32 bit integer timestamp b*/
+#define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts_integer - (b)) <= 0)
+/*True if 32 bit integer timestamp a expires before 32 bit integer timestamp b*/
+#define TIMER_VAL_LESS_THAN_VAL(a, b) ((int32_t)((a) - (b)) <= 0)
+
+/*Advance timer by delay, specified in 32:32 format. This should be used to
+  resume a recurring timer in a callback routine*/
+static inline void timer_advance_u64(pc_timer_t *timer, uint64_t delay)
+{
+       uint32_t int_delay = delay >> 32;
+       uint32_t frac_delay = delay & 0xffffffff;
+
+       if ((frac_delay + timer->ts_frac) < frac_delay)
+               timer->ts_integer++;
+       timer->ts_frac += frac_delay;
+       timer->ts_integer += int_delay;
+
+       timer_enable(timer);
+}
+
+/*Set a timer to the given delay, specified in 32:32 format. This should be used
+  when starting a timer*/
+static inline void timer_set_delay_u64(pc_timer_t *timer, uint64_t delay)
+{
+       uint32_t int_delay = delay >> 32;
+       uint32_t frac_delay = delay & 0xffffffff;
+
+       timer->ts_frac = frac_delay;
+       timer->ts_integer = int_delay + (uint32_t)tsc;
+
+       timer_enable(timer);
+}
+
+/*True if timer currently enabled*/
+static inline int timer_is_enabled(pc_timer_t *timer)
+{
+       return timer->enabled;
+}
+
+/*Return integer timestamp of timer*/
+static inline uint32_t timer_get_ts_int(pc_timer_t *timer)
+{
+       return timer->ts_integer;
+}
+
+/*Return remaining time before timer expires, in us. If the timer has already
+  expired then return 0*/
+static inline uint32_t timer_get_remaining_us(pc_timer_t *timer)
+{
+       if (timer->enabled)
+       {
+               int64_t remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32);
+
+               if (remaining < 0)
+                       return 0;
+               return remaining / TIMER_USEC;
+       }
+
+       return 0;
+}
+
+/*Return remaining time before timer expires, in 32:32 timestamp format. If the
+  timer has already expired then return 0*/
+static inline uint64_t timer_get_remaining_u64(pc_timer_t *timer)
+{
+       if (timer->enabled)
+       {
+               int64_t remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32);
 
-extern int timer_count;
-extern int timer_one;
+               if (remaining < 0)
+                       return 0;
+               return remaining;
+       }
 
-#define TIMER_SHIFT 6
+       return 0;
+}
 
-extern int TIMER_USEC;
+/*Set timer callback function*/
+static inline void timer_set_callback(pc_timer_t *timer, void (*callback)(void *p))
+{
+        timer->callback = callback;
+}
+/*Set timer private data*/
+static inline void timer_set_p(pc_timer_t *timer, void *p)
+{
+        timer->p = p;
+}
 
 #endif /*_TIMER_H_*/
diff --git a/pcem/vid_cl5429.cpp b/pcem/vid_cl5429.cpp
new file mode 100644 (file)
index 0000000..76c54fe
--- /dev/null
@@ -0,0 +1,2384 @@
+/*Cirrus Logic CL-GD5429 emulation*/
+#include <stdlib.h>
+#include "ibm.h"
+#include "cpu.h"
+#include "device.h"
+#include "io.h"
+#include "mca.h"
+#include "mem.h"
+#include "pci.h"
+#include "rom.h"
+#include "video.h"
+#include "vid_cl5429.h"
+#include "vid_svga.h"
+#include "vid_svga_render.h"
+#include "vid_vga.h"
+#include "vid_unk_ramdac.h"
+
+enum
+{
+        CL_TYPE_AVGA2 = 0,
+        CL_TYPE_GD5426,
+        CL_TYPE_GD5428,
+        CL_TYPE_GD5429,
+        CL_TYPE_GD5430,
+        CL_TYPE_GD5434
+};
+
+#define BLIT_DEPTH_8  0
+#define BLIT_DEPTH_16 1
+#define BLIT_DEPTH_32 3
+
+#define CL_GD5428_SYSTEM_BUS_MCA  5
+#define CL_GD5428_SYSTEM_BUS_VESA 6
+#define CL_GD5428_SYSTEM_BUS_ISA  7
+
+#define CL_GD5429_SYSTEM_BUS_VESA 5
+#define CL_GD5429_SYSTEM_BUS_ISA  7
+
+#define CL_GD543X_SYSTEM_BUS_PCI  4
+#define CL_GD543X_SYSTEM_BUS_VESA 6
+#define CL_GD543X_SYSTEM_BUS_ISA  7
+
+typedef struct gd5429_t
+{
+        mem_mapping_t mmio_mapping;
+        mem_mapping_t linear_mapping;
+        
+        svga_t svga;
+        
+        rom_t bios_rom;
+        
+        uint32_t bank[2];
+        uint32_t mask;
+        
+        uint32_t vram_mask;
+
+        int type;
+        
+        struct
+        {
+                uint32_t bg_col, fg_col;
+                uint16_t trans_col, trans_mask;
+                uint16_t width, height;
+                uint16_t dst_pitch, src_pitch;               
+                uint32_t dst_addr, src_addr;
+                uint8_t mask, mode, rop;
+                
+                uint32_t dst_addr_backup, src_addr_backup;
+                uint16_t width_backup, height_internal;
+                int x_count, y_count;
+                int depth;
+                
+                int mem_word_sel;
+                uint16_t mem_word_save;
+        } blt;
+
+        uint8_t hidden_dac_reg;
+        int dac_3c6_count;
+        
+        uint8_t pci_regs[256];
+        uint8_t int_line;
+        int card;
+        
+        uint8_t pos_regs[8];
+        svga_t *mb_vga;
+        
+        uint32_t lfb_base;
+        
+        int mmio_vram_overlap;
+        
+        uint8_t sr10_read, sr11_read;
+
+        uint8_t latch_ext[4];
+        
+        int vidsys_ena;
+} gd5429_t;
+
+#define GRB_X8_ADDRESSING (1 << 1)
+#define GRB_WRITEMODE_EXT (1 << 2)
+#define GRB_8B_LATCHES    (1 << 3)
+
+static void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p);
+static void gd5429_mmio_writew(uint32_t addr, uint16_t val, void *p);
+static void gd5429_mmio_writel(uint32_t addr, uint32_t val, void *p);
+static uint8_t gd5429_mmio_read(uint32_t addr, void *p);
+static uint16_t gd5429_mmio_readw(uint32_t addr, void *p);
+static uint32_t gd5429_mmio_readl(uint32_t addr, void *p);
+
+void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *p);
+void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *p);
+
+void gd5429_recalc_banking(gd5429_t *gd5429);
+void gd5429_recalc_mapping(gd5429_t *gd5429);
+
+uint8_t gd5429_read_linear(uint32_t addr, void *p);
+
+static void ibm_gd5428_mapping_update(gd5429_t *gd5429);
+
+void gd5429_out(uint16_t addr, uint8_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+        uint8_t old;
+        
+        if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
+                addr ^= 0x60;
+
+//        pclog("gd5429 out %04X %02X\n", addr, val);
+                
+        switch (addr)
+        {
+                case 0x3c3:
+                if (MCA)
+                {
+                        gd5429->vidsys_ena = val & 1;
+                        ibm_gd5428_mapping_update(gd5429);
+                }
+                break;
+                        
+                case 0x3c4:
+                svga->seqaddr = val;
+                break;
+                case 0x3c5:
+                if (svga->seqaddr > 5)
+                {
+                        svga->seqregs[svga->seqaddr & 0x1f] = val;
+                        switch (svga->seqaddr & 0x1f)
+                        {
+                                case 0x10: case 0x30: case 0x50: case 0x70:
+                                case 0x90: case 0xb0: case 0xd0: case 0xf0:
+                                svga->hwcursor.x = (val << 3) | ((svga->seqaddr >> 5) & 7);
+                                gd5429->sr10_read = svga->seqaddr & 0xe0;
+//                                pclog("svga->hwcursor.x = %i\n", svga->hwcursor.x);
+                                break;
+                                case 0x11: case 0x31: case 0x51: case 0x71:
+                                case 0x91: case 0xb1: case 0xd1: case 0xf1:
+                                svga->hwcursor.y = (val << 3) | ((svga->seqaddr >> 5) & 7);
+                                gd5429->sr11_read = svga->seqaddr & 0xe0;
+//                                pclog("svga->hwcursor.y = %i\n", svga->hwcursor.y);
+                                break;
+                                case 0x12:
+                                svga->hwcursor.ena = val & 1;
+                                svga->hwcursor.ysize = (val & 4) ? 64 : 32;
+                                svga->hwcursor.yoff = 0;
+                                if (svga->hwcursor.ysize == 64)
+                                        svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3c) * 256)) & svga->vram_mask;
+                                else
+                                        svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3f) * 256)) & svga->vram_mask;
+//                                pclog("svga->hwcursor.ena = %i\n", svga->hwcursor.ena);
+                                break;                               
+                                case 0x13:
+                                if (svga->hwcursor.ysize == 64)
+                                        svga->hwcursor.addr = (0x3fc000 + ((val & 0x3c) * 256)) & svga->vram_mask;
+                                else
+                                        svga->hwcursor.addr = (0x3fc000 + ((val & 0x3f) * 256)) & svga->vram_mask;
+//                                pclog("svga->hwcursor.addr = %x\n", svga->hwcursor.addr);
+                                break;                                
+                                
+                                case 0x07:
+                                svga->set_reset_disabled = svga->seqregs[7] & 1;
+                                case 0x17:
+                                if (gd5429->type >= CL_TYPE_GD5429)
+                                        gd5429_recalc_mapping(gd5429);
+                                break;
+                        }
+                        return;
+                }
+                break;
+
+                case 0x3c6:
+//                pclog("CL write 3c6 %02x %i\n", val, gd5429->dac_3c6_count);
+                if (gd5429->dac_3c6_count == 4)
+                {
+                        gd5429->dac_3c6_count = 0;
+                        gd5429->hidden_dac_reg = val;
+                        svga_recalctimings(svga);
+                        return;
+                }
+                gd5429->dac_3c6_count = 0;
+                break;
+                case 0x3c7: case 0x3c8: case 0x3c9:
+                gd5429->dac_3c6_count = 0;
+                break;
+
+                case 0x3cf:
+//                pclog("Write GDC %02x %02x\n", svga->gdcaddr, val);
+                if (svga->gdcaddr == 0)
+                        gd5429_mmio_write(0xb8000, val, gd5429);
+                if (svga->gdcaddr == 1)
+                        gd5429_mmio_write(0xb8004, val, gd5429);
+                if (svga->gdcaddr == 5)
+                {
+                        svga->gdcreg[5] = val;
+                        if (svga->gdcreg[0xb] & 0x04)
+                                svga->writemode = svga->gdcreg[5] & 7;
+                        else
+                                svga->writemode = svga->gdcreg[5] & 3;
+                        svga->readmode = val & 8;
+                        svga->chain2_read = val & 0x10;
+//                        pclog("writemode = %i\n", svga->writemode);
+                        return;
+                }
+                if (svga->gdcaddr == 6)
+                {
+                        if ((svga->gdcreg[6] & 0xc) != (val & 0xc))
+                        {
+                                svga->gdcreg[6] = val;
+                                gd5429_recalc_mapping(gd5429);
+                        }
+
+                        /*Hack - the Windows 3.x drivers for the GD5426/8 require VRAM wraparound
+                          for pattern & cursor writes to work correctly, but the BIOSes require
+                          no wrapping to detect memory size - albeit with odd/even mode enabled.
+                          This may be a quirk of address mapping. So change wrapping mode based on
+                          odd/even mode for now*/
+                        if (gd5429->type == CL_TYPE_GD5426 || gd5429->type == CL_TYPE_GD5428)
+                        {
+                                if (val & 2) /*Odd/Even*/
+                                        svga->decode_mask = 0x1fffff;
+                                else
+                                        svga->decode_mask = svga->vram_mask;
+                        }
+
+                        svga->gdcreg[6] = val;
+                        return;
+                }
+                if (svga->gdcaddr > 8)
+                {
+                        svga->gdcreg[svga->gdcaddr & 0x3f] = val;
+                        if (gd5429->type < CL_TYPE_GD5426 && (svga->gdcaddr > 0xb))
+                                return;
+                        switch (svga->gdcaddr)
+                        {
+                                case 0x09: case 0x0a: case 0x0b:
+                                gd5429_recalc_banking(gd5429);
+                                if (svga->gdcreg[0xb] & 0x04)
+                                        svga->writemode = svga->gdcreg[5] & 7;
+                                else
+                                        svga->writemode = svga->gdcreg[5] & 3;
+                                break;
+
+                                case 0x10:
+                                gd5429_mmio_write(0xb8001, val, gd5429);
+                                break;
+                                case 0x11:
+                                gd5429_mmio_write(0xb8005, val, gd5429);
+                                break;
+                                case 0x12:
+                                gd5429_mmio_write(0xb8002, val, gd5429);
+                                break;
+                                case 0x13:
+                                gd5429_mmio_write(0xb8006, val, gd5429);
+                                break;
+                                case 0x14:
+                                gd5429_mmio_write(0xb8003, val, gd5429);
+                                break;
+                                case 0x15:
+                                gd5429_mmio_write(0xb8007, val, gd5429);
+                                break;
+
+                                case 0x20:
+                                gd5429_mmio_write(0xb8008, val, gd5429);
+                                break;
+                                case 0x21:
+                                gd5429_mmio_write(0xb8009, val, gd5429);
+                                break;
+                                case 0x22:
+                                gd5429_mmio_write(0xb800a, val, gd5429);
+                                break;
+                                case 0x23:
+                                gd5429_mmio_write(0xb800b, val, gd5429);
+                                break;
+                                case 0x24:
+                                gd5429_mmio_write(0xb800c, val, gd5429);
+                                break;
+                                case 0x25:
+                                gd5429_mmio_write(0xb800d, val, gd5429);
+                                break;
+                                case 0x26:
+                                gd5429_mmio_write(0xb800e, val, gd5429);
+                                break;
+                                case 0x27:
+                                gd5429_mmio_write(0xb800f, val, gd5429);
+                                break;
+                
+                                case 0x28:
+                                gd5429_mmio_write(0xb8010, val, gd5429);
+                                break;
+                                case 0x29:
+                                gd5429_mmio_write(0xb8011, val, gd5429);
+                                break;
+                                case 0x2a:
+                                gd5429_mmio_write(0xb8012, val, gd5429);
+                                break;
+
+                                case 0x2c:
+                                gd5429_mmio_write(0xb8014, val, gd5429);
+                                break;
+                                case 0x2d:
+                                gd5429_mmio_write(0xb8015, val, gd5429);
+                                break;
+                                case 0x2e:
+                                gd5429_mmio_write(0xb8016, val, gd5429);
+                                break;
+
+                                case 0x2f:
+                                gd5429_mmio_write(0xb8017, val, gd5429);
+                                break;
+                                case 0x30:
+                                gd5429_mmio_write(0xb8018, val, gd5429);
+                                break;
+                
+                                case 0x32:
+                                gd5429_mmio_write(0xb801a, val, gd5429);
+                                break;
+                
+                                case 0x31:
+                                gd5429_mmio_write(0xb8040, val, gd5429);
+                                break;
+
+                                case 0x34:
+                                if (gd5429->type <= CL_TYPE_GD5428)
+                                        gd5429->blt.trans_col = (gd5429->blt.trans_col & 0xff00) | val;
+                                break;
+                                case 0x35:
+                                if (gd5429->type <= CL_TYPE_GD5428)
+                                        gd5429->blt.trans_col = (gd5429->blt.trans_col & 0x00ff) | (val << 8);
+                                break;
+                                case 0x36:
+                                if (gd5429->type <= CL_TYPE_GD5428)
+                                        gd5429->blt.trans_mask = (gd5429->blt.trans_mask & 0xff00) | val;
+                                break;
+                                case 0x37:
+                                if (gd5429->type <= CL_TYPE_GD5428)
+                                        gd5429->blt.trans_mask = (gd5429->blt.trans_mask & 0x00ff) | (val << 8);
+                                break;
+                        }
+                        return;
+                }
+                break;
+                
+                case 0x3D4:
+                svga->crtcreg = val & 0x3f;
+                return;
+                case 0x3D5:
+                if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
+                        return;
+                if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
+                        val = (svga->crtc[7] & ~0x10) | (val & 0x10);
+                old = svga->crtc[svga->crtcreg];
+                svga->crtc[svga->crtcreg] = val;
+
+                if (old != val)
+                {
+                        if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
+                        {
+                                svga->fullchange = changeframecount;
+                                svga_recalctimings(svga);
+                        }
+                }
+                break;
+        }
+        svga_out(addr, val, svga);
+}
+
+uint8_t gd5429_in(uint16_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
+                addr ^= 0x60;
+        
+//        if (addr != 0x3da) pclog("IN gd5429 %04X\n", addr);
+        
+        switch (addr)
+        {
+                case 0x3c3:
+                if (MCA)
+                        return gd5429->vidsys_ena;
+                break;
+
+                case 0x3c4:
+                if ((svga->seqaddr & 0x1f) == 0x10)
+                        return (svga->seqaddr & 0x1f) | gd5429->sr10_read;
+                if ((svga->seqaddr & 0x1f) == 0x11)
+                        return (svga->seqaddr & 0x1f) | gd5429->sr11_read;
+                return svga->seqaddr & 0x1f;
+                
+                case 0x3c5:
+                if (svga->seqaddr > 5)
+                {
+                        uint8_t temp;
+                        
+                        switch (svga->seqaddr)
+                        {
+                                case 6:
+                                return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f;
+
+                                case 0x17:
+                                if (gd5429->type < CL_TYPE_GD5426)
+                                        break;
+                                temp = svga->seqregs[0x17];
+                                temp &= ~(7 << 3);
+                                if (gd5429->type == CL_TYPE_GD5426 || gd5429->type == CL_TYPE_GD5428)
+                                {
+                                        if (MCA)
+                                                temp |= (CL_GD5428_SYSTEM_BUS_MCA << 3);
+                                        else if (has_vlb)
+                                                temp |= (CL_GD5428_SYSTEM_BUS_VESA << 3);
+                                        else
+                                                temp |= (CL_GD5428_SYSTEM_BUS_ISA << 3);
+                                }
+                                else if (gd5429->type == CL_TYPE_GD5429)
+                                {
+                                        if (has_vlb)
+                                                temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3);
+                                        else
+                                                temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3);
+                                }
+                                else
+                                {
+                                        if (PCI)
+                                                temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3);
+                                        else if (has_vlb)
+                                                temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3);
+                                        else
+                                                temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3);
+                                }
+                                return temp;                                
+                        }
+                        return svga->seqregs[svga->seqaddr & 0x3f];
+                }
+                break;
+                
+                case 0x3c6:
+//                pclog("CL read 3c6 %i\n", gd5429->dac_3c6_count);
+                if (gd5429->dac_3c6_count == 4)
+                {
+                        gd5429->dac_3c6_count = 0;
+                        return gd5429->hidden_dac_reg;
+                }
+                gd5429->dac_3c6_count++;
+                break;
+                case 0x3c7: case 0x3c8: case 0x3c9:
+                gd5429->dac_3c6_count = 0;
+                break;
+
+                case 0x3cf:
+                if (svga->gdcaddr > 8)
+                {
+                        return svga->gdcreg[svga->gdcaddr & 0x3f];
+                }
+                break;
+
+                case 0x3D4:
+                return svga->crtcreg;
+                case 0x3D5:
+                switch (svga->crtcreg)
+                {
+                        case 0x27: /*ID*/
+                        switch (gd5429->type)
+                        {
+                                case CL_TYPE_AVGA2:
+                                return 0x18; /*AVGA2*/
+                                case CL_TYPE_GD5426:
+                                return 0x90; /*GD5426*/
+                                case CL_TYPE_GD5428:
+                                return 0x98; /*GD5428*/
+                                case CL_TYPE_GD5429:
+                                return 0x9c; /*GD5429*/
+                                case CL_TYPE_GD5430:
+                                return 0xa0; /*GD5430*/
+                                case CL_TYPE_GD5434:
+                                return 0xa8; /*GD5434*/
+                        }
+                        break;
+                        case 0x28: /*Class ID*/
+                        if (gd5429->type == CL_TYPE_GD5430)
+                                return 0xff; /*Standard CL-GD5430*/
+                        break;
+                }
+                return svga->crtc[svga->crtcreg];
+        }
+        return svga_in(addr, svga);
+}
+
+void gd5429_recalc_banking(gd5429_t *gd5429)
+{
+        svga_t *svga = &gd5429->svga;
+        
+        if (svga->gdcreg[0xb] & 0x20)
+                gd5429->bank[0] = (svga->gdcreg[0x09] & 0xff) << 14;
+        else
+                gd5429->bank[0] = svga->gdcreg[0x09] << 12;
+                                
+        if (svga->gdcreg[0xb] & 0x01)
+        {
+                if (svga->gdcreg[0xb] & 0x20)
+                        gd5429->bank[1] = (svga->gdcreg[0x0a] & 0xff) << 14;
+                else
+                        gd5429->bank[1] = svga->gdcreg[0x0a] << 12;
+        }
+        else
+                gd5429->bank[1] = gd5429->bank[0] + 0x8000;
+}
+
+void gd5429_recalc_mapping(gd5429_t *gd5429)
+{
+        svga_t *svga = &gd5429->svga;
+        
+        if ((PCI && gd5429->type >= CL_TYPE_GD5430 && !(gd5429->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) ||
+                (MCA && (!(gd5429->pos_regs[2] & 0x01) || !gd5429->vidsys_ena)))
+        {
+                mem_mapping_disable(&svga->mapping);
+                mem_mapping_disable(&gd5429->linear_mapping);
+                mem_mapping_disable(&gd5429->mmio_mapping);
+                return;
+        }
+        
+        gd5429->mmio_vram_overlap = 0;
+        
+//        pclog("Write mapping %02X %i\n", svga->gdcreg[6], svga->seqregs[0x17] & 0x04);
+        if (!(svga->seqregs[7] & 0xf0))
+        {
+                mem_mapping_disable(&gd5429->linear_mapping);
+                switch (svga->gdcreg[6] & 0x0C)
+                {
+                        case 0x0: /*128k at A0000*/
+                        mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);                        
+                        svga->banked_mask = 0xffff;
+                        break;
+                        case 0x4: /*64k at A0000*/
+                        mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
+                        svga->banked_mask = 0xffff;
+                        break;
+                        case 0x8: /*32k at B0000*/
+                        mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
+                        svga->banked_mask = 0x7fff;
+                        break;
+                        case 0xC: /*32k at B8000*/
+                        mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
+                        svga->banked_mask = 0x7fff;
+                        gd5429->mmio_vram_overlap = 1;
+                        break;
+                }
+                if (gd5429->type >= CL_TYPE_GD5429 && svga->seqregs[0x17] & 0x04)
+                        mem_mapping_set_addr(&gd5429->mmio_mapping, 0xb8000, 0x00100);
+                else
+                        mem_mapping_disable(&gd5429->mmio_mapping);
+        }
+        else
+        {
+                uint32_t base, size;
+                
+                if (gd5429->type <= CL_TYPE_GD5429 || (!PCI && !has_vlb))
+                {
+                        base = (svga->seqregs[7] & 0xf0) << 16;
+                        if (svga->gdcreg[0xb] & 0x20)
+                                size = 1 * 1024 * 1024;
+                        else
+                                size = 2 * 1024 * 1024;
+                }
+                else if (PCI)
+                {
+                        base = gd5429->lfb_base;
+                        size = 4 * 1024 * 1024;
+                }
+                else /*VLB*/
+                {
+                        base = 128*1024*1024;
+                        size = 4 * 1024 * 1024;
+                }
+                mem_mapping_disable(&svga->mapping);
+                mem_mapping_set_addr(&gd5429->linear_mapping, base, size);
+                if (gd5429->type >= CL_TYPE_GD5429 && svga->seqregs[0x17] & 0x04)
+                        mem_mapping_set_addr(&gd5429->mmio_mapping, 0xb8000, 0x00100);
+                else
+                        mem_mapping_disable(&gd5429->mmio_mapping);
+        }        
+}
+        
+void gd5429_recalctimings(svga_t *svga)
+{
+        gd5429_t *gd5429 = (gd5429_t *)svga->p;
+        int clock = (svga->miscout >> 2) & 3;
+        int n, d, p;
+        double vclk;
+
+        if (svga->crtc[0x1b] & 0x10)
+                svga->rowoffset |= 0x100;
+                        
+        if (!svga->rowoffset)
+                svga->rowoffset = 0x100;
+        
+        svga->interlace = svga->crtc[0x1a] & 1;
+        
+        if (svga->seqregs[7] & 0x01)
+                svga->render = svga_render_8bpp_highres;
+        
+        svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15);
+//        pclog("MA now %05X %02X\n", svga->ma_latch, svga->crtc[0x1b]);
+        
+        svga->bpp = 8;
+        if (gd5429->hidden_dac_reg & 0x80)
+        {
+                if (gd5429->hidden_dac_reg & 0x40)
+                {
+                        switch (gd5429->hidden_dac_reg & 0xf)
+                        {
+                                case 0x0:
+                                svga->render = svga_render_15bpp_highres;
+                                svga->bpp = 15;
+                                break;
+                                case 0x1:
+                                svga->render = svga_render_16bpp_highres;
+                                svga->bpp = 16;
+                                break;
+                                case 0x5:
+                                if (gd5429->type >= CL_TYPE_GD5434 && (svga->seqregs[7] & 8))
+                                {
+                                        svga->render = svga_render_32bpp_highres;
+                                        svga->bpp = 32;
+                                        svga->rowoffset *= 2;
+                                }
+                                else
+                                {
+                                        svga->render = svga_render_24bpp_highres;
+                                        svga->bpp = 24;
+                                }
+                                break;
+                        }
+                }
+                else
+                {
+                        svga->render = svga_render_15bpp_highres; 
+                        svga->bpp = 15;
+                }
+        }
+        
+        n = svga->seqregs[0xb + clock] & 0x7f;
+        d = (svga->seqregs[0x1b + clock] >> 1) & 0x1f;
+        p = svga->seqregs[0x1b + clock] & 1;
+
+        /*Prevent divide by zero during clock setup*/
+        if (d && n)
+                vclk = (14318184.0 * ((float)n / (float)d)) / (float)(1 + p);
+        else
+                vclk = 14318184.0;
+        switch (svga->seqregs[7] & ((gd5429->type >= CL_TYPE_GD5434) ? 0xe : 0x6))
+        {
+                case 2:
+                vclk /= 2.0;
+                break;
+                case 4:
+                vclk /= 3.0;
+                break;
+        }
+        svga->clock = (cpuclock * (float)(1ull << 32)) / vclk;
+        
+        svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd5429->vram_mask : 0x3ffff;
+}
+
+void gd5429_hwcursor_draw(svga_t *svga, int displine)
+{
+        int x;
+        uint8_t dat[2];
+        int xx;
+        int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
+        int line_offset = (svga->seqregs[0x12] & 0x04) ? 16 : 4;
+
+        if (svga->interlace && svga->hwcursor_oddeven)
+                svga->hwcursor_latch.addr += line_offset;
+
+        if (svga->seqregs[0x12] & 0x04)
+        {
+                for (x = 0; x < 64; x += 8)
+                {
+                        dat[0] = svga->vram[svga->hwcursor_latch.addr];
+                        dat[1] = svga->vram[svga->hwcursor_latch.addr + 8];
+                        for (xx = 0; xx < 8; xx++)
+                        {
+                                if (offset >= svga->hwcursor_latch.x)
+                                {
+                                        if (dat[1] & 0x80)
+                                                ((uint32_t *)buffer32->line[displine])[offset + 32] = 0;
+                                        if (dat[0] & 0x80)
+                                                ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
+                                }
+
+                                offset++;
+                                dat[0] <<= 1;
+                                dat[1] <<= 1;
+                        }
+                        svga->hwcursor_latch.addr++;
+                }
+                svga->hwcursor_latch.addr += 8;
+        }
+        else
+        {
+                for (x = 0; x < 32; x += 8)
+                {
+                        dat[0] = svga->vram[svga->hwcursor_latch.addr];
+                        dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80];
+                        for (xx = 0; xx < 8; xx++)
+                        {
+                                if (offset >= svga->hwcursor_latch.x)
+                                {
+                                        if (dat[1] & 0x80)
+                                                ((uint32_t *)buffer32->line[displine])[offset + 32] = 0;
+                                        if (dat[0] & 0x80)
+                                                ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
+                                }
+
+                                offset++;
+                                dat[0] <<= 1;
+                                dat[1] <<= 1;
+                        }
+                        svga->hwcursor_latch.addr++;
+                }
+        }
+
+        if (svga->interlace && !svga->hwcursor_oddeven)
+                svga->hwcursor_latch.addr += line_offset;
+}
+
+
+void gd5429_write_linear(uint32_t addr, uint8_t val, void *p);
+
+static void gd5429_write(uint32_t addr, uint8_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+        
+        addr &= svga->banked_mask;
+        addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1];
+
+        gd5429_write_linear(addr, val, p);
+}
+static void gd5429_writew(uint32_t addr, uint16_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        addr &= svga->banked_mask;
+        addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1];
+
+        if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                svga_writew_linear(addr, val, svga);
+        else
+        {
+                gd5429_write_linear(addr, val, p);
+                gd5429_write_linear(addr+1, val >> 8, p);
+        }
+}
+static void gd5429_writel(uint32_t addr, uint32_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        addr &= svga->banked_mask;
+        addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1];
+
+        if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                svga_writel_linear(addr, val, svga);
+        else
+        {
+                gd5429_write_linear(addr, val, p);
+                gd5429_write_linear(addr+1, val >> 8, p);
+                gd5429_write_linear(addr+2, val >> 16, p);
+                gd5429_write_linear(addr+3, val >> 24, p);
+        }
+}
+
+static uint8_t gd5429_read(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        addr &= svga->banked_mask;
+        addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1];
+        return gd5429_read_linear(addr, gd5429);
+}
+static uint16_t gd5429_readw(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        addr &= svga->banked_mask;
+        addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1];
+
+        if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                return svga_readw_linear(addr, &gd5429->svga);
+        return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8);
+}
+static uint32_t gd5429_readl(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        addr &= svga->banked_mask;
+        addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1];
+
+        if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                return svga_readl_linear(addr, &gd5429->svga);
+        return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8) |
+                (gd5429_read_linear(addr+2, gd5429) << 16) | (gd5429_read_linear(addr+3, gd5429) << 24);
+}
+
+void gd5429_write_linear(uint32_t addr, uint8_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+        uint8_t vala, valb, valc, vald, wm = svga->writemask;
+        int writemask2 = svga->seqregs[2];
+
+        cycles -= video_timing_write_b;
+        cycles_lost += video_timing_write_b;
+
+        egawrites++;
+        
+//        if (svga_output) pclog("Write LFB %08X %02X ", addr, val);
+        if (!(svga->gdcreg[6] & 1)) 
+                svga->fullchange = 2;
+        if (svga->gdcreg[0xb] & GRB_X8_ADDRESSING)
+                addr <<= 3;
+        else if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4))
+        {
+                writemask2 = 1 << (addr & 3);
+                addr &= ~3;
+        }
+        else if (svga->chain2_write)
+        {
+                writemask2 &= ~0xa;
+                if (addr & 1)
+                        writemask2 <<= 1;
+                addr &= ~1;
+                addr <<= 2;
+        }
+        else
+        {
+                addr <<= 2;
+        }
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return;
+        addr &= svga->vram_mask;
+//        if (svga_output) pclog("%08X\n", addr);
+        svga->changedvram[addr >> 12] = changeframecount;
+        
+        switch (svga->writemode)
+        {
+                case 4:
+                if (svga->gdcreg[0xb] & 0x10)
+                {
+//                        pclog("Writemode 4 : %X ", addr);
+                        addr <<= 2;
+                        svga->changedvram[addr >> 12] = changeframecount;
+//                        pclog("%X %X  %02x\n", addr, val, svga->gdcreg[0xb]);
+                        if (val & svga->seqregs[2] & 0x80)
+                        {
+                                svga->vram[addr + 0] = svga->gdcreg[1];
+                                svga->vram[addr + 1] = svga->gdcreg[0x11];
+                        }
+                        if (val & svga->seqregs[2] & 0x40)
+                        {
+                                svga->vram[addr + 2] = svga->gdcreg[1];
+                                svga->vram[addr + 3] = svga->gdcreg[0x11];
+                        }
+                        if (val & svga->seqregs[2] & 0x20)
+                        {
+                                svga->vram[addr + 4] = svga->gdcreg[1];
+                                svga->vram[addr + 5] = svga->gdcreg[0x11];
+                        }
+                        if (val & svga->seqregs[2] & 0x10)
+                        {
+                                svga->vram[addr + 6] = svga->gdcreg[1];
+                                svga->vram[addr + 7] = svga->gdcreg[0x11];
+                        }
+                        if (val & svga->seqregs[2] & 0x08)
+                        {
+                                svga->vram[addr + 8] = svga->gdcreg[1];
+                                svga->vram[addr + 9] = svga->gdcreg[0x11];
+                        }
+                        if (val & svga->seqregs[2] & 0x04)
+                        {
+                                svga->vram[addr + 10] = svga->gdcreg[1];
+                                svga->vram[addr + 11] = svga->gdcreg[0x11];
+                        }
+                        if (val & svga->seqregs[2] & 0x02)
+                        {
+                                svga->vram[addr + 12] = svga->gdcreg[1];
+                                svga->vram[addr + 13] = svga->gdcreg[0x11];
+                        }
+                        if (val & svga->seqregs[2] & 0x01)
+                        {
+                                svga->vram[addr + 14] = svga->gdcreg[1];
+                                svga->vram[addr + 15] = svga->gdcreg[0x11];
+                        }
+                }
+                else
+                {
+//                        pclog("Writemode 4 : %X ", addr);
+                        svga->changedvram[addr >> 12] = changeframecount;
+//                        pclog("%X %X  %02x\n", addr, val, svga->gdcreg[0xb]);
+                        if (val & svga->seqregs[2] & 0x80)
+                                svga->vram[addr + 0] = svga->gdcreg[1];
+                        if (val & svga->seqregs[2] & 0x40)
+                                svga->vram[addr + 1] = svga->gdcreg[1];
+                        if (val & svga->seqregs[2] & 0x20)
+                                svga->vram[addr + 2] = svga->gdcreg[1];
+                        if (val & svga->seqregs[2] & 0x10)
+                                svga->vram[addr + 3] = svga->gdcreg[1];
+                        if (val & svga->seqregs[2] & 0x08)
+                                svga->vram[addr + 4] = svga->gdcreg[1];
+                        if (val & svga->seqregs[2] & 0x04)
+                                svga->vram[addr + 5] = svga->gdcreg[1];
+                        if (val & svga->seqregs[2] & 0x02)
+                                svga->vram[addr + 6] = svga->gdcreg[1];
+                        if (val & svga->seqregs[2] & 0x01)
+                                svga->vram[addr + 7] = svga->gdcreg[1];
+                }
+                break;
+                        
+                case 5:
+                if (svga->gdcreg[0xb] & 0x10)
+                {
+//                        pclog("Writemode 5 : %X ", addr);
+                        addr <<= 2;
+                        svga->changedvram[addr >> 12] = changeframecount;
+//                        pclog("%X %X  %02x\n", addr, val, svga->gdcreg[0xb]);
+                        if (svga->seqregs[2] & 0x80)
+                        {
+                                svga->vram[addr +  0] = (val & 0x80) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr +  1] = (val & 0x80) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                        if (svga->seqregs[2] & 0x40)
+                        {
+                                svga->vram[addr +  2] = (val & 0x40) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr +  3] = (val & 0x40) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                        if (svga->seqregs[2] & 0x20)
+                        {
+                                svga->vram[addr +  4] = (val & 0x20) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr +  5] = (val & 0x20) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                        if (svga->seqregs[2] & 0x10)
+                        {
+                                svga->vram[addr +  6] = (val & 0x10) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr +  7] = (val & 0x10) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                        if (svga->seqregs[2] & 0x08)
+                        {
+                                svga->vram[addr +  8] = (val & 0x08) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr +  9] = (val & 0x08) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                        if (svga->seqregs[2] & 0x04)
+                        {
+                                svga->vram[addr + 10] = (val & 0x04) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr + 11] = (val & 0x04) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                        if (svga->seqregs[2] & 0x02)
+                        {
+                                svga->vram[addr + 12] = (val & 0x02) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr + 13] = (val & 0x02) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                        if (svga->seqregs[2] & 0x01)
+                        {
+                                svga->vram[addr + 14] = (val & 0x01) ? svga->gdcreg[1] : svga->gdcreg[0];
+                                svga->vram[addr + 15] = (val & 0x01) ? svga->gdcreg[0x11] : svga->gdcreg[0x10];
+                        }
+                }
+                else
+                {
+//                        pclog("Writemode 5 : %X ", addr);
+                        svga->changedvram[addr >> 12] = changeframecount;
+//                        pclog("%X %X  %02x\n", addr, val, svga->gdcreg[0xb]);
+                        if (svga->seqregs[2] & 0x80)
+                                svga->vram[addr + 0] = (val & 0x80) ? svga->gdcreg[1] : svga->gdcreg[0];
+                        if (svga->seqregs[2] & 0x40)
+                                svga->vram[addr + 1] = (val & 0x40) ? svga->gdcreg[1] : svga->gdcreg[0];
+                        if (svga->seqregs[2] & 0x20)
+                                svga->vram[addr + 2] = (val & 0x20) ? svga->gdcreg[1] : svga->gdcreg[0];
+                        if (svga->seqregs[2] & 0x10)
+                                svga->vram[addr + 3] = (val & 0x10) ? svga->gdcreg[1] : svga->gdcreg[0];
+                        if (svga->seqregs[2] & 0x08)
+                                svga->vram[addr + 4] = (val & 0x08) ? svga->gdcreg[1] : svga->gdcreg[0];
+                        if (svga->seqregs[2] & 0x04)
+                                svga->vram[addr + 5] = (val & 0x04) ? svga->gdcreg[1] : svga->gdcreg[0];
+                        if (svga->seqregs[2] & 0x02)
+                                svga->vram[addr + 6] = (val & 0x02) ? svga->gdcreg[1] : svga->gdcreg[0];
+                        if (svga->seqregs[2] & 0x01)
+                                svga->vram[addr + 7] = (val & 0x01) ? svga->gdcreg[1] : svga->gdcreg[0];
+                }
+                break;
+                
+                case 1:
+                if (svga->gdcreg[0xb] & GRB_WRITEMODE_EXT)
+                {
+                        if (writemask2 & 0x80) svga->vram[addr]       = svga->la;
+                        if (writemask2 & 0x40) svga->vram[addr | 0x1] = svga->lb;
+                        if (writemask2 & 0x20) svga->vram[addr | 0x2] = svga->lc;
+                        if (writemask2 & 0x10) svga->vram[addr | 0x3] = svga->ld;
+                        if (svga->gdcreg[0xb] & GRB_8B_LATCHES)
+                        {
+                                if (writemask2 & 0x08) svga->vram[addr | 0x4] = gd5429->latch_ext[0];
+                                if (writemask2 & 0x04) svga->vram[addr | 0x5] = gd5429->latch_ext[1];
+                                if (writemask2 & 0x02) svga->vram[addr | 0x6] = gd5429->latch_ext[2];
+                                if (writemask2 & 0x01) svga->vram[addr | 0x7] = gd5429->latch_ext[3];
+                        }
+                }
+                else
+                {
+                        if (writemask2 & 1) svga->vram[addr]       = svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld;
+                }
+                break;
+                case 0:
+                if (svga->gdcreg[3] & 7) 
+                        val = svga_rotate[svga->gdcreg[3] & 7][val];
+                if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled))
+                {
+                        if (writemask2 & 1) svga->vram[addr]       = val;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = val;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = val;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = val;
+                }
+                else
+                {
+                        if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0;
+                        else                     vala = val;
+                        if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0;
+                        else                     valb = val;
+                        if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0;
+                        else                     valc = val;
+                        if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0;
+                        else                     vald = val;
+
+                        switch (svga->gdcreg[3] & 0x18)
+                        {
+                                case 0: /*Set*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                                break;
+                                case 8: /*AND*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                                break;
+                                case 0x10: /*OR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                                break;
+                                case 0x18: /*XOR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                                break;
+                        }
+//                        pclog("- %02X %02X %02X %02X   %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
+                }
+                break;
+                case 2:
+                if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1])
+                {
+                        if (writemask2 & 1) svga->vram[addr]       = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                }
+                else
+                {
+                        vala = ((val & 1) ? 0xff : 0);
+                        valb = ((val & 2) ? 0xff : 0);
+                        valc = ((val & 4) ? 0xff : 0);
+                        vald = ((val & 8) ? 0xff : 0);
+                        switch (svga->gdcreg[3] & 0x18)
+                        {
+                                case 0: /*Set*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                                break;
+                                case 8: /*AND*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                                break;
+                                case 0x10: /*OR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                                break;
+                                case 0x18: /*XOR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                                break;
+                        }
+                }
+                break;
+                case 3:
+                if (svga->gdcreg[3] & 7) 
+                        val = svga_rotate[svga->gdcreg[3] & 7][val];
+                wm = svga->gdcreg[8];
+                svga->gdcreg[8] &= val;
+
+                vala = (svga->gdcreg[0] & 1) ? 0xff : 0;
+                valb = (svga->gdcreg[0] & 2) ? 0xff : 0;
+                valc = (svga->gdcreg[0] & 4) ? 0xff : 0;
+                vald = (svga->gdcreg[0] & 8) ? 0xff : 0;
+                switch (svga->gdcreg[3] & 0x18)
+                {
+                        case 0: /*Set*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                        break;
+                        case 8: /*AND*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                        break;
+                        case 0x10: /*OR*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                        break;
+                        case 0x18: /*XOR*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                        break;
+                }
+                svga->gdcreg[8] = wm;
+                break;
+        }
+}
+
+uint8_t gd5429_read_linear(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+        uint8_t temp, temp2, temp3, temp4;
+        int readplane = svga->readplane;
+        uint32_t latch_addr;
+        
+        cycles -= video_timing_read_b;
+        cycles_lost += video_timing_read_b;
+
+        egareads++;
+
+        if (svga->gdcreg[0xb] & GRB_X8_ADDRESSING)
+                latch_addr = (addr << 3) & svga->decode_mask;
+        else
+                latch_addr = (addr << 2) & svga->decode_mask;
+        
+        if (svga->gdcreg[0xb] & GRB_X8_ADDRESSING)
+                addr <<= 3;
+        else if (svga->chain4 || svga->fb_only)
+        {
+                addr &= svga->decode_mask;
+                if (addr >= svga->vram_max)
+                        return 0xff;
+                return svga->vram[addr & svga->vram_mask];
+        }
+        else if (svga->chain2_read)
+        {
+                readplane = (readplane & 2) | (addr & 1);
+                addr &= ~1;
+                addr <<= 2;
+        }
+        else
+                addr<<=2;
+
+        addr &= svga->decode_mask;
+
+        if (latch_addr >= svga->vram_max)
+        {
+                svga->la = svga->lb = svga->lc = svga->ld = 0xff;
+                if (svga->gdcreg[0xb] & GRB_8B_LATCHES)
+                        gd5429->latch_ext[0] = gd5429->latch_ext[1] = gd5429->latch_ext[2] = gd5429->latch_ext[3] = 0xff;
+        }
+        else
+        {
+                latch_addr &= svga->vram_mask;
+                svga->la = svga->vram[latch_addr];
+                svga->lb = svga->vram[latch_addr | 0x1];
+                svga->lc = svga->vram[latch_addr | 0x2];
+                svga->ld = svga->vram[latch_addr | 0x3];
+                if (svga->gdcreg[0xb] & GRB_8B_LATCHES)
+                {
+                        gd5429->latch_ext[0] = svga->vram[latch_addr | 0x4];
+                        gd5429->latch_ext[1] = svga->vram[latch_addr | 0x5];
+                        gd5429->latch_ext[2] = svga->vram[latch_addr | 0x6];
+                        gd5429->latch_ext[3] = svga->vram[latch_addr | 0x7];
+                }
+        }
+
+        if (addr >= svga->vram_max)
+                return 0xff;
+
+        addr &= svga->vram_mask;
+
+        if (svga->readmode)
+        {
+                temp   = svga->la;
+                temp  ^= (svga->colourcompare & 1) ? 0xff : 0;
+                temp  &= (svga->colournocare & 1)  ? 0xff : 0;
+                temp2  = svga->lb;
+                temp2 ^= (svga->colourcompare & 2) ? 0xff : 0;
+                temp2 &= (svga->colournocare & 2)  ? 0xff : 0;
+                temp3  = svga->lc;
+                temp3 ^= (svga->colourcompare & 4) ? 0xff : 0;
+                temp3 &= (svga->colournocare & 4)  ? 0xff : 0;
+                temp4  = svga->ld;
+                temp4 ^= (svga->colourcompare & 8) ? 0xff : 0;
+                temp4 &= (svga->colournocare & 8)  ? 0xff : 0;
+                return ~(temp | temp2 | temp3 | temp4);
+        }
+//printf("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane);
+        return svga->vram[addr | readplane];
+}
+
+static void gd5429_writeb_linear(uint32_t addr, uint8_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                svga_write_linear(addr, val, svga);
+        else
+                gd5429_write_linear(addr, val & 0xff, gd5429);
+}
+static void gd5429_writew_linear(uint32_t addr, uint16_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                svga_writew_linear(addr, val, svga);
+        else
+        {
+                gd5429_write_linear(addr, val & 0xff, gd5429);
+                gd5429_write_linear(addr+1, val >> 8, gd5429);
+        }
+}
+static void gd5429_writel_linear(uint32_t addr, uint32_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                svga_writel_linear(addr, val, svga);
+        else
+        {
+                gd5429_write_linear(addr, val & 0xff, gd5429);
+                gd5429_write_linear(addr+1, val >> 8, gd5429);
+                gd5429_write_linear(addr+2, val >> 16, gd5429);
+                gd5429_write_linear(addr+3, val >> 24, gd5429);
+        }
+}
+
+static uint8_t gd5429_readb_linear(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                return svga_read_linear(addr, &gd5429->svga);
+        return gd5429_read_linear(addr, gd5429);
+}
+static uint16_t gd5429_readw_linear(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                return svga_readw_linear(addr, &gd5429->svga);
+        return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8);
+}
+static uint32_t gd5429_readl_linear(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+
+        if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES)))
+                return svga_readl_linear(addr, &gd5429->svga);
+        return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8) |
+                (gd5429_read_linear(addr+2, gd5429) << 16) | (gd5429_read_linear(addr+3, gd5429) << 24);
+}
+
+
+void gd5429_start_blit(uint32_t cpu_dat, int count, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        svga_t *svga = &gd5429->svga;
+        int blt_mask = gd5429->blt.mask & 7;
+        int x_max = 0;
+
+        switch (gd5429->blt.depth)
+        {
+                case BLIT_DEPTH_8:
+                x_max = 8;
+                break;
+                case BLIT_DEPTH_16:
+                x_max = 16;
+                blt_mask *= 2;
+                break;
+                case BLIT_DEPTH_32:
+                x_max = 32;
+                blt_mask *= 4;
+                break;
+        }
+                
+//        pclog("gd5429_start_blit %i\n", count);
+        if (count == -1)
+        {
+                gd5429->blt.dst_addr_backup = gd5429->blt.dst_addr;
+                gd5429->blt.src_addr_backup = gd5429->blt.src_addr;
+                gd5429->blt.width_backup    = gd5429->blt.width;
+                gd5429->blt.height_internal = gd5429->blt.height;
+                gd5429->blt.x_count         = 0;
+                if ((gd5429->blt.mode & 0xc0) == 0xc0)
+                        gd5429->blt.y_count = gd5429->blt.src_addr & 7;
+                else
+                        gd5429->blt.y_count = 0;
+//                pclog("gd5429_start_blit : size %i, %i %i\n", gd5429->blt.width, gd5429->blt.height, gd5429->blt.x_count);
+                
+                if (gd5429->blt.mode & 0x04)
+                {
+//                        pclog("blt.mode & 0x04\n");
+                        if (!(svga->seqregs[7] & 0xf0))
+                        {
+                                mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l);
+                                mem_mapping_set_p(&svga->mapping, gd5429);
+                        }
+                        else
+                        {
+                                mem_mapping_set_handler(&gd5429->linear_mapping, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l);
+                                mem_mapping_set_p(&gd5429->linear_mapping, gd5429);
+                        }
+                        gd5429_recalc_mapping(gd5429);
+                        return;
+                }
+                else
+                {
+                        if (!(svga->seqregs[7] & 0xf0))
+                                mem_mapping_set_handler(&svga->mapping, gd5429_read, gd5429_readw, gd5429_readl, gd5429_write, gd5429_writew, gd5429_writel);
+                        else
+                                mem_mapping_set_handler(&gd5429->linear_mapping, gd5429_readb_linear, gd5429_readw_linear, gd5429_readl_linear, gd5429_writeb_linear, gd5429_writew_linear, gd5429_writel_linear);
+                        gd5429_recalc_mapping(gd5429);
+                }                
+        }
+        else if (gd5429->blt.height_internal == 0xffff)
+                return;
+        
+        while (count)
+        {
+                uint8_t src = 0, dst;
+                int mask = 0;
+                int shift;
+                
+                if (gd5429->blt.depth == BLIT_DEPTH_32)
+                        shift = (gd5429->blt.x_count & 3) * 8;
+                else if (gd5429->blt.depth == BLIT_DEPTH_8)
+                        shift = 0;
+                else
+                        shift = (gd5429->blt.x_count & 1) * 8;
+                
+                if (gd5429->blt.mode & 0x04)
+                {
+                        if (gd5429->blt.mode & 0x80)
+                        {                                
+                                mask = cpu_dat & 0x80;
+                                
+                                switch (gd5429->blt.depth)
+                                {
+                                        case BLIT_DEPTH_8:
+                                        src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col;
+                                        cpu_dat <<= 1;
+                                        count--;
+                                        break;
+                                        case BLIT_DEPTH_16:
+                                        src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift);
+                                        if (gd5429->blt.x_count & 1)
+                                        {
+                                                cpu_dat <<= 1;
+                                                count--;
+                                        }
+                                        break;
+                                        case BLIT_DEPTH_32:
+                                        src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift);
+                                        if ((gd5429->blt.x_count & 3) == 3)
+                                        {
+                                                cpu_dat <<= 1;
+                                                count--;
+                                        }
+                                        break;
+                                }
+                        }
+                        else
+                        {
+                                src = cpu_dat & 0xff;
+                                cpu_dat >>= 8;
+                                count -= 8;
+                                mask = 1;
+                        }
+                }
+                else
+                {
+                        switch (gd5429->blt.mode & 0xc0)
+                        {
+                                case 0x00:
+                                src = svga->vram[gd5429->blt.src_addr & svga->vram_mask];
+                                gd5429->blt.src_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1);
+                                mask = 1;
+                                break;
+                                case 0x40:
+                                switch (gd5429->blt.depth)
+                                {
+                                        case BLIT_DEPTH_8:
+                                        src = svga->vram[(gd5429->blt.src_addr & (svga->vram_mask & ~7)) + (gd5429->blt.y_count << 3) + (gd5429->blt.x_count & 7)];
+                                        break;
+                                        case BLIT_DEPTH_16:
+                                        src = svga->vram[(gd5429->blt.src_addr & (svga->vram_mask & ~3)) + (gd5429->blt.y_count << 4) + (gd5429->blt.x_count & 15)];
+                                        break;
+                                        case BLIT_DEPTH_32:
+                                        src = svga->vram[(gd5429->blt.src_addr & (svga->vram_mask & ~3)) + (gd5429->blt.y_count << 5) + (gd5429->blt.x_count & 31)];
+                                        break;
+                                }
+                                mask = 1;
+                                break;
+                                case 0x80:
+                                switch (gd5429->blt.depth)
+                                {
+                                        case BLIT_DEPTH_8:
+                                        mask = svga->vram[gd5429->blt.src_addr & svga->vram_mask] & (0x80 >> gd5429->blt.x_count);
+                                        src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col;
+                                        break;
+                                        case BLIT_DEPTH_16:
+                                        mask = svga->vram[gd5429->blt.src_addr & svga->vram_mask] & (0x80 >> (gd5429->blt.x_count >> 1));
+                                        src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift);
+                                        break;
+                                        case BLIT_DEPTH_32:
+                                        mask = svga->vram[gd5429->blt.src_addr & svga->vram_mask] & (0x80 >> (gd5429->blt.x_count >> 2));
+                                        src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift);
+                                        break;
+                                }
+                                break;
+                                case 0xc0:                                
+                                switch (gd5429->blt.depth)
+                                {
+                                        case BLIT_DEPTH_8:
+                                        mask = svga->vram[(gd5429->blt.src_addr & svga->vram_mask & ~7) | gd5429->blt.y_count] & (0x80 >> gd5429->blt.x_count);
+                                        src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col;
+                                        break;
+                                        case BLIT_DEPTH_16:
+                                        mask = svga->vram[(gd5429->blt.src_addr & svga->vram_mask & ~7) | gd5429->blt.y_count] & (0x80 >> (gd5429->blt.x_count >> 1));
+                                        src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift);
+                                        break;
+                                        case BLIT_DEPTH_32:
+                                        mask = svga->vram[(gd5429->blt.src_addr & svga->vram_mask & ~7) | gd5429->blt.y_count] & (0x80 >> (gd5429->blt.x_count >> 2));
+                                        src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift);
+                                        break;
+                                }
+                                break;
+                        }
+                        count--;                        
+                }
+                dst = svga->vram[gd5429->blt.dst_addr & svga->vram_mask];
+                svga->changedvram[(gd5429->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount;
+               
+//                pclog("Blit %i,%i %06X %06X  %06X %02X %02X  %02X %02X ", gd5429->blt.width, gd5429->blt.height_internal, gd5429->blt.src_addr, gd5429->blt.dst_addr, gd5429->blt.src_addr & svga->vram_mask, svga->vram[gd5429->blt.src_addr & svga->vram_mask], 0x80 >> (gd5429->blt.dst_addr & 7), src, dst);
+                switch (gd5429->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;                       
+                }
+                //pclog("%02X  %02X\n", dst, mask);
+                
+                if (gd5429->type <= CL_TYPE_GD5428)
+                {
+                        if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask &&
+                                        (!(gd5429->blt.mode & 0x08) || (dst & gd5429->blt.trans_mask) != gd5429->blt.trans_col))
+                                svga->vram[gd5429->blt.dst_addr & svga->vram_mask] = dst;
+                }
+                else
+                {
+                        if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask &&
+                            !((gd5429->blt.mode & 0x08) && !mask))
+                                svga->vram[gd5429->blt.dst_addr & svga->vram_mask] = dst;
+                }
+                
+                gd5429->blt.dst_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1);
+
+                gd5429->blt.x_count++;
+                if (gd5429->blt.x_count == x_max)
+                {
+                        gd5429->blt.x_count = 0;
+                        if ((gd5429->blt.mode & 0xc0) == 0x80)
+                                gd5429->blt.src_addr++;
+                }
+                
+                gd5429->blt.width--;
+                
+                if (gd5429->blt.width == 0xffff)
+                {
+                        gd5429->blt.width = gd5429->blt.width_backup;
+
+                        gd5429->blt.dst_addr = gd5429->blt.dst_addr_backup = gd5429->blt.dst_addr_backup + ((gd5429->blt.mode & 0x01) ? -gd5429->blt.dst_pitch : gd5429->blt.dst_pitch);
+                        
+                        switch (gd5429->blt.mode & 0xc0)
+                        {
+                                case 0x00:
+                                gd5429->blt.src_addr = gd5429->blt.src_addr_backup = gd5429->blt.src_addr_backup + ((gd5429->blt.mode & 0x01) ? -gd5429->blt.src_pitch : gd5429->blt.src_pitch);
+                                break;
+                                case 0x80:
+                                if (gd5429->blt.x_count != 0)
+                                        gd5429->blt.src_addr++;
+                                break;
+                        }
+
+                        gd5429->blt.x_count = 0;
+                        if (gd5429->blt.mode & 0x01)
+                                gd5429->blt.y_count = (gd5429->blt.y_count - 1) & 7;
+                        else
+                                gd5429->blt.y_count = (gd5429->blt.y_count + 1) & 7;
+                        
+                        gd5429->blt.height_internal--;
+                        if (gd5429->blt.height_internal == 0xffff)
+                        {
+                                if (gd5429->blt.mode & 0x04)
+                                {
+                                        if (!(svga->seqregs[7] & 0xf0))
+                                                mem_mapping_set_handler(&svga->mapping, gd5429_read, gd5429_readw, gd5429_readl, gd5429_write, gd5429_writew, gd5429_writel);
+                                        else
+                                                mem_mapping_set_handler(&gd5429->linear_mapping, gd5429_readb_linear, gd5429_readw_linear, gd5429_readl_linear, gd5429_writeb_linear, gd5429_writew_linear, gd5429_writel_linear);
+//                                        mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL);
+//                                        mem_mapping_set_p(&gd5429->svga.mapping, gd5429);
+                                        gd5429_recalc_mapping(gd5429);
+                                }
+                                return;
+                        }
+                                
+                        if (gd5429->blt.mode & 0x04)
+                                return;
+                }                        
+        }
+}
+
+static void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+        if ((addr & ~0xff) == 0xb8000)
+        {
+        //        pclog("MMIO write %08X %02X\n", addr, val);
+                switch (addr & 0xff)
+                {
+                        case 0x00:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xffffff00) | val;
+                        else
+                                gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xff00) | val;
+                        break;
+                        case 0x01:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xffff00ff) | (val << 8);
+                        else
+                                gd5429->blt.bg_col = (gd5429->blt.bg_col & 0x00ff) | (val << 8);
+                        break;
+                        case 0x02:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xff00ffff) | (val << 16);
+                        break;
+                        case 0x03:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.bg_col = (gd5429->blt.bg_col & 0x00ffffff) | (val << 24);
+                        break;
+
+                        case 0x04:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xffffff00) | val;
+                        else
+                                gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xff00) | val;
+                        break;
+                        case 0x05:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xffff00ff) | (val << 8);
+                        else
+                                gd5429->blt.fg_col = (gd5429->blt.fg_col & 0x00ff) | (val << 8);
+                        break;
+                        case 0x06:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xff00ffff) | (val << 16);
+                        break;
+                        case 0x07:
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.fg_col = (gd5429->blt.fg_col & 0x00ffffff) | (val << 24);
+                        break;
+
+                        case 0x08:
+                        gd5429->blt.width = (gd5429->blt.width & 0xff00) | val;
+                        break;
+                        case 0x09:
+                        gd5429->blt.width = (gd5429->blt.width & 0x00ff) | (val << 8);
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.width &= 0x1fff;
+                        else
+                                gd5429->blt.width &= 0x07ff;
+                        break;
+                        case 0x0a:
+                        gd5429->blt.height = (gd5429->blt.height & 0xff00) | val;
+                        break;
+                        case 0x0b:
+                        gd5429->blt.height = (gd5429->blt.height & 0x00ff) | (val << 8);
+                        gd5429->blt.height &= 0x03ff;
+                        break;
+                        case 0x0c:
+                        gd5429->blt.dst_pitch = (gd5429->blt.dst_pitch & 0xff00) | val;
+                        break;
+                        case 0x0d:
+                        gd5429->blt.dst_pitch = (gd5429->blt.dst_pitch & 0x00ff) | (val << 8);
+                        break;
+                        case 0x0e:
+                        gd5429->blt.src_pitch = (gd5429->blt.src_pitch & 0xff00) | val;
+                        break;
+                        case 0x0f:
+                        gd5429->blt.src_pitch = (gd5429->blt.src_pitch & 0x00ff) | (val << 8);
+                        break;
+                
+                        case 0x10:
+                        gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0xffff00) | val;
+                        break;
+                        case 0x11:
+                        gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0xff00ff) | (val << 8);
+                        break;
+                        case 0x12:
+                        gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0x00ffff) | (val << 16);
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.dst_addr &= 0x3fffff;
+                        else
+                                gd5429->blt.dst_addr &= 0x1fffff;
+                        break;
+
+                        case 0x14:
+                        gd5429->blt.src_addr = (gd5429->blt.src_addr & 0xffff00) | val;
+                        break;
+                        case 0x15:
+                        gd5429->blt.src_addr = (gd5429->blt.src_addr & 0xff00ff) | (val << 8);
+                        break;
+                        case 0x16:
+                        gd5429->blt.src_addr = (gd5429->blt.src_addr & 0x00ffff) | (val << 16);
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.src_addr &= 0x3fffff;
+                        else
+                                gd5429->blt.src_addr &= 0x1fffff;
+                        break;
+
+                        case 0x17:
+                        gd5429->blt.mask = val;
+                        break;
+                        case 0x18:
+                        gd5429->blt.mode = val;
+                        if (gd5429->type >= CL_TYPE_GD5434)
+                                gd5429->blt.depth = (val >> 4) & 3;
+                        else
+                                gd5429->blt.depth = (val >> 4) & 1;
+                        break;
+                
+                        case 0x1a:
+                        gd5429->blt.rop = val;
+                        break;
+                
+                        case 0x40:
+                        if (val & 0x02)
+                                gd5429_start_blit(0, -1, gd5429);
+                        break;
+                }
+        }
+        else if (gd5429->mmio_vram_overlap)
+                gd5429_write(addr, val, gd5429);
+}
+static void gd5429_mmio_writew(uint32_t addr, uint16_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+        if ((addr & ~0xff) == 0xb8000)
+        {
+                gd5429_mmio_write(addr,     val & 0xff, gd5429);
+                gd5429_mmio_write(addr + 1, val >> 8, gd5429);
+        }
+        else if (gd5429->mmio_vram_overlap)
+                gd5429_writew(addr, val, gd5429);
+}
+static void gd5429_mmio_writel(uint32_t addr, uint32_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+        if ((addr & ~0xff) == 0xb8000)
+        {
+                gd5429_mmio_writew(addr,     val & 0xffff, gd5429);
+                gd5429_mmio_writew(addr + 2, val >> 16, gd5429);
+        }
+        else if (gd5429->mmio_vram_overlap)
+                gd5429_writel(addr, val, gd5429);
+}
+
+static uint8_t gd5429_mmio_read(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        
+        if ((addr & ~0xff) == 0xb8000)
+        {
+//        pclog("MMIO read %08X\n", addr);
+                switch (addr & 0xff)
+                {
+                        case 0x40: /*BLT status*/
+                        return 0;
+                }
+                return 0xff; /*All other registers read-only*/
+        }
+        if (gd5429->mmio_vram_overlap)
+                return gd5429_read(addr, gd5429);
+        return 0xff;
+}
+static uint16_t gd5429_mmio_readw(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        
+        if ((addr & ~0xff) == 0xb8000)
+                return gd5429_mmio_read(addr, gd5429) | (gd5429_mmio_read(addr+1, gd5429) << 8);
+        if (gd5429->mmio_vram_overlap)
+                return gd5429_readw(addr, gd5429);
+        return 0xffff;
+}
+static uint32_t gd5429_mmio_readl(uint32_t addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        
+        if ((addr & ~0xff) == 0xb8000)
+                return gd5429_mmio_readw(addr, gd5429) | (gd5429_mmio_readw(addr+2, gd5429) << 16);
+        if (gd5429->mmio_vram_overlap)
+                return gd5429_readl(addr, gd5429);
+        return 0xffffffff;
+}
+
+void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+//        pclog("gd5429_blt_write_w %08X %08X\n", addr, val);
+        if (!gd5429->blt.mem_word_sel)
+                gd5429->blt.mem_word_save = val;
+        else
+                gd5429_start_blit(gd5429->blt.mem_word_save | (val << 16), 32, p);
+        gd5429->blt.mem_word_sel = !gd5429->blt.mem_word_sel;
+
+}
+
+void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+        gd5429->blt.mem_word_sel = 0;
+//        pclog("gd5429_blt_write_l %08X %08X  %04X %04X\n", addr, val,  ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00), ((val >> 24) & 0x00ff) | ((val >> 8) & 0xff00));
+        if ((gd5429->blt.mode & 0x84) == 0x84)
+        {
+                gd5429_start_blit( val        & 0xff, 8, p);
+                gd5429_start_blit((val >> 8)  & 0xff, 8, p);
+                gd5429_start_blit((val >> 16) & 0xff, 8, p);
+                gd5429_start_blit((val >> 24) & 0xff, 8, p);
+        }
+        else
+                gd5429_start_blit(val, 32, p);
+}
+
+uint8_t ibm_gd5428_mca_read(int port, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+//        pclog("gd5429_pro_mcv_read: port=%04x %02x %04x:%04x\n", port, gd5429->pos_regs[port & 7], CS, cpu_state.pc);
+
+        return gd5429->pos_regs[port & 7];
+}
+
+static void ibm_gd5428_mapping_update(gd5429_t *gd5429)
+{
+        gd5429_recalc_mapping(gd5429);
+
+        io_removehandler(0x03a0, 0x0023, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+        io_removehandler(0x03c4, 0x001c, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+        if ((gd5429->pos_regs[2] & 0x01) && gd5429->vidsys_ena)
+        {
+//                pclog("  GD5429 enable registers\n");
+                io_sethandler(0x03c0, 0x0003, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                io_sethandler(0x03c4, 0x001c, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                if (!(gd5429->svga.miscout & 1))
+                        io_sethandler(0x03a0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                gd5429->svga.override = 0;
+                if (mb_vga)
+                        svga_set_override(mb_vga, 1);
+        }
+        else
+        {
+//                pclog("  GD5429 disable registers\n");
+                gd5429->svga.override = 1;
+                if (mb_vga)
+                        svga_set_override(mb_vga, 0);
+        }
+}
+
+void ibm_gd5428_mca_write(int port, uint8_t val, void *p)
+{
+//        svga_set_override(voodoo->svga, val & 1);
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+//        pclog("gd5429_pro_mcv_write: port=%04x val=%02x\n", port, val);
+        
+        if (port < 0x102)
+                return;
+        gd5429->pos_regs[port & 7] = val;
+        
+        if ((port & 7) == 2)
+        {
+                mem_mapping_disable(&gd5429->bios_rom.mapping);
+                io_removehandler(0x03c3, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                if (gd5429->pos_regs[2] & 0x01)
+                {
+//                        pclog("Enable BIOS mapping\n");
+                        mem_mapping_enable(&gd5429->bios_rom.mapping);
+                        io_sethandler(0x03c3, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                }
+//                else
+//                        pclog("Disable BIOS mapping\n");
+        }
+        
+        ibm_gd5428_mapping_update(gd5429);
+}
+
+static void ibm_gd5428_mca_reset(void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+//        pclog("ibm_gd5428_mca_reset\n");
+        gd5429->vidsys_ena = 0;
+        ibm_gd5428_mca_write(0x102, 0, gd5429);
+}
+
+static uint8_t cl_pci_read(int func, int addr, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+//        pclog("CL PCI read %08X\n", addr);
+        switch (addr)
+        {
+                case 0x00: return 0x13; /*Cirrus Logic*/
+                case 0x01: return 0x10;
+                
+                case 0x02:
+                switch (gd5429->type)
+                {
+                        case CL_TYPE_GD5430:
+                        return 0xa0;
+                        case CL_TYPE_GD5434:
+                        return 0xa8;
+                }
+                return 0xff;
+                case 0x03: return 0x00;
+                
+                case PCI_REG_COMMAND:
+                return gd5429->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/
+
+                case 0x07: return 0 << 1; /*Fast DEVSEL timing*/
+                
+                case 0x08: return 0; /*Revision ID*/
+                case 0x09: return 0; /*Programming interface*/
+                
+                case 0x0a: return 0x00; /*Supports VGA interface*/
+                case 0x0b: return 0x03;
+                
+                case 0x10: return 0x08; /*Linear frame buffer address*/
+                case 0x11: return 0x00;
+                case 0x12: return 0x00;
+                case 0x13: return gd5429->lfb_base >> 24;
+
+                case 0x30: return gd5429->pci_regs[0x30] & 0x01; /*BIOS ROM address*/
+                case 0x31: return 0x00;
+                case 0x32: return gd5429->pci_regs[0x32];
+                case 0x33: return gd5429->pci_regs[0x33];
+                
+                case 0x3c: return gd5429->int_line;
+                case 0x3d: return PCI_INTA;
+        }
+        return 0;
+}
+
+static void cl_pci_write(int func, int addr, uint8_t val, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+//        pclog("cl_pci_write: addr=%02x val=%02x\n", addr, val);
+        switch (addr)
+        {
+                case PCI_REG_COMMAND:
+                gd5429->pci_regs[PCI_REG_COMMAND] = val & 0x23;
+                io_removehandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                if (val & PCI_COMMAND_IO)
+                        io_sethandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                gd5429_recalc_mapping(gd5429);
+                break;
+                
+                case 0x13: 
+                gd5429->lfb_base = val << 24;
+                gd5429_recalc_mapping(gd5429); 
+                break;                
+
+                case 0x30: case 0x32: case 0x33:
+                gd5429->pci_regs[addr] = val;
+                if (gd5429->pci_regs[0x30] & 0x01)
+                {
+                        uint32_t addr = (gd5429->pci_regs[0x32] << 16) | (gd5429->pci_regs[0x33] << 24);
+                        mem_mapping_set_addr(&gd5429->bios_rom.mapping, addr, 0x8000);
+                }
+                else
+                        mem_mapping_disable(&gd5429->bios_rom.mapping);
+                return;
+                
+                case 0x3c:
+                gd5429->int_line = val;
+                return;
+        }
+}
+
+static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size)
+{
+        gd5429_t *gd5429 = malloc(sizeof(gd5429_t));
+        svga_t *svga = &gd5429->svga;
+        int vram_size;
+        memset(gd5429, 0, sizeof(gd5429_t));
+        
+        if (force_vram_size)
+                vram_size = force_vram_size;
+        else
+                vram_size = device_get_config_int("memory");
+        if (vram_size >= 256)
+                gd5429->vram_mask = (vram_size << 10) - 1;
+        else
+                gd5429->vram_mask = (vram_size << 20) - 1;
+        
+        gd5429->type = type;
+
+        if (fn)
+                rom_init(&gd5429->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+        
+        svga_init(&gd5429->svga, gd5429, (vram_size >= 256) ? (vram_size << 10) : (vram_size << 20),
+                   gd5429_recalctimings,
+                   gd5429_in, gd5429_out,
+                   gd5429_hwcursor_draw,
+                   NULL);
+
+        mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, gd5429_readw, gd5429_readl, gd5429_write, gd5429_writew, gd5429_writel);
+        mem_mapping_set_p(&gd5429->svga.mapping, gd5429);
+
+        mem_mapping_add(&gd5429->mmio_mapping, 0, 0, gd5429_mmio_read, gd5429_mmio_readw, gd5429_mmio_readl, gd5429_mmio_write, gd5429_mmio_writew, gd5429_mmio_writel,  NULL, 0, gd5429);
+        mem_mapping_add(&gd5429->linear_mapping, 0, 0, gd5429_readb_linear, gd5429_readw_linear, gd5429_readl_linear, gd5429_writeb_linear, gd5429_writew_linear, gd5429_writel_linear,  NULL, 0, gd5429);
+
+        io_sethandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+        if (type == CL_TYPE_AVGA2)
+        {
+                io_sethandler(0x0102, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                io_sethandler(0x46e8, 0x0002, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+                svga->decode_mask = svga->vram_mask;
+        }
+
+        svga->hwcursor.yoff = 32;
+        svga->hwcursor.xoff = 0;
+
+        gd5429->bank[1] = 0x8000;
+
+        /*Default VCLK values*/
+        svga->seqregs[0xb] = 0x66;
+        svga->seqregs[0xc] = 0x5b;
+        svga->seqregs[0xd] = 0x45;
+        svga->seqregs[0xe] = 0x7e;
+        svga->seqregs[0x1b] = 0x3b;
+        svga->seqregs[0x1c] = 0x2f;
+        svga->seqregs[0x1d] = 0x30;
+        svga->seqregs[0x1e] = 0x33;
+
+        if (PCI && type >= CL_TYPE_GD5430)
+        {
+                if (pci_card != -1)
+                {
+                        pci_add_specific(pci_card, cl_pci_read, cl_pci_write, gd5429);
+                        gd5429->card = pci_card;
+                }
+                else
+                        gd5429->card = pci_add(cl_pci_read, cl_pci_write, gd5429);
+
+                gd5429->pci_regs[0x04] = 7;
+        
+                gd5429->pci_regs[0x30] = 0x00;
+                gd5429->pci_regs[0x32] = 0x0c;
+                gd5429->pci_regs[0x33] = 0x00;
+        }
+        
+        return gd5429;
+}
+
+
+static void *avga2_init()
+{
+        return cl_init(CL_TYPE_AVGA2, "avga2vram.vbi", -1, 0);
+}
+static void *avga2_cbm_sl386sx_init()
+{
+        return cl_init(CL_TYPE_AVGA2, "cbm_sl386sx25/c000.rom", -1, 0);
+}
+static void *gd5426_ps1_init()
+{
+        return cl_init(CL_TYPE_GD5426, NULL, -1, 1);
+}
+static void *gd5428_init()
+{
+        return cl_init(CL_TYPE_GD5428, "Machspeed_VGA_GUI_2100_VLB.vbi", -1, 0);
+}
+static void *ibm_gd5428_init()
+{
+        gd5429_t *gd5429;
+        svga_t *mb_vga = svga_get_pri();
+
+        gd5429 = cl_init(CL_TYPE_GD5428, "SVGA141.ROM", -1, 1); /*Only supports 1MB*/
+        gd5429->mb_vga = mb_vga;
+        
+        mca_add(ibm_gd5428_mca_read, ibm_gd5428_mca_write, ibm_gd5428_mca_reset, gd5429);
+        gd5429->pos_regs[0] = 0x7b;
+        gd5429->pos_regs[1] = 0x91;
+        gd5429->pos_regs[2] = 0;
+        
+        gd5429_recalc_mapping(gd5429);
+        io_removehandler(0x03a0, 0x0040, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+        gd5429->svga.override = 1;
+        mem_mapping_disable(&gd5429->bios_rom.mapping);
+        io_sethandler(0x46e8, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
+
+        return gd5429;
+}
+static void *gd5429_init()
+{
+        return cl_init(CL_TYPE_GD5429, "5429.vbi", -1, 0);
+}
+static void *gd5430_init()
+{
+        return cl_init(CL_TYPE_GD5430, "gd5430/pci.bin", -1, 0);
+}
+static void *gd5430_pb570_init()
+{
+        return cl_init(CL_TYPE_GD5430, "pb570/gd5430.bin", 8, 0);
+}
+static void *gd5434_init()
+{
+        return cl_init(CL_TYPE_GD5434, "gd5434.bin", -1, 0);
+}
+static void *gd5434_pb520r_init()
+{
+        return cl_init(CL_TYPE_GD5434, "pb520r/gd5434.bin", 3, 0);
+}
+
+static int avga2_available()
+{
+        return rom_present("avga2vram.vbi");
+}
+static int gd5428_available()
+{
+        return rom_present("Machspeed_VGA_GUI_2100_VLB.vbi");
+}
+static int ibm_gd5428_available()
+{
+        return rom_present(/*"FILE.ROM"*/"SVGA141.ROM");
+}
+static int gd5429_available()
+{
+        return rom_present("5429.vbi");
+}
+static int gd5430_available()
+{
+        return rom_present("gd5430/pci.bin");
+}
+static int gd5434_available()
+{
+        return rom_present("gd5434.bin");
+}
+
+void gd5429_close(void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+        svga_close(&gd5429->svga);
+        
+        free(gd5429);
+}
+
+void gd5429_speed_changed(void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        
+        svga_recalctimings(&gd5429->svga);
+}
+
+void gd5429_force_redraw(void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+
+        gd5429->svga.fullchange = changeframecount;
+}
+
+void gd5429_add_status_info(char *s, int max_len, void *p)
+{
+        gd5429_t *gd5429 = (gd5429_t *)p;
+        
+        svga_add_status_info(s, max_len, &gd5429->svga);
+}
+
+static device_config_t avga2_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "256 kB",
+                                .value = 256
+                        },
+                        {
+                                .description = "512 kB",
+                                .value = 512
+                        },
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 512
+        },
+        {
+                .type = -1
+        }
+};
+
+static device_config_t gd5429_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "1 MB",
+                                .value = 1
+                        },
+                        {
+                                .description = "2 MB",
+                                .value = 2
+                        },
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 2
+        },
+        {
+                .type = -1
+        }
+};
+static device_config_t gd5434_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "2 MB",
+                                .value = 2
+                        },
+                        {
+                                .description = "4 MB",
+                                .value = 4
+                        },
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 4
+        },
+        {
+                .type = -1
+        }
+};
+
+device_t avga2_device =
+{
+        "AVGA2 / Cirrus Logic GD5402",
+        0,
+        avga2_init,
+        gd5429_close,
+        avga2_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        avga2_config
+};
+
+device_t avga2_cbm_sl386sx_device =
+{
+        "AVGA2 (Commodore SL386SX-25)",
+        0,
+        avga2_cbm_sl386sx_init,
+        gd5429_close,
+        gd5430_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        avga2_config
+};
+
+device_t gd5426_ps1_device =
+{
+        "Cirrus Logic GD5426 (IBM PS/1)",
+        0,
+        gd5426_ps1_init,
+        gd5429_close,
+        NULL,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        NULL
+};
+
+device_t gd5428_device =
+{
+        "Cirrus Logic GD5428",
+        0,
+        gd5428_init,
+        gd5429_close,
+        gd5428_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        gd5429_config
+};
+
+device_t ibm_gd5428_device =
+{
+        "IBM 1MB SVGA Adapter/A (Cirrus Logic GD5428)",
+        DEVICE_MCA,
+        ibm_gd5428_init,
+        gd5429_close,
+        ibm_gd5428_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        NULL
+};
+
+device_t gd5429_device =
+{
+        "Cirrus Logic GD5429",
+        0,
+        gd5429_init,
+        gd5429_close,
+        gd5429_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        gd5429_config
+};
+
+device_t gd5430_device =
+{
+        "Cirrus Logic GD5430",
+        0,
+        gd5430_init,
+        gd5429_close,
+        gd5430_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        gd5429_config
+};
+
+device_t gd5430_pb570_device =
+{
+        "Cirrus Logic GD5430 (PB570)",
+        0,
+        gd5430_pb570_init,
+        gd5429_close,
+        gd5430_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        gd5429_config
+};
+
+device_t gd5434_device =
+{
+        "Cirrus Logic GD5434",
+        0,
+        gd5434_init,
+        gd5429_close,
+        gd5434_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        gd5434_config
+};
+
+device_t gd5434_pb520r_device =
+{
+        "Cirrus Logic GD5434 (PB520r)",
+        0,
+        gd5434_pb520r_init,
+        gd5429_close,
+        gd5434_available,
+        gd5429_speed_changed,
+        gd5429_force_redraw,
+        gd5429_add_status_info,
+        gd5434_config
+};
diff --git a/pcem/vid_cl5429.h b/pcem/vid_cl5429.h
new file mode 100644 (file)
index 0000000..70b0321
--- /dev/null
@@ -0,0 +1,11 @@
+extern device_t avga2_device;
+extern device_t avga2_cbm_sl386sx_device;
+extern device_t gd5426_ps1_device;
+extern device_t gd5428_device;
+extern device_t ibm_gd5428_device;
+extern device_t gd5429_device;
+extern device_t gd5429_reply_m25_device;
+extern device_t gd5430_device;
+extern device_t gd5430_pb570_device;
+extern device_t gd5434_device;
+extern device_t gd5434_pb520r_device;
diff --git a/pcem/vid_s3.cpp b/pcem/vid_s3.cpp
new file mode 100644 (file)
index 0000000..338b39a
--- /dev/null
@@ -0,0 +1,3069 @@
+/*S3 emulation*/
+#include <stdlib.h>
+#include "ibm.h"
+#include "device.h"
+#include "io.h"
+#include "mem.h"
+#include "pci.h"
+#include "rom.h"
+#include "thread.h"
+#include "video.h"
+#include "vid_s3.h"
+#include "vid_svga.h"
+#include "vid_svga_render.h"
+#include "vid_sdac_ramdac.h"
+
+enum
+{
+        S3_VISION864,
+        S3_TRIO32,
+        S3_TRIO64
+};
+
+enum
+{
+        VRAM_4MB = 0,
+        VRAM_8MB = 3,
+        VRAM_2MB = 4,
+        VRAM_1MB = 6,
+        VRAM_512KB = 7
+};
+
+#define FIFO_SIZE 65536
+#define FIFO_MASK (FIFO_SIZE - 1)
+#define FIFO_ENTRY_SIZE (1 << 31)
+
+#define FIFO_ENTRIES (s3->fifo_write_idx - s3->fifo_read_idx)
+#define FIFO_FULL    ((s3->fifo_write_idx - s3->fifo_read_idx) >= FIFO_SIZE)
+#define FIFO_EMPTY   (s3->fifo_read_idx == s3->fifo_write_idx)
+
+#define FIFO_TYPE 0xff000000
+#define FIFO_ADDR 0x00ffffff
+
+enum
+{
+        FIFO_INVALID     = (0x00 << 24),
+        FIFO_WRITE_BYTE  = (0x01 << 24),
+        FIFO_WRITE_WORD  = (0x02 << 24),
+        FIFO_WRITE_DWORD = (0x03 << 24),
+        FIFO_OUT_BYTE    = (0x04 << 24),
+        FIFO_OUT_WORD    = (0x05 << 24),
+        FIFO_OUT_DWORD   = (0x06 << 24)
+};
+
+typedef struct
+{
+        uint32_t addr_type;
+        uint32_t val;
+} fifo_entry_t;
+
+typedef struct s3_t
+{
+        mem_mapping_t linear_mapping;
+        mem_mapping_t mmio_mapping;
+        
+        rom_t bios_rom;
+        
+        svga_t svga;
+        sdac_ramdac_t ramdac;
+
+        uint8_t bank;
+        uint8_t ma_ext;
+        int width;
+        int bpp;
+
+        int chip;
+        
+        uint8_t id, id_ext, id_ext_pci;
+        
+        uint8_t int_line;
+        
+        int packed_mmio;
+
+        uint32_t linear_base, linear_size;
+        
+        uint8_t pci_regs[256];
+        int card;
+
+        uint32_t vram_mask;
+        
+        float (*getclock)(int clock, void *p);
+        void *getclock_p;
+
+        struct
+        {
+                uint8_t subsys_cntl;
+                uint8_t setup_md;
+                uint8_t advfunc_cntl;
+                uint16_t cur_y, cur_y2;
+                uint16_t cur_x, cur_x2;
+                uint16_t x2;
+                 int16_t desty_axstp, desty_axstp2;
+                 int16_t destx_distp;
+                 int16_t err_term, err_term2;
+                 int16_t maj_axis_pcnt, maj_axis_pcnt2;
+                uint16_t cmd;
+                uint16_t short_stroke;
+                uint32_t bkgd_color;
+                uint32_t frgd_color;
+                uint32_t wrt_mask;
+                uint32_t rd_mask;
+                uint32_t color_cmp;
+                uint8_t bkgd_mix;
+                uint8_t frgd_mix;
+                uint16_t multifunc_cntl;
+                uint16_t multifunc[16];
+                uint8_t pix_trans[4];
+        
+                int cx, cy;
+                int sx, sy;
+                int dx, dy;
+                uint32_t src, dest, pattern;
+                int pix_trans_count;
+                
+                int poly_cx, poly_cx2;
+                int poly_cy, poly_cy2;
+                int point_1_updated, point_2_updated;
+                int poly_dx1, poly_dx2;
+                int poly_x;
+        
+                uint32_t dat_buf;
+                int dat_count;
+        } accel;
+
+        fifo_entry_t fifo[FIFO_SIZE];
+        volatile int fifo_read_idx, fifo_write_idx;
+
+        thread_t *fifo_thread;
+        event_t *wake_fifo_thread;
+        event_t *fifo_not_full_event;
+        
+        int blitter_busy;
+        uint64_t blitter_time;
+        uint64_t status_time;
+        
+        uint8_t subsys_cntl, subsys_stat;
+        
+        uint32_t hwc_fg_col, hwc_bg_col;
+        int hwc_col_stack_pos;
+        
+        volatile int force_busy;
+} s3_t;
+
+#define INT_VSY      (1 << 0)
+#define INT_GE_BSY   (1 << 1)
+#define INT_FIFO_OVR (1 << 2)
+#define INT_FIFO_EMP (1 << 3)
+#define INT_MASK     0xf
+
+void s3_updatemapping();
+
+void s3_accel_write(uint32_t addr, uint8_t val, void *p);
+void s3_accel_write_w(uint32_t addr, uint16_t val, void *p);
+void s3_accel_write_l(uint32_t addr, uint32_t val, void *p);
+uint8_t s3_accel_read(uint32_t addr, void *p);
+
+static inline void wake_fifo_thread(s3_t *s3)
+{
+        thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
+}
+
+static void s3_wait_fifo_idle(s3_t *s3)
+{
+        while (!FIFO_EMPTY)
+        {
+                wake_fifo_thread(s3);
+                thread_wait_event(s3->fifo_not_full_event, 1);
+        }
+}
+
+static void s3_update_irqs(s3_t *s3)
+{
+        if (s3->subsys_cntl & s3->subsys_stat & INT_MASK)
+                pci_set_irq(s3->card, PCI_INTA);
+        else
+                pci_clear_irq(s3->card, PCI_INTA);
+}
+
+void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3);
+
+#define WRITE8(addr, var, val)  switch ((addr) & 3)                                             \
+                                {                                                               \
+                                        case 0: var = (var & 0xffffff00) | (val);         break;  \
+                                        case 1: var = (var & 0xffff00ff) | ((val) << 8);  break;  \
+                                        case 2: var = (var & 0xff00ffff) | ((val) << 16); break;  \
+                                        case 3: var = (var & 0x00ffffff) | ((val) << 24); break;  \
+                                }
+
+static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val)
+{
+        switch (port)
+        {
+                case 0x82e8:
+                s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val;
+                s3->accel.poly_cy = s3->accel.cur_y;
+                break;
+                case 0x82e9:
+                s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8);
+                s3->accel.poly_cy = s3->accel.cur_y;
+                break;
+                case 0x82ea:
+                s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val;
+                s3->accel.poly_cy2 = s3->accel.cur_y2;
+                break;
+                case 0x82eb:
+                s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8);
+                s3->accel.poly_cy2 = s3->accel.cur_y2;
+                break;
+                
+                case 0x86e8:
+                s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val;
+                s3->accel.poly_cx = s3->accel.cur_x << 20;
+                s3->accel.poly_x = s3->accel.poly_cx >> 20;
+                break;
+                case 0x86e9:
+                s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8);
+                s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20;
+                s3->accel.poly_x = s3->accel.poly_cx >> 20;
+                break;
+                case 0x86ea:
+                s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val;
+                s3->accel.poly_cx2 = s3->accel.cur_x2 << 20;
+                break;
+                case 0x86eb:
+                s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x1f) << 8);
+                s3->accel.poly_cx2 = s3->accel.cur_x2 << 20;
+                break;
+                
+                case 0x8ae8:
+                s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val;
+                s3->accel.point_1_updated = 1;
+                break;
+                case 0x8ae9:
+                s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8);
+                if (val & 0x20)
+                        s3->accel.desty_axstp |= ~0x3fff;
+                s3->accel.point_1_updated = 1;
+                break;
+                case 0x8aea:
+                s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val;
+                s3->accel.point_2_updated = 1;
+                break;
+                case 0x8aeb:
+                s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0xff) | ((val & 0x3f) << 8);
+                if (val & 0x20)
+                        s3->accel.desty_axstp2 |= ~0x3fff;
+                s3->accel.point_2_updated = 1;
+                break;
+                
+                case 0x8ee8:
+                s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val;
+                s3->accel.point_1_updated = 1;
+                break;
+                case 0x8ee9:
+                s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8);
+                if (val & 0x20)
+                        s3->accel.destx_distp |= ~0x3fff;
+                s3->accel.point_1_updated = 1;
+                break;
+                case 0x8eea:
+                s3->accel.x2 = (s3->accel.x2 & 0xf00) | val;
+                s3->accel.point_2_updated = 1;
+                break;
+                case 0x8eeb:
+                s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8);
+                s3->accel.point_2_updated = 1;
+                break;
+                
+                case 0x92e8:
+                s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val;
+                break;
+                case 0x92e9:
+                s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8);
+                if (val & 0x20)
+                   s3->accel.err_term |= ~0x3fff;
+                break;
+                case 0x92ea:
+                s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val;
+                break;
+                case 0x92eb:
+                s3->accel.err_term2 = (s3->accel.err_term2 & 0xff) | ((val & 0x3f) << 8);
+                if (val & 0x20)
+                        s3->accel.err_term2 |= ~0x3fff;
+                break;
+
+                case 0x96e8:
+                s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val;
+                break;
+                case 0x96e9:
+                s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8);
+                if (val & 0x08)
+                   s3->accel.maj_axis_pcnt |= ~0x0fff;
+                break;
+                case 0x96ea:
+                s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val;
+                break;
+                case 0x96eb:
+                s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xff) | ((val & 0x0f) << 8);
+                if (val & 0x08)
+                        s3->accel.maj_axis_pcnt2 |= ~0x0fff;
+                break;
+
+                case 0x9ae8:
+                s3->accel.cmd = (s3->accel.cmd & 0xff00) | val;
+                break;
+                case 0x9ae9:
+                s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8);
+                s3_accel_start(-1, 0, 0xffffffff, 0, s3);
+                s3->accel.pix_trans_count = 0;
+                s3->accel.multifunc[0xe] &= ~0x10; /*hack*/
+                break;
+
+                case 0x9ee8:
+                s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val;
+                break;
+                case 0x9ee9:
+                s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8);
+                break;
+
+                case 0xa2e8:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16);
+                else
+                        s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val;
+                break;
+                case 0xa2e9:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24);
+                else
+                        s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8);
+                if (!(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                break;
+                case 0xa2ea:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16);
+                        else
+                                s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val;
+                }
+                break;
+                case 0xa2eb:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24);
+                        else
+                                s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8);
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                }
+                break;
+
+                case 0xa6e8:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16);
+                else
+                        s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val;
+                break;
+                case 0xa6e9:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24);
+                else
+                        s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8);
+                if (!(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                break;
+                case 0xa6ea:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16);
+                        else
+                                s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val;
+                }
+                break;
+                case 0xa6eb:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24);
+                        else
+                                s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8);
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                }
+                break;
+
+                case 0xaae8:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16);
+                else
+                        s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val;
+                break;
+                case 0xaae9:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24);
+                else
+                        s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8);
+                if (!(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                break;
+                case 0xaaea:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16);
+                        else
+                                s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val;
+                }
+                break;
+                case 0xaaeb:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24);
+                        else
+                                s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8);
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                }
+                break;
+
+                case 0xaee8:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16);
+                else
+                        s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val;
+                break;
+                case 0xaee9:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24);
+                else
+                        s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8);
+                if (!(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                break;
+                case 0xaeea:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16);
+                        else
+                                s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val;
+                }
+                break;
+                case 0xaeeb:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24);
+                        else
+                                s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8);
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                }
+                break;
+
+                case 0xb2e8:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16);
+                else
+                        s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val;
+                break;
+                case 0xb2e9:
+                if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24);
+                else
+                        s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8);
+                if (!(s3->accel.multifunc[0xe] & 0x200))
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                break;
+                case 0xb2ea:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16);
+                        else
+                                s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val;
+                }
+                break;
+                case 0xb2eb:
+                if (s3->accel.multifunc[0xe] & 0x200)
+                        s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24);
+                else if (s3->bpp == 3)
+                {
+                        if (s3->accel.multifunc[0xe] & 0x10)
+                                s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24);
+                        else
+                                s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8);
+                        s3->accel.multifunc[0xe] ^= 0x10;
+                }
+                break;
+
+                case 0xb6e8:
+                s3->accel.bkgd_mix = val;
+                break;
+
+                case 0xbae8:
+                s3->accel.frgd_mix = val;
+                break;
+                
+                case 0xbee8:
+                s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val;
+                break;
+                case 0xbee9:
+                s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8);
+                s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff;
+                break;
+
+                case 0xe2e8:
+                s3->accel.pix_trans[0] = val;
+                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100))
+                        s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
+                else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100))
+                        s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3);
+                break;
+                case 0xe2e9:
+                s3->accel.pix_trans[1] = val;
+                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100))
+                {
+                        if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3);
+                        else                        s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
+                }
+                else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100))
+                {
+                        if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3);
+                        else                        s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
+                }
+                break;
+                case 0xe2ea:
+                s3->accel.pix_trans[2] = val;
+                break;
+                case 0xe2eb:
+                s3->accel.pix_trans[3] = val;
+                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x600 && (s3->accel.cmd & 0x100) && s3->chip == S3_TRIO32)
+                {
+                        s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3);
+                        s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3);
+                        s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3);
+                        s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
+                }
+                else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100))
+                        s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
+                else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100))
+                        s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
+                break;
+        }
+}
+
+static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val)
+{
+//        pclog("Accel out w %04X %04X\n", port, val);
+        if (s3->accel.cmd & 0x100)
+        {
+                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
+                {
+                        if (s3->accel.cmd & 0x1000)
+                                val = (val >> 8) | (val << 8);
+                        if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32)
+                        {
+                                s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3);
+                                s3_accel_start(8, 1,  val       & 0xff, 0, s3);
+                        }
+                        if ((s3->accel.cmd & 0x600) == 0x000)
+                                s3_accel_start(8, 1, val | (val << 16), 0, s3);
+                        else
+                                s3_accel_start(16, 1, val | (val << 16), 0, s3);
+                }
+                else
+                {
+                        if ((s3->accel.cmd & 0x600) == 0x000)
+                                s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3);
+                        else
+                                s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3);
+                }
+        }
+}
+
+static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val)
+{
+//        pclog("Accel out l %04X %08X\n", port, val);
+        if (s3->accel.cmd & 0x100)
+        {
+                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
+                {
+                        if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32)
+                        {
+                                if (s3->accel.cmd & 0x1000)
+                                        val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
+                                s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3);
+                                s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3);
+                                s3_accel_start(8, 1, (val >> 8)  & 0xff, 0, s3);
+                                s3_accel_start(8, 1,  val        & 0xff, 0, s3);
+                        }
+                        else if (s3->accel.cmd & 0x400)
+                        {
+                                if (s3->accel.cmd & 0x1000)
+                                        val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
+                                s3_accel_start(32, 1, val, 0, s3);
+                        }
+                        else if ((s3->accel.cmd & 0x600) == 0x200)
+                        {
+                                if (s3->accel.cmd & 0x1000)
+                                        val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
+                                s3_accel_start(16, 1, val, 0, s3);
+                                s3_accel_start(16, 1, val >> 16, 0, s3);
+                        }
+                        else
+                        {
+                                if (s3->accel.cmd & 0x1000)
+                                        val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
+                                s3_accel_start(8, 1, val, 0, s3);
+                                s3_accel_start(8, 1, val >> 16, 0, s3);
+                        }
+                }
+                else
+                {
+                        if (s3->accel.cmd & 0x400)
+                                s3_accel_start(4, 1, 0xffffffff, val, s3);
+                        else if ((s3->accel.cmd & 0x600) == 0x200)
+                        {
+                                s3_accel_start(2, 1, 0xffffffff, val, s3);
+                                s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
+                        }
+                        else
+                        {
+                                s3_accel_start(1, 1, 0xffffffff, val, s3);
+                                s3_accel_start(1, 1, 0xffffffff, val >> 16, s3);
+                        }
+                }
+        }
+}
+
+static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val)
+{
+//        pclog("Write S3 accel %08X %02X\n", addr, val);
+        if (s3->packed_mmio)
+        {
+                int addr_lo = addr & 1;
+                switch (addr & 0xfffe)
+                {
+                        case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/
+                        case 0x8102: addr = 0x86e8; break;
+                        
+                        case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/
+                        case 0x8106: addr = 0x86ea; break;
+                        
+                        case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/
+                        case 0x810a: addr = 0x8ee8; break;
+                        
+                        case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/
+                        case 0x810e: addr = 0x8eea; break;
+
+                        case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/
+                        case 0x8112: addr = 0x92ee; break;
+
+                        case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/
+                        case 0x811a: addr = 0x9aea; break;
+                        
+                        case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/
+                        
+                        case 0x8120: case 0x8122:          /*BKGD_COLOR*/
+                        WRITE8(addr, s3->accel.bkgd_color, val);
+                        return;
+                        
+                        case 0x8124: case 0x8126:          /*FRGD_COLOR*/
+                        WRITE8(addr, s3->accel.frgd_color, val);
+                        return;
+
+                        case 0x8128: case 0x812a:          /*WRT_MASK*/
+                        WRITE8(addr, s3->accel.wrt_mask, val);
+                        return;
+
+                        case 0x812c: case 0x812e:          /*RD_MASK*/
+                        WRITE8(addr, s3->accel.rd_mask, val);
+                        return;
+
+                        case 0x8130: case 0x8132:          /*COLOR_CMP*/
+                        WRITE8(addr, s3->accel.color_cmp, val);
+                        return;
+
+                        case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/
+                        case 0x8136: addr = 0xbae8; break;
+                        
+                        case 0x8138:                       /*SCISSORS_T*/
+                        WRITE8(addr & 1, s3->accel.multifunc[1], val);
+                        return;
+                        case 0x813a:                       /*SCISSORS_L*/
+                        WRITE8(addr & 1, s3->accel.multifunc[2], val);
+                        return;
+                        case 0x813c:                       /*SCISSORS_B*/
+                        WRITE8(addr & 1, s3->accel.multifunc[3], val);
+                        return;
+                        case 0x813e:                       /*SCISSORS_R*/
+                        WRITE8(addr & 1, s3->accel.multifunc[4], val);
+                        return;
+
+                        case 0x8140:                       /*PIX_CNTL*/
+                        WRITE8(addr & 1, s3->accel.multifunc[0xa], val);
+                        return;
+                        case 0x8142:                       /*MULT_MISC2*/
+                        WRITE8(addr & 1, s3->accel.multifunc[0xd], val);
+                        return;
+                        case 0x8144:                       /*MULT_MISC*/
+                        WRITE8(addr & 1, s3->accel.multifunc[0xe], val);
+                        return;
+                        case 0x8146:                       /*READ_SEL*/
+                        WRITE8(addr & 1, s3->accel.multifunc[0xf], val);
+                        return;
+
+                        case 0x8148:                       /*ALT_PCNT*/
+                        WRITE8(addr & 1, s3->accel.multifunc[0], val);
+                        return;
+                        case 0x814a: addr = 0x96e8; break;
+                        case 0x814c: addr = 0x96ea; break;
+
+                        case 0x8168: addr = 0xeae8; break;
+                        case 0x816a: addr = 0xeaea; break;
+                }
+                addr |= addr_lo;
+        }
+        
+
+        if (addr & 0x8000)
+        {
+                s3_accel_out_fifo(s3, addr & 0xffff, val);
+        }
+        else
+        {
+                if (s3->accel.cmd & 0x100)
+                {
+                        if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
+                                s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3);
+                        else
+                                s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3);
+                }
+        }
+}
+
+static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val)
+{
+//        pclog("Write S3 accel w %08X %04X\n", addr, val);
+        if (addr & 0x8000)
+        {
+                s3_accel_write_fifo(s3, addr,     val);
+                s3_accel_write_fifo(s3, addr + 1, val >> 8);
+        }
+        else
+        {
+                if (s3->accel.cmd & 0x100)
+                {
+                        if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
+                        {
+                                if (s3->accel.cmd & 0x1000)
+                                        val = (val >> 8) | (val << 8);
+                                if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32)
+                                {
+                                        s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3);
+                                        s3_accel_start(8, 1,  val       & 0xff, 0, s3);
+                                }
+                                else if ((s3->accel.cmd & 0x600) == 0x000)
+                                        s3_accel_start(8, 1, val | (val << 16), 0, s3);
+                                else
+                                        s3_accel_start(16, 1, val | (val << 16), 0, s3);
+                        }
+                        else
+                        {
+                                if ((s3->accel.cmd & 0x600) == 0x000)
+                                        s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3);
+                                else
+                                        s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3);
+                        }
+                }
+        }
+}
+
+static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val)
+{
+//        pclog("Write S3 accel l %08X %08X\n", addr, val);
+        if (addr & 0x8000)
+        {
+                s3_accel_write_fifo(s3, addr,     val);
+                s3_accel_write_fifo(s3, addr + 1, val >> 8);
+                s3_accel_write_fifo(s3, addr + 2, val >> 16);
+                s3_accel_write_fifo(s3, addr + 3, val >> 24);
+        }
+        else
+        {
+                if (s3->accel.cmd & 0x100)
+                {
+                        if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
+                        {
+                                if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32)
+                                {
+                                        if (s3->accel.cmd & 0x1000)
+                                                val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
+                                        s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3);
+                                        s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3);
+                                        s3_accel_start(8, 1, (val >> 8)  & 0xff, 0, s3);
+                                        s3_accel_start(8, 1,  val        & 0xff, 0, s3);
+                                }
+                                else if (s3->accel.cmd & 0x400)
+                                {
+                                        if (s3->accel.cmd & 0x1000)
+                                                val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
+                                        s3_accel_start(32, 1, val, 0, s3);
+                                }
+                                else if ((s3->accel.cmd & 0x600) == 0x200)
+                                {
+                                        if (s3->accel.cmd & 0x1000)
+                                                val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
+                                        s3_accel_start(16, 1, val, 0, s3);
+                                        s3_accel_start(16, 1, val >> 16, 0, s3);
+                                }
+                                else
+                                {
+                                        if (s3->accel.cmd & 0x1000)
+                                                val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
+                                        s3_accel_start(8, 1, val, 0, s3);
+                                        s3_accel_start(8, 1, val >> 16, 0, s3);
+                                }
+                        }
+                        else
+                        {
+                                if (s3->accel.cmd & 0x400)
+                                        s3_accel_start(4, 1, 0xffffffff, val, s3);
+                                else if ((s3->accel.cmd & 0x600) == 0x200)
+                                {
+                                        s3_accel_start(2, 1, 0xffffffff, val, s3);
+                                        s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
+                                }
+                                else
+                                {
+                                        s3_accel_start(1, 1, 0xffffffff, val, s3);
+                                        s3_accel_start(1, 1, 0xffffffff, val >> 16, s3);
+                                }
+                        }
+                }
+        }
+}
+
+static void fifo_thread(void *param)
+{
+        s3_t *s3 = (s3_t *)param;
+        
+        while (1)
+        {
+                thread_set_event(s3->fifo_not_full_event);
+                thread_wait_event(s3->wake_fifo_thread, -1);
+                thread_reset_event(s3->wake_fifo_thread);
+                s3->blitter_busy = 1;
+                while (!FIFO_EMPTY)
+                {
+                        uint64_t start_time = timer_read();
+                        uint64_t end_time;
+                        fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK];
+
+                        switch (fifo->addr_type & FIFO_TYPE)
+                        {
+                                case FIFO_WRITE_BYTE:
+                                s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val);
+                                break;
+                                case FIFO_WRITE_WORD:
+                                s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val);
+                                break;
+                                case FIFO_WRITE_DWORD:
+                                s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val);
+                                break;
+                                case FIFO_OUT_BYTE:
+                                s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val);
+                                break;
+                                case FIFO_OUT_WORD:
+                                s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val);
+                                break;
+                                case FIFO_OUT_DWORD:
+                                s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val);
+                                break;
+                        }
+                                                
+                        s3->fifo_read_idx++;
+                        fifo->addr_type = FIFO_INVALID;
+
+                        if (FIFO_ENTRIES > 0xe000)
+                                thread_set_event(s3->fifo_not_full_event);
+
+                        end_time = timer_read();
+                        s3->blitter_time += end_time - start_time;
+                }
+                s3->blitter_busy = 0;
+                s3->subsys_stat |= INT_FIFO_EMP;
+                s3_update_irqs(s3);
+        }
+}
+
+static void s3_vblank_start(svga_t *svga)
+{
+        s3_t *s3 = (s3_t *)svga->p;
+
+        s3->subsys_stat |= INT_VSY;
+        s3_update_irqs(s3);
+}
+
+static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type)
+{
+        fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK];
+
+        if (FIFO_FULL)
+        {
+                thread_reset_event(s3->fifo_not_full_event);
+                if (FIFO_FULL)
+                {
+                        thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/
+                }
+        }
+
+        fifo->val = val;
+        fifo->addr_type = (addr & FIFO_ADDR) | type;
+
+        s3->fifo_write_idx++;
+        
+        if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8)
+                wake_fifo_thread(s3);
+}
+
+void s3_out(uint16_t addr, uint8_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        svga_t *svga = &s3->svga;
+        uint8_t old;
+
+        if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) 
+                addr ^= 0x60;
+        
+//        pclog("S3 out %04X %02X %04x:%08x\n", addr, val, CS, pc);
+
+        switch (addr)
+        {
+                case 0x3c5:
+                if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20)
+                {
+                        svga->seqregs[svga->seqaddr] = val;
+                        switch (svga->seqaddr)
+                        {
+                                case 0x12: case 0x13:
+                                svga_recalctimings(svga);
+                                return;
+                        }
+                }
+                if (svga->seqaddr == 4) /*Chain-4 - update banking*/
+                {
+                        if (val & 8) svga->write_bank = svga->read_bank = s3->bank << 16;
+                        else         svga->write_bank = svga->read_bank = s3->bank << 14;
+                }
+                break;
+                
+                case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
+//                pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc);
+                if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64)
+                        svga_out(addr, val, svga);
+                else
+                {
+                        if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2))
+                                sdac_ramdac_out((addr & 3) | 4, val, &s3->ramdac, svga);
+                        else
+                                sdac_ramdac_out(addr & 3, val, &s3->ramdac, svga);
+                }
+                return;
+
+                case 0x3D4:
+                svga->crtcreg = val & 0x7f;
+                return;
+                case 0x3D5:
+                if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
+                        return;
+                if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
+                        val = (svga->crtc[7] & ~0x10) | (val & 0x10);
+                if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return;
+                old = svga->crtc[svga->crtcreg];
+                svga->crtc[svga->crtcreg] = val;
+                switch (svga->crtcreg)
+                {
+                        case 0x31:
+                        s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4);
+                        break;
+                        case 0x32:
+                        svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask;
+                        break;
+                                                
+                        case 0x50:
+                        switch (svga->crtc[0x50] & 0xc1)
+                        {
+                                case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break;
+                                case 0x01: s3->width = 1152; break;
+                                case 0x40: s3->width = 640;  break;
+                                case 0x80: s3->width = 800;  break;
+                                case 0x81: s3->width = 1600; break;
+                                case 0xc0: s3->width = 1280; break;
+                        }
+                        s3->bpp = (svga->crtc[0x50] >> 4) & 3;
+                        break;
+                        case 0x69:
+                        s3->ma_ext = val & 0x1f;
+                        break;
+                        
+                        case 0x35:
+                        s3->bank = (s3->bank & 0x70) | (val & 0xf);
+//                        pclog("CRTC write R35 %02X\n", val);
+                        if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16;
+                        else              svga->write_bank = svga->read_bank = s3->bank << 14;
+                        break;
+                        case 0x51:
+                        s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2);
+//                        pclog("CRTC write R51 %02X\n", val);
+                        if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16;
+                        else              svga->write_bank = svga->read_bank = s3->bank << 14;
+                        s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2);
+                        break;
+                        case 0x6a:
+                        s3->bank = val;
+//                        pclog("CRTC write R6a %02X\n", val);
+                        if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16;
+                        else              svga->write_bank = svga->read_bank = s3->bank << 14;
+                        break;
+                        
+                        case 0x3a:
+                        if (val & 0x10) 
+                                svga->gdcreg[5] |= 0x40; /*Horrible cheat*/
+                        break;
+                        
+                        case 0x45:
+                        svga->hwcursor.ena = val & 1;
+                        break;
+                        case 0x48:
+                        svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff;
+                        if (svga->bpp == 32) svga->hwcursor.x >>= 1;
+                        svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff;
+                        svga->hwcursor.xoff = svga->crtc[0x4e] & 63;
+                        svga->hwcursor.yoff = svga->crtc[0x4f] & 63;
+                        svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16);
+                        if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32)
+                                svga->hwcursor.x <<= 1;
+                        break;
+                        
+                        case 0x4a:
+                        switch (s3->hwc_col_stack_pos)
+                        {
+                                case 0:
+                                s3->hwc_fg_col = (s3->hwc_fg_col & 0xffff00) | val;
+                                break;
+                                case 1:
+                                s3->hwc_fg_col = (s3->hwc_fg_col & 0xff00ff) | (val << 8);
+                                break;
+                                case 2:
+                                s3->hwc_fg_col = (s3->hwc_fg_col & 0x00ffff) | (val << 16);
+                                break;
+                        }
+                        s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3;
+                        break;
+                        case 0x4b:
+                        switch (s3->hwc_col_stack_pos)
+                        {
+                                case 0:
+                                s3->hwc_bg_col = (s3->hwc_bg_col & 0xffff00) | val;
+                                break;
+                                case 1:
+                                s3->hwc_bg_col = (s3->hwc_bg_col & 0xff00ff) | (val << 8);
+                                break;
+                                case 2:
+                                s3->hwc_bg_col = (s3->hwc_bg_col & 0x00ffff) | (val << 16);
+                                break;
+                        }
+                        s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3;
+                        break;
+
+                        case 0x53:
+                        case 0x58: case 0x59: case 0x5a:
+                        s3_updatemapping(s3);
+                        break;
+                        
+                        case 0x67:
+                        if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64)
+                        {
+                                switch (val >> 4)
+                                {
+                                        case 3:  svga->bpp = 15; break;
+                                        case 5:  svga->bpp = 16; break;
+                                        case 7:  svga->bpp = 24; break;
+                                        case 13: svga->bpp = 32; break;
+                                        default: svga->bpp = 8;  break;
+                                }
+                        }
+                        break;
+                        //case 0x55: case 0x43:
+//                                pclog("Write CRTC R%02X %02X\n", crtcreg, val);
+                }
+                if (old != val)
+                {
+                        if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
+                        {
+                                svga->fullchange = changeframecount;
+                                svga_recalctimings(svga);
+                        }
+                }
+                break;
+        }
+        svga_out(addr, val, svga);
+}
+
+uint8_t s3_in(uint16_t addr, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        svga_t *svga = &s3->svga;
+
+        if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) 
+                addr ^= 0x60;
+
+//        if (addr != 0x3da) pclog("S3 in %04X %08x:%02x\n", addr, CS, pc);
+        switch (addr)
+        {
+                case 0x3c1:
+                if (svga->attraddr > 0x14)
+                        return 0xff;
+                break;
+                        
+                case 0x3c5:
+                if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20)
+                        return svga->seqregs[svga->seqaddr];
+                break;
+                
+                case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9:
+//                pclog("Read RAMDAC %04X  %04X:%04X\n", addr, CS, pc);
+                if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64)
+                        return svga_in(addr, svga);
+                if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2))
+                        return sdac_ramdac_in((addr & 3) | 4, &s3->ramdac, svga);
+                return sdac_ramdac_in(addr & 3, &s3->ramdac, svga);
+
+                case 0x3d4:
+                return svga->crtcreg;
+                case 0x3d5:
+//                pclog("Read CRTC R%02X %02x %04X:%04X\n", svga->crtcreg, svga->crtc[svga->crtcreg], CS, pc);
+                switch (svga->crtcreg)
+                {
+                        case 0x2d: return 0x88;       /*Extended chip ID*/
+                        case 0x2e: return s3->id_ext; /*New chip ID*/
+                        case 0x2f: return 0;          /*Revision level*/
+                        case 0x30: return s3->id;     /*Chip ID*/
+                        case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4);
+                        case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf);
+                        case 0x45: s3->hwc_col_stack_pos = 0; break;
+                        case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3);
+                        case 0x69: return s3->ma_ext;
+                        case 0x6a: return s3->bank;
+                }
+                return svga->crtc[svga->crtcreg];
+        }
+        return svga_in(addr, svga);
+}
+
+void s3_recalctimings(svga_t *svga)
+{
+        s3_t *s3 = (s3_t *)svga->p;
+        svga->hdisp = svga->hdisp_old;
+        int clk_sel = (svga->miscout >> 2) & 3;
+
+        if (clk_sel == 3 && s3->chip == S3_VISION864)
+                clk_sel = svga->crtc[0x42] & 0xf;
+
+//        pclog("%i %i\n", svga->hdisp, svga->hdisp_time);
+//        pclog("recalctimings\n");
+        svga->ma_latch |= (s3->ma_ext << 16);
+//        pclog("SVGA_MA %08X\n", svga_ma);
+        if (svga->crtc[0x5d] & 0x01) svga->htotal     += 0x100;
+        if (svga->crtc[0x5d] & 0x02) 
+        {
+                svga->hdisp_time += 0x100;
+                svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8);
+        }
+        if (svga->crtc[0x5e] & 0x01) svga->vtotal      += 0x400;
+        if (svga->crtc[0x5e] & 0x02) svga->dispend     += 0x400;
+        if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400;
+        if (svga->crtc[0x5e] & 0x10) svga->vsyncstart  += 0x400;
+        if (svga->crtc[0x5e] & 0x40) svga->split       += 0x400;
+        if (svga->crtc[0x51] & 0x30)      svga->rowoffset  += (svga->crtc[0x51] & 0x30) << 4;
+        else if (svga->crtc[0x43] & 0x04) svga->rowoffset  += 0x100;
+        if (!svga->rowoffset) svga->rowoffset = 256;
+        svga->interlace = svga->crtc[0x42] & 0x20;
+        svga->clock = (cpuclock * (float)(1ull << 32)) / s3->getclock(clk_sel, s3->getclock_p);
+
+        switch (svga->crtc[0x67] >> 4)
+        {
+                case 3: case 5: case 7:
+                svga->clock /= 2;
+                break;
+        }                
+
+        svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10));
+        if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10))
+        {
+                switch (svga->bpp)
+                {
+                        case 8: 
+                        svga->render = svga_render_8bpp_highres; 
+                        break;
+                        case 15: 
+                        svga->render = svga_render_15bpp_highres; 
+                        svga->hdisp /= 2;
+                        break;
+                        case 16: 
+                        svga->render = svga_render_16bpp_highres; 
+                        svga->hdisp /= 2;
+                        break;
+                        case 24: 
+                        svga->render = svga_render_24bpp_highres; 
+                        svga->hdisp /= 3;
+                        break;
+                        case 32:
+                        svga->render = svga_render_32bpp_highres; 
+                        if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64)
+                                svga->hdisp /= 4;
+                        break;
+                }
+        }
+}
+
+void s3_updatemapping(s3_t *s3)
+{
+        svga_t *svga = &s3->svga;
+        
+//        video_write_a000_w = video_write_a000_l = NULL;
+
+        if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM))
+        {
+//                pclog("Update mapping - PCI disabled\n");
+                mem_mapping_disable(&svga->mapping);
+                mem_mapping_disable(&s3->linear_mapping);
+                mem_mapping_disable(&s3->mmio_mapping);
+                return;
+        }
+
+//        pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc);
+        /*Banked framebuffer*/
+        if (svga->crtc[0x31] & 0x08) /*Enhanced mode mappings*/
+        {
+                /*Enhanced mapping forces 64kb at 0xa0000*/
+                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
+                svga->banked_mask = 0xffff;
+        }
+        else switch (svga->gdcreg[6] & 0xc) /*VGA mapping*/
+        {
+                case 0x0: /*128k at A0000*/
+                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
+                svga->banked_mask = 0xffff;
+                break;
+                case 0x4: /*64k at A0000*/
+                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
+                svga->banked_mask = 0xffff;
+                break;
+                case 0x8: /*32k at B0000*/
+                mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+                case 0xC: /*32k at B8000*/
+                mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+        }
+        
+//        pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10);
+        if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/
+        {
+                mem_mapping_disable(&svga->mapping);
+                
+                s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24);
+                switch (svga->crtc[0x58] & 3)
+                {
+                        case 0: /*64k*/
+                        s3->linear_size = 0x10000;
+                        break;
+                        case 1: /*1mb*/
+                        s3->linear_size = 0x100000;
+                        break;
+                        case 2: /*2mb*/
+                        s3->linear_size = 0x200000;
+                        break;
+                        case 3: /*8mb*/
+                        s3->linear_size = 0x800000;
+                        break;
+                }
+                s3->linear_base &= ~(s3->linear_size - 1);
+//                pclog("%08X %08X  %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]);
+//                pclog("Linear framebuffer at %08X size %08X\n", s3->linear_base, s3->linear_size);
+                if (s3->linear_base == 0xa0000)
+                {
+                        mem_mapping_disable(&s3->linear_mapping);
+                        if (!(svga->crtc[0x53] & 0x10))
+                        {
+                                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
+                                svga->banked_mask = 0xffff;
+                        }
+//                        mem_mapping_set_addr(&s3->linear_mapping, 0xa0000, 0x10000);
+                }
+                else
+                        mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size);
+        }
+        else
+                mem_mapping_disable(&s3->linear_mapping);
+        
+//        pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x10);
+        if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/
+        {
+                mem_mapping_disable(&svga->mapping);
+                mem_mapping_enable(&s3->mmio_mapping);
+        }
+        else
+                mem_mapping_disable(&s3->mmio_mapping);
+}
+
+static float s3_trio64_getclock(int clock, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        svga_t *svga = &s3->svga;
+        float t;
+        int m, n1, n2;
+//        pclog("Trio64_getclock %i %02X %02X\n", clock, svga->seqregs[0x13], svga->seqregs[0x12]);
+        if (clock == 0) return 25175000.0;
+        if (clock == 1) return 28322000.0;
+        m  = svga->seqregs[0x13] + 2;
+        n1 = (svga->seqregs[0x12] & 0x1f) + 2;
+        n2 = ((svga->seqregs[0x12] >> 5) & 0x07);
+        t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2);
+//        pclog("TRIO64 clock %i %i %i %f  %f %i\n", m, n1, n2, t, 14318184.0 * ((float)m / (float)n1), 1 << n2);
+        return t;
+}
+
+
+void s3_accel_out(uint16_t port, uint8_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+//        pclog("Accel out %04X %02X\n", port, val);
+        
+        if (port >= 0x8000)
+        {
+                s3_queue(s3, port, val, FIFO_OUT_BYTE);
+        }
+        else switch (port)
+        {
+                case 0x42e8:
+                s3->subsys_stat &= ~val;
+                s3_update_irqs(s3);
+                break;
+                case 0x42e9:
+                s3->subsys_cntl = val;
+                s3_update_irqs(s3);
+                break;
+                case 0x46e8:
+                s3->accel.setup_md = val;
+                break;
+                case 0x4ae8:
+                s3->accel.advfunc_cntl = val;
+                break;
+        }
+}
+
+void s3_accel_out_w(uint16_t port, uint16_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+//        pclog("Accel out w %04X %04X\n", port, val);        
+        s3_queue(s3, port, val, FIFO_OUT_WORD);
+}
+
+void s3_accel_out_l(uint16_t port, uint32_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+//        pclog("Accel out l %04X %08X\n", port, val);                
+        s3_queue(s3, port, val, FIFO_OUT_DWORD);
+}
+
+uint8_t s3_accel_in(uint16_t port, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        int temp;
+//        pclog("Accel in  %04X\n", port);
+        switch (port)
+        {
+                case 0x42e8:
+                return s3->subsys_stat;
+                case 0x42e9:
+                return s3->subsys_cntl;
+
+                case 0x82e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.cur_y & 0xff;
+                case 0x82e9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.cur_y  >> 8;
+
+                case 0x86e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.cur_x & 0xff;
+                case 0x86e9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.cur_x  >> 8;
+
+                case 0x8ae8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.desty_axstp & 0xff;
+                case 0x8ae9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.desty_axstp >> 8;
+
+                case 0x8ee8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.destx_distp & 0xff;
+                case 0x8ee9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.destx_distp >> 8;
+
+                case 0x92e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.err_term & 0xff;
+                case 0x92e9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.err_term >> 8;
+
+                case 0x96e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.maj_axis_pcnt & 0xff;
+                case 0x96e9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.maj_axis_pcnt >> 8;
+
+                case 0x9ae8:
+                if (!s3->blitter_busy)
+                        wake_fifo_thread(s3);
+                if (FIFO_FULL)
+                        return 0xff; /*FIFO full*/
+                return 0;    /*FIFO empty*/
+                case 0x9ae9:
+                if (!s3->blitter_busy)
+                        wake_fifo_thread(s3);
+                temp = 0;
+                if (!FIFO_EMPTY || s3->force_busy)
+                        temp |= 0x02; /*Hardware busy*/
+                else
+                        temp |= 0x04; /*FIFO empty*/
+                s3->force_busy = 0;
+                if (FIFO_FULL)
+                        temp |= 0xf8; /*FIFO full*/
+                return temp;
+
+                case 0xa2e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.bkgd_color & 0xff;
+                case 0xa2e9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.bkgd_color >> 8;
+                case 0xa2ea:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.bkgd_color >> 16;
+                case 0xa2eb:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.bkgd_color >> 24;
+
+                case 0xa6e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.frgd_color & 0xff;
+                case 0xa6e9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.frgd_color >> 8;
+                case 0xa6ea:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.frgd_color >> 16;
+                case 0xa6eb:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.frgd_color >> 24;
+
+                case 0xaae8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.wrt_mask & 0xff;
+                case 0xaae9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.wrt_mask >> 8;
+                case 0xaaea:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.wrt_mask >> 16;
+                case 0xaaeb:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.wrt_mask >> 24;
+
+                case 0xaee8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.rd_mask & 0xff;
+                case 0xaee9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.rd_mask >> 8;
+                case 0xaeea:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.rd_mask >> 16;
+                case 0xaeeb:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.rd_mask >> 24;
+
+                case 0xb2e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.color_cmp & 0xff;
+                case 0xb2e9:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.color_cmp >> 8;
+                case 0xb2ea:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.color_cmp >> 16;
+                case 0xb2eb:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.color_cmp >> 24;
+
+                case 0xb6e8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.bkgd_mix;
+
+                case 0xbae8:
+                s3_wait_fifo_idle(s3);
+                return s3->accel.frgd_mix;
+
+                case 0xbee8:
+                s3_wait_fifo_idle(s3);
+                temp = s3->accel.multifunc[0xf] & 0xf;
+                switch (temp)
+                {
+                        case 0x0: return s3->accel.multifunc[0x0] & 0xff;
+                        case 0x1: return s3->accel.multifunc[0x1] & 0xff;
+                        case 0x2: return s3->accel.multifunc[0x2] & 0xff;
+                        case 0x3: return s3->accel.multifunc[0x3] & 0xff;
+                        case 0x4: return s3->accel.multifunc[0x4] & 0xff;
+                        case 0x5: return s3->accel.multifunc[0xa] & 0xff;
+                        case 0x6: return s3->accel.multifunc[0xe] & 0xff;
+                        case 0x7: return s3->accel.cmd            & 0xff;
+                        case 0x8: return s3->accel.subsys_cntl    & 0xff;
+                        case 0x9: return s3->accel.setup_md       & 0xff;
+                        case 0xa: return s3->accel.multifunc[0xd] & 0xff;
+                }
+                return 0xff;
+                case 0xbee9:
+                s3_wait_fifo_idle(s3);
+                temp = s3->accel.multifunc[0xf] & 0xf;
+                s3->accel.multifunc[0xf]++;
+                switch (temp)
+                {
+                        case 0x0: return  s3->accel.multifunc[0x0] >> 8;
+                        case 0x1: return  s3->accel.multifunc[0x1] >> 8;
+                        case 0x2: return  s3->accel.multifunc[0x2] >> 8;
+                        case 0x3: return  s3->accel.multifunc[0x3] >> 8;
+                        case 0x4: return  s3->accel.multifunc[0x4] >> 8;
+                        case 0x5: return  s3->accel.multifunc[0xa] >> 8;
+                        case 0x6: return  s3->accel.multifunc[0xe] >> 8;
+                        case 0x7: return  s3->accel.cmd            >> 8;
+                        case 0x8: return (s3->accel.subsys_cntl    >> 8) & ~0xe000;
+                        case 0x9: return (s3->accel.setup_md       >> 8) & ~0xf000;
+                        case 0xa: return  s3->accel.multifunc[0xd] >> 8;
+                }
+                return 0xff;
+
+                case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/
+                break;
+        }
+        return 0;
+}
+
+void s3_accel_write(uint32_t addr, uint8_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+//        pclog("s3_accel_write %08x %02x\n", addr, val);        
+        s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE);
+}
+void s3_accel_write_w(uint32_t addr, uint16_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+//        pclog("s3_accel_write_w %08x %04x\n", addr, val);        
+        s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD);
+}
+void s3_accel_write_l(uint32_t addr, uint32_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+//        pclog("s3_accel_write_l %08x %08x\n", addr, val);        
+        s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD);
+}
+
+uint8_t s3_accel_read(uint32_t addr, void *p)
+{
+        if (addr & 0x8000)
+           return s3_accel_in(addr & 0xffff, p);
+        return 0;
+}
+
+static void polygon_setup(s3_t *s3)
+{
+        if (s3->accel.point_1_updated)
+        {
+                int start_x = s3->accel.poly_cx;
+                int start_y = s3->accel.poly_cy;
+                int end_x = s3->accel.destx_distp << 20;
+                int end_y = s3->accel.desty_axstp;
+                                
+                if (end_y - start_y)
+                        s3->accel.poly_dx1 = (end_x - start_x) / (end_y - start_y);
+                else
+                        s3->accel.poly_dx1 = 0;
+                        
+                s3->accel.point_1_updated = 0;
+
+                if (end_y == s3->accel.poly_cy)
+                {
+                        s3->accel.poly_cx = end_x;
+                        s3->accel.poly_x = end_x >> 20;
+                }
+        }
+        if (s3->accel.point_2_updated)
+        {
+                int start_x = s3->accel.poly_cx2;
+                int start_y = s3->accel.poly_cy2;
+                int end_x = s3->accel.x2 << 20;
+                int end_y = s3->accel.desty_axstp2;
+
+                if (end_y - start_y)                                
+                        s3->accel.poly_dx2 = (end_x - start_x) / (end_y - start_y);
+                else
+                        s3->accel.poly_dx2 = 0;
+
+                s3->accel.point_2_updated = 0;
+                                
+                if (end_y == s3->accel.poly_cy)
+                        s3->accel.poly_cx2 = end_x;
+        }
+}
+
+#define READ_SRC(addr, dat) if (s3->bpp == 0)      dat = svga->vram[  (addr) & s3->vram_mask]; \
+                            else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \
+                            else                   dat = vram_l[(addr) & (s3->vram_mask >> 2)]; \
+                            if (vram_mask)                                           \
+                                    dat = ((dat & rd_mask) == rd_mask);
+
+#define READ_DST(addr, dat) if (s3->bpp == 0)      dat = svga->vram[  (addr) & s3->vram_mask]; \
+                            else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \
+                            else                   dat = vram_l[(addr) & (s3->vram_mask >> 2)];
+
+#define MIX     {                                                                                               \
+                        uint32_t old_dest_dat = dest_dat;                                                       \
+                        switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \
+                        {                                                                                       \
+                                case 0x0: dest_dat =             ~dest_dat;  break;                             \
+                                case 0x1: dest_dat =  0;                     break;                             \
+                                case 0x2: dest_dat = ~0;                     break;                             \
+                                case 0x3: dest_dat =              dest_dat;  break;                             \
+                                case 0x4: dest_dat =  ~src_dat;              break;                             \
+                                case 0x5: dest_dat =   src_dat ^  dest_dat;  break;                             \
+                                case 0x6: dest_dat = ~(src_dat ^  dest_dat); break;                             \
+                                case 0x7: dest_dat =   src_dat;              break;                             \
+                                case 0x8: dest_dat = ~(src_dat &  dest_dat); break;                             \
+                                case 0x9: dest_dat =  ~src_dat |  dest_dat;  break;                             \
+                                case 0xa: dest_dat =   src_dat | ~dest_dat;  break;                             \
+                                case 0xb: dest_dat =   src_dat |  dest_dat;  break;                             \
+                                case 0xc: dest_dat =   src_dat &  dest_dat;  break;                             \
+                                case 0xd: dest_dat =   src_dat & ~dest_dat;  break;                             \
+                                case 0xe: dest_dat =  ~src_dat &  dest_dat;  break;                             \
+                                case 0xf: dest_dat = ~(src_dat |  dest_dat); break;                             \
+                        }                                                                                       \
+                        dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask);      \
+                }
+
+
+#define WRITE(addr)     if (s3->bpp == 0)                                                                               \
+                        {                                                                                               \
+                                svga->vram[(addr) & s3->vram_mask] = dest_dat;                                          \
+                                svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount;                   \
+                        }                                                                                               \
+                        else if (s3->bpp == 1)                                                                          \
+                        {                                                                                               \
+                                vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat;                                       \
+                                svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount;            \
+                        }                                                                                               \
+                        else                                                                                            \
+                        {                                                                                               \
+                                vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat;                                       \
+                                svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount;            \
+                        }
+
+void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3)
+{
+        svga_t *svga = &s3->svga;
+        uint32_t src_dat, dest_dat;
+        int frgd_mix, bkgd_mix;
+        int clip_t = s3->accel.multifunc[1] & 0xfff;
+        int clip_l = s3->accel.multifunc[2] & 0xfff;
+        int clip_b = s3->accel.multifunc[3] & 0xfff;
+        int clip_r = s3->accel.multifunc[4] & 0xfff;
+        int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0;
+        uint32_t mix_mask = 0;
+        uint16_t *vram_w = (uint16_t *)svga->vram;
+        uint32_t *vram_l = (uint32_t *)svga->vram;
+        uint32_t compare = s3->accel.color_cmp;
+        int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3;
+        uint32_t rd_mask = s3->accel.rd_mask;
+        int cmd = s3->accel.cmd >> 13;
+        
+        if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11)))
+                cmd |= 8;
+        
+        s3->force_busy = 1;
+//return;
+//        if (!cpu_input) pclog("Start S3 command %i  %i, %i  %i, %i (clip %i, %i to %i, %i  %i)\n", s3->accel.cmd >> 13, s3->accel.cur_x, s3->accel.cur_y, s3->accel.maj_axis_pcnt & 0xfff, s3->accel.multifunc[0]  & 0xfff, clip_l, clip_t, clip_r, clip_b, s3->accel.multifunc[0xe] & 0x20);
+//        else            pclog("      S3 command %i, %i, %08x %08x\n", s3->accel.cmd >> 13, count, mix_dat, cpu_dat);
+
+        if (!cpu_input) s3->accel.dat_count = 0;
+        if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80)
+        {
+                if (s3->bpp == 3 && count == 2)
+                {
+                        if (s3->accel.dat_count)
+                        {
+                                cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf;
+                                count = 4;
+                                s3->accel.dat_count = 0;
+                        }
+                        else
+                        {
+                                s3->accel.dat_buf = cpu_dat & 0xffff;
+                                s3->accel.dat_count = 1;
+                        }
+                }
+                if (s3->bpp == 1) count >>= 1;
+                if (s3->bpp == 3) count >>= 2;
+        }
+
+        if (s3->bpp == 0)
+                rd_mask &= 0xff;
+        else if (s3->bpp == 1)
+                rd_mask &= 0xffff;
+        
+        switch (s3->accel.cmd & 0x600)
+        {
+                case 0x000: mix_mask = 0x80; break;
+                case 0x200: mix_mask = 0x8000; break;
+                case 0x400: mix_mask = 0x80000000; break;
+                case 0x600: mix_mask = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break;
+        }
+
+        if (s3->bpp == 0) compare &=   0xff;
+        if (s3->bpp == 1) compare &= 0xffff;
+        switch (cmd)
+        {
+                case 1: /*Draw line*/
+                if (!cpu_input) /*!cpu_input is trigger to start operation*/
+                {
+                        s3->accel.cx   = s3->accel.cur_x;
+                        if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
+                        s3->accel.cy   = s3->accel.cur_y;
+                        if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
+                        
+                        s3->accel.sy = s3->accel.maj_axis_pcnt;
+                }
+                if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
+
+                frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
+                bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
+
+                if (s3->accel.cmd & 8) /*Radial*/
+                {
+                        while (count-- && s3->accel.sy >= 0)
+                        {
+                                if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
+                                    s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
+                                {
+                                        switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
+                                        {
+                                                case 0: src_dat = s3->accel.bkgd_color; break;
+                                                case 1: src_dat = s3->accel.frgd_color; break;
+                                                case 2: src_dat = cpu_dat; break;
+                                                case 3: src_dat = 0; break;
+                                        }
+
+                                        if ((compare_mode == 2 && src_dat != compare) ||
+                                            (compare_mode == 3 && src_dat == compare) ||
+                                             compare_mode < 2)
+                                        {
+                                                READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat);
+
+                                                MIX
+
+                                                WRITE((s3->accel.cy * s3->width) + s3->accel.cx);
+                                        }
+                                }
+
+                                mix_dat <<= 1;
+                                mix_dat |= 1;
+                                if (s3->bpp == 0) cpu_dat >>= 8;
+                                else              cpu_dat >>= 16;
+                                if (!s3->accel.sy)
+                                        break;
+
+                                switch (s3->accel.cmd & 0xe0)
+                                {
+                                        case 0x00: s3->accel.cx++;                 break;
+                                        case 0x20: s3->accel.cx++; s3->accel.cy--; break;
+                                        case 0x40:                 s3->accel.cy--; break;
+                                        case 0x60: s3->accel.cx--; s3->accel.cy--; break;
+                                        case 0x80: s3->accel.cx--;                 break;
+                                        case 0xa0: s3->accel.cx--; s3->accel.cy++; break;
+                                        case 0xc0:                 s3->accel.cy++; break;
+                                        case 0xe0: s3->accel.cx++; s3->accel.cy++; break;
+                                }
+                                s3->accel.sy--;
+                        }
+                        s3->accel.cur_x = s3->accel.cx;
+                        s3->accel.cur_y = s3->accel.cy;
+                }
+                else /*Bresenham*/
+                {
+                        while (count-- && s3->accel.sy >= 0)
+                        {
+                                if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
+                                    s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
+                                {
+                                        switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
+                                        {
+                                                case 0: src_dat = s3->accel.bkgd_color; break;
+                                                case 1: src_dat = s3->accel.frgd_color; break;
+                                                case 2: src_dat = cpu_dat; break;
+                                                case 3: src_dat = 0; break;
+                                        }
+
+                                        if ((compare_mode == 2 && src_dat != compare) ||
+                                            (compare_mode == 3 && src_dat == compare) ||
+                                             compare_mode < 2)
+                                        {
+                                                READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat);
+
+//                                        pclog("Line : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X (%02X %02X)  ", s3->accel.cx, s3->accel.cy, s3->accel.dest + s3->accel.cx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat & mix_mask, s3->accel.src + s3->accel.cx, dest_dat, s3->accel.frgd_color, s3->accel.bkgd_color);
+                                        
+                                                MIX
+
+//                                        pclog("%02X\n", dest_dat);
+
+                                                WRITE((s3->accel.cy * s3->width) + s3->accel.cx);
+                                        }
+                                }
+
+                                mix_dat <<= 1;
+                                mix_dat |= 1;
+                                if (s3->bpp == 0) cpu_dat >>= 8;
+                                else             cpu_dat >>= 16;
+
+//                                pclog("%i, %i - %i %i  %i %i\n", s3->accel.cx, s3->accel.cy, s3->accel.err_term, s3->accel.maj_axis_pcnt, s3->accel.desty_axstp, s3->accel.destx_distp);
+
+                                if (!s3->accel.sy)
+                                        break;
+
+                                if (s3->accel.err_term >= s3->accel.maj_axis_pcnt)
+                                {
+                                        s3->accel.err_term += s3->accel.destx_distp;
+                                        /*Step minor axis*/
+                                        switch (s3->accel.cmd & 0xe0)
+                                        {
+                                                case 0x00: s3->accel.cy--; break;
+                                                case 0x20: s3->accel.cy--; break;
+                                                case 0x40: s3->accel.cx--; break;
+                                                case 0x60: s3->accel.cx++; break;
+                                                case 0x80: s3->accel.cy++; break;
+                                                case 0xa0: s3->accel.cy++; break;
+                                                case 0xc0: s3->accel.cx--; break;
+                                                case 0xe0: s3->accel.cx++; break;
+                                        }
+                                }
+                                else
+                                   s3->accel.err_term += s3->accel.desty_axstp;
+
+                                /*Step major axis*/
+                                switch (s3->accel.cmd & 0xe0)
+                                {
+                                        case 0x00: s3->accel.cx--; break;
+                                        case 0x20: s3->accel.cx++; break;
+                                        case 0x40: s3->accel.cy--; break;
+                                        case 0x60: s3->accel.cy--; break;
+                                        case 0x80: s3->accel.cx--; break;
+                                        case 0xa0: s3->accel.cx++; break;
+                                        case 0xc0: s3->accel.cy++; break;
+                                        case 0xe0: s3->accel.cy++; break;
+                                }
+                                s3->accel.sy--;
+                        }
+                        s3->accel.cur_x = s3->accel.cx;
+                        s3->accel.cur_y = s3->accel.cy;
+                }
+                break;
+                
+                case 2: /*Rectangle fill*/
+                if (!cpu_input) /*!cpu_input is trigger to start operation*/
+                {
+                        s3->accel.sx   = s3->accel.maj_axis_pcnt & 0xfff;
+                        s3->accel.sy   = s3->accel.multifunc[0]  & 0xfff;
+                        s3->accel.cx   = s3->accel.cur_x;
+                        if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
+                        s3->accel.cy   = s3->accel.cur_y;
+                        if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
+                        
+                        s3->accel.dest = s3->accel.cy * s3->width;
+
+//                        pclog("Dest %08X  (%i, %i) %04X %04X\n", s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.cur_x, s3->accel.cur_x & 0x1000);
+                }
+                if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
+//                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
+//                   return;
+
+                frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
+                bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
+                
+                while (count-- && s3->accel.sy >= 0)
+                {
+                        if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
+                            s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
+                        {
+                                switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
+                                {
+                                        case 0: src_dat = s3->accel.bkgd_color; break;
+                                        case 1: src_dat = s3->accel.frgd_color; break;
+                                        case 2: src_dat = cpu_dat; break;
+                                        case 3: src_dat = 0; break;
+                                }
+
+                                if ((compare_mode == 2 && src_dat != compare) ||
+                                    (compare_mode == 3 && src_dat == compare) ||
+                                     compare_mode < 2)
+                                {
+                                        READ_DST(s3->accel.dest + s3->accel.cx, dest_dat);
+                                
+
+//                                if (CS != 0xc000) pclog("Write %05X  %02X %02X  %04X (%02X %02X)  ", s3->accel.dest + s3->accel.cx, src_dat, dest_dat, mix_dat, s3->accel.frgd_mix, s3->accel.bkgd_mix);
+
+                                        MIX
+                                
+//                                if (CS != 0xc000) pclog("%02X\n", dest_dat);
+                                
+                                        WRITE(s3->accel.dest + s3->accel.cx);
+                                }
+                        }
+                
+                        mix_dat <<= 1;
+                        mix_dat |= 1;
+                        if (s3->bpp == 0) cpu_dat >>= 8;
+                        else             cpu_dat >>= 16;
+                        
+                        if (s3->accel.cmd & 0x20) s3->accel.cx++;
+                        else                     s3->accel.cx--;
+                        s3->accel.sx--;
+                        if (s3->accel.sx < 0)
+                        {
+                                if (s3->accel.cmd & 0x20) s3->accel.cx   -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                else                     s3->accel.cx   += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+//                                s3->accel.dest -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                s3->accel.sx    = s3->accel.maj_axis_pcnt & 0xfff;
+                                
+//                                s3->accel.dest  += s3_width;
+                                if (s3->accel.cmd & 0x80) s3->accel.cy++;
+                                else                     s3->accel.cy--;
+                                
+                                s3->accel.dest = s3->accel.cy * s3->width;
+                                s3->accel.sy--;
+
+                                if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
+                                if (s3->accel.sy < 0)
+                                {
+                                        s3->accel.cur_x = s3->accel.cx;
+                                        s3->accel.cur_y = s3->accel.cy;
+                                        return;
+                                }
+                        }
+                }
+                break;
+
+                case 6: /*BitBlt*/
+                if (!cpu_input) /*!cpu_input is trigger to start operation*/
+                {
+                        s3->accel.sx   = s3->accel.maj_axis_pcnt & 0xfff;
+                        s3->accel.sy   = s3->accel.multifunc[0]  & 0xfff;
+
+                        s3->accel.dx   = s3->accel.destx_distp & 0xfff;
+                        if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff;
+                        s3->accel.dy   = s3->accel.desty_axstp & 0xfff;
+                        if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff;
+
+                        s3->accel.cx   = s3->accel.cur_x & 0xfff;
+                        if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
+                        s3->accel.cy   = s3->accel.cur_y & 0xfff;
+                        if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
+
+                        s3->accel.src  = s3->accel.cy * s3->width;
+                        s3->accel.dest = s3->accel.dy * s3->width;
+                        
+//                        pclog("Source %08X Dest %08X  (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy);
+                }
+                if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
+//                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
+//                  return;
+
+                if (s3->accel.sy < 0)
+                   return;
+
+                frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
+                bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
+                
+                if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode &&
+                    (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7) 
+                {
+                        while (1)
+                        {
+                                if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
+                                    s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
+                                {
+                                        READ_SRC(s3->accel.src + s3->accel.cx, src_dat);
+                                        READ_DST(s3->accel.dest + s3->accel.dx, dest_dat);  
+                                        
+                                        dest_dat = (src_dat & s3->accel.wrt_mask) | (dest_dat & ~s3->accel.wrt_mask);
+                                        
+                                        WRITE(s3->accel.dest + s3->accel.dx);
+                                }
+        
+                                s3->accel.cx++;
+                                s3->accel.dx++;
+                                s3->accel.sx--;
+                                if (s3->accel.sx < 0)
+                                {
+                                        s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                        s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                        s3->accel.sx  =  s3->accel.maj_axis_pcnt & 0xfff;
+        
+                                        s3->accel.cy++;
+                                        s3->accel.dy++;
+        
+                                        s3->accel.src  = s3->accel.cy * s3->width;
+                                        s3->accel.dest = s3->accel.dy * s3->width;
+        
+                                        s3->accel.sy--;
+        
+                                        if (s3->accel.sy < 0)
+                                                return;
+                                }
+                        }
+                }
+                else
+                {                     
+                        while (count-- && s3->accel.sy >= 0)
+                        {
+                                if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
+                                    s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
+                                {
+                                        if (vram_mask)
+                                        {
+                                                READ_SRC(s3->accel.src + s3->accel.cx, mix_dat)
+
+                                                mix_dat = mix_dat ? mix_mask : 0;
+                                        }
+                                        switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
+                                        {
+                                                case 0: src_dat = s3->accel.bkgd_color;                  break;
+                                                case 1: src_dat = s3->accel.frgd_color;                  break;
+                                                case 2: src_dat = cpu_dat;                              break;
+                                                case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat);      break;
+                                        }
+
+                                        if ((compare_mode == 2 && src_dat != compare) ||
+                                            (compare_mode == 3 && src_dat == compare) ||
+                                             compare_mode < 2)
+                                        {
+                                                READ_DST(s3->accel.dest + s3->accel.dx, dest_dat);
+                                                                                
+//                                pclog("BitBlt : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X   ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat);
+                                
+                                                MIX
+
+//                                pclog("%02X\n", dest_dat);
+
+                                                WRITE(s3->accel.dest + s3->accel.dx);
+                                        }
+                                }
+
+                                mix_dat <<= 1;
+                                mix_dat |= 1;
+                                if (s3->bpp == 0) cpu_dat >>= 8;
+                                else             cpu_dat >>= 16;
+
+                                if (s3->accel.cmd & 0x20)
+                                {
+                                        s3->accel.cx++;
+                                        s3->accel.dx++;
+                                }
+                                else
+                                {
+                                        s3->accel.cx--;
+                                        s3->accel.dx--;
+                                }
+                                s3->accel.sx--;
+                                if (s3->accel.sx < 0)
+                                {
+                                        if (s3->accel.cmd & 0x20)
+                                        {
+                                                s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                                s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                        }
+                                        else
+                                        {
+                                                s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                                s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                        }
+                                        s3->accel.sx    =  s3->accel.maj_axis_pcnt & 0xfff;
+
+                                        if (s3->accel.cmd & 0x80)
+                                        {
+                                                s3->accel.cy++;
+                                                s3->accel.dy++;
+                                        }
+                                        else
+                                        {
+                                                s3->accel.cy--;
+                                                s3->accel.dy--;
+                                        }
+
+                                        s3->accel.src  = s3->accel.cy * s3->width;
+                                        s3->accel.dest = s3->accel.dy * s3->width;
+
+                                        s3->accel.sy--;
+
+                                        if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
+                                        if (s3->accel.sy < 0)
+                                                return;
+                                }
+                        }
+                }
+                break;
+
+                case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/
+                if (!cpu_input) /*!cpu_input is trigger to start operation*/
+                {
+                        s3->accel.sx   = s3->accel.maj_axis_pcnt & 0xfff;
+                        s3->accel.sy   = s3->accel.multifunc[0]  & 0xfff;
+
+                        s3->accel.dx   = s3->accel.destx_distp & 0xfff;
+                        if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff;
+                        s3->accel.dy   = s3->accel.desty_axstp & 0xfff;
+                        if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff;
+
+                        s3->accel.cx   = s3->accel.cur_x & 0xfff;
+                        if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
+                        s3->accel.cy   = s3->accel.cur_y & 0xfff;
+                        if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
+                        
+                        /*Align source with destination*/
+//                        s3->accel.cx = (s3->accel.cx & ~7) | (s3->accel.dx & 7);
+//                        s3->accel.cy = (s3->accel.cy & ~7) | (s3->accel.dy & 7);
+
+                        s3->accel.pattern  = (s3->accel.cy * s3->width) + s3->accel.cx;
+                        s3->accel.dest     = s3->accel.dy * s3->width;
+                        
+                        s3->accel.cx = s3->accel.dx & 7;
+                        s3->accel.cy = s3->accel.dy & 7;
+                        
+                        s3->accel.src  = s3->accel.pattern + (s3->accel.cy * s3->width);
+
+//                        pclog("Source %08X Dest %08X  (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy);
+//                        dumpregs();
+//                        exit(-1);
+                }
+                if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
+//                if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
+//                   return;
+
+                frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
+                bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
+
+                while (count-- && s3->accel.sy >= 0)
+                {
+                        if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
+                            s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
+                        {
+                                if (vram_mask)
+                                {
+                                        READ_SRC(s3->accel.src + s3->accel.cx, mix_dat)
+                                        mix_dat = mix_dat ? mix_mask : 0;
+                                }
+                                switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
+                                {
+                                        case 0: src_dat = s3->accel.bkgd_color;                  break;
+                                        case 1: src_dat = s3->accel.frgd_color;                  break;
+                                        case 2: src_dat = cpu_dat;                              break;
+                                        case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat);      break;
+                                }
+
+                                if ((compare_mode == 2 && src_dat != compare) ||
+                                    (compare_mode == 3 && src_dat == compare) ||
+                                     compare_mode < 2)
+                                {
+                                        READ_DST(s3->accel.dest + s3->accel.dx, dest_dat);
+                                
+//                                pclog("Pattern fill : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X   ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat);
+
+                                        MIX
+
+//                                pclog("%02X\n", dest_dat);
+
+                                        WRITE(s3->accel.dest + s3->accel.dx);
+                                }
+                        }
+
+                        mix_dat <<= 1;
+                        mix_dat |= 1;
+                        if (s3->bpp == 0) cpu_dat >>= 8;
+                        else             cpu_dat >>= 16;
+
+                        if (s3->accel.cmd & 0x20)
+                        {
+                                s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7);
+                                s3->accel.dx++;
+                        }
+                        else
+                        {
+                                s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7);
+                                s3->accel.dx--;
+                        }
+                        s3->accel.sx--;
+                        if (s3->accel.sx < 0)
+                        {
+                                if (s3->accel.cmd & 0x20)
+                                {
+                                        s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7);
+                                        s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                }
+                                else
+                                {
+                                        s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7);
+                                        s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
+                                }
+                                s3->accel.sx    =  s3->accel.maj_axis_pcnt & 0xfff;
+
+                                if (s3->accel.cmd & 0x80)
+                                {
+                                        s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7);
+                                        s3->accel.dy++;
+                                }
+                                else
+                                {
+                                        s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7);
+                                        s3->accel.dy--;
+                                }
+
+                                s3->accel.src  = s3->accel.pattern + (s3->accel.cy * s3->width);
+                                s3->accel.dest = s3->accel.dy * s3->width;
+
+                                s3->accel.sy--;
+
+                                if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
+                                if (s3->accel.sy < 0)
+                                        return;
+                        }
+                }
+                break;
+                
+                case 3: /*Polygon Fill Solid (Trio64 only)*/
+                {                      
+                        int end_y1, end_y2;
+                          
+                        if (s3->chip != S3_TRIO64)
+                                break;
+
+                        polygon_setup(s3);
+
+                        if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
+                        
+                        end_y1 = s3->accel.desty_axstp;
+                        end_y2 = s3->accel.desty_axstp2;
+
+                        frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
+                        
+
+                        while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2))
+                        {
+                                int y = s3->accel.poly_cy;
+                                int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1;
+
+                                s3->accel.dest = y * s3->width;
+                                
+                                while (x_count-- && count--)
+                                {
+                                        if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r &&
+                                            s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b)
+                                        {
+                                                switch (frgd_mix)
+                                                {
+                                                        case 0: src_dat = s3->accel.bkgd_color; break;
+                                                        case 1: src_dat = s3->accel.frgd_color; break;
+                                                        case 2: src_dat = cpu_dat;              break;
+                                                        case 3: src_dat = 0; /*Nor supported?*/ break;
+                                                }
+
+                                                if ((compare_mode == 2 && src_dat != compare) ||
+                                                    (compare_mode == 3 && src_dat == compare) ||
+                                                     compare_mode < 2)
+                                                {
+                                                        READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat);
+                                
+                                                        MIX
+
+                                                        WRITE(s3->accel.dest + s3->accel.poly_x);
+                                                }
+                                        }
+                                        if (s3->bpp == 0) cpu_dat >>= 8;
+                                        else              cpu_dat >>= 16;
+
+                                        if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20))
+                                                s3->accel.poly_x++;
+                                        else
+                                                s3->accel.poly_x--;
+                                }
+                                
+                                s3->accel.poly_cx += s3->accel.poly_dx1;
+                                s3->accel.poly_cx2 += s3->accel.poly_dx2;
+                                s3->accel.poly_x = s3->accel.poly_cx >> 20;
+                                                                
+                                s3->accel.poly_cy++;
+                                s3->accel.poly_cy2++;
+                                
+                                if (!count)
+                                        break;
+                        }
+                
+                        s3->accel.cur_x = s3->accel.poly_cx & 0xfff;
+                        s3->accel.cur_y = s3->accel.poly_cy & 0xfff;
+                        s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff;
+                        s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff;
+                }
+                break;
+
+                case 11: /*Polygon Fill Pattern (Trio64 only)*/
+                {                      
+                        int end_y1, end_y2;
+                          
+                        if (s3->chip != S3_TRIO64)
+                                break;
+
+                        polygon_setup(s3);
+
+                        if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
+                        
+                        end_y1 = s3->accel.desty_axstp;
+                        end_y2 = s3->accel.desty_axstp2;
+
+                        frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
+                        bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
+                        
+                        while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2))
+                        {
+                                int y = s3->accel.poly_cy;
+                                int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1;
+
+                                s3->accel.src  = s3->accel.pattern + ((y & 7) * s3->width);
+                                s3->accel.dest = y * s3->width;
+                                
+                                while (x_count-- && count--)
+                                {
+                                        int pat_x = s3->accel.poly_x & 7;
+                                        
+                                        if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r &&
+                                            s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b)
+                                        {
+                                                if (vram_mask)
+                                                {
+                                                        READ_SRC(s3->accel.src + pat_x, mix_dat)
+                                                        mix_dat = mix_dat ? mix_mask : 0;
+                                                }
+                                                switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
+                                                {
+                                                        case 0: src_dat = s3->accel.bkgd_color; break;
+                                                        case 1: src_dat = s3->accel.frgd_color; break;
+                                                        case 2: src_dat = cpu_dat;              break;
+                                                        case 3: READ_SRC(s3->accel.src + pat_x, src_dat); break;
+                                                }
+
+                                                if ((compare_mode == 2 && src_dat != compare) ||
+                                                    (compare_mode == 3 && src_dat == compare) ||
+                                                     compare_mode < 2)
+                                                {
+                                                        READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat);
+                                
+                                                        MIX
+
+                                                        WRITE(s3->accel.dest + s3->accel.poly_x);
+                                                }
+                                        }
+                                        if (s3->bpp == 0) cpu_dat >>= 8;
+                                        else              cpu_dat >>= 16;
+
+                                        mix_dat <<= 1;
+                                        mix_dat |= 1;
+
+                                        if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20))
+                                                s3->accel.poly_x++;
+                                        else
+                                                s3->accel.poly_x--;
+                                }
+                                
+                                s3->accel.poly_cx += s3->accel.poly_dx1;
+                                s3->accel.poly_cx2 += s3->accel.poly_dx2;
+                                s3->accel.poly_x = s3->accel.poly_cx >> 20;
+                                                                
+                                s3->accel.poly_cy++;
+                                s3->accel.poly_cy2++;
+                                
+                                if (!count)
+                                        break;
+                        }
+                
+                        s3->accel.cur_x = s3->accel.poly_cx & 0xfff;
+                        s3->accel.cur_y = s3->accel.poly_cy & 0xfff;
+                        s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff;
+                        s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff;
+                }
+                break;
+        }
+}
+
+void s3_hwcursor_draw(svga_t *svga, int displine)
+{
+        s3_t *s3 = (s3_t *)svga->p;
+        int x;
+        uint16_t dat[2];
+        int xx;
+        int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
+        uint32_t fg = 0, bg = 0;
+                
+        switch (svga->bpp)
+        {               
+                case 15:
+                fg = video_15to32[s3->hwc_fg_col & 0xffff];
+                bg = video_15to32[s3->hwc_bg_col & 0xffff];
+                break;
+                
+                case 16:
+                fg = video_16to32[s3->hwc_fg_col & 0xffff];
+                bg = video_16to32[s3->hwc_bg_col & 0xffff];
+                break;
+                
+                case 24: case 32:
+                fg = s3->hwc_fg_col;
+                bg = s3->hwc_bg_col;
+                break;
+
+                default:
+                if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64)
+                {
+                        fg = svga->pallook[s3->hwc_fg_col & 0xff];
+                        bg = svga->pallook[s3->hwc_bg_col & 0xff];
+                }
+                else
+                {
+                        fg = svga->pallook[svga->crtc[0xe]];
+                        bg = svga->pallook[svga->crtc[0xf]];
+                }
+                break;
+        }
+
+        if (svga->interlace && svga->hwcursor_oddeven)
+                svga->hwcursor_latch.addr += 16;
+
+//        pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y);
+        for (x = 0; x < 64; x += 16)
+        {
+                dat[0] = (svga->vram[svga->hwcursor_latch.addr]     << 8) | svga->vram[svga->hwcursor_latch.addr + 1];
+                dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3];
+                for (xx = 0; xx < 16; xx++)
+                {
+                        if (offset >= svga->hwcursor_latch.x)
+                        {
+                                if (!(dat[0] & 0x8000))
+                                   ((uint32_t *)buffer32->line[displine])[offset + 32]  = (dat[1] & 0x8000) ? fg : bg;
+                                else if (dat[1] & 0x8000)
+                                   ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
+//                                pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]);
+                        }
+                           
+                        offset++;
+                        dat[0] <<= 1;
+                        dat[1] <<= 1;
+                }
+                svga->hwcursor_latch.addr += 4;
+        }
+        if (svga->interlace && !svga->hwcursor_oddeven)
+                svga->hwcursor_latch.addr += 16;
+}
+
+
+static void s3_io_remove(s3_t *s3)
+{
+        io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
+        
+        io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l,  s3);
+}
+
+static void s3_io_set(s3_t *s3)
+{
+        s3_io_remove(s3);
+
+        io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
+        
+        io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        if (s3->chip == S3_TRIO64)
+        {
+                io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        }
+        else
+        {
+                io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+                io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        }
+        io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL,  s3);
+        io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l,  s3);
+}
+
+        
+uint8_t s3_pci_read(int func, int addr, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        svga_t *svga = &s3->svga;
+//        pclog("S3 PCI read %08X\n", addr);
+        switch (addr)
+        {
+                case 0x00: return 0x33; /*'S3'*/
+                case 0x01: return 0x53;
+                
+                case 0x02: return s3->id_ext_pci;
+                case 0x03: return 0x88;
+                
+                case PCI_REG_COMMAND:
+                return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/
+
+                case 0x07: return 1 << 1; /*Medium DEVSEL timing*/
+                
+                case 0x08: return 0; /*Revision ID*/
+                case 0x09: return 0; /*Programming interface*/
+                
+                case 0x0a: return 0x00; /*Supports VGA interface*/
+                case 0x0b: return 0x03;
+                
+                case 0x10: return 0x00; /*Linear frame buffer address*/
+                case 0x11: return 0x00;
+                case 0x12: return svga->crtc[0x5a] & 0x80;
+                case 0x13: return svga->crtc[0x59];
+
+                case 0x30: return s3->pci_regs[0x30] & 0x01; /*BIOS ROM address*/
+                case 0x31: return 0x00;
+                case 0x32: return s3->pci_regs[0x32];
+                case 0x33: return s3->pci_regs[0x33];
+                
+                case 0x3c: return s3->int_line;
+                case 0x3d: return PCI_INTA;
+        }
+        return 0;
+}
+
+void s3_pci_write(int func, int addr, uint8_t val, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        svga_t *svga = &s3->svga;
+//        pclog("s3_pci_write: addr=%02x val=%02x\n", addr, val);
+        switch (addr)
+        {
+                case PCI_REG_COMMAND:
+                s3->pci_regs[PCI_REG_COMMAND] = val & 0x23;
+                if (val & PCI_COMMAND_IO)
+                        s3_io_set(s3);
+                else
+                        s3_io_remove(s3);
+                s3_updatemapping(s3);
+                break;
+                
+                case 0x12: 
+                svga->crtc[0x5a] = val & 0x80; 
+                s3_updatemapping(s3); 
+                break;
+                case 0x13: 
+                svga->crtc[0x59] = val;        
+                s3_updatemapping(s3); 
+                break;                
+
+                case 0x30: case 0x32: case 0x33:
+                s3->pci_regs[addr] = val;
+                if (s3->pci_regs[0x30] & 0x01)
+                {
+                        uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24);
+//                        pclog("S3 bios_rom enabled at %08x\n", addr);
+                        mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000);
+                }
+                else
+                {
+//                        pclog("S3 bios_rom disabled\n");
+                        mem_mapping_disable(&s3->bios_rom.mapping);
+                }
+                return;
+                
+                case 0x3c:
+                s3->int_line = val;
+                return;
+        }
+}
+
+static int vram_sizes[] =
+{
+        7, /*512 kB*/
+        6, /*1 MB*/
+        4, /*2 MB*/
+        0,
+        0, /*4 MB*/
+        0,
+        0,
+        0,
+        3 /*8 MB*/
+};
+
+static void *s3_init(char *bios_fn, int chip)
+{
+        s3_t *s3 = malloc(sizeof(s3_t));
+        svga_t *svga = &s3->svga;
+        int vram;
+        uint32_t vram_size;
+        
+        memset(s3, 0, sizeof(s3_t));
+        
+        vram = device_get_config_int("memory");
+        if (vram)
+                vram_size = vram << 20;
+        else
+                vram_size = 512 << 10;
+        s3->vram_mask = vram_size - 1;
+
+        rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+        if (PCI)
+                mem_mapping_disable(&s3->bios_rom.mapping);
+
+        mem_mapping_add(&s3->linear_mapping, 0,       0,       svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga);
+        mem_mapping_add(&s3->mmio_mapping,   0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3);
+        mem_mapping_disable(&s3->mmio_mapping);
+
+        svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/
+                   s3_recalctimings,
+                   s3_in, s3_out,
+                   s3_hwcursor_draw,
+                   NULL);
+
+        svga->decode_mask = (4 << 20) - 1;
+        switch (vram)
+        {
+                case 0: /*512kb*/
+                svga->vram_mask = (1 << 19) - 1;
+                svga->vram_max = 2 << 20;
+                break;
+                case 1: /*1MB*/
+                /*VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus*/
+                /*This works with the #9 9FX BIOS, and matches how my real Trio64 behaves,
+                  but does not work with the Phoenix EDO BIOS. Possibly an FPM/EDO difference?*/
+                svga->vram_mask = (1 << 20) - 1;
+                svga->vram_max = 2 << 20;
+                break;
+                case 2: default: /*2MB*/
+                /*VRAM in first 2 MB, 3rd and 4th MBs are open bus*/
+                svga->vram_mask = (2 << 20) - 1;
+                svga->vram_max = 2 << 20;
+                break;
+                case 4: /*4MB*/
+                svga->vram_mask = (4 << 20) - 1;
+                svga->vram_max = 4 << 20;
+                break;
+        }
+                
+        if (PCI)
+                svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
+        else
+                svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
+        svga->crtc[0x37] = 1 | (7 << 5);
+        
+        svga->vblank_start = s3_vblank_start;
+
+        s3_io_set(s3);
+
+        s3->card = pci_add(s3_pci_read, s3_pci_write, s3);
+        
+        s3->pci_regs[0x04] = 7;
+        
+        s3->pci_regs[0x30] = 0x00;
+        s3->pci_regs[0x32] = 0x0c;
+        s3->pci_regs[0x33] = 0x00;
+        
+        s3->chip = chip;
+
+        s3->wake_fifo_thread = thread_create_event();
+        s3->fifo_not_full_event = thread_create_event();
+        s3->fifo_thread = thread_create(fifo_thread, s3);
+        
+        s3->int_line = 0;
+        return s3;
+}
+
+void *s3_bahamas64_init()
+{
+        s3_t *s3 = s3_init("bahamas64.bin", S3_VISION864);
+
+        s3->id = 0xc0; /*Vision864P*/
+        s3->id_ext = s3->id_ext_pci = 0xc0;
+        s3->packed_mmio = 0;
+        
+        s3->getclock = sdac_getclock;
+        s3->getclock_p = &s3->ramdac;
+        sdac_init(&s3->ramdac);
+
+        return s3;
+}
+
+int s3_bahamas64_available()
+{
+        return rom_present("bahamas64.bin");
+}
+
+void *s3_9fx_init()
+{
+        s3_t *s3 = s3_init("s3_764.bin", S3_TRIO64);
+
+        s3->id = 0xe1; /*Trio64*/
+        s3->id_ext = s3->id_ext_pci = 0x11;
+        s3->packed_mmio = 1;
+
+        s3->getclock = s3_trio64_getclock;
+        s3->getclock_p = s3;
+
+        return s3;
+}
+
+int s3_9fx_available()
+{
+        return rom_present("s3_764.bin");
+}
+
+void *s3_phoenix_trio32_init()
+{
+        s3_t *s3 = s3_init("86c732p.bin", S3_TRIO32);
+
+        s3->id = 0xe1; /*Trio32*/
+        s3->id_ext = 0x10;
+        s3->id_ext_pci = 0x11;
+        s3->packed_mmio = 1;
+
+        s3->getclock = s3_trio64_getclock;
+        s3->getclock_p = s3;
+
+        return s3;
+}
+
+int s3_phoenix_trio32_available()
+{
+        return rom_present("86c732p.bin");
+}
+
+void *s3_phoenix_trio64_init()
+{
+        s3_t *s3 = s3_init("86c764x1.bin", S3_TRIO64);
+
+        s3->id = 0xe1; /*Trio64*/
+        s3->id_ext = s3->id_ext_pci = 0x11;
+        s3->packed_mmio = 1;
+        if (device_get_config_int("memory") == 1)
+                s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/
+
+        s3->getclock = s3_trio64_getclock;
+        s3->getclock_p = s3;
+
+        return s3;
+}
+
+int s3_phoenix_trio64_available()
+{
+        return rom_present("86c764x1.bin");
+}
+
+void s3_close(void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+
+        svga_close(&s3->svga);
+        
+        thread_kill(s3->fifo_thread);
+        thread_destroy_event(s3->wake_fifo_thread);
+        thread_destroy_event(s3->fifo_not_full_event);
+
+        free(s3);
+}
+
+void s3_speed_changed(void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        
+        svga_recalctimings(&s3->svga);
+}
+
+void s3_force_redraw(void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+
+        s3->svga.fullchange = changeframecount;
+}
+
+void s3_add_status_info(char *s, int max_len, void *p)
+{
+        s3_t *s3 = (s3_t *)p;
+        char temps[256];
+        uint64_t new_time = timer_read();
+        uint64_t status_diff = new_time - s3->status_time;
+        s3->status_time = new_time;
+
+        if (!status_diff)
+                status_diff = 1;
+        
+        svga_add_status_info(s, max_len, &s3->svga);
+        sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)s3->blitter_time * 100.0) / timer_freq, ((double)s3->blitter_time * 100.0) / status_diff);
+        strncat(s, temps, max_len);
+
+        s3->blitter_time = 0;
+}
+
+static device_config_t s3_bahamas64_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "1 MB",
+                                .value = 1
+                        },
+                        {
+                                .description = "2 MB",
+                                .value = 2
+                        },
+                        /*Vision864 also supports 4 and 8 MB, however the Paradise
+                          BIOS is buggy (VESA modes don't work correctly), and UNIVBE and
+                          OS/2 Warp misdetect the VRAM size. Bahamas 64 only supports
+                          up to 2 MB on the board anyway. */
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 4
+        },
+        {
+                .type = -1
+        }
+};
+
+static device_config_t s3_9fx_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "1 MB",
+                                .value = 1
+                        },
+                        {
+                                .description = "2 MB",
+                                .value = 2
+                        },
+                        /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 2
+        },
+        {
+                .type = -1
+        }
+};
+
+static device_config_t s3_phoenix_trio32_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "512 KB",
+                                .value = 0
+                        },
+                        {
+                                .description = "1 MB",
+                                .value = 1
+                        },
+                        {
+                                .description = "2 MB",
+                                .value = 2
+                        },
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 2
+        },
+        {
+                .type = -1
+        }
+};
+
+static device_config_t s3_phoenix_trio64_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "1 MB",
+                                .value = 1
+                        },
+                        {
+                                .description = "2 MB",
+                                .value = 2
+                        },
+                        {
+                                .description = "4 MB",
+                                .value = 4
+                        },
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 2
+        },
+        {
+                .type = -1
+        }
+};
+
+device_t s3_bahamas64_device =
+{
+        "Paradise Bahamas 64 (S3 Vision864)",
+        0,
+        s3_bahamas64_init,
+        s3_close,
+        s3_bahamas64_available,
+        s3_speed_changed,
+        s3_force_redraw,
+        s3_add_status_info,
+        s3_bahamas64_config
+};
+
+device_t s3_9fx_device =
+{
+        "Number 9 9FX (S3 Trio64)",
+        0,
+        s3_9fx_init,
+        s3_close,
+        s3_9fx_available,
+        s3_speed_changed,
+        s3_force_redraw,
+        s3_add_status_info,
+        s3_9fx_config
+};
+
+device_t s3_phoenix_trio32_device =
+{
+        "Phoenix S3 Trio32",
+        0,
+        s3_phoenix_trio32_init,
+        s3_close,
+        s3_phoenix_trio32_available,
+        s3_speed_changed,
+        s3_force_redraw,
+        s3_add_status_info,
+        s3_phoenix_trio32_config
+};
+
+device_t s3_phoenix_trio64_device =
+{
+        "Phoenix S3 Trio64",
+        0,
+        s3_phoenix_trio64_init,
+        s3_close,
+        s3_phoenix_trio64_available,
+        s3_speed_changed,
+        s3_force_redraw,
+        s3_add_status_info,
+        s3_phoenix_trio64_config
+};
diff --git a/pcem/vid_s3.h b/pcem/vid_s3.h
new file mode 100644 (file)
index 0000000..ee04039
--- /dev/null
@@ -0,0 +1,4 @@
+device_t s3_bahamas64_device;
+device_t s3_9fx_device;
+device_t s3_phoenix_trio32_device;
+device_t s3_phoenix_trio64_device;
diff --git a/pcem/vid_s3_virge.cpp b/pcem/vid_s3_virge.cpp
new file mode 100644 (file)
index 0000000..33e85fd
--- /dev/null
@@ -0,0 +1,4150 @@
+/*S3 ViRGE emulation*/
+#include <stdlib.h>
+#include "ibm.h"
+#include "device.h"
+#include "io.h"
+#include "mem.h"
+#include "pci.h"
+#include "rom.h"
+#include "thread.h"
+#include "video.h"
+#include "vid_s3_virge.h"
+#include "vid_svga.h"
+#include "vid_svga_render.h"
+
+#ifdef MIN
+#undef MIN
+#endif
+#ifdef MAX
+#undef MAX
+#endif
+#ifdef CLAMP
+#undef CLAMP
+#endif
+
+static uint64_t virge_time = 0;
+static uint64_t status_time = 0;
+static int reg_writes = 0, reg_reads = 0;
+
+static int dither[4][4] =
+{
+        {0,  4,  1,  5},
+        {6,  2,  7,  3},
+        {1,  5,  0,  4},
+        {7,  3,  6,  2},
+};
+
+#define RB_SIZE 256
+#define RB_MASK (RB_SIZE - 1)
+
+#define RB_ENTRIES (virge->s3d_write_idx - virge->s3d_read_idx)
+#define RB_FULL (RB_ENTRIES == RB_SIZE)
+#define RB_EMPTY (!RB_ENTRIES)
+
+#define FIFO_SIZE 65536
+#define FIFO_MASK (FIFO_SIZE - 1)
+#define FIFO_ENTRY_SIZE (1 << 31)
+
+#define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx)
+#define FIFO_FULL    ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE)
+#define FIFO_EMPTY   (virge->fifo_read_idx == virge->fifo_write_idx)
+
+#define FIFO_TYPE 0xff000000
+#define FIFO_ADDR 0x00ffffff
+
+enum
+{
+        FIFO_INVALID     = (0x00 << 24),
+        FIFO_WRITE_BYTE  = (0x01 << 24),
+        FIFO_WRITE_WORD  = (0x02 << 24),
+        FIFO_WRITE_DWORD = (0x03 << 24),
+};
+
+typedef struct
+{
+        uint32_t addr_type;
+        uint32_t val;
+} fifo_entry_t;
+
+typedef struct s3d_t
+{
+        uint32_t cmd_set;
+        int clip_l, clip_r, clip_t, clip_b;
+                
+        uint32_t dest_base;
+        uint32_t dest_str;
+        
+        uint32_t z_base;
+        uint32_t z_str;
+
+        uint32_t tex_base;
+        uint32_t tex_bdr_clr;
+        uint32_t tbv, tbu;
+        int32_t TdVdX, TdUdX;
+        int32_t TdVdY, TdUdY;
+        uint32_t tus, tvs;
+
+        int32_t TdZdX, TdZdY;
+        uint32_t tzs;
+
+        int32_t TdWdX, TdWdY;
+        uint32_t tws;
+                
+        int32_t TdDdX, TdDdY;
+        uint32_t tds;
+                
+        int16_t TdGdX, TdBdX, TdRdX, TdAdX;
+        int16_t TdGdY, TdBdY, TdRdY, TdAdY;
+        uint32_t tgs, tbs, trs, tas;
+                                
+        uint32_t TdXdY12;
+        uint32_t txend12;
+        uint32_t TdXdY01;
+        uint32_t txend01;
+        uint32_t TdXdY02;
+        uint32_t txs;
+        uint32_t tys;
+        int ty01, ty12, tlr;
+} s3d_t;
+        
+typedef struct virge_t
+{
+        mem_mapping_t   linear_mapping;
+        mem_mapping_t     mmio_mapping;
+        mem_mapping_t new_mmio_mapping;
+        
+        rom_t bios_rom;
+        
+        svga_t svga;
+        
+        uint8_t bank;
+        uint8_t ma_ext;
+
+        uint8_t virge_id, virge_id_high, virge_id_low, virge_rev;
+
+        uint32_t linear_base, linear_size;
+
+        uint8_t pci_regs[256];
+        int card;
+
+        int is_375;
+
+        int bilinear_enabled;
+        int dithering_enabled;
+        int memory_size;
+        
+        int pixel_count, tri_count;
+        
+        thread_t *render_thread;
+        event_t *wake_render_thread;
+        event_t *wake_main_thread;
+        event_t *not_full_event;
+        
+        uint32_t hwc_fg_col, hwc_bg_col;
+        int hwc_col_stack_pos;
+                        
+        struct
+        {
+                uint32_t src_base;
+                uint32_t dest_base;
+                int clip_l, clip_r, clip_t, clip_b;
+                int dest_str, src_str;
+                uint32_t mono_pat_0;
+                uint32_t mono_pat_1;
+                uint32_t pat_bg_clr;
+                uint32_t pat_fg_clr;
+                uint32_t src_bg_clr;
+                uint32_t src_fg_clr;
+                uint32_t cmd_set;
+                int r_width, r_height;
+                int rsrc_x, rsrc_y;
+                int rdest_x, rdest_y;
+                
+                int lxend0, lxend1;
+                int32_t ldx;
+                uint32_t lxstart, lystart;
+                int lycnt;
+                int line_dir;
+                
+                int src_x, src_y;
+                int dest_x, dest_y;
+                int w, h;
+                uint8_t rop;
+                
+                int data_left_count;
+                uint32_t data_left;
+                
+                uint32_t pattern_8[8*8];
+                uint32_t pattern_16[8*8];
+                uint32_t pattern_32[8*8];
+
+                uint32_t prdx;
+                uint32_t prxstart;
+                uint32_t pldx;
+                uint32_t plxstart;
+                uint32_t pystart;
+                uint32_t pycnt;
+                uint32_t dest_l, dest_r;
+        } s3d;
+        
+        s3d_t s3d_tri;
+
+        s3d_t s3d_buffer[RB_SIZE];
+        int s3d_read_idx, s3d_write_idx;
+        int s3d_busy;
+                
+        struct
+        {
+                uint32_t pri_ctrl;
+                uint32_t chroma_ctrl;
+                uint32_t sec_ctrl;
+                uint32_t chroma_upper_bound;
+                uint32_t sec_filter;
+                uint32_t blend_ctrl;
+                uint32_t pri_fb0, pri_fb1;
+                uint32_t pri_stride;
+                uint32_t buffer_ctrl;
+                uint32_t sec_fb0, sec_fb1;
+                uint32_t sec_stride;
+                uint32_t overlay_ctrl;
+                 int32_t k1_vert_scale;
+                 int32_t k2_vert_scale;
+                 int32_t dda_vert_accumulator;
+                 int32_t k1_horiz_scale;
+                 int32_t k2_horiz_scale;
+                 int32_t dda_horiz_accumulator;
+                uint32_t fifo_ctrl;
+                uint32_t pri_start;
+                uint32_t pri_size;
+                uint32_t sec_start;
+                uint32_t sec_size;
+                
+                int sdif;
+                
+                int pri_x, pri_y, pri_w, pri_h;
+                int sec_x, sec_y, sec_w, sec_h;
+        } streams;
+
+        fifo_entry_t fifo[FIFO_SIZE];
+        volatile int fifo_read_idx, fifo_write_idx;
+
+        thread_t *fifo_thread;
+        event_t *wake_fifo_thread;
+        event_t *fifo_not_full_event;
+        
+        int virge_busy;
+        
+        uint8_t subsys_stat, subsys_cntl;
+} virge_t;
+
+static inline void wake_fifo_thread(virge_t *virge)
+{
+        thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
+}
+
+static void queue_triangle(virge_t *virge);
+
+static void s3_virge_recalctimings(svga_t *svga);
+static void s3_virge_updatemapping(virge_t *virge);
+
+static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat);
+
+static uint8_t  s3_virge_mmio_read(uint32_t addr, void *p);
+static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p);
+static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p);
+static void     s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p);
+static void     s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p);
+static void     s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p);
+
+enum
+{
+        CMD_SET_AE = 1,
+        CMD_SET_HC = (1 << 1),
+        
+        CMD_SET_FORMAT_MASK = (7 << 2),
+        CMD_SET_FORMAT_8 = (0 << 2),
+        CMD_SET_FORMAT_16 = (1 << 2),
+        CMD_SET_FORMAT_24 = (2 << 2),
+        
+        CMD_SET_MS = (1 << 6),
+        CMD_SET_IDS = (1 << 7),
+        CMD_SET_MP = (1 << 8),
+        CMD_SET_TP = (1 << 9),
+        
+        CMD_SET_ITA_MASK = (3 << 10),
+        CMD_SET_ITA_BYTE = (0 << 10),
+        CMD_SET_ITA_WORD = (1 << 10),
+        CMD_SET_ITA_DWORD = (2 << 10),
+        
+        CMD_SET_ZUP = (1 << 23),
+        
+        CMD_SET_ZB_MODE = (3 << 24),
+
+        CMD_SET_XP = (1 << 25),
+        CMD_SET_YP = (1 << 26),
+        
+        CMD_SET_COMMAND_MASK = (15 << 27)
+};
+
+#define CMD_SET_ABC_SRC    (1 << 18)
+#define CMD_SET_ABC_ENABLE (1 << 19)
+#define CMD_SET_TWE        (1 << 26)
+
+enum
+{
+        CMD_SET_COMMAND_BITBLT = (0 << 27),
+        CMD_SET_COMMAND_RECTFILL = (2 << 27),
+        CMD_SET_COMMAND_LINE = (3 << 27),
+        CMD_SET_COMMAND_POLY = (5 << 27),
+        CMD_SET_COMMAND_NOP = (15 << 27)
+};
+
+#define INT_VSY      (1 << 0)
+#define INT_S3D_DONE (1 << 1)
+#define INT_FIFO_OVF (1 << 2)
+#define INT_FIFO_EMP (1 << 3)
+#define INT_3DF_EMP  (1 << 6)
+#define INT_MASK 0xff
+
+static void s3_virge_update_irqs(virge_t *virge)
+{
+        if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & virge->subsys_cntl & INT_MASK))
+                pci_set_irq(virge->card, PCI_INTA);
+        else
+                pci_clear_irq(virge->card, PCI_INTA);
+}
+
+static void s3_virge_out(uint16_t addr, uint8_t val, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        svga_t *svga = &virge->svga;
+        uint8_t old;
+
+        if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) 
+                addr ^= 0x60;
+       
+//        pclog("S3 out %04X %02X %04X:%08X  %04X %04X %i\n", addr, val, CS, pc, ES, BX, ins);
+
+        switch (addr)
+        {
+                case 0x3c5:
+                if (svga->seqaddr >= 0x10)
+                {
+                        svga->seqregs[svga->seqaddr & 0x1f]=val;
+                        svga_recalctimings(svga);
+                        return;
+                }
+                if (svga->seqaddr == 4) /*Chain-4 - update banking*/
+                {
+                        if (val & 8) svga->write_bank = svga->read_bank = virge->bank << 16;
+                        else         svga->write_bank = svga->read_bank = virge->bank << 14;
+                }
+                break;
+                
+                //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
+//                pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc);
+                //sdac_ramdac_out(addr,val);
+                //return;
+
+                case 0x3d4:
+                svga->crtcreg = val;// & 0x7f;
+                return;
+                case 0x3d5:
+                //pclog("Write CRTC R%02X %02X  %04x(%08x):%08x\n", svga->crtcreg, val, CS, cs, pc);
+                if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
+                        return;
+                if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
+                        val = (svga->crtc[7] & ~0x10) | (val & 0x10);
+                if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) 
+                        return;
+                if (svga->crtcreg >= 0x80)
+                        return;
+                old = svga->crtc[svga->crtcreg];
+                svga->crtc[svga->crtcreg] = val;
+                switch (svga->crtcreg)
+                {
+                        case 0x31:
+                        virge->ma_ext = (virge->ma_ext & 0x1c) | ((val & 0x30) >> 4);
+                        break;
+                        case 0x32:
+                        s3_virge_update_irqs(virge);
+                        break;
+                        
+                        case 0x69:
+                        virge->ma_ext = val & 0x1f;
+                        break;
+                        
+                        case 0x35:
+                        virge->bank = (virge->bank & 0x70) | (val & 0xf);
+//                        pclog("CRTC write R35 %02X\n", val);
+                        if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16;
+                        else              svga->write_bank = svga->read_bank = virge->bank << 14;
+                        break;
+                        case 0x51:
+                        virge->bank = (virge->bank & 0x4f) | ((val & 0xc) << 2);
+                        if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16;
+                        else              svga->write_bank = svga->read_bank = virge->bank << 14;
+                        virge->ma_ext = (virge->ma_ext & ~0xc) | ((val & 3) << 2);
+                        break;
+                        case 0x6a:
+                        virge->bank = val;
+//                        pclog("CRTC write R6a %02X\n", val);
+                        if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16;
+                        else              svga->write_bank = svga->read_bank = virge->bank << 14;
+                        break;
+                        
+                        case 0x3a:
+                        if (val & 0x10) svga->gdcreg[5] |= 0x40; /*Horrible cheat*/
+                        break;
+                        
+                        case 0x45:
+                        svga->hwcursor.ena = val & 1;
+                        break;
+                        case 0x46: case 0x47: case 0x48: case 0x49:
+                        case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+                        svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff;
+                        svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff;
+                        svga->hwcursor.xoff = svga->crtc[0x4e] & 63;
+                        svga->hwcursor.yoff = svga->crtc[0x4f] & 63;
+                        svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16);
+                        break;
+                        
+                        case 0x4a:
+                        switch (virge->hwc_col_stack_pos)
+                        {
+                                case 0:
+                                virge->hwc_fg_col = (virge->hwc_fg_col & 0xffff00) | val;
+                                break;
+                                case 1:
+                                virge->hwc_fg_col = (virge->hwc_fg_col & 0xff00ff) | (val << 8);
+                                break;
+                                case 2:
+                                virge->hwc_fg_col = (virge->hwc_fg_col & 0x00ffff) | (val << 16);
+                                break;
+                        }
+                        virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 3;
+                        break;
+                        case 0x4b:
+                        switch (virge->hwc_col_stack_pos)
+                        {
+                                case 0:
+                                virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val;
+                                break;
+                                case 1:
+                                virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8);
+                                break;
+                                case 2:
+                                virge->hwc_bg_col = (virge->hwc_bg_col & 0x00ffff) | (val << 16);
+                                break;
+                        }
+                        virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 3;
+                        break;
+
+                        case 0x53:
+                        case 0x58: case 0x59: case 0x5a:
+                        s3_virge_updatemapping(virge);
+                        break;
+                        
+                        case 0x67:
+                        switch (val >> 4)
+                        {
+                                case 3:  svga->bpp = 15; break;
+                                case 5:  svga->bpp = 16; break;
+                                case 7:  svga->bpp = 24; break;
+                                case 13: svga->bpp = 32; break;
+                                default: svga->bpp = 8;  break;
+                        }
+                        break;
+                        //case 0x55: case 0x43:
+//                                pclog("Write CRTC R%02X %02X\n", crtcreg, val);
+                }
+                if (old != val)
+                {
+                        if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
+                        {
+                                svga->fullchange = changeframecount;
+                                svga_recalctimings(svga);
+                        }
+                }
+                break;
+        }
+        svga_out(addr, val, svga);
+}
+
+static uint8_t s3_virge_in(uint16_t addr, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        svga_t *svga = &virge->svga;
+        uint8_t ret;
+        
+        if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) 
+                addr ^= 0x60;
+
+//        if (addr != 0x3da) pclog("S3 in %04X %04X:%08X  ", addr, CS, pc);
+        switch (addr)
+        {
+                case 0x3c1:
+                if (svga->attraddr > 0x14)
+                        ret = 0xff;
+                else
+                        ret = svga_in(addr, svga);
+                break; 
+                //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
+//                pclog("Read RAMDAC %04X  %04X:%04X\n", addr, CS, pc);
+                //return sdac_ramdac_in(addr);
+
+                case 0x3c5:
+                if (svga->seqaddr >= 8)
+                        ret = svga->seqregs[svga->seqaddr & 0x1f];
+                else if (svga->seqaddr <= 4)
+                        ret = svga_in(addr, svga);
+                else
+                        ret = 0xff;
+                break;
+
+                case 0x3D4:
+                ret = svga->crtcreg;
+                break;
+                case 0x3D5:
+                //pclog("Read CRTC R%02X %04X:%04X (%02x)\n", svga->crtcreg, CS, pc, svga->crtc[svga->crtcreg]);
+                switch (svga->crtcreg)
+                {
+                        case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/
+                        case 0x2e: ret = virge->virge_id_low;  break; /*New chip ID*/
+                        case 0x2f: ret = virge->virge_rev;     break; 
+                        case 0x30: ret = virge->virge_id;      break; /*Chip ID*/
+                        case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); break;
+                        case 0x35: ret = (svga->crtc[0x35] & 0xf0) | (virge->bank & 0xf); break;
+                        case 0x36: ret = (svga->crtc[0x36] & 0xfc) | 2; break; /*PCI bus*/
+                        case 0x45: virge->hwc_col_stack_pos = 0; ret = svga->crtc[0x45]; break;
+                        case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break;
+                        case 0x69: ret = virge->ma_ext; break;
+                        case 0x6a: ret = virge->bank; break;
+                        default:   ret = svga->crtc[svga->crtcreg]; break;
+                }
+                break;
+                
+                default:
+                ret = svga_in(addr, svga);
+                break; 
+        }
+//        if (addr != 0x3da) pclog("%02X\n", ret);
+        return ret;
+}
+
+static void s3_virge_recalctimings(svga_t *svga)
+{
+        virge_t *virge = (virge_t *)svga->p;
+
+        if (svga->crtc[0x5d] & 0x01) svga->htotal      += 0x100;
+        if (svga->crtc[0x5d] & 0x02) svga->hdisp       += 0x100;
+        if (svga->crtc[0x5e] & 0x01) svga->vtotal      += 0x400;
+        if (svga->crtc[0x5e] & 0x02) svga->dispend     += 0x400;
+        if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400;
+        if (svga->crtc[0x5e] & 0x10) svga->vsyncstart  += 0x400;
+        if (svga->crtc[0x5e] & 0x40) svga->split       += 0x400;
+        svga->interlace = svga->crtc[0x42] & 0x20;
+
+        if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/
+        {
+                svga->ma_latch |= (virge->ma_ext << 16);
+//pclog("VGA mode\n");
+                if (svga->crtc[0x51] & 0x30)      svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4;
+                else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100;
+                if (!svga->rowoffset) svga->rowoffset = 256;
+
+                if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10))
+                {
+                        switch (svga->bpp)
+                        {
+                                case 8: 
+                                svga->render = svga_render_8bpp_highres; 
+                                break;
+                                case 15: 
+                                svga->render = svga_render_15bpp_highres; 
+                                break;
+                                case 16: 
+                                svga->render = svga_render_16bpp_highres; 
+                                break;
+                                case 24: 
+                                svga->render = svga_render_24bpp_highres; 
+                                break;
+                                case 32: 
+                                svga->render = svga_render_32bpp_highres; 
+                                break;
+                        }
+                }
+        
+//                pclog("svga->rowoffset = %i bpp=%i\n", svga->rowoffset, svga->bpp);
+                if (svga->bpp == 15 || svga->bpp == 16)
+                {
+                        svga->htotal >>= 1;
+                        svga->hdisp >>= 1;
+                }
+                if (svga->bpp == 24)
+                {
+                        svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/
+                }
+                svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : ((virge->memory_size << 20) - 1);
+//pclog("VGA mode   x_disp=%i dispend=%i vtotal=%i\n", svga->hdisp, svga->dispend, svga->vtotal);
+        }
+        else /*Streams mode*/
+        {
+                if (virge->streams.buffer_ctrl & 1)
+                        svga->ma_latch = virge->streams.pri_fb1 >> 2;
+                else
+                        svga->ma_latch = virge->streams.pri_fb0 >> 2;
+                        
+                svga->hdisp = virge->streams.pri_w + 1;
+                if (virge->streams.pri_h < svga->dispend)
+                        svga->dispend = virge->streams.pri_h;
+                
+                svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x;
+                svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y;
+                svga->overlay.ysize = virge->streams.sec_h;
+
+                if (virge->streams.buffer_ctrl & 2)
+                        svga->overlay.addr = virge->streams.sec_fb1;
+                else
+                        svga->overlay.addr = virge->streams.sec_fb0;
+
+                svga->overlay.ena = (svga->overlay.x >= 0);
+                svga->overlay.v_acc = virge->streams.dda_vert_accumulator;
+//pclog("Streams mode   x_disp=%i dispend=%i vtotal=%i  x=%i y=%i ysize=%i\n", svga->hdisp, svga->dispend, svga->vtotal, svga->overlay.x, svga->overlay.y, svga->overlay.ysize);
+                svga->rowoffset = virge->streams.pri_stride >> 3;
+
+                switch ((virge->streams.pri_ctrl >> 24) & 0x7)
+                {
+                        case 0: /*RGB-8 (CLUT)*/
+                        svga->render = svga_render_8bpp_highres; 
+                        break;
+                        case 3: /*KRGB-16 (1.5.5.5)*/ 
+                        svga->htotal >>= 1;
+                        svga->render = svga_render_15bpp_highres; 
+                        break;
+                        case 5: /*RGB-16 (5.6.5)*/ 
+                        svga->htotal >>= 1;
+                        svga->render = svga_render_16bpp_highres; 
+                        break;
+                        case 6: /*RGB-24 (8.8.8)*/ 
+                        svga->render = svga_render_24bpp_highres; 
+                        break;
+                        case 7: /*XRGB-32 (X.8.8.8)*/
+                        svga->render = svga_render_32bpp_highres; 
+                        break;
+                }
+                svga->vram_display_mask = (virge->memory_size << 20) - 1;
+        }
+
+        if (((svga->miscout >> 2) & 3) == 3)
+        {
+                int n = svga->seqregs[0x12] & 0x1f;
+                int r = (svga->seqregs[0x12] >> 5) & (virge->is_375 ? 7 : 3);
+                int m = svga->seqregs[0x13] & 0x7f;
+                double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0;
+
+                svga->clock = (cpuclock * (float)(1ull << 32)) / freq;
+        }
+}
+
+static void s3_virge_updatemapping(virge_t *virge)
+{
+        svga_t *svga = &virge->svga;
+
+        if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM))
+        {
+//                pclog("Update mapping - PCI disabled\n");
+                mem_mapping_disable(&svga->mapping);
+                mem_mapping_disable(&virge->linear_mapping);
+                mem_mapping_disable(&virge->mmio_mapping);
+                mem_mapping_disable(&virge->new_mmio_mapping);
+                return;
+        }
+
+        pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc);        
+        switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/
+        {
+                case 0x0: /*128k at A0000*/
+                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
+                svga->banked_mask = 0xffff;
+                break;
+                case 0x4: /*64k at A0000*/
+                mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
+                svga->banked_mask = 0xffff;
+                break;
+                case 0x8: /*32k at B0000*/
+                mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+                case 0xC: /*32k at B8000*/
+                mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+        }
+        
+        virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24);
+        
+        pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10);
+        if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/
+        {
+                switch (svga->crtc[0x58] & 3)
+                {
+                        case 0: /*64k*/
+                        virge->linear_size = 0x10000;
+                        break;
+                        case 1: /*1mb*/
+                        virge->linear_size = 0x100000;
+                        break;
+                        case 2: /*2mb*/
+                        virge->linear_size = 0x200000;
+                        break;
+                        case 3: /*8mb*/
+                        virge->linear_size = 0x400000;
+                        break;
+                }
+                virge->linear_base &= ~(virge->linear_size - 1);
+//                pclog("%08X %08X  %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]);
+                pclog("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size);
+                if (virge->linear_base == 0xa0000)
+                {
+                        mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
+                        mem_mapping_disable(&virge->linear_mapping);
+                }
+                else
+                        mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size);
+                svga->fb_only = 1;
+        }
+        else
+        {
+                mem_mapping_disable(&virge->linear_mapping);
+                svga->fb_only = 0;
+        }
+        
+        pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18);
+        if (svga->crtc[0x53] & 0x10) /*Old MMIO*/
+        {
+                if (svga->crtc[0x53] & 0x20)
+                        mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000);
+                else
+                        mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000);
+        }
+        else
+                mem_mapping_disable(&virge->mmio_mapping);
+
+        if (svga->crtc[0x53] & 0x08) /*New MMIO*/
+                mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000);
+        else
+                mem_mapping_disable(&virge->new_mmio_mapping);
+
+}
+
+static void s3_virge_vblank_start(svga_t *svga)
+{
+        virge_t *virge = (virge_t *)svga->p;
+
+        virge->subsys_stat |= INT_VSY;
+        s3_virge_update_irqs(virge);
+}
+
+static void s3_virge_wait_fifo_idle(virge_t *virge)
+{
+        while (!FIFO_EMPTY)
+        {
+                wake_fifo_thread(virge);
+                thread_wait_event(virge->fifo_not_full_event, 1);
+        }
+}
+
+static uint8_t s3_virge_mmio_read(uint32_t addr, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        uint8_t ret;
+
+        reg_reads++;
+//        pclog("New MMIO readb %08X\n", addr);
+        switch (addr & 0xffff)
+        {
+                case 0x8505:
+                if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY)
+                        ret = 0x10;
+                else
+                        ret = 0x10 | (1 << 5);
+                if (!virge->virge_busy)
+                        wake_fifo_thread(virge);
+                return ret;
+                
+                case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3:
+                case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7:
+                case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb:
+                case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf:
+                case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3:
+                case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7:
+                case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb:
+                case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf:
+                case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3:
+                case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7:
+                case 0x83d8: case 0x83d9: case 0x83da: case 0x83db:
+                case 0x83dc: case 0x83dd: case 0x83de: case 0x83df:
+                return s3_virge_in(addr & 0x3ff, p);
+        }
+        return 0xff;
+}
+static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p)
+{
+        reg_reads++;
+//        pclog("New MMIO readw %08X\n", addr);
+        switch (addr & 0xfffe)
+        {
+                default:
+                return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8);
+        }
+        return 0xffff;
+}
+static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        uint32_t ret = 0xffffffff;
+        reg_reads++;
+//        pclog("New MMIO readl %08X %04X(%08X):%08X  ", addr, CS, cs, pc);
+        switch (addr & 0xfffc)
+        {
+                case 0x8180:
+                ret = virge->streams.pri_ctrl;
+                break;
+                case 0x8184:
+                ret = virge->streams.chroma_ctrl;
+                break;
+                case 0x8190:
+                ret = virge->streams.sec_ctrl;
+                break;
+                case 0x8194:
+                ret = virge->streams.chroma_upper_bound;
+                break;
+                case 0x8198:
+                ret = virge->streams.sec_filter;
+                break;
+                case 0x81a0:
+                ret = virge->streams.blend_ctrl;
+                break;
+                case 0x81c0:
+                ret = virge->streams.pri_fb0;
+                break;
+                case 0x81c4:
+                ret = virge->streams.pri_fb1;
+                break;
+                case 0x81c8:
+                ret = virge->streams.pri_stride;
+                break;
+                case 0x81cc:
+                ret = virge->streams.buffer_ctrl;
+                break;
+                case 0x81d0:
+                ret = virge->streams.sec_fb0;
+                break;
+                case 0x81d4:
+                ret = virge->streams.sec_fb1;
+                break;
+                case 0x81d8:
+                ret = virge->streams.sec_stride;
+                break;
+                case 0x81dc:
+                ret = virge->streams.overlay_ctrl;
+                break;
+                case 0x81e0:
+                ret = virge->streams.k1_vert_scale;
+                break;
+                case 0x81e4:
+                ret = virge->streams.k2_vert_scale;
+                break;
+                case 0x81e8:
+                ret = virge->streams.dda_vert_accumulator;
+                break;
+                case 0x81ec:
+                ret = virge->streams.fifo_ctrl;
+                break;
+                case 0x81f0:
+                ret = virge->streams.pri_start;
+                break;
+                case 0x81f4:
+                ret = virge->streams.pri_size;
+                break;
+                case 0x81f8:
+                ret = virge->streams.sec_start;
+                break;
+                case 0x81fc:
+                ret = virge->streams.sec_size;
+                break;
+                
+                case 0x8504:
+                if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY)
+                        ret = (0x10 << 8);
+                else
+                        ret = (0x10 << 8) | (1 << 13);
+                ret |= virge->subsys_stat;
+                if (!virge->virge_busy)
+                        wake_fifo_thread(virge);
+//                pclog("Read status %04x %i\n", ret, virge->s3d_busy);
+                break;
+                case 0xa4d4:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.src_base;
+                break;
+                case 0xa4d8:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.dest_base;
+                break;
+                case 0xa4dc:
+                s3_virge_wait_fifo_idle(virge);
+                ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r;
+                break;
+                case 0xa4e0:
+                s3_virge_wait_fifo_idle(virge);
+                ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b;
+                break;
+                case 0xa4e4:
+                s3_virge_wait_fifo_idle(virge);
+                ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str;
+                break;
+                case 0xa4e8: case 0xace8:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.mono_pat_0;
+                break;
+                case 0xa4ec: case 0xacec:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.mono_pat_1;
+                break;
+                case 0xa4f0:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.pat_bg_clr;
+                break;
+                case 0xa4f4:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.pat_fg_clr;
+                break;
+                case 0xa4f8:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.src_bg_clr;
+                break;
+                case 0xa4fc:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.src_fg_clr;
+                break;
+                case 0xa500:
+                s3_virge_wait_fifo_idle(virge);
+                ret = virge->s3d.cmd_set;
+                break;
+                case 0xa504:
+                s3_virge_wait_fifo_idle(virge);
+                ret = (virge->s3d.r_width << 16) | virge->s3d.r_height;
+                break;
+                case 0xa508:
+                s3_virge_wait_fifo_idle(virge);
+                ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y;
+                break;
+                case 0xa50c:
+                s3_virge_wait_fifo_idle(virge);
+                ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y;
+                break;
+                
+                default:
+                ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16);
+        }
+//        /*if ((addr & 0xfffc) != 0x8504) */pclog("%02x\n", ret);
+        return ret;
+}
+
+static void fifo_thread(void *param)
+{
+        virge_t *virge = (virge_t *)param;
+        
+        while (1)
+        {
+                thread_set_event(virge->fifo_not_full_event);
+                thread_wait_event(virge->wake_fifo_thread, -1);
+                thread_reset_event(virge->wake_fifo_thread);
+                virge->virge_busy = 1;
+                while (!FIFO_EMPTY)
+                {
+                        uint64_t start_time = timer_read();
+                        uint64_t end_time;
+                        fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK];
+                        uint32_t val = fifo->val;
+
+                        switch (fifo->addr_type & FIFO_TYPE)
+                        {
+                                case FIFO_WRITE_BYTE:
+                                if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000)
+                                        s3_virge_bitblt(virge, 8, val);
+                                break;
+                                case FIFO_WRITE_WORD:
+                                if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000)
+                                {
+                                        if (virge->s3d.cmd_set & CMD_SET_MS)
+                                                s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16);
+                                        else
+                                                s3_virge_bitblt(virge, 16, val);
+                                }
+                                break;
+                                case FIFO_WRITE_DWORD:
+                                if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000)
+                                {
+                                        if (virge->s3d.cmd_set & CMD_SET_MS)
+                                                s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24));
+                                        else
+                                                s3_virge_bitblt(virge, 32, val);
+                                }
+                                else
+                                {
+                                        switch ((fifo->addr_type & FIFO_ADDR) & 0xfffc)
+                                        {
+                                                case 0xa000: case 0xa004: case 0xa008: case 0xa00c:
+                                                case 0xa010: case 0xa014: case 0xa018: case 0xa01c:
+                                                case 0xa020: case 0xa024: case 0xa028: case 0xa02c:
+                                                case 0xa030: case 0xa034: case 0xa038: case 0xa03c:
+                                                case 0xa040: case 0xa044: case 0xa048: case 0xa04c:
+                                                case 0xa050: case 0xa054: case 0xa058: case 0xa05c:
+                                                case 0xa060: case 0xa064: case 0xa068: case 0xa06c:
+                                                case 0xa070: case 0xa074: case 0xa078: case 0xa07c:
+                                                case 0xa080: case 0xa084: case 0xa088: case 0xa08c:
+                                                case 0xa090: case 0xa094: case 0xa098: case 0xa09c:
+                                                case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac:
+                                                case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc:
+                                                case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc:
+                                                case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc:
+                                                case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec:
+                                                case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc:
+                                                case 0xa100: case 0xa104: case 0xa108: case 0xa10c:
+                                                case 0xa110: case 0xa114: case 0xa118: case 0xa11c:
+                                                case 0xa120: case 0xa124: case 0xa128: case 0xa12c:
+                                                case 0xa130: case 0xa134: case 0xa138: case 0xa13c:
+                                                case 0xa140: case 0xa144: case 0xa148: case 0xa14c:
+                                                case 0xa150: case 0xa154: case 0xa158: case 0xa15c:
+                                                case 0xa160: case 0xa164: case 0xa168: case 0xa16c:
+                                                case 0xa170: case 0xa174: case 0xa178: case 0xa17c:
+                                                case 0xa180: case 0xa184: case 0xa188: case 0xa18c:
+                                                case 0xa190: case 0xa194: case 0xa198: case 0xa19c:
+                                                case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac:
+                                                case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc:
+                                                case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc:
+                                                case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc:
+                                                case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec:
+                                                case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc:
+                                                {
+                                                        int x = (fifo->addr_type & FIFO_ADDR) & 4;
+                                                        int y = ((fifo->addr_type & FIFO_ADDR) >> 3) & 7;
+                                                        virge->s3d.pattern_8[y*8 + x]     = val & 0xff;
+                                                        virge->s3d.pattern_8[y*8 + x + 1] = val >> 8;
+                                                        virge->s3d.pattern_8[y*8 + x + 2] = val >> 16;
+                                                        virge->s3d.pattern_8[y*8 + x + 3] = val >> 24;
+                        
+                                                        x = ((fifo->addr_type & FIFO_ADDR) >> 1) & 6;
+                                                        y = ((fifo->addr_type & FIFO_ADDR) >> 4) & 7;
+                                                        virge->s3d.pattern_16[y*8 + x]     = val & 0xffff;
+                                                        virge->s3d.pattern_16[y*8 + x + 1] = val >> 16;
+
+                                                        x = ((fifo->addr_type & FIFO_ADDR) >> 2) & 7;
+                                                        y = ((fifo->addr_type & FIFO_ADDR) >> 5) & 7;
+                                                        virge->s3d.pattern_32[y*8 + x] = val & 0xffffff;
+                                                }
+                                                break;
+
+                                                case 0xa4d4: case 0xa8d4:
+                                                virge->s3d.src_base = val & 0x3ffff8;
+                                                break;
+                                                case 0xa4d8: case 0xa8d8:
+                                                virge->s3d.dest_base = val & 0x3ffff8;
+                                                break;
+                                                case 0xa4dc: case 0xa8dc:
+                                                virge->s3d.clip_l = (val >> 16) & 0x7ff;
+                                                virge->s3d.clip_r = val & 0x7ff;
+                                                break;
+                                                case 0xa4e0: case 0xa8e0:
+                                                virge->s3d.clip_t = (val >> 16) & 0x7ff;
+                                                virge->s3d.clip_b = val & 0x7ff;
+                                                break;
+                                                case 0xa4e4: case 0xa8e4:
+                                                virge->s3d.dest_str = (val >> 16) & 0xff8;
+                                                virge->s3d.src_str = val & 0xff8;
+                                                break;
+                                                case 0xa4e8: case 0xace8:
+                                                virge->s3d.mono_pat_0 = val;
+                                                break;
+                                                case 0xa4ec: case 0xacec:
+                                                virge->s3d.mono_pat_1 = val;
+                                                break;
+                                                case 0xa4f0: case 0xacf0:
+                                                virge->s3d.pat_bg_clr = val;
+                                                break;
+                                                case 0xa4f4: case 0xa8f4: case 0xacf4:
+                                                virge->s3d.pat_fg_clr = val;
+                                                break;
+                                                case 0xa4f8:
+                                                virge->s3d.src_bg_clr = val;
+                                                break;
+                                                case 0xa4fc:
+                                                virge->s3d.src_fg_clr = val;
+                                                break;
+                                                case 0xa500: case 0xa900:
+                                                virge->s3d.cmd_set = val;
+                                                if (!(val & CMD_SET_AE))
+                                                        s3_virge_bitblt(virge, -1, 0);
+                                                break;
+                                                case 0xa504:
+                                                virge->s3d.r_width = (val >> 16) & 0x7ff;
+                                                virge->s3d.r_height = val & 0x7ff;
+                                                break;
+                                                case 0xa508:
+                                                virge->s3d.rsrc_x = (val >> 16) & 0x7ff;
+                                                virge->s3d.rsrc_y = val & 0x7ff;
+                                                break;
+                                                case 0xa50c:
+                                                virge->s3d.rdest_x = (val >> 16) & 0x7ff;
+                                                virge->s3d.rdest_y = val & 0x7ff;
+                                                if (virge->s3d.cmd_set & CMD_SET_AE)
+                                                        s3_virge_bitblt(virge, -1, 0);
+                                                break;
+                                                case 0xa96c:
+                                                virge->s3d.lxend0 = (val >> 16) & 0x7ff;
+                                                virge->s3d.lxend1 = val & 0x7ff;
+                                                break;
+                                                case 0xa970:
+                                                virge->s3d.ldx = (int32_t)val;
+                                                break;
+                                                case 0xa974:
+                                                virge->s3d.lxstart = val;
+                                                break;
+                                                case 0xa978:
+                                                virge->s3d.lystart = val & 0x7ff;
+                                                break;
+                                                case 0xa97c:
+                                                virge->s3d.lycnt = val & 0x7ff;
+                                                virge->s3d.line_dir = val >> 31;
+                                                if (virge->s3d.cmd_set & CMD_SET_AE)
+                                                        s3_virge_bitblt(virge, -1, 0);
+                                                break;
+
+                                                case 0xad00:
+                                                virge->s3d.cmd_set = val;
+                                                if (!(val & CMD_SET_AE))
+                                                        s3_virge_bitblt(virge, -1, 0);
+                                                break;
+                                                case 0xad68:
+                                                virge->s3d.prdx = val;
+                                                break;
+                                                case 0xad6c:
+                                                virge->s3d.prxstart = val;
+                                                break;
+                                                case 0xad70:
+                                                virge->s3d.pldx = val;
+                                                break;
+                                                case 0xad74:
+                                                virge->s3d.plxstart = val;
+                                                break;
+                                                case 0xad78:
+                                                virge->s3d.pystart = val & 0x7ff;
+                                                break;
+                                                case 0xad7c:
+                                                virge->s3d.pycnt = val & 0x300007ff;
+                                                if (virge->s3d.cmd_set & CMD_SET_AE)
+                                                        s3_virge_bitblt(virge, -1, 0);
+                                                break;
+                
+                                                case 0xb4d4:
+                                                virge->s3d_tri.z_base = val & 0x3ffff8;
+                                                break;
+                                                case 0xb4d8:
+                                                virge->s3d_tri.dest_base = val & 0x3ffff8;
+                                                break;
+                                                case 0xb4dc:
+                                                virge->s3d_tri.clip_l = (val >> 16) & 0x7ff;
+                                                virge->s3d_tri.clip_r = val & 0x7ff;
+                                                break;
+                                                case 0xb4e0:
+                                                virge->s3d_tri.clip_t = (val >> 16) & 0x7ff;
+                                                virge->s3d_tri.clip_b = val & 0x7ff;
+                                                break;
+                                                case 0xb4e4:
+                                                virge->s3d_tri.dest_str = (val >> 16) & 0xff8;
+                                                virge->s3d.src_str = val & 0xff8;
+                                                break;
+                                                case 0xb4e8:
+                                                virge->s3d_tri.z_str = val & 0xff8;
+                                                break;
+                                                case 0xb4ec:
+                                                virge->s3d_tri.tex_base = val & 0x3ffff8;
+                                                break;
+                                                case 0xb4f0:
+                                                virge->s3d_tri.tex_bdr_clr = val & 0xffffff;
+                                                break;
+                                                case 0xb500:
+                                                virge->s3d_tri.cmd_set = val;
+                                                if (!(val & CMD_SET_AE))
+                                                        queue_triangle(virge);
+                                                break;
+                                                case 0xb504:
+                                                virge->s3d_tri.tbv = val & 0xfffff;
+                                                break;
+                                                case 0xb508:
+                                                virge->s3d_tri.tbu = val & 0xfffff;
+                                                break;
+                                                case 0xb50c:
+                                                virge->s3d_tri.TdWdX = val;
+                                                break;
+                                                case 0xb510:
+                                                virge->s3d_tri.TdWdY = val;
+                                                break;
+                                                case 0xb514:
+                                                virge->s3d_tri.tws = val;
+                                                break;
+                                                case 0xb518:
+                                                virge->s3d_tri.TdDdX = val;
+                                                break;
+                                                case 0xb51c:
+                                                virge->s3d_tri.TdVdX = val;
+                                                break;
+                                                case 0xb520:
+                                                virge->s3d_tri.TdUdX = val;
+                                                break;
+                                                case 0xb524:
+                                                virge->s3d_tri.TdDdY = val;
+                                                break;
+                                                case 0xb528:
+                                                virge->s3d_tri.TdVdY = val;
+                                                break;
+                                                case 0xb52c:
+                                                virge->s3d_tri.TdUdY = val;
+                                                break;
+                                                case 0xb530:
+                                                virge->s3d_tri.tds = val;
+                                                break;
+                                                case 0xb534:
+                                                virge->s3d_tri.tvs = val;
+                                                break;
+                                                case 0xb538:
+                                                virge->s3d_tri.tus = val;
+                                                break;
+                                                case 0xb53c:
+                                                virge->s3d_tri.TdGdX = val >> 16;
+                                                virge->s3d_tri.TdBdX = val & 0xffff;
+                                                break;
+                                                case 0xb540:
+                                                virge->s3d_tri.TdAdX = val >> 16;
+                                                virge->s3d_tri.TdRdX = val & 0xffff;
+                                                break;
+                                                case 0xb544:
+                                                virge->s3d_tri.TdGdY = val >> 16;
+                                                virge->s3d_tri.TdBdY = val & 0xffff;
+                                                break;
+                                                case 0xb548:
+                                                virge->s3d_tri.TdAdY = val >> 16;
+                                                virge->s3d_tri.TdRdY = val & 0xffff;
+                                                break;
+                                                case 0xb54c:
+                                                virge->s3d_tri.tgs = (val >> 16) & 0xffff;
+                                                virge->s3d_tri.tbs = val & 0xffff;
+                                                break;
+                                                case 0xb550:
+                                                virge->s3d_tri.tas = (val >> 16) & 0xffff;
+                                                virge->s3d_tri.trs = val & 0xffff;
+                                                break;
+                
+                                                case 0xb554:
+                                                virge->s3d_tri.TdZdX = val;
+                                                break;
+                                                case 0xb558:
+                                                virge->s3d_tri.TdZdY = val;
+                                                break;
+                                                case 0xb55c:
+                                                virge->s3d_tri.tzs = val;
+                                                break;
+                                                case 0xb560:
+                                                virge->s3d_tri.TdXdY12 = val;
+                                                break;
+                                                case 0xb564:
+                                                virge->s3d_tri.txend12 = val;
+                                                break;
+                                                case 0xb568:
+                                                virge->s3d_tri.TdXdY01 = val;
+                                                break;
+                                                case 0xb56c:
+                                                virge->s3d_tri.txend01 = val;
+                                                break;
+                                                case 0xb570:
+                                                virge->s3d_tri.TdXdY02 = val;
+                                                break;
+                                                case 0xb574:
+                                                virge->s3d_tri.txs = val;
+                                                break;
+                                                case 0xb578:
+                                                virge->s3d_tri.tys = val;
+                                                break;
+                                                case 0xb57c:
+                                                virge->s3d_tri.ty01 = (val >> 16) & 0x7ff;
+                                                virge->s3d_tri.ty12 = val & 0x7ff;
+                                                virge->s3d_tri.tlr = val >> 31;
+                                                if (virge->s3d_tri.cmd_set & CMD_SET_AE)
+                                                        queue_triangle(virge);
+                                                break;
+                                        }
+                                }
+                                break;
+                        }
+                                                
+                        virge->fifo_read_idx++;
+                        fifo->addr_type = FIFO_INVALID;
+
+                        if (FIFO_ENTRIES > 0xe000)
+                                thread_set_event(virge->fifo_not_full_event);
+
+                        end_time = timer_read();
+                        virge_time += end_time - start_time;
+                }
+                virge->virge_busy = 0;
+                virge->subsys_stat |= INT_FIFO_EMP | INT_3DF_EMP;
+                s3_virge_update_irqs(virge);
+        }
+}
+
+static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type)
+{
+        fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK];
+
+        if (FIFO_FULL)
+        {
+                thread_reset_event(virge->fifo_not_full_event);
+                if (FIFO_FULL)
+                {
+                        thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/
+                }
+        }
+
+        fifo->val = val;
+        fifo->addr_type = (addr & FIFO_ADDR) | type;
+
+        virge->fifo_write_idx++;
+        
+        if (FIFO_ENTRIES > 0xe000)
+                wake_fifo_thread(virge);
+        if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8)
+                wake_fifo_thread(virge);
+}
+
+static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        
+//        pclog("New MMIO writeb %08X %02X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
+        reg_writes++;       
+        if ((addr & 0xfffc) < 0x8000)
+        {
+                s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE);
+        }
+        else switch (addr & 0xffff)
+        {
+                case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3:
+                case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7:
+                case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb:
+                case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf:
+                case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3:
+                case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7:
+                case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb:
+                case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf:
+                case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3:
+                case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7:
+                case 0x83d8: case 0x83d9: case 0x83da: case 0x83db:
+                case 0x83dc: case 0x83dd: case 0x83de: case 0x83df:
+                s3_virge_out(addr & 0x3ff, val, p);
+                break;
+        }
+
+                
+}
+static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        reg_writes++;
+//        pclog("New MMIO writew %08X %04X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
+        if ((addr & 0xfffc) < 0x8000)
+        {
+                s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD);
+        } 
+        else switch (addr & 0xfffe)
+        {
+                case 0x83d4:
+                s3_virge_mmio_write(addr, val, p);
+                s3_virge_mmio_write(addr + 1, val >> 8, p);
+                break;
+        }
+}
+static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        svga_t *svga = &virge->svga;
+        reg_writes++;
+//        if ((addr & 0xfffc) >= 0xb400 && (addr & 0xfffc) < 0xb800)
+//                pclog("New MMIO writel %08X %08X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
+
+        if ((addr & 0xfffc) < 0x8000)
+        {
+                s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD);
+        }
+        else if ((addr & 0xe000) == 0xa000)
+        {
+                s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD);
+        }
+        else switch (addr & 0xfffc)
+        {
+                case 0x8180:
+                virge->streams.pri_ctrl = val;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x8184:
+                virge->streams.chroma_ctrl = val;
+                break;
+                case 0x8190:
+                virge->streams.sec_ctrl = val;
+                virge->streams.dda_horiz_accumulator = val & 0xfff;
+                if (val & (1 << 11))
+                        virge->streams.dda_horiz_accumulator |= 0xfffff800;
+                virge->streams.sdif = (val >> 24) & 7;
+                break;
+                case 0x8194:
+                virge->streams.chroma_upper_bound = val;
+                break;
+                case 0x8198:
+                virge->streams.sec_filter = val;
+                virge->streams.k1_horiz_scale = val & 0x7ff;
+                if (val & (1 << 10))
+                        virge->streams.k1_horiz_scale |= 0xfffff800;
+                virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff;
+                if ((val >> 16) & (1 << 10))
+                        virge->streams.k2_horiz_scale |= 0xfffff800;
+                break;
+                case 0x81a0:
+                virge->streams.blend_ctrl = val;
+                break;
+                case 0x81c0:
+//                        pclog("Write pri_fb0 %08x\n", val);
+                virge->streams.pri_fb0 = val & 0x3fffff;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81c4:
+//                        pclog("Write pri_fb1 %08x\n", val);
+                virge->streams.pri_fb1 = val & 0x3fffff;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81c8:
+                virge->streams.pri_stride = val & 0xfff;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81cc:
+//                        pclog("Write buffer_ctrl %08x\n", val);
+                virge->streams.buffer_ctrl = val;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81d0:
+                virge->streams.sec_fb0 = val;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81d4:
+                virge->streams.sec_fb1 = val;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81d8:
+                virge->streams.sec_stride = val;
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81dc:
+                virge->streams.overlay_ctrl = val;
+                break;
+                case 0x81e0:
+                virge->streams.k1_vert_scale = val & 0x7ff;
+                if (val & (1 << 10))
+                        virge->streams.k1_vert_scale |= 0xfffff800;
+                break;
+                case 0x81e4:
+                virge->streams.k2_vert_scale = val & 0x7ff;
+                if (val & (1 << 10))
+                        virge->streams.k2_vert_scale |= 0xfffff800;
+                break;
+                case 0x81e8:
+                virge->streams.dda_vert_accumulator = val & 0xfff;
+                if (val & (1 << 11))
+                        virge->streams.dda_vert_accumulator |= 0xfffff800;
+                break;
+                case 0x81ec:
+                virge->streams.fifo_ctrl = val;
+                break;
+                case 0x81f0:
+                virge->streams.pri_start = val;
+                virge->streams.pri_x = (val >> 16) & 0x7ff;
+                virge->streams.pri_y = val & 0x7ff;                
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81f4:
+                virge->streams.pri_size = val;
+                virge->streams.pri_w = (val >> 16) & 0x7ff;
+                virge->streams.pri_h = val & 0x7ff;                
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81f8:
+                virge->streams.sec_start = val;
+                virge->streams.sec_x = (val >> 16) & 0x7ff;
+                virge->streams.sec_y = val & 0x7ff;                
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                case 0x81fc:
+                virge->streams.sec_size = val;
+                virge->streams.sec_w = (val >> 16) & 0x7ff;
+                virge->streams.sec_h = val & 0x7ff;                
+                svga_recalctimings(svga);
+                svga->fullchange = changeframecount;
+                break;
+                
+                case 0x8504:
+                virge->subsys_stat &= ~(val & 0xff);
+                virge->subsys_cntl = (val >> 8);
+                s3_virge_update_irqs(virge);
+                break;
+                
+                case 0xa000: case 0xa004: case 0xa008: case 0xa00c:
+                case 0xa010: case 0xa014: case 0xa018: case 0xa01c:
+                case 0xa020: case 0xa024: case 0xa028: case 0xa02c:
+                case 0xa030: case 0xa034: case 0xa038: case 0xa03c:
+                case 0xa040: case 0xa044: case 0xa048: case 0xa04c:
+                case 0xa050: case 0xa054: case 0xa058: case 0xa05c:
+                case 0xa060: case 0xa064: case 0xa068: case 0xa06c:
+                case 0xa070: case 0xa074: case 0xa078: case 0xa07c:
+                case 0xa080: case 0xa084: case 0xa088: case 0xa08c:
+                case 0xa090: case 0xa094: case 0xa098: case 0xa09c:
+                case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac:
+                case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc:
+                case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc:
+                case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc:
+                case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec:
+                case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc:
+                case 0xa100: case 0xa104: case 0xa108: case 0xa10c:
+                case 0xa110: case 0xa114: case 0xa118: case 0xa11c:
+                case 0xa120: case 0xa124: case 0xa128: case 0xa12c:
+                case 0xa130: case 0xa134: case 0xa138: case 0xa13c:
+                case 0xa140: case 0xa144: case 0xa148: case 0xa14c:
+                case 0xa150: case 0xa154: case 0xa158: case 0xa15c:
+                case 0xa160: case 0xa164: case 0xa168: case 0xa16c:
+                case 0xa170: case 0xa174: case 0xa178: case 0xa17c:
+                case 0xa180: case 0xa184: case 0xa188: case 0xa18c:
+                case 0xa190: case 0xa194: case 0xa198: case 0xa19c:
+                case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac:
+                case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc:
+                case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc:
+                case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc:
+                case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec:
+                case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc:
+                {
+                        int x = addr & 4;
+                        int y = (addr >> 3) & 7;
+                        virge->s3d.pattern_8[y*8 + x]     = val & 0xff;
+                        virge->s3d.pattern_8[y*8 + x + 1] = val >> 8;
+                        virge->s3d.pattern_8[y*8 + x + 2] = val >> 16;
+                        virge->s3d.pattern_8[y*8 + x + 3] = val >> 24;
+                        
+                        x = (addr >> 1) & 6;
+                        y = (addr >> 4) & 7;
+                        virge->s3d.pattern_16[y*8 + x]     = val & 0xffff;
+                        virge->s3d.pattern_16[y*8 + x + 1] = val >> 16;
+
+                        x = (addr >> 2) & 7;
+                        y = (addr >> 5) & 7;
+                        virge->s3d.pattern_32[y*8 + x] = val & 0xffffff;
+                }
+                break;
+
+                case 0xa4d4: case 0xa8d4:
+                virge->s3d.src_base = val & 0x3ffff8;
+                break;
+                case 0xa4d8: case 0xa8d8:
+                virge->s3d.dest_base = val & 0x3ffff8;
+                break;
+                case 0xa4dc: case 0xa8dc:
+                virge->s3d.clip_l = (val >> 16) & 0x7ff;
+                virge->s3d.clip_r = val & 0x7ff;
+                break;
+                case 0xa4e0: case 0xa8e0:
+                virge->s3d.clip_t = (val >> 16) & 0x7ff;
+                virge->s3d.clip_b = val & 0x7ff;
+                break;
+                case 0xa4e4: case 0xa8e4:
+                virge->s3d.dest_str = (val >> 16) & 0xff8;
+                virge->s3d.src_str = val & 0xff8;
+                break;
+                case 0xa4e8: case 0xace8:
+                virge->s3d.mono_pat_0 = val;
+                break;
+                case 0xa4ec: case 0xacec:
+                virge->s3d.mono_pat_1 = val;
+                break;
+                case 0xa4f0: case 0xacf0:
+                virge->s3d.pat_bg_clr = val;
+                break;
+                case 0xa4f4: case 0xa8f4: case 0xacf4:
+                virge->s3d.pat_fg_clr = val;
+                break;
+                case 0xa4f8:
+                virge->s3d.src_bg_clr = val;
+                break;
+                case 0xa4fc:
+                virge->s3d.src_fg_clr = val;
+                break;
+                case 0xa500: case 0xa900:
+                virge->s3d.cmd_set = val;
+                if (!(val & CMD_SET_AE))
+                        s3_virge_bitblt(virge, -1, 0);
+                break;
+                case 0xa504:
+                virge->s3d.r_width = (val >> 16) & 0x7ff;
+                virge->s3d.r_height = val & 0x7ff;
+                break;
+                case 0xa508:
+                virge->s3d.rsrc_x = (val >> 16) & 0x7ff;
+                virge->s3d.rsrc_y = val & 0x7ff;
+                break;
+                case 0xa50c:
+                virge->s3d.rdest_x = (val >> 16) & 0x7ff;
+                virge->s3d.rdest_y = val & 0x7ff;
+                if (virge->s3d.cmd_set & CMD_SET_AE)
+                        s3_virge_bitblt(virge, -1, 0);
+                break;
+                case 0xa96c:
+                virge->s3d.lxend0 = (val >> 16) & 0x7ff;
+                virge->s3d.lxend1 = val & 0x7ff;
+                break;
+                case 0xa970:
+                virge->s3d.ldx = (int32_t)val;
+                break;
+                case 0xa974:
+                virge->s3d.lxstart = val;
+                break;
+                case 0xa978:
+                virge->s3d.lystart = val & 0x7ff;
+                break;
+                case 0xa97c:
+                virge->s3d.lycnt = val & 0x7ff;
+                virge->s3d.line_dir = val >> 31;
+                if (virge->s3d.cmd_set & CMD_SET_AE)
+                        s3_virge_bitblt(virge, -1, 0);
+                break;
+
+                case 0xad00:
+                virge->s3d.cmd_set = val;
+                if (!(val & CMD_SET_AE))
+                        s3_virge_bitblt(virge, -1, 0);
+                break;
+                case 0xad68:
+                virge->s3d.prdx = val;
+                break;
+                case 0xad6c:
+                virge->s3d.prxstart = val;
+                break;
+                case 0xad70:
+                virge->s3d.pldx = val;
+                break;
+                case 0xad74:
+                virge->s3d.plxstart = val;
+                break;
+                case 0xad78:
+                virge->s3d.pystart = val & 0x7ff;
+                break;
+                case 0xad7c:
+                virge->s3d.pycnt = val & 0x300007ff;
+                if (virge->s3d.cmd_set & CMD_SET_AE)
+                        s3_virge_bitblt(virge, -1, 0);
+                break;
+                
+                case 0xb4d4:
+                virge->s3d_tri.z_base = val & 0x3ffff8;
+                break;
+                case 0xb4d8:
+                virge->s3d_tri.dest_base = val & 0x3ffff8;
+                break;
+                case 0xb4dc:
+                virge->s3d_tri.clip_l = (val >> 16) & 0x7ff;
+                virge->s3d_tri.clip_r = val & 0x7ff;
+                break;
+                case 0xb4e0:
+                virge->s3d_tri.clip_t = (val >> 16) & 0x7ff;
+                virge->s3d_tri.clip_b = val & 0x7ff;
+                break;
+                case 0xb4e4:
+                virge->s3d_tri.dest_str = (val >> 16) & 0xff8;
+                virge->s3d.src_str = val & 0xff8;
+                break;
+                case 0xb4e8:
+                virge->s3d_tri.z_str = val & 0xff8;
+                break;
+                case 0xb4ec:
+                virge->s3d_tri.tex_base = val & 0x3ffff8;
+                break;
+                case 0xb4f0:
+                virge->s3d_tri.tex_bdr_clr = val & 0xffffff;
+                break;
+                case 0xb500:
+                virge->s3d_tri.cmd_set = val;
+                if (!(val & CMD_SET_AE))
+                        queue_triangle(virge);
+/*                {
+                        thread_set_event(virge->wake_render_thread);
+                        thread_wait_event(virge->wake_main_thread, -1);
+                }                        */
+//                        s3_virge_triangle(virge);
+                break;
+                case 0xb504:
+                virge->s3d_tri.tbv = val & 0xfffff;
+                break;
+                case 0xb508:
+                virge->s3d_tri.tbu = val & 0xfffff;
+                break;
+                case 0xb50c:
+                virge->s3d_tri.TdWdX = val;
+                break;
+                case 0xb510:
+                virge->s3d_tri.TdWdY = val;
+                break;
+                case 0xb514:
+                virge->s3d_tri.tws = val;
+                break;
+                case 0xb518:
+                virge->s3d_tri.TdDdX = val;
+                break;
+                case 0xb51c:
+                virge->s3d_tri.TdVdX = val;
+                break;
+                case 0xb520:
+                virge->s3d_tri.TdUdX = val;
+                break;
+                case 0xb524:
+                virge->s3d_tri.TdDdY = val;
+                break;
+                case 0xb528:
+                virge->s3d_tri.TdVdY = val;
+                break;
+                case 0xb52c:
+                virge->s3d_tri.TdUdY = val;
+                break;
+                case 0xb530:
+                virge->s3d_tri.tds = val;
+                break;
+                case 0xb534:
+                virge->s3d_tri.tvs = val;
+                break;
+                case 0xb538:
+                virge->s3d_tri.tus = val;
+                break;
+                case 0xb53c:
+                virge->s3d_tri.TdGdX = val >> 16;
+                virge->s3d_tri.TdBdX = val & 0xffff;
+                break;
+                case 0xb540:
+                virge->s3d_tri.TdAdX = val >> 16;
+                virge->s3d_tri.TdRdX = val & 0xffff;
+                break;
+                case 0xb544:
+                virge->s3d_tri.TdGdY = val >> 16;
+                virge->s3d_tri.TdBdY = val & 0xffff;
+                break;
+                case 0xb548:
+                virge->s3d_tri.TdAdY = val >> 16;
+                virge->s3d_tri.TdRdY = val & 0xffff;
+                break;
+                case 0xb54c:
+                virge->s3d_tri.tgs = (val >> 16) & 0xffff;
+                virge->s3d_tri.tbs = val & 0xffff;
+                break;
+                case 0xb550:
+                virge->s3d_tri.tas = (val >> 16) & 0xffff;
+                virge->s3d_tri.trs = val & 0xffff;
+                break;
+                
+                case 0xb554:
+                virge->s3d_tri.TdZdX = val;
+                break;
+                case 0xb558:
+                virge->s3d_tri.TdZdY = val;
+                break;
+                case 0xb55c:
+                virge->s3d_tri.tzs = val;
+                break;
+                case 0xb560:
+                virge->s3d_tri.TdXdY12 = val;
+                break;
+                case 0xb564:
+                virge->s3d_tri.txend12 = val;
+                break;
+                case 0xb568:
+                virge->s3d_tri.TdXdY01 = val;
+                break;
+                case 0xb56c:
+                virge->s3d_tri.txend01 = val;
+                break;
+                case 0xb570:
+                virge->s3d_tri.TdXdY02 = val;
+                break;
+                case 0xb574:
+                virge->s3d_tri.txs = val;
+                break;
+                case 0xb578:
+                virge->s3d_tri.tys = val;
+                break;
+                case 0xb57c:
+                virge->s3d_tri.ty01 = (val >> 16) & 0x7ff;
+                virge->s3d_tri.ty12 = val & 0x7ff;
+                virge->s3d_tri.tlr = val >> 31;
+                if (virge->s3d_tri.cmd_set & CMD_SET_AE)
+                        queue_triangle(virge);
+/*                {
+                        thread_set_event(virge->wake_render_thread);
+                        thread_wait_event(virge->wake_main_thread, -1);
+                }*/
+
+//                        s3_virge_triangle(virge);
+                break;
+        }
+}
+
+#define READ(addr, val)                                                                         \
+        do                                                                                      \
+        {                                                                                       \
+                switch (bpp)                                                                    \
+                {                                                                               \
+                        case 0: /*8 bpp*/                                                       \
+                        val = vram[addr & svga->vram_mask];                                            \
+                        break;                                                                  \
+                        case 1: /*16 bpp*/                                                      \
+                        val = *(uint16_t *)&vram[addr & svga->vram_mask];                              \
+                        break;                                                                  \
+                        case 2: /*24 bpp*/                                                      \
+                        val = (*(uint32_t *)&vram[addr & svga->vram_mask]) & 0xffffff;                 \
+                        break;                                                                  \
+                }                                                                               \
+        } while (0)
+
+#define Z_READ(addr) *(uint16_t *)&vram[addr & svga->vram_mask]
+
+#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & svga->vram_mask] = val
+
+#define CLIP(x, y)                                              \
+        do                                                      \
+        {                                                       \
+                if ((virge->s3d.cmd_set & CMD_SET_HC) &&     \
+                    (x < virge->s3d.clip_l ||                \
+                     x > virge->s3d.clip_r ||                \
+                     y < virge->s3d.clip_t ||                \
+                     y > virge->s3d.clip_b))                 \
+                        update = 0;                             \
+        } while (0)
+
+#define CLIP_3D(x, y)                                           \
+        do                                                      \
+        {                                                       \
+                if ((s3d_tri->cmd_set & CMD_SET_HC) &&        \
+                    (x < s3d_tri->clip_l ||                   \
+                     x > s3d_tri->clip_r ||                   \
+                     y < s3d_tri->clip_t ||                   \
+                     y > s3d_tri->clip_b))                    \
+                        update = 0;                             \
+        } while (0)
+
+#define Z_CLIP(Zzb, Zs)                                                 \
+        do                                                              \
+        {                                                               \
+                if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE))            \
+                switch ((s3d_tri->cmd_set >> 20) & 7)                 \
+                {                                                       \
+                        case 0: update = 0; break;                      \
+                        case 1: if (Zs <= Zzb) update = 0; else Zzb = Zs; break;       \
+                        case 2: if (Zs != Zzb) update = 0; else Zzb = Zs; break;       \
+                        case 3: if (Zs <  Zzb) update = 0; else Zzb = Zs; break;       \
+                        case 4: if (Zs >= Zzb) update = 0; else Zzb = Zs; break;       \
+                        case 5: if (Zs == Zzb) update = 0; else Zzb = Zs; break;       \
+                        case 6: if (Zs >  Zzb) update = 0; else Zzb = Zs; break;       \
+                        case 7: update = 1; Zzb = Zs; break;                      \
+                }                                                       \
+        } while (0)
+        
+#define MIX()                                                   \
+        do                                                      \
+        {                                                       \
+                int c;                                          \
+                for (c = 0; c < 24; c++)                        \
+                {                                               \
+                        int d = (dest & (1 << c)) ? 1 : 0;      \
+                        if (source & (1 << c))  d |= 2;         \
+                        if (pattern & (1 << c)) d |= 4;         \
+                        if (virge->s3d.rop & (1 << d)) out |= (1 << c);    \
+                }                                               \
+        } while (0)
+
+#define WRITE(addr, val)                                                                        \
+        do                                                                                      \
+        {                                                                                       \
+                switch (bpp)                                                                    \
+                {                                                                               \
+                        case 0: /*8 bpp*/                                                       \
+                        vram[addr & svga->vram_mask] = val;                                            \
+                        virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount;    \
+                        break;                                                                  \
+                        case 1: /*16 bpp*/                                                      \
+                        *(uint16_t *)&vram[addr & svga->vram_mask] = val;                              \
+                        virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount;    \
+                        break;                                                                  \
+                        case 2: /*24 bpp*/                                                      \
+                        *(uint32_t *)&vram[addr & svga->vram_mask] = (val & 0xffffff) |                \
+                                                              (vram[(addr + 3) & svga->vram_mask] << 24);  \
+                        virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount;    \
+                        break;                                                                  \
+                }                                                                               \
+        } while (0)
+
+static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat)
+{
+        svga_t *svga = &virge->svga;
+        uint8_t *vram = virge->svga.vram;
+        uint32_t mono_pattern[64];
+        int count_mask;
+        int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1;
+        int y_inc = (virge->s3d.cmd_set & CMD_SET_YP) ? 1 : -1;
+        int bpp;
+        int x_mul;
+        int cpu_dat_shift;
+        uint32_t *pattern_data;
+        uint32_t src_fg_clr, src_bg_clr;
+        
+        switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK)
+        {
+                case CMD_SET_FORMAT_8:
+                bpp = 0;
+                x_mul = 1;
+                cpu_dat_shift = 8;
+                pattern_data = virge->s3d.pattern_8;
+                src_fg_clr = virge->s3d.src_fg_clr & 0xff;
+                src_bg_clr = virge->s3d.src_bg_clr & 0xff;
+                break;
+                case CMD_SET_FORMAT_16:
+                bpp = 1;
+                x_mul = 2;
+                cpu_dat_shift = 16;
+                pattern_data = virge->s3d.pattern_16;
+                src_fg_clr = virge->s3d.src_fg_clr & 0xffff;
+                src_bg_clr = virge->s3d.src_bg_clr & 0xffff;
+                break;
+                case CMD_SET_FORMAT_24:
+                default:
+                bpp = 2;
+                x_mul = 3;
+                cpu_dat_shift = 24;
+                pattern_data = virge->s3d.pattern_32;
+                src_fg_clr = virge->s3d.src_fg_clr;
+                src_bg_clr = virge->s3d.src_bg_clr;
+                break;
+        }
+        if (virge->s3d.cmd_set & CMD_SET_MP)
+                pattern_data = mono_pattern;
+        
+        switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK)
+        {
+                case CMD_SET_ITA_BYTE:
+                count_mask = ~0x7;
+                break;
+                case CMD_SET_ITA_WORD:
+                count_mask = ~0xf;
+                break;
+                case CMD_SET_ITA_DWORD:
+                default:
+                count_mask = ~0x1f;
+                break;
+        }
+        if (virge->s3d.cmd_set & CMD_SET_MP)
+        {
+                int x, y;
+                for (y = 0; y < 4; y++)
+                {
+                        for (x = 0; x < 8; x++)
+                        {
+                                if (virge->s3d.mono_pat_0 & (1 << (x + y*8)))
+                                        mono_pattern[y*8 + x] = virge->s3d.pat_fg_clr;
+                                else
+                                        mono_pattern[y*8 + x] = virge->s3d.pat_bg_clr;
+                                if (virge->s3d.mono_pat_1 & (1 << (x + y*8)))
+                                        mono_pattern[(y+4)*8 + x] = virge->s3d.pat_fg_clr;
+                                else
+                                        mono_pattern[(y+4)*8 + x] = virge->s3d.pat_bg_clr;
+                        }
+                }
+        }
+        switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK)
+        {
+                case CMD_SET_COMMAND_NOP:
+                break;
+                
+                case CMD_SET_COMMAND_BITBLT:
+                if (count == -1)
+                {
+                        virge->s3d.src_x = virge->s3d.rsrc_x;
+                        virge->s3d.src_y = virge->s3d.rsrc_y;
+                        virge->s3d.dest_x = virge->s3d.rdest_x;
+                        virge->s3d.dest_y = virge->s3d.rdest_y;
+                        virge->s3d.w = virge->s3d.r_width;
+                        virge->s3d.h = virge->s3d.r_height;
+                        virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff;
+                        virge->s3d.data_left_count = 0;
+                        
+/*                        pclog("BitBlt start %i,%i %i,%i %i,%i %02X %x %x\n",
+                                                                 virge->s3d.src_x,
+                                                                 virge->s3d.src_y,
+                                                                 virge->s3d.dest_x,
+                                                                 virge->s3d.dest_y,
+                                                                 virge->s3d.w,
+                                                                 virge->s3d.h,
+                                                                 virge->s3d.rop,
+                                                                 virge->s3d.src_base,
+                                                                 virge->s3d.dest_base);*/
+                        
+                        if (virge->s3d.cmd_set & CMD_SET_IDS)
+                                return;
+                }
+                if (!virge->s3d.h)
+                        return;
+                while (count)
+                {
+                        uint32_t src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str);
+                        uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str);
+                        uint32_t source = 0, dest, pattern;
+                        uint32_t out = 0;
+                        int update = 1;
+
+                        switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS))
+                        {
+                                case 0:
+                                case CMD_SET_MS:
+                                READ(src_addr, source);
+                                if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr)
+                                        update = 0;
+                                break;
+                                case CMD_SET_IDS:
+                                if (virge->s3d.data_left_count)
+                                {
+                                        /*Handle shifting for 24-bit data*/
+                                        source = virge->s3d.data_left;
+                                        source |= ((cpu_dat << virge->s3d.data_left_count) & ~0xff000000);
+                                        cpu_dat >>= (cpu_dat_shift - virge->s3d.data_left_count);
+                                        count -= (cpu_dat_shift - virge->s3d.data_left_count);
+                                        virge->s3d.data_left_count = 0;
+                                        if (count < cpu_dat_shift)
+                                        {
+                                                virge->s3d.data_left = cpu_dat;
+                                                virge->s3d.data_left_count = count;
+                                                count = 0;
+                                        }
+                                }
+                                else
+                                {
+                                        source = cpu_dat;
+                                        cpu_dat >>= cpu_dat_shift;
+                                        count -= cpu_dat_shift;
+                                        if (count < cpu_dat_shift)
+                                        {
+                                                virge->s3d.data_left = cpu_dat;
+                                                virge->s3d.data_left_count = count;
+                                                count = 0;
+                                        }
+                                }
+                                if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr)
+                                        update = 0;
+                                break;
+                                case CMD_SET_IDS | CMD_SET_MS:
+                                source = (cpu_dat & (1 << 31)) ? src_fg_clr : src_bg_clr;
+                                if ((virge->s3d.cmd_set & CMD_SET_TP) && !(cpu_dat & (1 << 31)))
+                                        update = 0;
+                                cpu_dat <<= 1;
+                                count--;
+                                break;
+                        }
+
+                        CLIP(virge->s3d.dest_x, virge->s3d.dest_y);
+
+                        if (update)
+                        {
+                                READ(dest_addr, dest);
+                                pattern = pattern_data[(virge->s3d.dest_y & 7)*8 + (virge->s3d.dest_x & 7)];
+                                MIX();
+
+                                WRITE(dest_addr, out);
+                        }
+                
+                        virge->s3d.src_x += x_inc;
+                        virge->s3d.src_x &= 0x7ff;
+                        virge->s3d.dest_x += x_inc;
+                        virge->s3d.dest_x &= 0x7ff;
+                        if (!virge->s3d.w)
+                        {
+                                virge->s3d.src_x = virge->s3d.rsrc_x;
+                                virge->s3d.dest_x = virge->s3d.rdest_x;
+                                virge->s3d.w = virge->s3d.r_width;
+
+                                virge->s3d.src_y += y_inc;
+                                virge->s3d.dest_y += y_inc;
+                                virge->s3d.h--;
+                                
+                                switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS))
+                                {
+                                        case CMD_SET_IDS:
+                                        cpu_dat >>= (count - (count & count_mask));
+                                        count &= count_mask;
+                                        virge->s3d.data_left_count = 0;
+                                        break;
+
+                                        case CMD_SET_IDS | CMD_SET_MS:
+                                        cpu_dat <<= (count - (count & count_mask));
+                                        count &= count_mask;
+                                        break;
+                                }
+                                if (!virge->s3d.h)
+                                {
+                                        return;
+                                }
+                        }
+                        else
+                                virge->s3d.w--;                        
+                }
+                break;
+                
+                case CMD_SET_COMMAND_RECTFILL:
+                /*No source, pattern = pat_fg_clr*/
+                if (count == -1)
+                {
+                        virge->s3d.src_x = virge->s3d.rsrc_x;
+                        virge->s3d.src_y = virge->s3d.rsrc_y;
+                        virge->s3d.dest_x = virge->s3d.rdest_x;
+                        virge->s3d.dest_y = virge->s3d.rdest_y;
+                        virge->s3d.w = virge->s3d.r_width;
+                        virge->s3d.h = virge->s3d.r_height;
+                        virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff;
+                        
+/*                        pclog("RctFll start %i,%i %i,%i %02X %08x\n", virge->s3d.dest_x,
+                                                                 virge->s3d.dest_y,
+                                                                 virge->s3d.w,
+                                                                 virge->s3d.h,
+                                                                 virge->s3d.rop, virge->s3d.dest_base);*/
+                }
+
+                while (count && virge->s3d.h)
+                {
+                        uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str);
+                        uint32_t source = 0, dest, pattern = virge->s3d.pat_fg_clr;
+                        uint32_t out = 0;
+                        int update = 1;
+
+                        CLIP(virge->s3d.dest_x, virge->s3d.dest_y);
+
+                        if (update)
+                        {
+                                READ(dest_addr, dest);
+
+                                MIX();
+
+                                WRITE(dest_addr, out);
+                        }
+
+                        virge->s3d.src_x += x_inc;
+                        virge->s3d.src_x &= 0x7ff;
+                        virge->s3d.dest_x += x_inc;
+                        virge->s3d.dest_x &= 0x7ff;
+                        if (!virge->s3d.w)
+                        {
+                                virge->s3d.src_x = virge->s3d.rsrc_x;
+                                virge->s3d.dest_x = virge->s3d.rdest_x;
+                                virge->s3d.w = virge->s3d.r_width;
+
+                                virge->s3d.src_y += y_inc;
+                                virge->s3d.dest_y += y_inc;
+                                virge->s3d.h--;
+                                if (!virge->s3d.h)
+                                {
+                                        return;
+                                }
+                        }
+                        else
+                                virge->s3d.w--;                        
+                        count--;
+                }
+                break;
+                
+                case CMD_SET_COMMAND_LINE:
+                if (count == -1)
+                {
+                        virge->s3d.dest_x = virge->s3d.lxstart;
+                        virge->s3d.dest_y = virge->s3d.lystart;
+                        virge->s3d.h = virge->s3d.lycnt;
+                        virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff;
+                }
+                while (virge->s3d.h)
+                {
+                        int x;
+                        int new_x;
+                        int first_pixel = 1;
+                        
+                        x = virge->s3d.dest_x >> 20;
+
+                        if (virge->s3d.h == virge->s3d.lycnt &&
+                           ((virge->s3d.line_dir && x > virge->s3d.lxend0) ||
+                           (!virge->s3d.line_dir && x < virge->s3d.lxend0)))
+                                x = virge->s3d.lxend0;
+
+                        if (virge->s3d.h == 1)
+                                new_x = virge->s3d.lxend1 + (virge->s3d.line_dir ? 1 : -1);
+                        else
+                                new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20;
+
+                        
+                        if ((virge->s3d.line_dir && x > new_x) ||
+                            (!virge->s3d.line_dir && x < new_x))
+                                goto skip_line;
+                                
+                        do
+                        {
+                                uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str);
+                                uint32_t source = 0, dest, pattern;
+                                uint32_t out = 0;
+                                int update = 1;
+
+                                if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) &&
+                                   ((virge->s3d.line_dir && x < virge->s3d.lxend0) ||
+                                   (!virge->s3d.line_dir && x > virge->s3d.lxend0)))
+                                        update = 0;
+
+                                if ((virge->s3d.h == 1  || !first_pixel) &&
+                                   ((virge->s3d.line_dir && x > virge->s3d.lxend1) ||
+                                   (!virge->s3d.line_dir && x < virge->s3d.lxend1)))
+                                        update = 0;
+
+                                CLIP(x, virge->s3d.dest_y);
+
+                                if (update)
+                                {
+                                        READ(dest_addr, dest);
+                                        pattern = virge->s3d.pat_fg_clr;
+
+                                        MIX();
+
+                                        WRITE(dest_addr, out);
+                                }
+                                
+                                if (x < new_x)
+                                        x++;
+                                else if (x > new_x)
+                                        x--;
+                                first_pixel = 0;
+                        } while (x != new_x);
+
+skip_line:
+                        virge->s3d.dest_x += virge->s3d.ldx;
+                        virge->s3d.dest_y--;
+                        virge->s3d.h--;
+                }
+                break;
+
+                case CMD_SET_COMMAND_POLY:
+                /*No source*/
+                if (virge->s3d.pycnt & (1 << 28))
+                        virge->s3d.dest_r = virge->s3d.prxstart;
+                if (virge->s3d.pycnt & (1 << 29))
+                        virge->s3d.dest_l = virge->s3d.plxstart;
+                virge->s3d.h = virge->s3d.pycnt & 0x7ff;
+                virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff;
+                //pclog("Start poly - l=%08x r=%08x h=%i rop=%02x\n", virge->s3d.dest_l, virge->s3d.dest_r, virge->s3d.h, virge->s3d.rop);
+                while (virge->s3d.h)
+                {
+                        int x = virge->s3d.dest_l >> 20;
+                        int xend = virge->s3d.dest_r >> 20;
+                        int y = virge->s3d.pystart & 0x7ff;
+                        int xdir = (x < xend) ? 1 : -1;
+                        //pclog(" %03i: %i - %i  %08x-%08x\n", y, x, xend, virge->s3d.dest_l, virge->s3d.dest_r);
+                        do
+                        {
+                                uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str);
+                                uint32_t source = 0, dest, pattern;
+                                uint32_t out = 0;
+                                int update = 1;
+
+                                CLIP(x, y);
+
+                                if (update)
+                                {
+                                        READ(dest_addr, dest);
+                                        pattern = pattern_data[(y & 7)*8 + (x & 7)];
+                                        MIX();
+
+                                        WRITE(dest_addr, out);
+                                }
+                                
+                                x = (x + xdir) & 0x7ff;
+                        }
+                        while (x != (xend + xdir));
+
+                        virge->s3d.dest_l += virge->s3d.pldx;
+                        virge->s3d.dest_r += virge->s3d.prdx;
+                        virge->s3d.h--;
+                        virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff;
+                }
+                break;
+
+                default:
+                fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set);
+        }
+}
+
+#define RGB15_TO_24(val, r, g, b) b = ((val & 0x001f) << 3) | ((val & 0x001f) >> 2);     \
+                                  g = ((val & 0x03e0) >> 2) | ((val & 0x03e0) >> 7);     \
+                                  r = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
+
+#define RGB24_TO_24(val, r, g, b) b = val & 0xff;             \
+                                  g = (val & 0xff00) >> 8;    \
+                                  r = (val & 0xff0000) >> 16
+
+#define RGB15(r, g, b, dest) \
+        if (virge->dithering_enabled)                           \
+        {                                                       \
+                int add = dither[_y & 3][_x & 3];               \
+                int _r = (r > 248) ? 248 : r+add;               \
+                int _g = (g > 248) ? 248 : g+add;               \
+                int _b = (b > 248) ? 248 : b+add;               \
+                dest = ((_b >> 3) & 0x1f) | (((_g >> 3) & 0x1f) << 5) | (((_r >> 3) & 0x1f) << 10);     \
+        }                                                                                               \
+        else                                                                                            \
+                dest = ((b >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((r >> 3) & 0x1f) << 10)
+
+#define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16))
+
+typedef struct rgba_t
+{
+        int r, g, b, a;
+} rgba_t;
+
+typedef struct s3d_state_t
+{
+        int32_t r, g, b, a, u, v, d, w;
+
+        int32_t base_r, base_g, base_b, base_a, base_u, base_v, base_d, base_w;
+        
+        uint32_t base_z;
+
+        uint32_t tbu, tbv;
+
+        uint32_t cmd_set;
+        int max_d;
+        
+        uint16_t *texture[10];
+        
+        uint32_t tex_bdr_clr;
+        
+        int32_t x1, x2;
+        int y;
+        
+        rgba_t dest_rgba;
+} s3d_state_t;
+
+typedef struct s3d_texture_state_t
+{
+        int level;
+        int texture_shift;
+        
+        int32_t u, v;
+} s3d_texture_state_t;
+
+static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out);
+static void (*tex_sample)(s3d_state_t *state);
+static void (*dest_pixel)(s3d_state_t *state);
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static int _x, _y;
+
+static void tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
+{
+        int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
+                     (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
+        uint16_t val = state->texture[texture_state->level][offset];
+
+        out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12);
+        out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7);
+        out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2);
+        out->a = (val & 0x8000) ? 0xff : 0;
+}
+
+static void tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
+{
+        int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
+                     (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
+        uint16_t val = state->texture[texture_state->level][offset];
+
+        if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000)
+                val = state->tex_bdr_clr;
+
+        out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12);
+        out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7);
+        out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2);
+        out->a = (val & 0x8000) ? 0xff : 0;
+}
+
+static void tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
+{
+        int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
+                     (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
+        uint16_t val = state->texture[texture_state->level][offset];
+
+        out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8);
+        out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4);
+        out->b = ((val & 0x000f) << 4) | (val & 0x000f);
+        out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12);
+}
+
+static void tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
+{
+        int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
+                     (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
+        uint16_t val = state->texture[texture_state->level][offset];
+
+        if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000)
+                val = state->tex_bdr_clr;
+
+        out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8);
+        out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4);
+        out->b = ((val & 0x000f) << 4) | (val & 0x000f);
+        out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12);
+}
+
+static void tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
+{
+        int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
+                     (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
+        uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset];
+
+        out->r = (val >> 16) & 0xff;
+        out->g = (val >> 8)  & 0xff;
+        out->b =  val        & 0xff;
+        out->a = (val >> 24) & 0xff;
+}
+static void tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
+{
+        int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
+                     (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
+        uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset];
+
+        if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000)
+                val = state->tex_bdr_clr;
+
+        out->r = (val >> 16) & 0xff;
+        out->g = (val >> 8)  & 0xff;
+        out->b =  val        & 0xff;
+        out->a = (val >> 24) & 0xff;
+}
+
+static void tex_sample_normal(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        
+        texture_state.level = state->max_d;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        texture_state.u = state->u + state->tbu;
+        texture_state.v = state->v + state->tbv;
+
+        tex_read(state, &texture_state, &state->dest_rgba);
+}
+
+static void tex_sample_normal_filter(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int tex_offset;
+        rgba_t tex_samples[4];
+        int du, dv;
+        int d[4];
+
+        texture_state.level = state->max_d;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        tex_offset = 1 << texture_state.texture_shift;
+
+        texture_state.u = state->u + state->tbu;
+        texture_state.v = state->v + state->tbv;
+        tex_read(state, &texture_state, &tex_samples[0]);
+        du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff;
+        dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff;
+
+        texture_state.u = state->u + state->tbu + tex_offset;
+        texture_state.v = state->v + state->tbv;
+        tex_read(state, &texture_state, &tex_samples[1]);
+
+        texture_state.u = state->u + state->tbu;
+        texture_state.v = state->v + state->tbv + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[2]);
+
+        texture_state.u = state->u + state->tbu + tex_offset;
+        texture_state.v = state->v + state->tbv + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[3]);
+        
+        d[0] = (256 - du) * (256 - dv);
+        d[1] =  du * (256 - dv);
+        d[2] = (256 - du) * dv;
+        d[3] = du * dv;
+        
+        state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
+        state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
+        state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
+        state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
+}
+
+static void tex_sample_mipmap(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+
+        texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
+        if (texture_state.level < 0)
+                texture_state.level = 0;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        texture_state.u = state->u + state->tbu;
+        texture_state.v = state->v + state->tbv;
+
+        tex_read(state, &texture_state, &state->dest_rgba);
+}
+
+static void tex_sample_mipmap_filter(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int tex_offset;
+        rgba_t tex_samples[4];
+        int du, dv;
+        int d[4];
+
+        texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
+        if (texture_state.level < 0)
+                texture_state.level = 0;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        tex_offset = 1 << texture_state.texture_shift;
+        
+        texture_state.u = state->u + state->tbu;
+        texture_state.v = state->v + state->tbv;
+        tex_read(state, &texture_state, &tex_samples[0]);
+        du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff;
+        dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff;
+
+        texture_state.u = state->u + state->tbu + tex_offset;
+        texture_state.v = state->v + state->tbv;
+        tex_read(state, &texture_state, &tex_samples[1]);
+
+        texture_state.u = state->u + state->tbu;
+        texture_state.v = state->v + state->tbv + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[2]);
+
+        texture_state.u = state->u + state->tbu + tex_offset;
+        texture_state.v = state->v + state->tbv + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[3]);
+
+        d[0] = (256 - du) * (256 - dv);
+        d[1] =  du * (256 - dv);
+        d[2] = (256 - du) * dv;
+        d[3] = du * dv;
+        
+        state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
+        state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
+        state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
+        state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
+}
+
+static void tex_sample_persp_normal(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0;
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+        
+        texture_state.level = state->max_d;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);      
+        texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
+        texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
+
+        tex_read(state, &texture_state, &state->dest_rgba);
+}
+
+static void tex_sample_persp_normal_filter(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0, u, v;
+        int tex_offset;
+        rgba_t tex_samples[4];
+        int du, dv;
+        int d[4];
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+
+        u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
+        v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
+
+        texture_state.level = state->max_d;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        tex_offset = 1 << texture_state.texture_shift;
+        
+        texture_state.u = u;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[0]);
+        du = (u >> (texture_state.texture_shift - 8)) & 0xff;
+        dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[1]);
+
+        texture_state.u = u;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[2]);
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[3]);
+
+        d[0] = (256 - du) * (256 - dv);
+        d[1] =  du * (256 - dv);
+        d[2] = (256 - du) * dv;
+        d[3] = du * dv;
+        
+        state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
+        state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
+        state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
+        state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
+}
+
+static void tex_sample_persp_normal_375(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0;
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+        
+        texture_state.level = state->max_d;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);      
+        texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
+        texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
+
+        tex_read(state, &texture_state, &state->dest_rgba);
+}
+
+static void tex_sample_persp_normal_filter_375(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0, u, v;
+        int tex_offset;
+        rgba_t tex_samples[4];
+        int du, dv;
+        int d[4];
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+
+        u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
+        v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
+        
+        texture_state.level = state->max_d;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        tex_offset = 1 << texture_state.texture_shift;
+
+        texture_state.u = u;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[0]);
+        du = (u >> (texture_state.texture_shift - 8)) & 0xff;
+        dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[1]);
+
+        texture_state.u = u;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[2]);
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[3]);
+
+        d[0] = (256 - du) * (256 - dv);
+        d[1] =  du * (256 - dv);
+        d[2] = (256 - du) * dv;
+        d[3] = du * dv;
+        
+        state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
+        state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
+        state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
+        state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
+}
+
+
+static void tex_sample_persp_mipmap(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0;
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+        
+        texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
+        if (texture_state.level < 0)
+                texture_state.level = 0;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
+        texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
+
+        tex_read(state, &texture_state, &state->dest_rgba);
+}
+
+static void tex_sample_persp_mipmap_filter(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0, u, v;
+        int tex_offset;
+        rgba_t tex_samples[4];
+        int du, dv;
+        int d[4];
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+
+        u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
+        v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
+        
+        texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
+        if (texture_state.level < 0)
+                texture_state.level = 0;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        tex_offset = 1 << texture_state.texture_shift;
+
+        texture_state.u = u;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[0]);
+        du = (u >> (texture_state.texture_shift - 8)) & 0xff;
+        dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[1]);
+
+        texture_state.u = u;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[2]);
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[3]);
+
+        d[0] = (256 - du) * (256 - dv);
+        d[1] =  du * (256 - dv);
+        d[2] = (256 - du) * dv;
+        d[3] = du * dv;
+        
+        state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
+        state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
+        state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
+        state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
+}
+
+static void tex_sample_persp_mipmap_375(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0;
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+        
+        texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
+        if (texture_state.level < 0)
+                texture_state.level = 0;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
+        texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
+
+        tex_read(state, &texture_state, &state->dest_rgba);
+}
+
+static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state)
+{
+        s3d_texture_state_t texture_state;
+        int32_t w = 0, u, v;
+        int tex_offset;
+        rgba_t tex_samples[4];
+        int du, dv;
+        int d[4];
+
+        if (state->w)
+                w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
+
+        u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
+        v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
+        
+        texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
+        if (texture_state.level < 0)
+                texture_state.level = 0;
+        texture_state.texture_shift = 18 + (9 - texture_state.level);
+        tex_offset = 1 << texture_state.texture_shift;
+        
+        texture_state.u = u;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[0]);
+        du = (u >> (texture_state.texture_shift - 8)) & 0xff;
+        dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v;
+        tex_read(state, &texture_state, &tex_samples[1]);
+
+        texture_state.u = u;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[2]);
+
+        texture_state.u = u + tex_offset;
+        texture_state.v = v + tex_offset;
+        tex_read(state, &texture_state, &tex_samples[3]);
+
+        d[0] = (256 - du) * (256 - dv);
+        d[1] =  du * (256 - dv);
+        d[2] = (256 - du) * dv;
+        d[3] = du * dv;
+        
+        state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
+        state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
+        state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
+        state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
+}
+
+
+#define CLAMP(x) do                                     \
+        {                                               \
+                if ((x) & ~0xff)                        \
+                        x = ((x) < 0) ? 0 : 0xff;       \
+        }                               \
+        while (0)
+
+#define CLAMP_RGBA(r, g, b, a)        \
+                if ((r) & ~0xff)                        \
+                        r = ((r) < 0) ? 0 : 0xff;       \
+                if ((g) & ~0xff)                        \
+                        g = ((g) < 0) ? 0 : 0xff;       \
+                if ((b) & ~0xff)                        \
+                        b = ((b) < 0) ? 0 : 0xff;       \
+                if ((a) & ~0xff)                        \
+                        a = ((a) < 0) ? 0 : 0xff;
+        
+#define CLAMP_RGB(r, g, b) do           \
+        {                               \
+                if ((r) < 0)            \
+                        r = 0;          \
+                if ((r) > 0xff)         \
+                        r = 0xff;       \
+                if ((g) < 0)            \
+                        g = 0;          \
+                if ((g) > 0xff)         \
+                        g = 0xff;       \
+                if ((b) < 0)            \
+                        b = 0;          \
+                if ((b) > 0xff)         \
+                        b = 0xff;       \
+        }                               \
+        while (0)
+
+static void dest_pixel_gouraud_shaded_triangle(s3d_state_t *state)
+{
+        state->dest_rgba.r = state->r >> 7;
+        CLAMP(state->dest_rgba.r);
+
+        state->dest_rgba.g = state->g >> 7;
+        CLAMP(state->dest_rgba.g);
+
+        state->dest_rgba.b = state->b >> 7;
+        CLAMP(state->dest_rgba.b);
+
+        state->dest_rgba.a = state->a >> 7;
+        CLAMP(state->dest_rgba.a);
+}
+
+static void dest_pixel_unlit_texture_triangle(s3d_state_t *state)
+{
+        tex_sample(state);
+
+        if (state->cmd_set & CMD_SET_ABC_SRC)
+                state->dest_rgba.a = state->a >> 7;
+}
+
+static void dest_pixel_lit_texture_decal(s3d_state_t *state)
+{
+        tex_sample(state);
+
+        if (state->cmd_set & CMD_SET_ABC_SRC)
+                state->dest_rgba.a = state->a >> 7;
+}
+
+static void dest_pixel_lit_texture_reflection(s3d_state_t *state)
+{
+        tex_sample(state);
+
+        state->dest_rgba.r += (state->r >> 7);
+        state->dest_rgba.g += (state->g >> 7);
+        state->dest_rgba.b += (state->b >> 7);
+        if (state->cmd_set & CMD_SET_ABC_SRC)
+                state->dest_rgba.a += (state->a >> 7);
+
+        CLAMP_RGBA(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, state->dest_rgba.a);
+}
+
+static void dest_pixel_lit_texture_modulate(s3d_state_t *state)
+{
+        int r = state->r >> 7, g = state->g >> 7, b = state->b >> 7, a = state->a >> 7;
+        
+        tex_sample(state);
+        
+        CLAMP_RGBA(r, g, b, a);
+        
+        state->dest_rgba.r = ((state->dest_rgba.r) * r) >> 8;
+        state->dest_rgba.g = ((state->dest_rgba.g) * g) >> 8;
+        state->dest_rgba.b = ((state->dest_rgba.b) * b) >> 8;
+
+        if (state->cmd_set & CMD_SET_ABC_SRC)
+                state->dest_rgba.a = a;
+}
+
+static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2)
+{
+        svga_t *svga = &virge->svga;
+        uint8_t *vram = virge->svga.vram;
+
+        int x_dir = s3d_tri->tlr ? 1 : -1;
+        
+        int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE);
+
+        int y_count = yc;
+        
+        int bpp = (s3d_tri->cmd_set >> 2) & 7;
+        
+        uint32_t dest_offset, z_offset;
+
+        dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str);
+        z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str);
+
+        if (s3d_tri->cmd_set & CMD_SET_HC)
+        {
+                if (state->y < s3d_tri->clip_t)
+                        return;
+                if (state->y > s3d_tri->clip_b)
+                {
+                        int diff_y = state->y - s3d_tri->clip_b;
+                        
+                        if (diff_y > y_count)
+                                diff_y = y_count;
+                        
+                        state->base_u += (s3d_tri->TdUdY * diff_y);
+                        state->base_v += (s3d_tri->TdVdY * diff_y);
+                        state->base_z += (s3d_tri->TdZdY * diff_y);
+                        state->base_r += (s3d_tri->TdRdY * diff_y);
+                        state->base_g += (s3d_tri->TdGdY * diff_y);
+                        state->base_b += (s3d_tri->TdBdY * diff_y);
+                        state->base_a += (s3d_tri->TdAdY * diff_y);
+                        state->base_d += (s3d_tri->TdDdY * diff_y);
+                        state->base_w += (s3d_tri->TdWdY * diff_y);
+                        state->x1 += (dx1 * diff_y);
+                        state->x2 += (dx2 * diff_y);
+                        state->y -= diff_y;
+                        dest_offset -= s3d_tri->dest_str;
+                        z_offset -= s3d_tri->z_str;
+                        y_count -= diff_y;
+                }
+                if ((state->y - y_count) < s3d_tri->clip_t)
+                        y_count = (state->y - s3d_tri->clip_t) + 1;
+        }
+        
+        for (; y_count > 0; y_count--)
+        {
+                int x  = (state->x1 + ((1 << 20) - 1)) >> 20;
+                int xe = (state->x2 + ((1 << 20) - 1)) >> 20;
+                uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0;
+                if (x_dir < 0)
+                {
+                        x--;
+                        xe--;
+                }
+
+                if (x != xe && ((x_dir > 0 && x < xe) || (x_dir < 0 && x > xe)))
+                {
+                        uint32_t dest_addr, z_addr;
+                        int dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f);
+                        int x_offset = x_dir * (bpp + 1);
+                        int xz_offset = x_dir << 1;
+                        if (x_dir > 0)
+                                dx += 1;
+                        state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5);
+                        state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5);
+                        state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5);
+                        state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5);
+                        state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5);
+                        state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5);
+                        state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5);
+                        state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5);
+                        z += ((s3d_tri->TdZdX * dx) >> 5);
+
+//                        pclog("Draw Y=%i X=%i to XE=%i  %i   %08x %08x %08x %08x  %08x %08x %08x %08x  %i %08x\n", state->y, x, xe, dx, state->x1, state->x2, dx1, virge->s3d.TdWdX, state->u, state->v, virge->s3d.TdUdX, virge->s3d.TdUdY, dx, (virge->s3d.TdUdX * dx) >> 4);
+
+                        if (s3d_tri->cmd_set & CMD_SET_HC)
+                        {
+                                if (x_dir > 0)
+                                {
+                                        if (x > s3d_tri->clip_r)
+                                                goto tri_skip_line;
+                                        if (xe < s3d_tri->clip_l)
+                                                goto tri_skip_line;
+                                        if (xe > s3d_tri->clip_r)
+                                                xe = s3d_tri->clip_r + 1;
+                                        if (x < s3d_tri->clip_l)
+                                        {
+                                                int diff_x = s3d_tri->clip_l - x;
+                                                
+                                                z += (s3d_tri->TdZdX * diff_x);
+                                                state->u += (s3d_tri->TdUdX * diff_x);
+                                                state->v += (s3d_tri->TdVdX * diff_x);
+                                                state->r += (s3d_tri->TdRdX * diff_x);
+                                                state->g += (s3d_tri->TdGdX * diff_x);
+                                                state->b += (s3d_tri->TdBdX * diff_x);
+                                                state->a += (s3d_tri->TdAdX * diff_x);
+                                                state->d += (s3d_tri->TdDdX * diff_x);
+                                                state->w += (s3d_tri->TdWdX * diff_x);
+                                                
+                                                x = s3d_tri->clip_l;
+                                        }
+                                }
+                                else
+                                {
+                                        if (x < s3d_tri->clip_l)
+                                                goto tri_skip_line;
+                                        if (xe > s3d_tri->clip_r)
+                                                goto tri_skip_line;
+                                        if (xe < s3d_tri->clip_l)
+                                                xe = s3d_tri->clip_l - 1;
+                                        if (x > s3d_tri->clip_r)
+                                        {
+                                                int diff_x = x - s3d_tri->clip_r;
+                                                
+                                                z += (s3d_tri->TdZdX * diff_x);
+                                                state->u += (s3d_tri->TdUdX * diff_x);
+                                                state->v += (s3d_tri->TdVdX * diff_x);
+                                                state->r += (s3d_tri->TdRdX * diff_x);
+                                                state->g += (s3d_tri->TdGdX * diff_x);
+                                                state->b += (s3d_tri->TdBdX * diff_x);
+                                                state->a += (s3d_tri->TdAdX * diff_x);
+                                                state->d += (s3d_tri->TdDdX * diff_x);
+                                                state->w += (s3d_tri->TdWdX * diff_x);
+                                                
+                                                x = s3d_tri->clip_r;
+                                        }
+                                }
+                        }
+
+                        virge->svga.changedvram[(dest_offset & svga->vram_mask) >> 12] = changeframecount;
+
+                        dest_addr = dest_offset + (x * (bpp + 1));
+                        z_addr = z_offset + (x << 1);
+
+                        x &= 0xfff;
+                        xe &= 0xfff;
+
+                        for (; x != xe; x = (x + x_dir) & 0xfff)
+                        {
+                                int update = 1;
+                                uint16_t src_z = 0;
+                                _x = x; _y = state->y;
+
+                                if (use_z)
+                                {
+                                        src_z = Z_READ(z_addr);
+                                        Z_CLIP(src_z, z >> 16);
+                                }
+
+                                if (update)
+                                {
+                                        uint32_t dest_col;
+
+                                        dest_pixel(state);
+
+                                        if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE)
+                                        {
+                                                uint32_t src_col;
+                                                int src_r = 0, src_g = 0, src_b = 0;
+                                                
+                                                switch (bpp)
+                                                {
+                                                        case 0: /*8 bpp*/
+                                                        /*Not implemented yet*/
+                                                        break;
+                                                        case 1: /*16 bpp*/
+                                                        src_col = *(uint16_t *)&vram[dest_addr & svga->vram_mask];
+                                                        RGB15_TO_24(src_col, src_r, src_g, src_b);
+                                                        break;
+                                                        case 2: /*24 bpp*/
+                                                        src_col = (*(uint32_t *)&vram[dest_addr & svga->vram_mask]) & 0xffffff;
+                                                        RGB24_TO_24(src_col, src_r, src_g, src_b);
+                                                        break;
+                                                }
+
+                                                state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255;
+                                                state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255;
+                                                state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255;
+                                        }
+
+                                        switch (bpp)
+                                        {
+                                                case 0: /*8 bpp*/ 
+                                                /*Not implemented yet*/
+                                                break;
+                                                case 1: /*16 bpp*/
+                                                RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col);
+                                                *(uint16_t *)&vram[dest_addr] = dest_col;
+                                                break;
+                                                case 2: /*24 bpp*/
+                                                dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b);
+                                                *(uint8_t *)&vram[dest_addr] = dest_col & 0xff;
+                                                *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff;
+                                                *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff;
+                                                break;
+                                        }
+
+                                        if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP))
+                                                Z_WRITE(z_addr, src_z);
+                                }
+
+                                z += s3d_tri->TdZdX;
+                                state->u += s3d_tri->TdUdX;
+                                state->v += s3d_tri->TdVdX;
+                                state->r += s3d_tri->TdRdX;
+                                state->g += s3d_tri->TdGdX;
+                                state->b += s3d_tri->TdBdX;
+                                state->a += s3d_tri->TdAdX;
+                                state->d += s3d_tri->TdDdX;
+                                state->w += s3d_tri->TdWdX;
+                                dest_addr += x_offset;
+                                z_addr += xz_offset;
+                                virge->pixel_count++;
+                        }
+                }
+tri_skip_line:
+                state->x1 += dx1;
+                state->x2 += dx2;
+                state->base_u += s3d_tri->TdUdY;
+                state->base_v += s3d_tri->TdVdY;
+                state->base_z += s3d_tri->TdZdY;
+                state->base_r += s3d_tri->TdRdY;
+                state->base_g += s3d_tri->TdGdY;
+                state->base_b += s3d_tri->TdBdY;
+                state->base_a += s3d_tri->TdAdY;
+                state->base_d += s3d_tri->TdDdY;
+                state->base_w += s3d_tri->TdWdY;
+                state->y--;
+                dest_offset -= s3d_tri->dest_str;
+                z_offset -= s3d_tri->z_str;
+        }
+}
+
+static int tex_size[8] =
+{
+        4*2,
+        2*2,
+        2*2,
+        1*2,
+        2/1,
+        2/1,
+        1*2,
+        1*2
+};
+
+static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri)
+{
+        s3d_state_t state;
+
+        uint32_t tex_base;
+        int c;
+
+        uint64_t start_time = timer_read();
+        uint64_t end_time;
+
+        state.tbu = s3d_tri->tbu << 11;
+        state.tbv = s3d_tri->tbv << 11;
+        
+        state.max_d = (s3d_tri->cmd_set >> 8) & 15;
+        
+        state.tex_bdr_clr = s3d_tri->tex_bdr_clr;
+        
+        state.cmd_set = s3d_tri->cmd_set;
+
+        state.base_u = s3d_tri->tus;
+        state.base_v = s3d_tri->tvs;
+        state.base_z = s3d_tri->tzs;
+        state.base_r = (int32_t)s3d_tri->trs;
+        state.base_g = (int32_t)s3d_tri->tgs;
+        state.base_b = (int32_t)s3d_tri->tbs;
+        state.base_a = (int32_t)s3d_tri->tas;
+        state.base_d = s3d_tri->tds;
+        state.base_w = s3d_tri->tws;
+        
+        tex_base = s3d_tri->tex_base;
+        for (c = 9; c >= 0; c--)
+        {
+                state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base];
+                if (c <= state.max_d)
+                        tex_base += ((1 << (c*2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2;
+        }
+
+        switch ((s3d_tri->cmd_set >> 27) & 0xf)
+        {
+                case 0:
+                dest_pixel = dest_pixel_gouraud_shaded_triangle;
+//                pclog("dest_pixel_gouraud_shaded_triangle\n");
+                break;
+                case 1:
+                case 5:
+                switch ((s3d_tri->cmd_set >> 15) & 0x3)
+                {
+                        case 0:
+                        dest_pixel = dest_pixel_lit_texture_reflection;
+//                        pclog("dest_pixel_lit_texture_reflection\n");
+                        break;
+                        case 1:
+                        dest_pixel = dest_pixel_lit_texture_modulate;
+//                        pclog("dest_pixel_lit_texture_modulate\n");
+                        break;
+                        case 2:
+                        dest_pixel = dest_pixel_lit_texture_decal;
+//                        pclog("dest_pixel_lit_texture_decal\n");
+                        break;
+                        default:
+                        pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf);
+                        return;
+                }
+                break;
+                case 2:
+                case 6:
+                dest_pixel = dest_pixel_unlit_texture_triangle;
+//                pclog("dest_pixel_unlit_texture_triangle\n");
+                break;
+                default:
+                pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf);
+                return;
+        }        
+        
+        switch (((s3d_tri->cmd_set >> 12) & 7) | ((s3d_tri->cmd_set & (1 << 29)) ? 8 : 0))
+        {
+                case 0: case 1:
+                tex_sample = tex_sample_mipmap;
+//                pclog("use tex_sample_mipmap\n");
+                break;
+                case 2: case 3:
+                tex_sample = virge->bilinear_enabled ? tex_sample_mipmap_filter : tex_sample_mipmap;
+//                pclog("use tex_sample_mipmap_filter\n");
+                break;
+                case 4: case 5:
+                tex_sample = tex_sample_normal;
+//                pclog("use tex_sample_normal\n");
+                break;
+                case 6: case 7:
+                tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal;
+//                pclog("use tex_sample_normal_filter\n");
+                break;
+                case (0 | 8): case (1 | 8):
+                if (virge->is_375)
+                        tex_sample = tex_sample_persp_mipmap_375;
+                else
+                        tex_sample = tex_sample_persp_mipmap;
+//                pclog("use tex_sample_persp_mipmap\n");
+                break;
+                case (2 | 8): case (3 | 8):
+                if (virge->is_375)
+                        tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375;
+                else
+                        tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap;
+//                pclog("use tex_sample_persp_mipmap_filter\n");
+                break;
+                case (4 | 8): case (5 | 8):
+                if (virge->is_375)
+                        tex_sample = tex_sample_persp_normal_375;
+                else
+                        tex_sample = tex_sample_persp_normal;
+//                pclog("use tex_sample_persp_normal\n");
+                break;
+                case (6 | 8): case (7 | 8):
+                if (virge->is_375)
+                        tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375;
+                else
+                        tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal;
+//                pclog("use tex_sample_persp_normal_filter\n");
+                break;
+        }
+        
+        switch ((s3d_tri->cmd_set >> 5) & 7)
+        {
+                case 0:
+                tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB8888 : tex_ARGB8888_nowrap;
+                break;
+                case 1:
+                tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB4444 : tex_ARGB4444_nowrap;
+//                pclog("tex_ARGB4444\n");
+                break;
+                case 2:
+                tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap;
+//                pclog("tex_ARGB1555 %i\n", (s3d_tri->cmd_set >> 5) & 7);
+                break;
+                default:
+                pclog("bad texture type %i\n", (s3d_tri->cmd_set >> 5) & 7);
+                tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap;
+                break;
+        }
+        
+//        pclog("Triangle %i %i,%i to %i,%i  %08x\n", y, x1 >> 20, y, s3d_tri->txend01 >> 20, y - (s3d_tri->ty01 + s3d_tri->ty12), state.cmd_set);
+
+        state.y  = s3d_tri->tys;
+        state.x1 = s3d_tri->txs;
+        state.x2 = s3d_tri->txend01;
+        tri(virge, s3d_tri, &state, s3d_tri->ty01, s3d_tri->TdXdY02, s3d_tri->TdXdY01);
+        state.x2 = s3d_tri->txend12;
+        tri(virge, s3d_tri, &state, s3d_tri->ty12, s3d_tri->TdXdY02, s3d_tri->TdXdY12);
+
+        virge->tri_count++;
+
+        end_time = timer_read();
+        
+        virge_time += end_time - start_time;
+}
+
+static void render_thread(void *param)
+{
+        virge_t *virge = (virge_t *)param;
+        
+        while (1)
+        {
+                thread_wait_event(virge->wake_render_thread, -1);
+                thread_reset_event(virge->wake_render_thread);
+                virge->s3d_busy = 1;
+                while (!RB_EMPTY)
+                {
+                        s3_virge_triangle(virge, &virge->s3d_buffer[virge->s3d_read_idx & RB_MASK]);
+                        virge->s3d_read_idx++;
+                        
+                        if (RB_ENTRIES == RB_SIZE - 1)
+                                thread_set_event(virge->not_full_event);
+                }
+                virge->s3d_busy = 0;
+                virge->subsys_stat |= INT_S3D_DONE;
+                s3_virge_update_irqs(virge);
+        }
+}
+
+static void queue_triangle(virge_t *virge)
+{
+//        pclog("queue_triangle: read=%i write=%i RB_ENTRIES=%i RB_FULL=%i\n", virge->s3d_read_idx, virge->s3d_write_idx, RB_ENTRIES, RB_FULL);
+        if (RB_FULL)
+        {
+                thread_reset_event(virge->not_full_event);
+                if (RB_FULL)
+                        thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/
+        }
+//        pclog("                add at read=%i write=%i %i\n", virge->s3d_read_idx, virge->s3d_write_idx, virge->s3d_write_idx & RB_MASK);
+        virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri;
+        virge->s3d_write_idx++;
+        if (!virge->s3d_busy)
+                thread_set_event(virge->wake_render_thread); /*Wake up render thread if moving from idle*/
+}
+
+static void s3_virge_hwcursor_draw(svga_t *svga, int displine)
+{
+        virge_t *virge = (virge_t *)svga->p;
+        int x;
+        uint16_t dat[2];
+        int xx;
+        int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
+        uint32_t fg, bg;
+        
+//        pclog("HWcursor %i %i  %08x %08x\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y, virge->hwcursor_col[0],virge->hwcursor_col[1]);
+        switch (svga->bpp)
+        {               
+                case 15:
+                fg = video_15to32[virge->hwc_fg_col & 0xffff];
+                bg = video_15to32[virge->hwc_bg_col & 0xffff];
+                break;
+                
+                case 16:
+                fg = video_16to32[virge->hwc_fg_col & 0xffff];
+                bg = video_16to32[virge->hwc_bg_col & 0xffff];
+                break;
+                
+                case 24: case 32:
+                fg = virge->hwc_fg_col;
+                bg = virge->hwc_bg_col;
+                break;
+
+                default:
+                fg = svga->pallook[virge->hwc_fg_col & 0xff];
+                bg = svga->pallook[virge->hwc_bg_col & 0xff];
+                break;
+        }
+
+        for (x = 0; x < 64; x += 16)
+        {
+                dat[0] = (svga->vram[svga->hwcursor_latch.addr]     << 8) | svga->vram[svga->hwcursor_latch.addr + 1];
+                dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3];
+                if (svga->crtc[0x55] & 0x10)
+                {
+                        /*X11*/
+                        for (xx = 0; xx < 16; xx++)
+                        {
+                                if (offset >= svga->hwcursor_latch.x)
+                                {
+                                        if (dat[0] & 0x8000)
+                                                ((uint32_t *)buffer32->line[displine])[offset + 32]  = (dat[1] & 0x8000) ? fg : bg;
+                                }
+                           
+                                offset++;
+                                dat[0] <<= 1;
+                                dat[1] <<= 1;
+                        }
+                }
+                else
+                {
+                        /*Windows*/
+                        for (xx = 0; xx < 16; xx++)
+                        {
+                                if (offset >= svga->hwcursor_latch.x)
+                                {
+                                        if (!(dat[0] & 0x8000))
+                                           ((uint32_t *)buffer32->line[displine])[offset + 32]  = (dat[1] & 0x8000) ? fg : bg;
+                                        else if (dat[1] & 0x8000)
+                                           ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
+//                                pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga->hwcursor_on, dat[0], dat[1]);
+                                }
+                           
+                                offset++;
+                                dat[0] <<= 1;
+                                dat[1] <<= 1;
+                        }
+                }
+                svga->hwcursor_latch.addr += 4;
+        }
+}
+
+#define DECODE_YCbCr()                                                  \
+        do                                                              \
+        {                                                               \
+                int c;                                                  \
+                                                                        \
+                for (c = 0; c < 2; c++)                                 \
+                {                                                       \
+                        uint8_t y1, y2;                                 \
+                        int8_t Cr, Cb;                                  \
+                        int dR, dG, dB;                                 \
+                                                                        \
+                        y1 = src[0];                                    \
+                        Cr = src[1] - 0x80;                             \
+                        y2 = src[2];                                    \
+                        Cb = src[3] - 0x80;                             \
+                        src += 4;                                       \
+                                                                        \
+                        dR = (359*Cr) >> 8;                             \
+                        dG = (88*Cb + 183*Cr) >> 8;                     \
+                        dB = (453*Cb) >> 8;                             \
+                                                                        \
+                        r[x_write] = y1 + dR;                           \
+                        CLAMP(r[x_write]);                              \
+                        g[x_write] = y1 - dG;                           \
+                        CLAMP(g[x_write]);                              \
+                        b[x_write] = y1 + dB;                           \
+                        CLAMP(b[x_write]);                              \
+                                                                        \
+                        r[x_write+1] = y2 + dR;                         \
+                        CLAMP(r[x_write+1]);                            \
+                        g[x_write+1] = y2 - dG;                         \
+                        CLAMP(g[x_write+1]);                            \
+                        b[x_write+1] = y2 + dB;                         \
+                        CLAMP(b[x_write+1]);                            \
+                                                                        \
+                        x_write = (x_write + 2) & 7;                    \
+                }                                                       \
+        } while (0)
+
+/*Both YUV formats are untested*/
+#define DECODE_YUV211()                                         \
+        do                                                      \
+        {                                                       \
+                uint8_t y1, y2, y3, y4;                         \
+                int8_t U, V;                                    \
+                int dR, dG, dB;                                 \
+                                                                \
+                U = src[0] - 0x80;                              \
+                y1 = (298 * (src[1] - 16)) >> 8;                \
+                y2 = (298 * (src[2] - 16)) >> 8;                \
+                V = src[3] - 0x80;                              \
+                y3 = (298 * (src[4] - 16)) >> 8;                \
+                y4 = (298 * (src[5] - 16)) >> 8;                \
+                src += 6;                                       \
+                                                                \
+                dR = (309*V) >> 8;                              \
+                dG = (100*U + 208*V) >> 8;                      \
+                dB = (516*U) >> 8;                              \
+                                                                \
+                r[x_write] = y1 + dR;                           \
+                CLAMP(r[x_write]);                              \
+                g[x_write] = y1 - dG;                           \
+                CLAMP(g[x_write]);                              \
+                b[x_write] = y1 + dB;                           \
+                CLAMP(b[x_write]);                              \
+                                                                \
+                r[x_write+1] = y2 + dR;                         \
+                CLAMP(r[x_write+1]);                            \
+                g[x_write+1] = y2 - dG;                         \
+                CLAMP(g[x_write+1]);                            \
+                b[x_write+1] = y2 + dB;                         \
+                CLAMP(b[x_write+1]);                            \
+                                                                \
+                r[x_write+2] = y3 + dR;                         \
+                CLAMP(r[x_write+2]);                            \
+                g[x_write+2] = y3 - dG;                         \
+                CLAMP(g[x_write+2]);                            \
+                b[x_write+2] = y3 + dB;                         \
+                CLAMP(b[x_write+2]);                            \
+                                                                \
+                r[x_write+3] = y4 + dR;                         \
+                CLAMP(r[x_write+3]);                            \
+                g[x_write+3] = y4 - dG;                         \
+                CLAMP(g[x_write+3]);                            \
+                b[x_write+3] = y4 + dB;                         \
+                CLAMP(b[x_write+3]);                            \
+                                                                \
+                x_write = (x_write + 4) & 7;                    \
+        } while (0)
+
+#define DECODE_YUV422()                                                 \
+        do                                                              \
+        {                                                               \
+                int c;                                                  \
+                                                                        \
+                for (c = 0; c < 2; c++)                                 \
+                {                                                       \
+                        uint8_t y1, y2;                                 \
+                        int8_t U, V;                                    \
+                        int dR, dG, dB;                                 \
+                                                                        \
+                        U = src[0] - 0x80;                              \
+                        y1 = (298 * (src[1] - 16)) >> 8;                \
+                        V = src[2] - 0x80;                              \
+                        y2 = (298 * (src[3] - 16)) >> 8;                \
+                        src += 4;                                       \
+                                                                        \
+                        dR = (309*V) >> 8;                              \
+                        dG = (100*U + 208*V) >> 8;                      \
+                        dB = (516*U) >> 8;                              \
+                                                                        \
+                        r[x_write] = y1 + dR;                           \
+                        CLAMP(r[x_write]);                              \
+                        g[x_write] = y1 - dG;                           \
+                        CLAMP(g[x_write]);                              \
+                        b[x_write] = y1 + dB;                           \
+                        CLAMP(b[x_write]);                              \
+                                                                        \
+                        r[x_write+1] = y2 + dR;                         \
+                        CLAMP(r[x_write+1]);                            \
+                        g[x_write+1] = y2 - dG;                         \
+                        CLAMP(g[x_write+1]);                            \
+                        b[x_write+1] = y2 + dB;                         \
+                        CLAMP(b[x_write+1]);                            \
+                                                                        \
+                        x_write = (x_write + 2) & 7;                    \
+                }                                                       \
+        } while (0)
+
+#define DECODE_RGB555()                                                 \
+        do                                                              \
+        {                                                               \
+                int c;                                                  \
+                                                                        \
+                for (c = 0; c < 4; c++)                                 \
+                {                                                       \
+                        uint16_t dat;                                   \
+                                                                        \
+                        dat = *(uint16_t *)src;                         \
+                        src += 2;                                       \
+                                                                        \
+                        r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \
+                        g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \
+                        b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \
+                }                                                       \
+                x_write = (x_write + 4) & 7;                            \
+        } while (0)
+
+#define DECODE_RGB565()                                                 \
+        do                                                              \
+        {                                                               \
+                int c;                                                  \
+                                                                        \
+                for (c = 0; c < 4; c++)                                 \
+                {                                                       \
+                        uint16_t dat;                                   \
+                                                                        \
+                        dat = *(uint16_t *)src;                         \
+                        src += 2;                                       \
+                                                                        \
+                        r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \
+                        g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \
+                        b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \
+                }                                                       \
+                x_write = (x_write + 4) & 7;                            \
+        } while (0)
+
+#define DECODE_RGB888()                                                 \
+        do                                                              \
+        {                                                               \
+                int c;                                                  \
+                                                                        \
+                for (c = 0; c < 4; c++)                                 \
+                {                                                       \
+                        r[x_write + c] = src[0];                        \
+                        g[x_write + c] = src[1];                        \
+                        b[x_write + c] = src[2];                        \
+                        src += 3;                                       \
+                }                                                       \
+                x_write = (x_write + 4) & 7;                            \
+        } while (0)
+
+#define DECODE_XRGB8888()                                               \
+        do                                                              \
+        {                                                               \
+                int c;                                                  \
+                                                                        \
+                for (c = 0; c < 4; c++)                                 \
+                {                                                       \
+                        r[x_write + c] = src[0];                        \
+                        g[x_write + c] = src[1];                        \
+                        b[x_write + c] = src[2];                        \
+                        src += 4;                                       \
+                }                                                       \
+                x_write = (x_write + 4) & 7;                            \
+        } while (0)
+
+#define OVERLAY_SAMPLE()                        \
+        do                                      \
+        {                                       \
+                switch (virge->streams.sdif)    \
+                {                               \
+                        case 1:                 \
+                        DECODE_YCbCr();         \
+                        break;                  \
+                        case 2:                 \
+                        DECODE_YUV422();        \
+                        break;                  \
+                        case 3:                 \
+                        DECODE_RGB555();        \
+                        break;                  \
+                        case 4:                 \
+                        DECODE_YUV211();        \
+                        break;                  \
+                        case 5:                 \
+                        DECODE_RGB565();        \
+                        break;                  \
+                        case 6:                 \
+                        DECODE_RGB888();        \
+                        break;                  \
+                        case 7:                 \
+                        default:                \
+                        DECODE_XRGB8888();      \
+                        break;                  \
+                }                               \
+        } while (0)
+
+static void s3_virge_overlay_draw(svga_t *svga, int displine)
+{
+        virge_t *virge = (virge_t *)svga->p;
+        int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1;
+        int h_acc = virge->streams.dda_horiz_accumulator;
+        int r[8], g[8], b[8];
+        int x_size, x_read = 4, x_write = 4;
+        int x;
+        uint32_t *p;
+        uint8_t *src = &svga->vram[svga->overlay_latch.addr];
+        
+        p = &((uint32_t *)buffer32->line[displine])[offset + 32];
+        
+        if ((offset + virge->streams.sec_w) > virge->streams.pri_w)
+                x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1;
+        else
+                x_size = virge->streams.sec_w + 1;
+
+        OVERLAY_SAMPLE();
+        
+        for (x = 0; x < x_size; x++)
+        {
+                *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16);
+
+                h_acc += virge->streams.k1_horiz_scale;
+                if (h_acc >= 0)
+                {
+                        if ((x_read ^ (x_read + 1)) & ~3)
+                                OVERLAY_SAMPLE();
+                        x_read = (x_read + 1) & 7;
+
+                        h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale);
+                }
+        }
+
+        svga->overlay_latch.v_acc += virge->streams.k1_vert_scale;
+        if (svga->overlay_latch.v_acc >= 0)
+        {
+                svga->overlay_latch.v_acc += (virge->streams.k2_vert_scale - virge->streams.k1_vert_scale);
+                svga->overlay_latch.addr += virge->streams.sec_stride;
+        }
+}
+
+static uint8_t s3_virge_pci_read(int func, int addr, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        svga_t *svga = &virge->svga;
+        uint8_t ret = 0;
+//        pclog("S3 PCI read %08X  ", addr);
+        switch (addr)
+        {
+                case 0x00: ret = 0x33; break; /*'S3'*/
+                case 0x01: ret = 0x53; break;
+                
+                case 0x02: ret = virge->virge_id_low; break;
+                case 0x03: ret = virge->virge_id_high; break;
+
+                case 0x04: ret = virge->pci_regs[0x04] & 0x27; break;
+                
+                case 0x07: ret = virge->pci_regs[0x07] & 0x36; break;
+                                
+                case 0x08: ret = 0; break; /*Revision ID*/
+                case 0x09: ret = 0; break; /*Programming interface*/
+                
+                case 0x0a: ret = 0x00; break; /*Supports VGA interface*/
+                case 0x0b: ret = 0x03; /*output = 3; */break;
+
+                case 0x0d: ret = virge->pci_regs[0x0d] & 0xf8; break;
+                                
+                case 0x10: ret = 0x00; break;/*Linear frame buffer address*/
+                case 0x11: ret = 0x00; break;
+                case 0x12: ret = 0x00; break;
+                case 0x13: ret = svga->crtc[0x59] & 0xfc; break;
+
+                case 0x30: ret = virge->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/
+                case 0x31: ret = 0x00; break;
+                case 0x32: ret = virge->pci_regs[0x32]; break;
+                case 0x33: ret = virge->pci_regs[0x33]; break;
+
+                case 0x3c: ret = virge->pci_regs[0x3c]; break;
+                                
+                case 0x3d: ret = 0x01; break; /*INTA*/
+                
+                case 0x3e: ret = 0x04; break;
+                case 0x3f: ret = 0xff; break;
+                
+        }
+//        pclog("%02X\n", ret);
+        return ret;
+}
+
+static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        svga_t *svga = &virge->svga;
+//        pclog("S3 PCI write %08X %02X %04X:%08X\n", addr, val, CS, pc);
+        switch (addr)
+        {
+                case 0x00: case 0x01: case 0x02: case 0x03:
+                case 0x08: case 0x09: case 0x0a: case 0x0b:
+                case 0x3d: case 0x3e: case 0x3f:
+                return;
+                
+                case PCI_REG_COMMAND:
+                if (val & PCI_COMMAND_IO)
+                {
+                        io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
+                        io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
+                }
+                else
+                        io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
+                virge->pci_regs[PCI_REG_COMMAND] = val & 0x27;
+                s3_virge_updatemapping(virge); 
+                return;
+                case 0x07:
+                virge->pci_regs[0x07] = val & 0x3e;
+                return;
+                case 0x0d: 
+                virge->pci_regs[0x0d] = val & 0xf8;
+                return;
+                
+                case 0x13: 
+                svga->crtc[0x59] = val & 0xfc; 
+                s3_virge_updatemapping(virge); 
+                return;
+
+                case 0x30: case 0x32: case 0x33:
+                virge->pci_regs[addr] = val;
+                if (virge->pci_regs[0x30] & 0x01)
+                {
+                        uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24);
+//                        pclog("Virge bios_rom enabled at %08x\n", addr);
+                        mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000);
+                        mem_mapping_enable(&virge->bios_rom.mapping);
+                }
+                else
+                {
+//                        pclog("Virge bios_rom disabled\n");
+                        mem_mapping_disable(&virge->bios_rom.mapping);
+                }
+                return;
+                case 0x3c: 
+                virge->pci_regs[0x3c] = val;
+                return;
+        }
+}
+
+static void *s3_virge_init()
+{
+        virge_t *virge = malloc(sizeof(virge_t));
+        memset(virge, 0, sizeof(virge_t));
+
+        virge->bilinear_enabled = device_get_config_int("bilinear");
+        virge->dithering_enabled = device_get_config_int("dithering");
+        virge->memory_size = device_get_config_int("memory");
+        
+        svga_init(&virge->svga, virge, virge->memory_size << 20,
+                   s3_virge_recalctimings,
+                   s3_virge_in, s3_virge_out,
+                   s3_virge_hwcursor_draw,
+                   s3_virge_overlay_draw);
+
+        rom_init(&virge->bios_rom, "s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+        if (PCI)
+                mem_mapping_disable(&virge->bios_rom.mapping);
+
+        mem_mapping_add(&virge->mmio_mapping,     0, 0, s3_virge_mmio_read,
+                                                        s3_virge_mmio_read_w,
+                                                        s3_virge_mmio_read_l,
+                                                        s3_virge_mmio_write,
+                                                        s3_virge_mmio_write_w,
+                                                        s3_virge_mmio_write_l,
+                                                        NULL,
+                                                        0,
+                                                        virge);
+        mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read,
+                                                        s3_virge_mmio_read_w,
+                                                        s3_virge_mmio_read_l,
+                                                        s3_virge_mmio_write,
+                                                        s3_virge_mmio_write_w,
+                                                        s3_virge_mmio_write_l,
+                                                        NULL,
+                                                        0,
+                                                        virge);
+        mem_mapping_add(&virge->linear_mapping,   0, 0, svga_read_linear,
+                                                        svga_readw_linear,
+                                                        svga_readl_linear,
+                                                        svga_write_linear,
+                                                        svga_writew_linear,
+                                                        svga_writel_linear,
+                                                        NULL,
+                                                        0,
+                                                        &virge->svga);
+
+        io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
+
+        virge->pci_regs[4] = 3;
+        virge->pci_regs[5] = 0;        
+        virge->pci_regs[6] = 0;
+        virge->pci_regs[7] = 2;
+        virge->pci_regs[0x32] = 0x0c;
+        virge->pci_regs[0x3d] = 1; 
+        virge->pci_regs[0x3e] = 4;
+        virge->pci_regs[0x3f] = 0xff;
+        
+        virge->virge_id_high = 0x56;
+        virge->virge_id_low = 0x31;
+        virge->virge_rev = 0;
+        virge->virge_id = 0xe1;
+
+        switch (virge->memory_size)
+        {
+                case 2:
+                virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5);
+                break;
+                case 4:
+                default:
+                virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5);
+                break;
+        }
+                
+        virge->svga.crtc[0x37] = 1;// | (7 << 5);
+        virge->svga.crtc[0x53] = 1 << 3;
+        virge->svga.crtc[0x59] = 0x70;
+
+        virge->is_375 = 0;
+        
+        pci_add(s3_virge_pci_read, s3_virge_pci_write, virge);
+        
+        virge->wake_render_thread = thread_create_event();
+        virge->wake_main_thread = thread_create_event();
+        virge->not_full_event = thread_create_event();
+        virge->render_thread = thread_create(render_thread, virge);
+
+        virge->wake_fifo_thread = thread_create_event();
+        virge->fifo_not_full_event = thread_create_event();
+        virge->fifo_thread = thread_create(fifo_thread, virge);
+        return virge;
+}
+
+static void *s3_virge_375_init()
+{
+        virge_t *virge = malloc(sizeof(virge_t));
+        memset(virge, 0, sizeof(virge_t));
+        
+        virge->bilinear_enabled = device_get_config_int("bilinear");
+        virge->dithering_enabled = device_get_config_int("dithering");
+        virge->memory_size = device_get_config_int("memory");
+
+        svga_init(&virge->svga, virge, virge->memory_size << 20,
+                   s3_virge_recalctimings,
+                   s3_virge_in, s3_virge_out,
+                   s3_virge_hwcursor_draw,
+                   s3_virge_overlay_draw);
+        virge->svga.vblank_start = s3_virge_vblank_start;
+
+        rom_init(&virge->bios_rom, "86c375_1.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+        if (PCI)
+                mem_mapping_disable(&virge->bios_rom.mapping);
+
+        mem_mapping_add(&virge->mmio_mapping,     0, 0, s3_virge_mmio_read,
+                                                        s3_virge_mmio_read_w,
+                                                        s3_virge_mmio_read_l,
+                                                        s3_virge_mmio_write,
+                                                        s3_virge_mmio_write_w,
+                                                        s3_virge_mmio_write_l,
+                                                        NULL,
+                                                        0,
+                                                        virge);
+        mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read,
+                                                        s3_virge_mmio_read_w,
+                                                        s3_virge_mmio_read_l,
+                                                        s3_virge_mmio_write,
+                                                        s3_virge_mmio_write_w,
+                                                        s3_virge_mmio_write_l,
+                                                        NULL,
+                                                        0,
+                                                        virge);
+        mem_mapping_add(&virge->linear_mapping,   0, 0, svga_read_linear,
+                                                        svga_readw_linear,
+                                                        svga_readl_linear,
+                                                        svga_write_linear,
+                                                        svga_writew_linear,
+                                                        svga_writel_linear,
+                                                        NULL,
+                                                        0,
+                                                        &virge->svga);
+
+        io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
+
+        virge->pci_regs[4] = 3;
+        virge->pci_regs[5] = 0;        
+        virge->pci_regs[6] = 0;
+        virge->pci_regs[7] = 2;
+        virge->pci_regs[0x32] = 0x0c;
+        virge->pci_regs[0x3d] = 1; 
+        virge->pci_regs[0x3e] = 4;
+        virge->pci_regs[0x3f] = 0xff;
+        
+        virge->virge_id_high = 0x8a;
+        virge->virge_id_low = 0x01;
+        virge->virge_rev = 0;
+        virge->virge_id = 0xe1;
+
+        switch (virge->memory_size)
+        {
+                case 2:
+                virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5);
+                break;
+                case 4:
+                default:
+                virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5);
+                break;
+        }
+//        virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4);
+        virge->svga.crtc[0x37] = 1;// | (7 << 5);
+        virge->svga.crtc[0x53] = 1 << 3;
+        virge->svga.crtc[0x59] = 0x70;
+        
+        virge->svga.crtc[0x6c] = 0x01;
+        
+        virge->is_375 = 1;
+        
+        virge->card = pci_add(s3_virge_pci_read, s3_virge_pci_write, virge);
+        virge->wake_render_thread = thread_create_event();
+        virge->wake_main_thread = thread_create_event();
+        virge->not_full_event = thread_create_event();
+        virge->render_thread = thread_create(render_thread, virge);
+
+        virge->wake_fifo_thread = thread_create_event();
+        virge->fifo_not_full_event = thread_create_event();
+        virge->fifo_thread = thread_create(fifo_thread, virge);
+        return virge;
+}
+
+static void s3_virge_close(void *p)
+{
+        virge_t *virge = (virge_t *)p;
+#ifndef RELEASE_BUILD
+        FILE *f = fopen("vram.dmp", "wb");
+        fwrite(virge->svga.vram, 4 << 20, 1, f);
+        fclose(f);
+#endif
+
+        thread_kill(virge->render_thread);
+        thread_destroy_event(virge->not_full_event);
+        thread_destroy_event(virge->wake_main_thread);
+        thread_destroy_event(virge->wake_render_thread);
+        
+        thread_kill(virge->fifo_thread);
+        thread_destroy_event(virge->wake_fifo_thread);
+        thread_destroy_event(virge->fifo_not_full_event);
+
+        svga_close(&virge->svga);
+        
+        free(virge);
+}
+
+static int s3_virge_available()
+{
+        return rom_present("s3virge.bin");
+}
+
+static int s3_virge_375_available()
+{
+        return rom_present("86c375_1.bin");
+}
+
+static void s3_virge_speed_changed(void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        
+        svga_recalctimings(&virge->svga);
+}
+
+static void s3_virge_force_redraw(void *p)
+{
+        virge_t *virge = (virge_t *)p;
+
+        virge->svga.fullchange = changeframecount;
+}
+
+static void s3_virge_add_status_info(char *s, int max_len, void *p)
+{
+        virge_t *virge = (virge_t *)p;
+        char temps[256];
+        uint64_t new_time = timer_read();
+        uint64_t status_diff = new_time - status_time;
+        status_time = new_time;
+
+        if (!status_diff)
+                status_diff = 1;
+
+        svga_add_status_info(s, max_len, &virge->svga);
+        sprintf(temps, "%f Mpixels/sec\n%f ktris/sec\n%f%% CPU\n%f%% CPU (real)\n%d writes %i reads\n\n", (double)virge->pixel_count/1000000.0, (double)virge->tri_count/1000.0, ((double)virge_time * 100.0) / timer_freq, ((double)virge_time * 100.0) / status_diff, reg_writes, reg_reads);
+        strncat(s, temps, max_len);
+
+        virge->pixel_count = virge->tri_count = 0;
+        virge_time = 0;
+        reg_reads = 0;
+        reg_writes = 0;
+}
+
+static device_config_t s3_virge_config[] =
+{
+        {
+                .name = "memory",
+                .description = "Memory size",
+                .type = CONFIG_SELECTION,
+                .selection =
+                {
+                        {
+                                .description = "2 MB",
+                                .value = 2
+                        },
+                        {
+                                .description = "4 MB",
+                                .value = 4
+                        },
+                        {
+                                .description = ""
+                        }
+                },
+                .default_int = 4
+        },
+        {
+                .name = "bilinear",
+                .description = "Bilinear filtering",
+                .type = CONFIG_BINARY,
+                .default_int = 1
+        },
+        {
+                .name = "dithering",
+                .description = "Dithering",
+                .type = CONFIG_BINARY,
+                .default_int = 1
+        },
+        {
+                .type = -1
+        }
+};
+
+device_t s3_virge_device =
+{
+        "Diamond Stealth 3D 2000 (S3 ViRGE)",
+        0,
+        s3_virge_init,
+        s3_virge_close,
+        s3_virge_available,
+        s3_virge_speed_changed,
+        s3_virge_force_redraw,
+        s3_virge_add_status_info,
+        s3_virge_config
+};
+
+device_t s3_virge_375_device =
+{
+        "S3 ViRGE/DX",
+        0,
+        s3_virge_375_init,
+        s3_virge_close,
+        s3_virge_375_available,
+        s3_virge_speed_changed,
+        s3_virge_force_redraw,
+        s3_virge_add_status_info,
+        s3_virge_config
+};
diff --git a/pcem/vid_s3_virge.h b/pcem/vid_s3_virge.h
new file mode 100644 (file)
index 0000000..dce1a24
--- /dev/null
@@ -0,0 +1,2 @@
+extern device_t s3_virge_device;
+extern device_t s3_virge_375_device;
diff --git a/pcem/vid_sdac_ramdac.cpp b/pcem/vid_sdac_ramdac.cpp
new file mode 100644 (file)
index 0000000..08288ac
--- /dev/null
@@ -0,0 +1,187 @@
+/*87C716 'SDAC' true colour RAMDAC emulation*/
+#include "ibm.h"
+#include "mem.h"
+#include "video.h"
+#include "vid_svga.h"
+#include "vid_sdac_ramdac.h"
+
+static void sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val)
+{
+        ramdac->command = val;
+//        pclog("RAMDAC command reg now %02X\n", val);
+        switch (val & 0xf0)
+        {
+                case 0x00: case 0x10:
+                svga->bpp = 8;
+                break;
+                
+                case 0x20: case 0x30: case 0x80: case 0xa0:
+                svga->bpp = 15;
+                break;
+                
+                case 0x50: case 0x60: case 0xc0:
+                svga->bpp = 16;
+                break;
+                
+                case 0x40: case 0x90: case 0xe0:
+                svga->bpp = 24;
+                break;
+                
+                case 0x70:
+                svga->bpp = 32;
+                break;
+                
+                default:
+                svga->bpp = 8;
+                break;
+        }
+}
+
+static void sdac_reg_write(sdac_ramdac_t *ramdac, int reg, uint8_t val)
+{
+        if ((reg >= 2 && reg <= 7) || (reg == 0xa) || (reg == 0xe))
+        {
+                if (!ramdac->reg_ff)
+                        ramdac->regs[reg] = (ramdac->regs[reg] & 0xff00) | val;
+                else
+                        ramdac->regs[reg] = (ramdac->regs[reg] & 0x00ff) | (val << 8);
+        }
+        ramdac->reg_ff = !ramdac->reg_ff;
+        if (!ramdac->reg_ff)
+                ramdac->windex++;
+}
+
+static uint8_t sdac_reg_read(sdac_ramdac_t *ramdac, int reg)
+{
+        uint8_t temp;
+        
+        if (!ramdac->reg_ff)
+                temp = ramdac->regs[reg] & 0xff;
+        else
+                temp = ramdac->regs[reg] >> 8;
+        ramdac->reg_ff = !ramdac->reg_ff;
+        if (!ramdac->reg_ff)
+                ramdac->rindex++;
+
+        return temp;
+}
+
+void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga)
+{
+//        /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X  %i  %i %i\n",addr,val,ramdac->magic_count,CS,cpu_state.pc, ramdac->rs2, ramdac->rindex, ramdac->windex);
+        switch (addr)
+        {               
+                case 2:
+                if (ramdac->magic_count == 4)
+                        sdac_control_write(ramdac, svga, val);
+                ramdac->magic_count = 0;
+                break;
+                
+                case 3:
+                ramdac->magic_count = 0;
+                break;
+                case 0:
+                ramdac->magic_count = 0;
+                break;
+                case 1:
+                ramdac->magic_count = 0;
+                break;
+
+                case 4:
+                ramdac->windex = val;
+                ramdac->reg_ff = 0;
+                break;
+                case 5:
+                sdac_reg_write(ramdac, ramdac->windex & 0xff, val);
+                break;
+                case 6:
+                sdac_control_write(ramdac, svga, val);
+                break;
+                case 7:
+                ramdac->rindex = val;
+                ramdac->reg_ff = 0;
+                break;
+        }
+        if (!(addr & 4))
+        {
+                if (addr < 2)
+                        svga_out(addr + 0x3c8, val, svga);
+                else
+                        svga_out(addr + 0x3c4, val, svga);
+        }
+}
+
+uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga)
+{
+//        /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i  %i %i\n",addr,CS,cpu_state.pc, ramdac->rs2, ramdac->rindex, ramdac->windex);
+        switch (addr)
+        {
+                case 2:
+                if (ramdac->magic_count < 5)
+                        ramdac->magic_count++;
+                if (ramdac->magic_count == 4)
+                {
+                        ramdac->rs2 = 1;
+                        return 0x70; /*SDAC ID*/
+                }
+                if (ramdac->magic_count == 5)
+                {
+                        ramdac->magic_count = 0;
+                        return ramdac->command;
+                }
+                break;
+                case 3:
+                ramdac->magic_count=0;
+                break;
+                case 0:
+                ramdac->magic_count=0;
+                break;
+                case 1:
+                ramdac->magic_count=0;
+                break;
+
+                case 4:
+                return ramdac->windex;
+                case 5:
+                return sdac_reg_read(ramdac, ramdac->rindex & 0xff);
+                case 6:
+                return ramdac->command;
+                case 7:
+                return ramdac->rindex;
+        }
+        if (!(addr & 4))
+        {
+                if (addr < 2)
+                        return svga_in(addr + 0x3c8, svga);
+                else
+                        return svga_in(addr + 0x3c4, svga);
+        }
+        return 0xff;
+}
+
+float sdac_getclock(int clock, void *p)
+{
+        sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p;
+        float t;
+        int m, n1, n2;
+        
+        if (ramdac->regs[0xe] & (1 << 5))
+                clock = ramdac->regs[0xe] & 7;
+                
+//        pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]);
+        clock &= 7;
+        if (clock == 0) return 25175000.0;
+        if (clock == 1) return 28322000.0;
+        m  =  (ramdac->regs[clock] & 0x7f) + 2;
+        n1 = ((ramdac->regs[clock] >>  8) & 0x1f) + 2;
+        n2 = ((ramdac->regs[clock] >> 13) & 0x07);
+        t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2);
+//        pclog("SDAC clock %i %i %i %f %04X  %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2);
+        return t;
+}
+
+void sdac_init(sdac_ramdac_t *ramdac)
+{
+        ramdac->regs[0] = 0x6128;
+        ramdac->regs[1] = 0x623d;
+}
diff --git a/pcem/vid_sdac_ramdac.h b/pcem/vid_sdac_ramdac.h
new file mode 100644 (file)
index 0000000..48126f7
--- /dev/null
@@ -0,0 +1,16 @@
+typedef struct sdac_ramdac_t
+{
+        int magic_count;
+        uint8_t command;
+        int windex, rindex;
+        uint16_t regs[256];
+        int reg_ff;
+        int rs2;
+} sdac_ramdac_t;
+
+void sdac_init(sdac_ramdac_t *ramdac);
+
+void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga);
+uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga);
+
+float sdac_getclock(int clock, void *p);
diff --git a/pcem/vid_svga.cpp b/pcem/vid_svga.cpp
new file mode 100644 (file)
index 0000000..314c4d7
--- /dev/null
@@ -0,0 +1,1554 @@
+/*Generic SVGA handling*/
+/*This is intended to be used by another SVGA driver, and not as a card in it's own right*/
+#include <stdlib.h>
+#include "ibm.h"
+#include "mem.h"
+#include "video.h"
+#include "vid_svga.h"
+#include "vid_svga_render.h"
+#include "io.h"
+#include "timer.h"
+
+#define svga_output 0
+
+void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga);
+
+extern uint8_t edatlookup[4][4];
+
+uint8_t svga_rotate[8][256];
+
+/*Primary SVGA device. As multiple video cards are not yet supported this is the
+  only SVGA device.*/
+static svga_t *svga_pri;
+
+svga_t *svga_get_pri()
+{
+        return svga_pri;
+}
+void svga_set_override(svga_t *svga, int val)
+{
+        if (svga->override && !val)
+                svga->fullchange = changeframecount;
+        svga->override = val;
+}
+
+void svga_out(uint16_t addr, uint8_t val, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        int c;
+        uint8_t o;
+//        printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc);
+        switch (addr)
+        {
+                case 0x3C0:
+                if (!svga->attrff)
+                {
+                        svga->attraddr = val & 31;
+                        if ((val & 0x20) != svga->attr_palette_enable)
+                        {
+                                svga->fullchange = 3;
+                                svga->attr_palette_enable = val & 0x20;
+                                svga_recalctimings(svga);
+                        }
+                }
+                else
+                {
+                        if ((svga->attraddr == 0x13) && (svga->attrregs[0x13] != val))
+                                svga->fullchange = changeframecount;
+                        svga->attrregs[svga->attraddr & 31] = val;
+                        if (svga->attraddr < 16) 
+                                svga->fullchange = changeframecount;
+                        if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10)
+                        {
+                                for (c = 0; c < 16; c++)
+                                {
+                                        if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] &  0xf) | ((svga->attrregs[0x14] & 0xf) << 4);
+                                        else                             svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4);
+                                }
+                        }
+                        if (svga->attraddr == 0x10) 
+                                svga_recalctimings(svga);
+                        if (svga->attraddr == 0x12)
+                        {
+                                if ((val & 0xf) != svga->plane_mask)
+                                        svga->fullchange = changeframecount;
+                                svga->plane_mask = val & 0xf;
+                        }
+                }
+                svga->attrff ^= 1;
+                break;
+                case 0x3C2:
+                svga->miscout = val;
+                svga->vidclock = val & 4;// printf("3C2 write %02X\n",val);
+                io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p);
+                if (!(val & 1))
+                        io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p);
+                svga_recalctimings(svga);
+                break;
+                case 0x3C4: 
+                svga->seqaddr = val; 
+                break;
+                case 0x3C5:
+                if (svga->seqaddr > 0xf) return;
+                o = svga->seqregs[svga->seqaddr & 0xf];
+                svga->seqregs[svga->seqaddr & 0xf] = val;
+                if (o != val && (svga->seqaddr & 0xf) == 1)
+                        svga_recalctimings(svga);
+                switch (svga->seqaddr & 0xf)
+                {
+                        case 1: 
+                        if (svga->scrblank && !(val & 0x20)) 
+                                svga->fullchange = 3; 
+                        svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); 
+                        svga_recalctimings(svga);
+                        break;
+                        case 2: 
+                        svga->writemask = val & 0xf; 
+                        break;
+                        case 3:
+                        svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2;
+                        svga->charseta = ((val & 3)  * 0x10000) + 2;
+                        if (val & 0x10)
+                                svga->charseta += 0x8000;
+                        if (val & 0x20)
+                                svga->charsetb += 0x8000;
+                        break;
+                        case 4: 
+                        svga->chain2_write = !(val & 4);
+                        svga->chain4 = val & 8;
+                        svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4;
+                        break;
+                }
+                break;
+                case 0x3c6: 
+                svga->dac_mask = val; 
+                break;
+                case 0x3C7: 
+                svga->dac_read = val; 
+                svga->dac_pos = 0; 
+                break;
+                case 0x3C8: 
+                svga->dac_write = val; 
+                svga->dac_read = val - 1; 
+                svga->dac_pos = 0; 
+                break;
+                case 0x3C9:
+                svga->dac_status = 0;
+                svga->fullchange = changeframecount;
+                switch (svga->dac_pos)
+                {
+                        case 0: 
+                        svga->dac_r = val;
+                        svga->dac_pos++; 
+                        break;
+                        case 1: 
+                        svga->dac_g = val;
+                        svga->dac_pos++; 
+                        break;
+                        case 2: 
+                        svga->vgapal[svga->dac_write].r = svga->dac_r;
+                        svga->vgapal[svga->dac_write].g = svga->dac_g;
+                        svga->vgapal[svga->dac_write].b = val; 
+                        if (svga->ramdac_type == RAMDAC_8BIT)
+                                svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b);
+                        else
+                                svga->pallook[svga->dac_write] = makecol32((svga->vgapal[svga->dac_write].r & 0x3f) * 4, (svga->vgapal[svga->dac_write].g & 0x3f) * 4, (svga->vgapal[svga->dac_write].b & 0x3f) * 4); 
+                        svga->dac_pos = 0; 
+                        svga->dac_write = (svga->dac_write + 1) & 255; 
+                        break;
+                }
+                break;
+                case 0x3CE: 
+                svga->gdcaddr = val; 
+                break;
+                case 0x3CF:
+                o = svga->gdcreg[svga->gdcaddr & 15];
+                switch (svga->gdcaddr & 15)
+                {
+                        case 2: svga->colourcompare=val; break;
+                        case 4: svga->readplane=val&3; break;
+                        case 5:
+                        svga->writemode = val & 3;
+                        svga->readmode = val & 8;
+                        svga->chain2_read = val & 0x10;
+                        break;
+                        case 6:
+//                                pclog("svga_out recalcmapping %p\n", svga);
+                        if ((svga->gdcreg[6] & 0xc) != (val & 0xc))
+                        {
+//                                pclog("Write mapping %02X\n", val);
+                                switch (val&0xC)
+                                {
+                                        case 0x0: /*128k at A0000*/
+                                        mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
+                                        svga->banked_mask = 0xffff;
+                                        break;
+                                        case 0x4: /*64k at A0000*/
+                                        mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
+                                        svga->banked_mask = 0xffff;
+                                        break;
+                                        case 0x8: /*32k at B0000*/
+                                        mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
+                                        svga->banked_mask = 0x7fff;
+                                        break;
+                                        case 0xC: /*32k at B8000*/
+                                        mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
+                                        svga->banked_mask = 0x7fff;
+                                        break;
+                                }
+                        }
+                        break;
+                        case 7: svga->colournocare=val; break;
+                }
+                svga->gdcreg[svga->gdcaddr & 15] = val;                
+                svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4;
+                if (((svga->gdcaddr & 15) == 5  && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1))
+                        svga_recalctimings(svga);
+                break;
+        }
+}
+
+uint8_t svga_in(uint16_t addr, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        uint8_t temp;
+//        if (addr!=0x3da) pclog("Read port %04X\n",addr);
+        switch (addr)
+        {
+                case 0x3C0: 
+                return svga->attraddr | svga->attr_palette_enable;
+                case 0x3C1: 
+                return svga->attrregs[svga->attraddr];
+                case 0x3c2:
+                if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50)
+                        temp = 0;
+                else
+                        temp = 0x10;
+                return temp;
+                case 0x3C4: 
+                return svga->seqaddr;
+                case 0x3C5:
+                return svga->seqregs[svga->seqaddr & 0xF];
+                case 0x3c6: return svga->dac_mask;
+                case 0x3c7: return svga->dac_status;
+                case 0x3c8: return svga->dac_write;
+                case 0x3c9:
+                svga->dac_status = 3;
+                switch (svga->dac_pos)
+                {
+                        case 0: 
+                        svga->dac_pos++; 
+                        if (svga->ramdac_type == RAMDAC_8BIT)
+                                return svga->vgapal[svga->dac_read].r;
+                        return svga->vgapal[svga->dac_read].r & 0x3f;
+                        case 1: 
+                        svga->dac_pos++; 
+                        if (svga->ramdac_type == RAMDAC_8BIT)
+                                return svga->vgapal[svga->dac_read].g;
+                        return svga->vgapal[svga->dac_read].g & 0x3f;
+                        case 2: 
+                        svga->dac_pos=0; 
+                        svga->dac_read = (svga->dac_read + 1) & 255; 
+                        if (svga->ramdac_type == RAMDAC_8BIT)
+                                return svga->vgapal[(svga->dac_read - 1) & 255].b;
+                        return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f;
+                }
+                break;
+                case 0x3CC: 
+                return svga->miscout;
+                case 0x3CE: 
+                return svga->gdcaddr;
+                case 0x3CF:
+                return svga->gdcreg[svga->gdcaddr & 0xf];
+                case 0x3DA:
+                svga->attrff = 0;
+
+                if (svga->cgastat & 0x01)
+                        svga->cgastat &= ~0x30;
+                else
+                        svga->cgastat ^= 0x30;
+                return svga->cgastat;
+        }
+//        printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc);
+        return 0xFF;
+}
+
+void svga_set_ramdac_type(svga_t *svga, int type)
+{
+        int c;
+        
+        if (svga->ramdac_type != type)
+        {
+                svga->ramdac_type = type;
+                        
+                for (c = 0; c < 256; c++)
+                {
+                        if (svga->ramdac_type == RAMDAC_8BIT)
+                                svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b);
+                        else
+                                svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, (svga->vgapal[c].g & 0x3f) * 4, (svga->vgapal[c].b & 0x3f) * 4); 
+                }
+        }
+}
+
+void svga_recalctimings(svga_t *svga)
+{
+        double crtcconst;
+        double _dispontime, _dispofftime, disptime;
+
+        svga->vtotal = svga->crtc[6];
+        svga->dispend = svga->crtc[0x12];
+        svga->vsyncstart = svga->crtc[0x10];
+        svga->split = svga->crtc[0x18];
+        svga->vblankstart = svga->crtc[0x15];
+
+        if (svga->crtc[7] & 1)  svga->vtotal |= 0x100;
+        if (svga->crtc[7] & 32) svga->vtotal |= 0x200;
+        svga->vtotal += 2;
+
+        if (svga->crtc[7] & 2)  svga->dispend |= 0x100;
+        if (svga->crtc[7] & 64) svga->dispend |= 0x200;
+        svga->dispend++;
+
+        if (svga->crtc[7] & 4)   svga->vsyncstart |= 0x100;
+        if (svga->crtc[7] & 128) svga->vsyncstart |= 0x200;
+        svga->vsyncstart++;
+
+        if (svga->crtc[7] & 0x10) svga->split|=0x100;
+        if (svga->crtc[9] & 0x40) svga->split|=0x200;
+        svga->split++;
+        
+        if (svga->crtc[7] & 0x08) svga->vblankstart |= 0x100;
+        if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200;
+        svga->vblankstart++;
+        
+        svga->hdisp = svga->crtc[1];
+        svga->hdisp++;
+
+        svga->htotal = svga->crtc[0];
+        svga->htotal += 6; /*+6 is required for Tyrian*/
+
+        svga->rowoffset = svga->crtc[0x13];
+
+        svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1;
+        
+        svga->lowres = svga->attrregs[0x10] & 0x40;
+        
+        svga->interlace = 0;
+        
+        svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd];
+
+        svga->hdisp_time = svga->hdisp;
+        svga->render = svga_render_blank;
+        if (!svga->scrblank && svga->attr_palette_enable)
+        {
+                if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) /*Text mode*/
+                {
+                        if (svga->seqregs[1] & 8) /*40 column*/
+                        {
+                                svga->render = svga_render_text_40;
+                                svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18;
+                        }
+                        else
+                        {
+                                svga->render = svga_render_text_80;
+                                svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9;
+                        }
+                        svga->hdisp_old = svga->hdisp;
+                }
+                else 
+                {
+                        svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8;
+                        svga->hdisp_old = svga->hdisp;                        
+                        
+                        switch (svga->gdcreg[5] & 0x60)
+                        {
+                                case 0x00: /*16 colours*/
+                                if (svga->seqregs[1] & 8) /*Low res (320)*/
+                                        svga->render = svga_render_4bpp_lowres;
+                                else
+                                        svga->render = svga_render_4bpp_highres;
+                                break;
+                                case 0x20: /*4 colours*/
+                                if (svga->seqregs[1] & 8) /*Low res (320)*/
+                                        svga->render = svga_render_2bpp_lowres;
+                                else
+                                        svga->render = svga_render_2bpp_highres;
+                                break;
+                                case 0x40: case 0x60: /*256+ colours*/
+                                switch (svga->bpp)
+                                {
+                                        case 8:
+                                        if (svga->lowres)
+                                                svga->render = svga_render_8bpp_lowres;
+                                        else
+                                                svga->render = svga_render_8bpp_highres;
+                                        break;
+                                        case 15:
+                                        if (svga->lowres)
+                                                svga->render = svga_render_15bpp_lowres;
+                                        else
+                                                svga->render = svga_render_15bpp_highres;
+                                        break;
+                                        case 16:
+                                        if (svga->lowres)
+                                                svga->render = svga_render_16bpp_lowres;
+                                        else
+                                                svga->render = svga_render_16bpp_highres;
+                                        break;
+                                        case 24:
+                                        if (svga->lowres)
+                                                svga->render = svga_render_24bpp_lowres;
+                                        else
+                                                svga->render = svga_render_24bpp_highres;
+                                        break;
+                                        case 32:
+                                        if (svga->lowres)
+                                                svga->render = svga_render_32bpp_lowres;
+                                        else
+                                                svga->render = svga_render_32bpp_highres;
+                                        break;
+                                }
+                                break;
+                        }
+                }
+        }        
+
+//        pclog("svga_render %08X : %08X %08X %08X %08X %08X  %i %i %02X %i %i\n", svga_render, svga_render_text_40, svga_render_text_80, svga_render_8bpp_lowres, svga_render_8bpp_highres, svga_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8);
+        
+        svga->linedbl = svga->crtc[9] & 0x80;
+        svga->rowcount = svga->crtc[9] & 31;
+        svga->char_width = (svga->seqregs[1] & 1) ? 8 : 9;
+        if (svga->recalctimings_ex) 
+                svga->recalctimings_ex(svga);
+
+        if (svga->vblankstart < svga->dispend)
+                svga->dispend = svga->vblankstart;
+
+        crtcconst = svga->clock * svga->char_width;
+
+        disptime  = svga->htotal;
+        _dispontime = svga->hdisp_time;
+        
+//        printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8);
+        if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; }
+        _dispofftime = disptime - _dispontime;
+        _dispontime *= crtcconst;
+        _dispofftime *= crtcconst;
+
+       svga->dispontime = (uint64_t)_dispontime;
+       svga->dispofftime = (uint64_t)_dispofftime;
+       if (svga->dispontime < TIMER_USEC)
+               svga->dispontime = TIMER_USEC;
+       if (svga->dispofftime < TIMER_USEC)
+               svga->dispofftime = TIMER_USEC;
+/*        printf("SVGA horiz total %i display end %i vidclock %f\n",svga->crtc[0],svga->crtc[1],svga->clock);
+        printf("SVGA vert total %i display end %i max row %i vsync %i\n",svga->vtotal,svga->dispend,(svga->crtc[9]&31)+1,svga->vsyncstart);
+        printf("total %f on %i cycles off %i cycles frame %i sec %i %02X\n",disptime*crtcconst,svga->dispontime,svga->dispofftime,(svga->dispontime+svga->dispofftime)*svga->vtotal,(svga->dispontime+svga->dispofftime)*svga->vtotal*70,svga->seqregs[1]);
+
+        pclog("svga->render %08X\n", svga->render);*/
+}
+
+extern int cyc_total;
+void svga_poll(void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        int x;
+
+        if (!svga->linepos)
+        {
+//                if (!(vc & 15)) pclog("VC %i %i\n", vc, GetTickCount());
+                if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena)
+                {
+                        svga->hwcursor_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff;
+                        if (svga->hwcursor_on < 0)
+                                svga->hwcursor_on = 0;
+                        svga->hwcursor_oddeven = 0;
+                }
+
+                if (svga->displine == svga->hwcursor_latch.y+1 && svga->hwcursor_latch.ena && svga->interlace)
+                {
+                        svga->hwcursor_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff;
+                        if (svga->hwcursor_on < 0)
+                                svga->hwcursor_on = 0;
+                        svga->hwcursor_oddeven = 1;
+                }
+
+                if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena)
+                {
+                        svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff;
+                        svga->overlay_oddeven = 0;
+                }
+                if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace)
+                {
+                        svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff;
+                        svga->overlay_oddeven = 1;
+                }
+
+                timer_advance_u64(&svga->timer, svga->dispofftime);
+//                if (output) printf("Display off %f\n",vidtime);
+                svga->cgastat |= 1;
+                svga->linepos = 1;
+
+                if (svga->dispon)
+                {
+                        svga->hdisp_on=1;
+                        
+                        svga->ma &= svga->vram_display_mask;
+                        if (svga->firstline == 2000)
+                        {
+                                svga->firstline = svga->displine;
+                                video_wait_for_buffer();
+                        }
+                        
+                        if (svga->hwcursor_on || svga->overlay_on)
+                                svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2;
+                      
+                        if (!svga->override)
+                                svga->render(svga);
+                        
+                        if (svga->overlay_on)
+                        {
+                                if (!svga->override)
+                                        svga->overlay_draw(svga, svga->displine);
+                                svga->overlay_on--;
+                                if (svga->overlay_on && svga->interlace)
+                                        svga->overlay_on--;
+                        }
+
+                        if (svga->hwcursor_on)
+                        {
+                                if (!svga->override)
+                                        svga->hwcursor_draw(svga, svga->displine);
+                                svga->hwcursor_on--;
+                                if (svga->hwcursor_on && svga->interlace)
+                                        svga->hwcursor_on--;
+                        }
+
+                        if (svga->lastline < svga->displine) 
+                                svga->lastline = svga->displine;
+                }
+
+//                pclog("%03i %06X %06X\n",displine,ma,vrammask);
+                svga->displine++;
+                if (svga->interlace) 
+                        svga->displine++;
+                if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines)
+                {
+//                        printf("Vsync off at line %i\n",displine);
+                        svga->cgastat &= ~8;
+                }
+                svga->vslines++;
+                if (svga->displine > 1500)
+                        svga->displine = 0;
+//                pclog("Col is %08X %08X %08X   %i %i  %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322],
+//                                                                displine, vc, ma);
+        }
+        else
+        {
+//                pclog("VC %i ma %05X\n", svga->vc, svga->ma);
+                timer_advance_u64(&svga->timer, svga->dispontime);
+
+//                if (output) printf("Display on %f\n",vidtime);
+                if (svga->dispon) 
+                        svga->cgastat &= ~1;
+                svga->hdisp_on = 0;
+                
+                svga->linepos = 0;
+                if (svga->sc == (svga->crtc[11] & 31)) 
+                        svga->con = 0;
+                if (svga->dispon)
+                {
+                        if (svga->linedbl && !svga->linecountff)
+                        {
+                                svga->linecountff = 1;
+                                svga->ma = svga->maback;
+                        }
+                        else if (svga->sc == svga->rowcount)
+                        {
+                                svga->linecountff = 0;
+                                svga->sc = 0;
+
+                                svga->maback += (svga->rowoffset << 3);
+                                if (svga->interlace)
+                                        svga->maback += (svga->rowoffset << 3);
+                                svga->maback &= svga->vram_display_mask;
+                                svga->ma = svga->maback;
+                        }
+                        else
+                        {
+                                svga->linecountff = 0;
+                                svga->sc++;
+                                svga->sc &= 31;
+                                svga->ma = svga->maback;
+                        }
+                }
+                svga->hsync_divisor = !svga->hsync_divisor;
+                
+                if (svga->hsync_divisor && (svga->crtc[0x17] & 4))
+                        return;
+
+                svga->vc++;
+                svga->vc &= 2047;
+
+                if (svga->vc == svga->split)
+                {
+                        int ret = 1;
+                        
+                        if (svga->line_compare)
+                                ret = svga->line_compare(svga);
+                                
+                        if (ret)
+                        {
+//                               pclog("VC split\n");
+                                svga->ma = svga->maback = 0;
+                                svga->sc = 0;
+                                if (svga->attrregs[0x10] & 0x20)
+                                        svga->scrollcache = 0;
+                        }
+                }
+                if (svga->vc == svga->dispend)
+                {
+                        if (svga->vblank_start)
+                                svga->vblank_start(svga);
+//                        pclog("VC dispend\n");
+                        svga->dispon=0;
+                        if (svga->crtc[10] & 0x20) svga->cursoron = 0;
+                        else                       svga->cursoron = svga->blink & 16;
+                        if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) 
+                                svga->fullchange = 2;
+                        svga->blink++;
+
+                        for (x = 0; x < ((svga->vram_mask+1) >> 12); x++) 
+                        {
+                                if (svga->changedvram[x]) 
+                                        svga->changedvram[x]--;
+                        }
+//                        memset(changedvram,0,2048);
+                        if (svga->fullchange) 
+                                svga->fullchange--;
+                }
+                if (svga->vc == svga->vsyncstart)
+                {
+                        int wx, wy;
+//                        pclog("VC vsync  %i %i\n", svga->firstline_draw, svga->lastline_draw);
+                        svga->dispon=0;
+                        svga->cgastat |= 8;
+                        x = svga->hdisp;
+
+                        if (svga->interlace && !svga->oddeven) svga->lastline++;
+                        if (svga->interlace &&  svga->oddeven) svga->firstline--;
+
+                        wx = x;
+                        wy = svga->lastline - svga->firstline;
+
+                        if (!svga->override)
+                                svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga);
+
+                        readflash = 0;
+
+                        svga->firstline = 2000;
+                        svga->lastline = 0;
+                        
+                        svga->firstline_draw = 2000;
+                        svga->lastline_draw = 0;
+                        
+                        svga->oddeven ^= 1;
+
+                        changeframecount = svga->interlace ? 3 : 2;
+                        svga->vslines = 0;
+                        
+                        if (svga->interlace && svga->oddeven) svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1);
+                        else                                  svga->ma = svga->maback = svga->ma_latch;
+                        svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf];
+
+                        svga->ma <<= 2;
+                        svga->maback <<= 2;
+                        svga->ca <<= 2;
+
+                        svga->video_res_x = wx;
+                        svga->video_res_y = wy + 1;
+//                        pclog("%i %i %i\n", svga->video_res_x, svga->video_res_y, svga->lowres);
+                        if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) /*Text mode*/
+                        {
+                                svga->video_res_x /= svga->char_width;
+                                svga->video_res_y /= (svga->crtc[9] & 31) + 1;
+                                svga->video_bpp = 0;
+                        }
+                        else
+                        {
+                                if (svga->crtc[9] & 0x80)
+                                   svga->video_res_y /= 2;
+                                if (!(svga->crtc[0x17] & 2))
+                                   svga->video_res_y *= 4;
+                                else if (!(svga->crtc[0x17] & 1))
+                                   svga->video_res_y *= 2;
+                                svga->video_res_y /= (svga->crtc[9] & 31) + 1;                                   
+                                if (svga->render == svga_render_8bpp_lowres ||
+                                    svga->render == svga_render_15bpp_lowres ||
+                                    svga->render == svga_render_16bpp_lowres ||
+                                    svga->render == svga_render_24bpp_lowres ||
+                                    svga->render == svga_render_32bpp_lowres)
+                                        svga->video_res_x /= 2;
+
+                                switch (svga->gdcreg[5] & 0x60)
+                                {
+                                        case 0x00:            svga->video_bpp = 4;   break;
+                                        case 0x20:            svga->video_bpp = 2;   break;
+                                        case 0x40: case 0x60: svga->video_bpp = svga->bpp; break;
+                                }
+                        }
+//                        if (svga_interlace && oddeven) ma=maback=ma+(svga_rowoffset<<2);
+                        
+//                        pclog("Addr %08X vson %03X vsoff %01X  %02X %02X %02X %i %i\n",ma,svga_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], svga_interlace, oddeven);
+
+                        if (svga->vsync_callback)
+                                svga->vsync_callback(svga);
+                }
+                if (svga->vc == svga->vtotal)
+                {
+//                        pclog("VC vtotal\n");
+
+
+//                        printf("Frame over at line %i %i  %i %i\n",displine,vc,svga_vsyncstart,svga_dispend);
+                        svga->vc = 0;
+                        svga->sc = svga->crtc[8] & 0x1f;
+                        svga->dispon = 1;
+                        svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0;
+                        svga->scrollcache = svga->attrregs[0x13] & 7;
+                        svga->linecountff = 0;
+                        
+                        svga->hwcursor_on = 0;
+                        svga->hwcursor_latch = svga->hwcursor;
+
+                        svga->overlay_on = 0;
+                        svga->overlay_latch = svga->overlay;
+//                        pclog("Latch HWcursor addr %08X\n", svga_hwcursor_latch.addr);
+                        
+//                        pclog("ADDR %08X\n",hwcursor_addr);
+                }
+                if (svga->sc == (svga->crtc[10] & 31)) 
+                        svga->con = 1;
+        }
+//        printf("2 %i\n",svga_vsyncstart);
+//pclog("svga_poll %i %i %i %i %i  %i %i\n", ins, svga->dispofftime, svga->dispontime, svga->vidtime, cyc_total, svga->linepos, svga->vc);
+}
+
+int svga_init(svga_t *svga, void *p, int memsize, 
+               void (*recalctimings_ex)(struct svga_t *svga),
+               uint8_t (*video_in) (uint16_t addr, void *p),
+               void    (*video_out)(uint16_t addr, uint8_t val, void *p),
+               void (*hwcursor_draw)(struct svga_t *svga, int displine),
+               void (*overlay_draw)(struct svga_t *svga, int displine))
+{
+        int c, d, e;
+        
+        svga->p = p;
+        
+        for (c = 0; c < 256; c++)
+        {
+                e = c;
+                for (d = 0; d < 8; d++)
+                {
+                        svga_rotate[d][c] = e;
+                        e = (e >> 1) | ((e & 1) ? 0x80 : 0);
+                }
+        }
+        svga->readmode = 0;
+
+        svga->crtc[0] = 63;
+        svga->crtc[6] = 255;
+        svga->dispontime = 1000ull << 32;
+        svga->dispofftime = 1000ull << 32;
+        svga->bpp = 8;
+        svga->vram = malloc(memsize);
+        svga->vram_max = memsize;
+        svga->vram_display_mask = memsize - 1;
+        svga->vram_mask = memsize - 1;
+        svga->decode_mask = 0x7fffff;
+        svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x800000 >> 12);
+        svga->recalctimings_ex = recalctimings_ex;
+        svga->video_in  = video_in;
+        svga->video_out = video_out;
+        svga->hwcursor_draw = hwcursor_draw;
+        svga->overlay_draw = overlay_draw;
+        svga->hwcursor.ysize = 64;
+//        _svga_recalctimings(svga);
+
+        mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga);
+
+        timer_add(&svga->timer, svga_poll, svga, 1);
+        
+        svga_pri = svga;
+        
+        svga->ramdac_type = RAMDAC_6BIT;
+        
+        return 0;
+}
+
+void svga_close(svga_t *svga)
+{
+        free(svga->changedvram);
+        free(svga->vram);
+        
+        svga_pri = NULL;
+}
+
+void svga_write(uint32_t addr, uint8_t val, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        uint8_t vala, valb, valc, vald, wm = svga->writemask;
+        int writemask2 = svga->writemask;
+
+        egawrites++;
+
+        cycles -= video_timing_write_b;
+        cycles_lost += video_timing_write_b;
+
+        if (svga_output) pclog("Writeega %06X   ",addr);
+        addr &= svga->banked_mask;
+        addr += svga->write_bank;
+
+        if (!(svga->gdcreg[6] & 1)) svga->fullchange=2;
+        if (svga->chain4 || svga->fb_only)
+        {
+                writemask2=1<<(addr&3);
+                addr&=~3;
+        }
+        else if (svga->chain2_write)
+        {
+                writemask2 &= ~0xa;
+                if (addr & 1)
+                        writemask2 <<= 1;
+                addr &= ~1;
+                addr <<= 2;
+        }
+        else
+        {
+                addr<<=2;
+        }
+        addr &= svga->decode_mask;
+
+        if (addr >= svga->vram_max)
+                return;
+        
+        addr &= svga->vram_mask;
+
+        if (svga_output) pclog("%08X (%i, %i) %02X %i %i %i %02X\n", addr, addr & 1023, addr >> 10, val, writemask2, svga->writemode, svga->chain4, svga->gdcreg[8]);
+        svga->changedvram[addr >> 12] = changeframecount;
+
+        switch (svga->writemode)
+        {
+                case 1:
+                if (writemask2 & 1) svga->vram[addr]       = svga->la;
+                if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb;
+                if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc;
+                if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld;
+                break;
+                case 0:
+                if (svga->gdcreg[3] & 7) 
+                        val = svga_rotate[svga->gdcreg[3] & 7][val];
+                if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled))
+                {
+                        if (writemask2 & 1) svga->vram[addr]       = val;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = val;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = val;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = val;
+                }
+                else
+                {
+                        if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0;
+                        else                     vala = val;
+                        if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0;
+                        else                     valb = val;
+                        if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0;
+                        else                     valc = val;
+                        if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0;
+                        else                     vald = val;
+
+                        switch (svga->gdcreg[3] & 0x18)
+                        {
+                                case 0: /*Set*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                                break;
+                                case 8: /*AND*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                                break;
+                                case 0x10: /*OR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                                break;
+                                case 0x18: /*XOR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                                break;
+                        }
+//                        pclog("- %02X %02X %02X %02X   %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
+                }
+                break;
+                case 2:
+                if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled))
+                {
+                        if (writemask2 & 1) svga->vram[addr]       = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                }
+                else
+                {
+                        vala = ((val & 1) ? 0xff : 0);
+                        valb = ((val & 2) ? 0xff : 0);
+                        valc = ((val & 4) ? 0xff : 0);
+                        vald = ((val & 8) ? 0xff : 0);
+                        switch (svga->gdcreg[3] & 0x18)
+                        {
+                                case 0: /*Set*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                                break;
+                                case 8: /*AND*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                                break;
+                                case 0x10: /*OR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                                break;
+                                case 0x18: /*XOR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                                break;
+                        }
+                }
+                break;
+                case 3:
+                if (svga->gdcreg[3] & 7) 
+                        val = svga_rotate[svga->gdcreg[3] & 7][val];
+                wm = svga->gdcreg[8];
+                svga->gdcreg[8] &= val;
+
+                vala = (svga->gdcreg[0] & 1) ? 0xff : 0;
+                valb = (svga->gdcreg[0] & 2) ? 0xff : 0;
+                valc = (svga->gdcreg[0] & 4) ? 0xff : 0;
+                vald = (svga->gdcreg[0] & 8) ? 0xff : 0;
+                switch (svga->gdcreg[3] & 0x18)
+                {
+                        case 0: /*Set*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                        break;
+                        case 8: /*AND*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                        break;
+                        case 0x10: /*OR*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                        break;
+                        case 0x18: /*XOR*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                        break;
+                }
+                svga->gdcreg[8] = wm;
+                break;
+        }
+}
+
+uint8_t svga_read(uint32_t addr, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        uint8_t temp, temp2, temp3, temp4;
+        uint32_t latch_addr;
+        int readplane = svga->readplane;
+        
+        cycles -= video_timing_read_b;
+        cycles_lost += video_timing_read_b;
+        
+        egareads++;
+//        pclog("Readega %06X   ",addr);
+
+        addr &= svga->banked_mask;
+        addr += svga->read_bank;
+                
+        latch_addr = (addr << 2) & svga->decode_mask;
+        
+//        pclog("%05X %i %04X:%04X %02X %02X %i\n",addr,svga->chain4,CS,pc, vram[addr & 0x7fffff], vram[(addr << 2) & 0x7fffff], svga->readmode);
+//        pclog("%i\n", svga->readmode);
+        if (svga->chain4 || svga->fb_only) 
+        { 
+                addr &= svga->decode_mask;
+                if (addr >= svga->vram_max)
+                        return 0xff;
+                return svga->vram[addr & svga->vram_mask];
+        }
+        else if (svga->chain2_read)
+        {
+                readplane = (readplane & 2) | (addr & 1);
+                addr &= ~1;
+                addr <<= 2;
+        }
+        else
+                addr<<=2;
+
+        addr &= svga->decode_mask;
+        
+        if (latch_addr >= svga->vram_max)
+        {
+                svga->la = svga->lb = svga->lc = svga->ld = 0xff;
+        }
+        else
+        {   
+                latch_addr &= svga->vram_mask;
+                svga->la = svga->vram[latch_addr];
+                svga->lb = svga->vram[latch_addr | 0x1];
+                svga->lc = svga->vram[latch_addr | 0x2];
+                svga->ld = svga->vram[latch_addr | 0x3];
+        }
+
+        if (addr >= svga->vram_max)
+                return 0xff;
+        
+        addr &= svga->vram_mask;
+        
+        if (svga->readmode)
+        {
+                temp   = svga->la;
+                temp  ^= (svga->colourcompare & 1) ? 0xff : 0;
+                temp  &= (svga->colournocare & 1)  ? 0xff : 0;
+                temp2  = svga->lb;
+                temp2 ^= (svga->colourcompare & 2) ? 0xff : 0;
+                temp2 &= (svga->colournocare & 2)  ? 0xff : 0;
+                temp3  = svga->lc;
+                temp3 ^= (svga->colourcompare & 4) ? 0xff : 0;
+                temp3 &= (svga->colournocare & 4)  ? 0xff : 0;
+                temp4  = svga->ld;
+                temp4 ^= (svga->colourcompare & 8) ? 0xff : 0;
+                temp4 &= (svga->colournocare & 8)  ? 0xff : 0;
+                return ~(temp | temp2 | temp3 | temp4);
+        }
+//pclog("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane);
+
+        return svga->vram[addr | readplane];
+}
+
+void svga_write_linear(uint32_t addr, uint8_t val, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        uint8_t vala, valb, valc, vald, wm = svga->writemask;
+        int writemask2 = svga->writemask;
+
+        cycles -= video_timing_write_b;
+        cycles_lost += video_timing_write_b;
+
+        egawrites++;
+        
+        if (svga_output) pclog("Write LFB %08X %02X ", addr, val);
+        if (!(svga->gdcreg[6] & 1)) 
+                svga->fullchange = 2;
+        if (svga->chain4 || svga->fb_only)
+        {
+                writemask2=1<<(addr&3);
+                addr&=~3;
+        }
+        else if (svga->chain2_write)
+        {
+                writemask2 &= ~0xa;
+                if (addr & 1)
+                        writemask2 <<= 1;
+                addr &= ~1;
+                addr <<= 2;
+        }
+        else
+        {
+                addr<<=2;
+        }
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return;
+        addr &= svga->vram_mask;
+        if (svga_output) pclog("%08X\n", addr);
+        svga->changedvram[addr >> 12]=changeframecount;
+        
+        switch (svga->writemode)
+        {
+                case 1:
+                if (writemask2 & 1) svga->vram[addr]       = svga->la;
+                if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb;
+                if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc;
+                if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld;
+                break;
+                case 0:
+                if (svga->gdcreg[3] & 7) 
+                        val = svga_rotate[svga->gdcreg[3] & 7][val];
+                if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled))
+                {
+                        if (writemask2 & 1) svga->vram[addr]       = val;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = val;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = val;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = val;
+                }
+                else
+                {
+                        if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0;
+                        else                     vala = val;
+                        if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0;
+                        else                     valb = val;
+                        if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0;
+                        else                     valc = val;
+                        if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0;
+                        else                     vald = val;
+
+                        switch (svga->gdcreg[3] & 0x18)
+                        {
+                                case 0: /*Set*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                                break;
+                                case 8: /*AND*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                                break;
+                                case 0x10: /*OR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                                break;
+                                case 0x18: /*XOR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                                break;
+                        }
+//                        pclog("- %02X %02X %02X %02X   %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
+                }
+                break;
+                case 2:
+                if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled))
+                {
+                        if (writemask2 & 1) svga->vram[addr]       = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                }
+                else
+                {
+                        vala = ((val & 1) ? 0xff : 0);
+                        valb = ((val & 2) ? 0xff : 0);
+                        valc = ((val & 4) ? 0xff : 0);
+                        vald = ((val & 8) ? 0xff : 0);
+                        switch (svga->gdcreg[3] & 0x18)
+                        {
+                                case 0: /*Set*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                                break;
+                                case 8: /*AND*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                                break;
+                                case 0x10: /*OR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                                break;
+                                case 0x18: /*XOR*/
+                                if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                                if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                                if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                                if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                                break;
+                        }
+                }
+                break;
+                case 3:
+                if (svga->gdcreg[3] & 7) 
+                        val = svga_rotate[svga->gdcreg[3] & 7][val];
+                wm = svga->gdcreg[8];
+                svga->gdcreg[8] &= val;
+
+                vala = (svga->gdcreg[0] & 1) ? 0xff : 0;
+                valb = (svga->gdcreg[0] & 2) ? 0xff : 0;
+                valc = (svga->gdcreg[0] & 4) ? 0xff : 0;
+                vald = (svga->gdcreg[0] & 8) ? 0xff : 0;
+                switch (svga->gdcreg[3] & 0x18)
+                {
+                        case 0: /*Set*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]);
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]);
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]);
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]);
+                        break;
+                        case 8: /*AND*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala | ~svga->gdcreg[8]) & svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld;
+                        break;
+                        case 0x10: /*OR*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) | svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld;
+                        break;
+                        case 0x18: /*XOR*/
+                        if (writemask2 & 1) svga->vram[addr]       = (vala & svga->gdcreg[8]) ^ svga->la;
+                        if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb;
+                        if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc;
+                        if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld;
+                        break;
+                }
+                svga->gdcreg[8] = wm;
+                break;
+        }
+}
+
+uint8_t svga_read_linear(uint32_t addr, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        uint8_t temp, temp2, temp3, temp4;
+        int readplane = svga->readplane;
+        uint32_t latch_addr = (addr << 2) & svga->decode_mask;
+  
+        cycles -= video_timing_read_b;
+        cycles_lost += video_timing_read_b;
+
+        egareads++;
+        
+        if (svga->chain4 || svga->fb_only) 
+        { 
+                addr &= svga->decode_mask;
+                if (addr >= svga->vram_max)
+                        return 0xff;
+                return svga->vram[addr & svga->vram_mask]; 
+        }
+        else if (svga->chain2_read)
+        {
+                readplane = (readplane & 2) | (addr & 1);
+                addr &= ~1;
+                addr <<= 2;
+        }
+        else
+                addr<<=2;
+
+        addr &= svga->decode_mask;
+        
+        if (latch_addr >= svga->vram_max)
+        {
+                svga->la = svga->lb = svga->lc = svga->ld = 0xff;
+        }
+        else
+        {
+                latch_addr &= svga->vram_mask;
+                svga->la = svga->vram[latch_addr];
+                svga->lb = svga->vram[latch_addr | 0x1];
+                svga->lc = svga->vram[latch_addr | 0x2];
+                svga->ld = svga->vram[latch_addr | 0x3];
+        }
+
+        if (addr >= svga->vram_max)
+                return 0xff;
+                
+        addr &= svga->vram_mask;
+
+        if (svga->readmode)
+        {
+                temp   = svga->la;
+                temp  ^= (svga->colourcompare & 1) ? 0xff : 0;
+                temp  &= (svga->colournocare & 1)  ? 0xff : 0;
+                temp2  = svga->lb;
+                temp2 ^= (svga->colourcompare & 2) ? 0xff : 0;
+                temp2 &= (svga->colournocare & 2)  ? 0xff : 0;
+                temp3  = svga->lc;
+                temp3 ^= (svga->colourcompare & 4) ? 0xff : 0;
+                temp3 &= (svga->colournocare & 4)  ? 0xff : 0;
+                temp4  = svga->ld;
+                temp4 ^= (svga->colourcompare & 8) ? 0xff : 0;
+                temp4 &= (svga->colournocare & 8)  ? 0xff : 0;
+                return ~(temp | temp2 | temp3 | temp4);
+        }
+//printf("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane);
+        return svga->vram[addr | readplane];
+}
+
+void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga)
+{
+//        pclog("svga_doblit start\n");
+        svga->frames++;
+//        pclog("doblit %i %i\n", y1, y2);
+//        pclog("svga_doblit %i %i\n", wx, svga->hdisp);
+        if (y1 > y2) 
+        {
+                video_blit_memtoscreen(32, 0, 0, 0, xsize, ysize);
+                return;   
+        }     
+
+        if ((wx!=xsize || wy!=ysize) && !vid_resize)
+        {
+                xsize=wx;
+                ysize=wy+1;
+                if (xsize<64) xsize=656;
+                if (ysize<32) ysize=200;
+
+                if (svga->vertical_linedbl)
+                        updatewindowsize(xsize,ysize*2);
+                else
+                        updatewindowsize(xsize,ysize);
+        }
+        if (vid_resize)
+        {
+                xsize = wx;
+                ysize = wy + 1;
+        }
+        video_blit_memtoscreen(32, 0, y1, y2, xsize, ysize);
+//        pclog("svga_doblit end\n");
+}
+
+void svga_writew(uint32_t addr, uint16_t val, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        if (!svga->fast)
+        {
+                svga_write(addr, val, p);
+                svga_write(addr + 1, val >> 8, p);
+                return;
+        }
+        
+        egawrites += 2;
+
+        cycles -= video_timing_write_w;
+        cycles_lost += video_timing_write_w;
+
+        if (svga_output) pclog("svga_writew: %05X ", addr);
+        addr = (addr & svga->banked_mask) + svga->write_bank;
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return;
+        addr &= svga->vram_mask;
+        if (svga_output) pclog("%08X (%i, %i) %04X\n", addr, addr & 1023, addr >> 10, val);
+        svga->changedvram[addr >> 12] = changeframecount;
+        *(uint16_t *)&svga->vram[addr] = val;
+}
+
+void svga_writel(uint32_t addr, uint32_t val, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        
+        if (!svga->fast)
+        {
+                svga_write(addr, val, p);
+                svga_write(addr + 1, val >> 8, p);
+                svga_write(addr + 2, val >> 16, p);
+                svga_write(addr + 3, val >> 24, p);
+                return;
+        }
+        
+        egawrites += 4;
+
+        cycles -= video_timing_write_l;
+        cycles_lost += video_timing_write_l;
+
+        if (svga_output) pclog("svga_writel: %05X ", addr);
+        addr = (addr & svga->banked_mask) + svga->write_bank;
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return;
+        addr &= svga->vram_mask;
+        if (svga_output) pclog("%08X (%i, %i) %08X\n", addr, addr & 1023, addr >> 10, val);
+        
+        svga->changedvram[addr >> 12] = changeframecount;
+        *(uint32_t *)&svga->vram[addr] = val;
+}
+
+uint16_t svga_readw(uint32_t addr, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        
+        if (!svga->fast)
+           return svga_read(addr, p) | (svga_read(addr + 1, p) << 8);
+        
+        egareads += 2;
+
+        cycles -= video_timing_read_w;
+        cycles_lost += video_timing_read_w;
+
+//        pclog("Readw %05X ", addr);
+        addr = (addr & svga->banked_mask) + svga->read_bank;
+        addr &= svga->decode_mask;
+//        pclog("%08X %04X\n", addr, *(uint16_t *)&vram[addr]);
+        if (addr >= svga->vram_max)
+                return 0xffff;
+        
+        return *(uint16_t *)&svga->vram[addr & svga->vram_mask];
+}
+
+uint32_t svga_readl(uint32_t addr, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        
+        if (!svga->fast)
+           return svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24);
+        
+        egareads += 4;
+
+        cycles -= video_timing_read_l;
+        cycles_lost += video_timing_read_l;
+
+//        pclog("Readl %05X ", addr);
+        addr = (addr & svga->banked_mask) + svga->read_bank;
+        addr &= svga->decode_mask;
+//        pclog("%08X %08X\n", addr, *(uint32_t *)&vram[addr]);
+        if (addr >= svga->vram_max)
+                return 0xffffffff;
+        
+        return *(uint32_t *)&svga->vram[addr & svga->vram_mask];
+}
+
+void svga_writew_linear(uint32_t addr, uint16_t val, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        
+        if (!svga->fast)
+        {
+                svga_write_linear(addr, val, p);
+                svga_write_linear(addr + 1, val >> 8, p);
+                return;
+        }
+        
+        egawrites += 2;
+
+        cycles -= video_timing_write_w;
+        cycles_lost += video_timing_write_w;
+
+       if (svga_output) pclog("Write LFBw %08X %04X\n", addr, val);
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return;
+        addr &= svga->vram_mask;
+        svga->changedvram[addr >> 12] = changeframecount;
+        *(uint16_t *)&svga->vram[addr] = val;
+}
+
+void svga_writel_linear(uint32_t addr, uint32_t val, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        
+        if (!svga->fast)
+        {
+                svga_write_linear(addr, val, p);
+                svga_write_linear(addr + 1, val >> 8, p);
+                svga_write_linear(addr + 2, val >> 16, p);
+                svga_write_linear(addr + 3, val >> 24, p);
+                return;
+        }
+        
+        egawrites += 4;
+
+        cycles -= video_timing_write_l;
+        cycles_lost += video_timing_write_l;
+
+       if (svga_output) pclog("Write LFBl %08X %08X\n", addr, val);
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return;
+        addr &= svga->vram_mask;
+        svga->changedvram[addr >> 12] = changeframecount;
+        *(uint32_t *)&svga->vram[addr] = val;
+}
+
+uint16_t svga_readw_linear(uint32_t addr, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        
+        if (!svga->fast)
+           return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8);
+        
+        egareads += 2;
+
+        cycles -= video_timing_read_w;
+        cycles_lost += video_timing_read_w;
+
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return 0xffff;
+        
+        return *(uint16_t *)&svga->vram[addr & svga->vram_mask];
+}
+
+uint32_t svga_readl_linear(uint32_t addr, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        
+        if (!svga->fast)
+           return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8) | (svga_read_linear(addr + 2, p) << 16) | (svga_read_linear(addr + 3, p) << 24);
+        
+        egareads += 4;
+
+        cycles -= video_timing_read_l;
+        cycles_lost += video_timing_read_l;
+
+        addr &= svga->decode_mask;
+        if (addr >= svga->vram_max)
+                return 0xffffffff;
+
+        return *(uint32_t *)&svga->vram[addr & svga->vram_mask];
+}
+
+
+void svga_add_status_info(char *s, int max_len, void *p)
+{
+        svga_t *svga = (svga_t *)p;
+        char temps[128];
+        
+        if (svga->chain4) strcpy(temps, "SVGA chained (possibly mode 13h)\n");
+        else              strcpy(temps, "SVGA unchained (possibly mode-X)\n");
+        strncat(s, temps, max_len);
+
+        if (!svga->video_bpp) strcpy(temps, "SVGA in text mode\n");
+        else                  sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp);
+        strncat(s, temps, max_len);
+        
+        sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y);
+        strncat(s, temps, max_len);
+        
+        sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames);
+        svga->frames = 0;
+        strncat(s, temps, max_len);
+}
diff --git a/pcem/vid_svga.h b/pcem/vid_svga.h
new file mode 100644 (file)
index 0000000..219eb6b
--- /dev/null
@@ -0,0 +1,185 @@
+typedef struct svga_t
+{
+        mem_mapping_t mapping;
+        
+        uint8_t crtcreg;
+        uint8_t crtc[128];
+        uint8_t gdcreg[64];
+        int gdcaddr;
+        uint8_t attrregs[32];
+        int attraddr, attrff;
+        int attr_palette_enable;
+        uint8_t seqregs[64];
+        int seqaddr;
+        
+        uint8_t miscout;
+        int vidclock;
+
+        /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 :
+          0MB-1MB - VRAM
+          1MB-2MB - VRAM mirror
+          2MB-4MB - open bus
+          4MB-xMB - mirror of above
+          
+          For the example memory map, decode_mask would be 4MB-1 (4MB address space), vram_max would be 2MB
+          (present video memory only responds to first 2MB), vram_mask would be 1MB-1 (video memory wraps at 1MB)
+        */
+        uint32_t decode_mask;
+        uint32_t vram_max;
+        uint32_t vram_mask;
+        
+        uint8_t la, lb, lc, ld;
+        
+        uint8_t dac_mask, dac_status;
+        int dac_read, dac_write, dac_pos;
+        int dac_r, dac_g;
+                
+        uint8_t cgastat;
+        
+        uint8_t plane_mask;
+        
+        int fb_only;
+        
+        int fast;
+        uint8_t colourcompare, colournocare;
+        int readmode, writemode, readplane;
+        int chain4, chain2_write, chain2_read;
+        uint8_t writemask;
+        uint32_t charseta, charsetb;
+
+        int set_reset_disabled;
+        
+        uint8_t egapal[16];
+        uint32_t pallook[256];
+        PALETTE vgapal;
+        
+        int ramdac_type;
+
+        int vtotal, dispend, vsyncstart, split, vblankstart;
+        int hdisp,  hdisp_old, htotal,  hdisp_time, rowoffset;
+        int lowres, interlace;
+        int linedbl, rowcount;
+        double clock;
+        uint32_t ma_latch;
+        int bpp;
+        
+        uint64_t dispontime, dispofftime;
+        pc_timer_t timer;
+        
+        uint8_t scrblank;
+        
+        int dispon;
+        int hdisp_on;
+
+        uint32_t ma, maback, ca;
+        int vc;
+        int sc;
+        int linepos, vslines, linecountff, oddeven;
+        int con, cursoron, blink;
+        int scrollcache;
+        int char_width;
+        
+        int firstline, lastline;
+        int firstline_draw, lastline_draw;
+        int displine;
+        
+        uint8_t *vram;
+        uint8_t *changedvram;
+        uint32_t vram_display_mask;
+        uint32_t banked_mask;
+
+        uint32_t write_bank, read_bank;
+                
+        int fullchange;
+        
+        int video_res_x, video_res_y, video_bpp;
+        int frames, fps;
+
+        struct
+        {
+                int ena;
+                int x, y;
+                int xoff, yoff;
+                int xsize, ysize;
+                uint32_t addr;
+                uint32_t pitch;
+                int v_acc, h_acc;
+        } hwcursor, hwcursor_latch, overlay, overlay_latch;
+        
+        int hwcursor_on;
+        int overlay_on;
+        
+        int hwcursor_oddeven;
+        int overlay_oddeven;
+        
+        void (*render)(struct svga_t *svga);
+        void (*recalctimings_ex)(struct svga_t *svga);
+
+        void    (*video_out)(uint16_t addr, uint8_t val, void *p);
+        uint8_t (*video_in) (uint16_t addr, void *p);
+
+        void (*hwcursor_draw)(struct svga_t *svga, int displine);
+
+        void (*overlay_draw)(struct svga_t *svga, int displine);
+        
+        void (*vblank_start)(struct svga_t *svga);
+        
+        /*Called when VC=R18 and friends. If this returns zero then MA resetting
+          is skipped. Matrox Mystique in Power mode reuses this counter for
+          vertical line interrupt*/
+        int (*line_compare)(struct svga_t *svga);
+        
+        /*Called at the start of vertical sync*/
+        void (*vsync_callback)(struct svga_t *svga);
+        
+        /*If set then another device is driving the monitor output and the SVGA
+          card should not attempt to display anything */
+        int override;
+        void *p;
+
+        uint8_t ksc5601_sbyte_mask;
+        
+        int vertical_linedbl;
+        
+        /*Used to implement CRTC[0x17] bit 2 hsync divisor*/
+        int hsync_divisor;
+} svga_t;
+
+extern int svga_init(svga_t *svga, void *p, int memsize, 
+               void (*recalctimings_ex)(struct svga_t *svga),
+               uint8_t (*video_in) (uint16_t addr, void *p),
+               void    (*video_out)(uint16_t addr, uint8_t val, void *p),
+               void (*hwcursor_draw)(struct svga_t *svga, int displine),
+               void (*overlay_draw)(struct svga_t *svga, int displine));
+void svga_close(svga_t *svga);
+extern void svga_recalctimings(svga_t *svga);
+
+
+uint8_t  svga_read(uint32_t addr, void *p);
+uint16_t svga_readw(uint32_t addr, void *p);
+uint32_t svga_readl(uint32_t addr, void *p);
+void     svga_write(uint32_t addr, uint8_t val, void *p);
+void     svga_writew(uint32_t addr, uint16_t val, void *p);
+void     svga_writel(uint32_t addr, uint32_t val, void *p);
+uint8_t  svga_read_linear(uint32_t addr, void *p);
+uint16_t svga_readw_linear(uint32_t addr, void *p);
+uint32_t svga_readl_linear(uint32_t addr, void *p);
+void     svga_write_linear(uint32_t addr, uint8_t val, void *p);
+void     svga_writew_linear(uint32_t addr, uint16_t val, void *p);
+void     svga_writel_linear(uint32_t addr, uint32_t val, void *p);
+
+void svga_add_status_info(char *s, int max_len, void *p);
+
+extern uint8_t svga_rotate[8][256];
+
+void svga_out(uint16_t addr, uint8_t val, void *p);
+uint8_t svga_in(uint16_t addr, void *p);
+
+svga_t *svga_get_pri();
+void svga_set_override(svga_t *svga, int val);
+
+#define RAMDAC_6BIT 0
+#define RAMDAC_8BIT 1
+void svga_set_ramdac_type(svga_t *svga, int type);
+
+void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga);
diff --git a/pcem/vid_svga_render.cpp b/pcem/vid_svga_render.cpp
new file mode 100644 (file)
index 0000000..505f362
--- /dev/null
@@ -0,0 +1,782 @@
+#include "ibm.h"
+#include "mem.h"
+#include "video.h"
+#include "vid_svga.h"
+#include "vid_svga_render.h"
+
+void svga_render_blank(svga_t *svga)
+{
+        int x, xx;
+        
+        if (svga->firstline_draw == 2000) 
+                svga->firstline_draw = svga->displine;
+        svga->lastline_draw = svga->displine;
+        
+        for (x = 0; x < svga->hdisp; x++)
+        {
+                switch (svga->seqregs[1] & 9)
+                {
+                        case 0:
+                        for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine])[(x * 9) + xx + 32] = 0;
+                        break;
+                        case 1:
+                        for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine])[(x * 8) + xx + 32] = 0;
+                        break;
+                        case 8:
+                        for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine])[(x * 18) + xx + 32] = 0;
+                        break;
+                        case 9:
+                        for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine])[(x * 16) + xx + 32] = 0;
+                        break;
+                }
+        }
+}
+
+void svga_render_text_40(svga_t *svga)
+{     
+        if (svga->firstline_draw == 2000) 
+                svga->firstline_draw = svga->displine;
+        svga->lastline_draw = svga->displine;
+        
+        if (svga->fullchange)
+        {
+                int offset = ((8 - svga->scrollcache) << 1) + 16;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                int x, xx;
+                int drawcursor;
+                uint8_t chr, attr, dat;
+                uint32_t charaddr;
+                int fg, bg;
+                int xinc = (svga->seqregs[1] & 1) ? 16 : 18;
+                
+                for (x = 0; x < svga->hdisp; x += xinc)
+                {
+                        drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron);
+                        chr  = svga->vram[(svga->ma << 1) & svga->vram_display_mask];
+                        attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask];
+                        if (attr & 8) charaddr = svga->charsetb + (chr * 128);
+                        else          charaddr = svga->charseta + (chr * 128);
+
+                        if (drawcursor) 
+                        { 
+                                bg = svga->pallook[svga->egapal[attr & 15]]; 
+                                fg = svga->pallook[svga->egapal[attr >> 4]]; 
+                        }
+                        else
+                        {
+                                fg = svga->pallook[svga->egapal[attr & 15]];
+                                bg = svga->pallook[svga->egapal[attr >> 4]];
+                                if (attr & 0x80 && svga->attrregs[0x10] & 8)
+                                {
+                                        bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
+                                        if (svga->blink & 16) 
+                                                fg = bg;
+                                }
+                        }
+
+                        dat = svga->vram[charaddr + (svga->sc << 2)];
+                        if (svga->seqregs[1] & 1) 
+                        { 
+                                for (xx = 0; xx < 16; xx += 2) 
+                                        p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg;
+                        }
+                        else
+                        {
+                                for (xx = 0; xx < 16; xx += 2)
+                                        p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg;
+                                if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) 
+                                        p[16] = p[17] = bg;
+                                else                  
+                                        p[16] = p[17] = (dat & 1) ? fg : bg;
+                        }
+                        svga->ma += 4; 
+                        p += xinc;
+                }
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_text_80(svga_t *svga)
+{
+        if (svga->firstline_draw == 2000) 
+                svga->firstline_draw = svga->displine;
+        svga->lastline_draw = svga->displine;
+        
+        if (svga->fullchange)
+        {
+                int offset = (8 - svga->scrollcache) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                int x, xx;
+                int drawcursor;
+                uint8_t chr, attr, dat;
+                uint32_t charaddr;
+                int fg, bg;
+                int xinc = (svga->seqregs[1] & 1) ? 8 : 9;
+
+                for (x = 0; x < svga->hdisp; x += xinc)
+                {
+                        drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron);
+                        chr  = svga->vram[(svga->ma << 1) & svga->vram_display_mask];
+                        attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask];
+                        if (attr & 8) charaddr = svga->charsetb + (chr * 128);
+                        else          charaddr = svga->charseta + (chr * 128);
+
+                        if (drawcursor) 
+                        { 
+                                bg = svga->pallook[svga->egapal[attr & 15]]; 
+                                fg = svga->pallook[svga->egapal[attr >> 4]]; 
+                        }
+                        else
+                        {
+                                fg = svga->pallook[svga->egapal[attr & 15]];
+                                bg = svga->pallook[svga->egapal[attr >> 4]];
+                                if (attr & 0x80 && svga->attrregs[0x10] & 8)
+                                {
+                                        bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
+                                        if (svga->blink & 16) 
+                                                fg = bg;
+                                }
+                        }
+
+                        dat = svga->vram[charaddr + (svga->sc << 2)];
+                        if (svga->seqregs[1] & 1) 
+                        { 
+                                for (xx = 0; xx < 8; xx++) 
+                                        p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
+                        }
+                        else
+                        {
+                                for (xx = 0; xx < 8; xx++) 
+                                        p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
+                                if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) 
+                                        p[8] = bg;
+                                else                  
+                                        p[8] = (dat & 1) ? fg : bg;
+                        }
+                        svga->ma += 4; 
+                        p += xinc;
+                }
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_text_80_ksc5601(svga_t *svga)
+{
+        if (svga->firstline_draw == 2000) 
+                svga->firstline_draw = svga->displine;
+        svga->lastline_draw = svga->displine;
+        
+        if (svga->fullchange)
+        {
+                int offset = (8 - svga->scrollcache) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                int x, xx;
+                int drawcursor;
+                uint8_t chr, attr, dat, nextchr;
+                uint32_t charaddr;
+                int fg, bg;
+                int xinc = (svga->seqregs[1] & 1) ? 8 : 9;
+
+                for (x = 0; x < svga->hdisp; x += xinc)
+                {
+                        drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron);
+                        chr  = svga->vram[(svga->ma << 1) & svga->vram_display_mask];
+                        nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask];
+                        attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask];
+
+                        if (drawcursor) 
+                        { 
+                                bg = svga->pallook[svga->egapal[attr & 15]]; 
+                                fg = svga->pallook[svga->egapal[attr >> 4]]; 
+                        }
+                        else
+                        {
+                                fg = svga->pallook[svga->egapal[attr & 15]];
+                                bg = svga->pallook[svga->egapal[attr >> 4]];
+                                if (attr & 0x80 && svga->attrregs[0x10] & 8)
+                                {
+                                        bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
+                                        if (svga->blink & 16) 
+                                                fg = bg;
+                                }
+                        }
+
+                        if(x + xinc < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80))
+                        {
+                                if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff))
+                                        dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20][svga->sc];
+                                else if(nextchr & 0x80)
+                                        dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc];
+                                else
+                                        dat = 0xFF;
+                        }
+                        else
+                        {
+                                if (attr & 8) charaddr = svga->charsetb + (chr * 128);
+                                else          charaddr = svga->charseta + (chr * 128);
+
+                                dat = svga->vram[charaddr + (svga->sc << 2)];
+                        }
+                        if (svga->seqregs[1] & 1) 
+                        { 
+                                for (xx = 0; xx < 8; xx++) 
+                                        p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
+                        }
+                        else
+                        {
+                                for (xx = 0; xx < 8; xx++) 
+                                        p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
+                                if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) 
+                                        p[8] = bg;
+                                else                  
+                                        p[8] = (dat & 1) ? fg : bg;
+                        }
+                        svga->ma += 4; 
+                        p += xinc;
+
+                        if(x + xinc < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80))
+                        {
+                                attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask];
+
+                                if (drawcursor) 
+                                { 
+                                        bg = svga->pallook[svga->egapal[attr & 15]]; 
+                                        fg = svga->pallook[svga->egapal[attr >> 4]]; 
+                                }
+                                else
+                                {
+                                        fg = svga->pallook[svga->egapal[attr & 15]];
+                                        bg = svga->pallook[svga->egapal[attr >> 4]];
+                                        if (attr & 0x80 && svga->attrregs[0x10] & 8)
+                                        {
+                                                bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
+                                                if (svga->blink & 16) 
+                                                        fg = bg;
+                                        }
+                                }
+
+                                if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff))
+                                        dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20][svga->sc + 16];
+                                else if(nextchr & 0x80)
+                                        dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc + 16];
+                                else
+                                        dat = 0xFF;
+                                if (svga->seqregs[1] & 1) 
+                                { 
+                                        for (xx = 0; xx < 8; xx++) 
+                                                p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
+                                }
+                                else
+                                {
+                                        for (xx = 0; xx < 8; xx++) 
+                                                p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
+                                        if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) 
+                                                p[8] = bg;
+                                        else                  
+                                                p[8] = (dat & 1) ? fg : bg;
+                                }
+
+                                svga->ma += 4; 
+                                p += xinc;
+                                x += xinc;
+                        }
+                }
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_2bpp_lowres(svga_t *svga)
+{
+        int changed_offset;
+        
+        changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12;
+                
+        if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = ((8 - svga->scrollcache) << 1) + 16;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+                       
+                for (x = 0; x <= svga->hdisp; x += 16)
+                {
+                        uint8_t dat[2];
+                        
+                        dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000];
+                        dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1];
+                        svga->ma += 4; 
+                        svga->ma &= svga->vram_display_mask;
+
+                        p[0]  = p[1]  = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]];
+                        p[2]  = p[3]  = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]];
+                        p[4]  = p[5]  = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]];
+                        p[6]  = p[7]  = svga->pallook[svga->egapal[dat[0] & 3]];
+                        p[8]  = p[9]  = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]];
+                        p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]];
+                        p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]];
+                        p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]];
+
+                        p += 16;
+                }
+        }
+}
+
+void svga_render_2bpp_highres(svga_t *svga)
+{
+        int changed_offset;
+        
+        changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12;
+                                
+        if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - svga->scrollcache) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+                       
+                for (x = 0; x <= svga->hdisp; x += 8)
+                {
+                        uint8_t dat[2];
+                        
+                        dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000];
+                        dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1];
+                        svga->ma += 4; 
+                        svga->ma &= svga->vram_display_mask;
+
+                        p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]];
+                        p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]];
+                        p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]];
+                        p[3] = svga->pallook[svga->egapal[dat[0] & 3]];
+                        p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]];
+                        p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]];
+                        p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]];
+                        p[7] = svga->pallook[svga->egapal[dat[1] & 3]];
+                        
+                        p += 8;
+                }
+        }
+}
+
+void svga_render_4bpp_lowres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = ((8 - svga->scrollcache) << 1) + 16;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                for (x = 0; x <= svga->hdisp; x += 16)
+                {
+                        uint8_t edat[4];
+                        uint8_t dat;
+
+                        *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]);                        
+                        svga->ma += 4; 
+                        svga->ma &= svga->vram_display_mask;
+
+                        dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2);
+                        p[0]  = p[1]  = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[2]  = p[3]  = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                        dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2);
+                        p[4]  = p[5]  = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[6]  = p[7]  = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                        dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2);
+                        p[8]  = p[9]  = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                        dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2);
+                        p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                                                
+                        p += 16;
+                }
+        }
+}
+
+void svga_render_4bpp_highres(svga_t *svga)
+{
+        int changed_offset;
+        
+        changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12;
+                
+        if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - svga->scrollcache) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+        
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+                
+                for (x = 0; x <= svga->hdisp; x += 8)
+                {
+                        uint8_t edat[4];
+                        uint8_t dat;
+
+                        *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma | ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]);
+                        svga->ma += 4;
+                        svga->ma &= svga->vram_display_mask;
+
+                        dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2);
+                        p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                        dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2);
+                        p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                        dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2);
+                        p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                        dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2);
+                        p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]];
+                        p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]];
+                        
+                        p += 8;
+                }
+        }
+}
+
+void svga_render_8bpp_lowres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - (svga->scrollcache & 6)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+                                                                
+                for (x = 0; x <= svga->hdisp; x += 8)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]);
+                        
+                        p[0] = p[1] = svga->pallook[dat & 0xff];
+                        p[2] = p[3] = svga->pallook[(dat >> 8) & 0xff];
+                        p[4] = p[5] = svga->pallook[(dat >> 16) & 0xff];
+                        p[6] = p[7] = svga->pallook[(dat >> 24) & 0xff];
+                        
+                        svga->ma += 4;
+                        p += 8;
+                }
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_8bpp_highres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+                                                                
+                for (x = 0; x <= svga->hdisp; x += 8)
+                {
+                        uint32_t dat;
+                        dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]);
+                        p[0] = svga->pallook[dat & 0xff];
+                        p[1] = svga->pallook[(dat >> 8) & 0xff];
+                        p[2] = svga->pallook[(dat >> 16) & 0xff];
+                        p[3] = svga->pallook[(dat >> 24) & 0xff];
+
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]);
+                        p[4] = svga->pallook[dat & 0xff];
+                        p[5] = svga->pallook[(dat >> 8) & 0xff];
+                        p[6] = svga->pallook[(dat >> 16) & 0xff];
+                        p[7] = svga->pallook[(dat >> 24) & 0xff];
+                        
+                        svga->ma += 8;
+                        p += 8;
+                }
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_15bpp_lowres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - (svga->scrollcache & 6)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+               
+                for (x = 0; x <= svga->hdisp; x += 4)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]);
+
+                        p[x]     = video_15to32[dat & 0xffff];
+                        p[x + 1] = video_15to32[dat >> 16];
+
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]);
+
+                        p[x]     = video_15to32[dat & 0xffff];
+                        p[x + 1] = video_15to32[dat >> 16];
+                }
+                svga->ma += x << 1; 
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_15bpp_highres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                for (x = 0; x <= svga->hdisp; x += 8)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]);
+                        p[x]     = video_15to32[dat & 0xffff];
+                        p[x + 1] = video_15to32[dat >> 16];
+                        
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]);
+                        p[x + 2] = video_15to32[dat & 0xffff];
+                        p[x + 3] = video_15to32[dat >> 16];
+
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]);
+                        p[x + 4] = video_15to32[dat & 0xffff];
+                        p[x + 5] = video_15to32[dat >> 16];
+
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]);
+                        p[x + 6] = video_15to32[dat & 0xffff];
+                        p[x + 7] = video_15to32[dat >> 16];
+                }
+                svga->ma += x << 1; 
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_16bpp_lowres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - (svga->scrollcache & 6)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+               
+                for (x = 0; x <= svga->hdisp; x += 4)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]);
+
+                        p[x]     = video_16to32[dat & 0xffff];
+                        p[x + 1] = video_16to32[dat >> 16];
+
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]);
+
+                        p[x]     = video_16to32[dat & 0xffff];
+                        p[x + 1] = video_16to32[dat >> 16];
+                }
+                svga->ma += x << 1; 
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_16bpp_highres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                for (x = 0; x <= svga->hdisp; x += 8)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]);
+                        p[x]     = video_16to32[dat & 0xffff];
+                        p[x + 1] = video_16to32[dat >> 16];
+                        
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]);
+                        p[x + 2] = video_16to32[dat & 0xffff];
+                        p[x + 3] = video_16to32[dat >> 16];
+
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]);
+                        p[x + 4] = video_16to32[dat & 0xffff];
+                        p[x + 5] = video_16to32[dat >> 16];
+
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]);
+                        p[x + 6] = video_16to32[dat & 0xffff];
+                        p[x + 7] = video_16to32[dat >> 16];
+                }
+                svga->ma += x << 1; 
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_24bpp_lowres(svga_t *svga)
+{
+        int x, offset;
+        uint32_t fg;
+        
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                offset = (8 - (svga->scrollcache & 6)) + 24;
+
+                for (x = 0; x <= svga->hdisp; x++)
+                {
+                        fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16);
+                        svga->ma += 3; 
+                        svga->ma &= svga->vram_display_mask;
+                        ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + offset] = ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + 1 + offset] = fg;
+                }
+        }
+}
+
+void svga_render_24bpp_highres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                for (x = 0; x <= svga->hdisp; x += 4)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]);
+                        p[x] = dat & 0xffffff;
+                        
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]);
+                        p[x + 1] = dat & 0xffffff;
+                        
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]);
+                        p[x + 2] = dat & 0xffffff;
+                        
+                        dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]);
+                        p[x + 3] = dat & 0xffffff;
+                        
+                        svga->ma += 12;
+                }
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_32bpp_lowres(svga_t *svga)
+{
+        int x, offset;
+        uint32_t fg;
+        
+        if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange)
+        {
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                offset = (8 - (svga->scrollcache & 6)) + 24;
+
+                for (x = 0; x <= svga->hdisp; x++)
+                {
+                        fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16);
+                        svga->ma += 4; 
+                        svga->ma &= svga->vram_display_mask;
+                        ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + offset] = ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + 1 + offset] = fg;
+                }
+        }
+}
+
+/*72%
+  91%*/
+void svga_render_32bpp_highres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] ||  svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                for (x = 0; x <= svga->hdisp; x++)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]);
+                        p[x] = dat & 0xffffff;
+                }
+                svga->ma += 4; 
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_ABGR8888_highres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] ||  svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                for (x = 0; x <= svga->hdisp; x++)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]);
+                        p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16);
+                }
+                svga->ma += 4; 
+                svga->ma &= svga->vram_display_mask;
+        }
+}
+
+void svga_render_RGBA8888_highres(svga_t *svga)
+{
+        if (svga->changedvram[svga->ma >> 12] ||  svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange)
+        {
+                int x;
+                int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24;
+                uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
+                
+                if (svga->firstline_draw == 2000) 
+                        svga->firstline_draw = svga->displine;
+                svga->lastline_draw = svga->displine;
+
+                for (x = 0; x <= svga->hdisp; x++)
+                {
+                        uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]);
+                        p[x] = dat >> 8;
+                }
+                svga->ma += 4; 
+                svga->ma &= svga->vram_display_mask;
+        }
+}
diff --git a/pcem/vid_svga_render.h b/pcem/vid_svga_render.h
new file mode 100644 (file)
index 0000000..be8105f
--- /dev/null
@@ -0,0 +1,34 @@
+extern int firstline_draw, lastline_draw;
+extern int displine;
+extern int sc;
+
+extern uint32_t ma, ca;
+extern int con, cursoron, cgablink;
+
+extern int scrollcache;
+
+extern uint8_t edatlookup[4][4];
+
+void svga_render_blank(svga_t *svga);
+void svga_render_text_40(svga_t *svga);
+void svga_render_text_80(svga_t *svga);
+void svga_render_text_80_ksc5601(svga_t *svga);
+
+void svga_render_2bpp_lowres(svga_t *svga);
+void svga_render_2bpp_highres(svga_t *svga);
+void svga_render_4bpp_lowres(svga_t *svga);
+void svga_render_4bpp_highres(svga_t *svga);
+void svga_render_8bpp_lowres(svga_t *svga);
+void svga_render_8bpp_highres(svga_t *svga);
+void svga_render_15bpp_lowres(svga_t *svga);
+void svga_render_15bpp_highres(svga_t *svga);
+void svga_render_16bpp_lowres(svga_t *svga);
+void svga_render_16bpp_highres(svga_t *svga);
+void svga_render_24bpp_lowres(svga_t *svga);
+void svga_render_24bpp_highres(svga_t *svga);
+void svga_render_32bpp_lowres(svga_t *svga);
+void svga_render_32bpp_highres(svga_t *svga);
+void svga_render_ABGR8888_highres(svga_t *svga);
+void svga_render_RGBA8888_highres(svga_t *svga);
+
+extern void (*svga_render)(svga_t *svga);
diff --git a/pcem/vid_unk_ramdac.h b/pcem/vid_unk_ramdac.h
new file mode 100644 (file)
index 0000000..0f92848
--- /dev/null
@@ -0,0 +1,8 @@
+typedef struct unk_ramdac_t
+{
+        int state;
+        uint8_t ctrl;
+} unk_ramdac_t;
+
+void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *svga);
+uint8_t unk_ramdac_in(uint16_t addr, unk_ramdac_t *ramdac, svga_t *svga);
diff --git a/pcem/vid_vga.h b/pcem/vid_vga.h
new file mode 100644 (file)
index 0000000..329195b
--- /dev/null
@@ -0,0 +1,8 @@
+extern device_t vga_device;
+extern device_t ps1vga_device;
+
+void vga_disable(void *p);
+void vga_enable(void *p);
+
+struct svga_t;
+extern struct svga_t *mb_vga;
index 939b19d68762741841e429e8a8f6b3536521d296..3fc28622e627562d244197b38aabad9b8f296957 100644 (file)
@@ -23,8 +23,8 @@ extern BITMAP *buffer32;
 
 int video_card_available(int card);
 char *video_card_getname(int card);
-struct device_t *video_card_getdevice(int card);
-int video_card_has_config(int card);
+struct device_t *video_card_getdevice(int card, int romset);
+int video_card_has_config(int card, int romset);
 int video_card_getid(char *s);
 int video_old_to_new(int card);
 int video_new_to_old(int card);
@@ -82,7 +82,21 @@ extern int vid_resize;
 
 void video_wait_for_blit();
 void video_wait_for_buffer();
-void loadfont(char *s, int format);
+
+typedef enum
+{
+       FONT_MDA,       /* MDA 8x14 */
+       FONT_PC200,     /* MDA 8x14 and CGA 8x8, four fonts */
+       FONT_CGA,       /* CGA 8x8, two fonts */
+       FONT_WY700,     /* Wy700 16x16, two fonts */
+       FONT_MDSI,      /* MDSI Genius 8x12 */
+       FONT_T3100E,    /* Toshiba T3100e, four fonts */
+       FONT_KSC5601,   /* Korean KSC-5601 */
+       FONT_SIGMA400,  /* Sigma Color 400, 8x8 and 8x16 */
+       FONT_IM1024,    /* Image Manager 1024 */
+} fontformat_t;
+
+void loadfont(char *s, fontformat_t format);
 
 void initvideo();
 void video_init();
index a55adc1f58f76acbb6ee0f3cb5c9d63cc96ad97f..7bcd75b93fe4f62e3239e10d2ce1b941c15b1dd2 100644 (file)
-extern uint16_t oldcs;
-extern uint32_t rmdat32;
+#ifndef _X86_H_
+#define _X86_H_
+
+#define EAX cpu_state.regs[0].l
+#define ECX cpu_state.regs[1].l
+#define EDX cpu_state.regs[2].l
+#define EBX cpu_state.regs[3].l
+#define ESP cpu_state.regs[4].l
+#define EBP cpu_state.regs[5].l
+#define ESI cpu_state.regs[6].l
+#define EDI cpu_state.regs[7].l
+#define AX cpu_state.regs[0].w
+#define CX cpu_state.regs[1].w
+#define DX cpu_state.regs[2].w
+#define BX cpu_state.regs[3].w
+#define SP cpu_state.regs[4].w
+#define BP cpu_state.regs[5].w
+#define SI cpu_state.regs[6].w
+#define DI cpu_state.regs[7].w
+#define AL cpu_state.regs[0].b.l
+#define AH cpu_state.regs[0].b.h
+#define CL cpu_state.regs[1].b.l
+#define CH cpu_state.regs[1].b.h
+#define DL cpu_state.regs[2].b.l
+#define DH cpu_state.regs[2].b.h
+#define BL cpu_state.regs[3].b.l
+#define BH cpu_state.regs[3].b.h
+
+typedef union
+{
+        uint32_t l;
+        uint16_t w;
+        struct
+        {
+                uint8_t l,h;
+        } b;
+} x86reg;
+
+typedef struct
+{
+        uint32_t base;
+        uint32_t limit;
+        uint8_t access;
+        uint16_t seg;
+        uint32_t limit_low, limit_high;
+        int checked; /*Non-zero if selector is known to be valid*/
+} x86seg;
+
+typedef union MMX_REG
+{
+        uint64_t q;
+        int64_t  sq;
+        uint32_t l[2];
+        int32_t  sl[2];
+        uint16_t w[4];
+        int16_t  sw[4];
+        uint8_t  b[8];
+        int8_t   sb[8];
+        float    f[2];
+} MMX_REG;
+
+struct
+{
+        x86reg regs[8];
+
+        uint8_t tag[8];
+
+        x86seg *ea_seg;
+        uint32_t eaaddr;
+
+        int flags_op;
+        uint32_t flags_res;
+        uint32_t flags_op1, flags_op2;
+
+        uint32_t pc;
+        uint32_t oldpc;
+        uint32_t op32;
+
+        int TOP;
+
+        union
+        {
+                struct
+                {
+                        int8_t rm, mod, reg;
+                } rm_mod_reg;
+                uint32_t rm_mod_reg_data;
+        } rm_data;
+
+        int8_t ssegs;
+        int8_t ismmx;
+        int8_t abrt;
+
+        int _cycles;
+        int cpu_recomp_ins;
+
+        uint16_t npxs, npxc;
+
+        double ST[8];
+
+        uint16_t MM_w4[8];
+
+        MMX_REG MM[8];
+
+        uint32_t old_fp_control, new_fp_control;
+#if defined i386 || defined __i386 || defined __i386__ || defined _X86_
+        uint16_t old_fp_control2, new_fp_control2;
+#endif
+#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined __amd64__
+        uint32_t trunc_fp_control;
+#endif
+        x86seg seg_cs,seg_ds,seg_es,seg_ss,seg_fs,seg_gs;
+
+        union
+        {
+                uint32_t l;
+                uint16_t w;
+        } CR0;
+
+        uint16_t flags, eflags;
+} cpu_state;
+
+#define cpu_state_offset(MEMBER) ((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128)
+
+#define cycles cpu_state._cycles
+
+#define cr0 cpu_state.CR0.l
+#define msw cpu_state.CR0.w
+
+/*Segments -
+  _cs,_ds,_es,_ss are the segment structures
+  CS,DS,ES,SS is the 16-bit data
+  cs,ds,es,ss are defines to the bases*/
+#define CS cpu_state.seg_cs.seg
+#define DS cpu_state.seg_ds.seg
+#define ES cpu_state.seg_es.seg
+#define SS cpu_state.seg_ss.seg
+#define FS cpu_state.seg_fs.seg
+#define GS cpu_state.seg_gs.seg
+#define cs cpu_state.seg_cs.base
+#define ds cpu_state.seg_ds.base
+#define es cpu_state.seg_es.base
+#define ss cpu_state.seg_ss.base
+//#define seg_fs _fs.base
+#define gs cpu_state.seg_gs.base
+
+#define CPL ((cpu_state.seg_cs.access>>5)&3)
+
+#define C_FLAG  0x0001
+#define P_FLAG  0x0004
+#define A_FLAG  0x0010
+#define Z_FLAG  0x0040
+#define N_FLAG  0x0080
+#define T_FLAG  0x0100
+#define I_FLAG  0x0200
+#define D_FLAG  0x0400
+#define V_FLAG  0x0800
+#define NT_FLAG 0x4000
+#define VM_FLAG 0x0002 /*In EFLAGS*/
+#define VIF_FLAG 0x0008 /*In EFLAGS*/
+#define VIP_FLAG 0x0010 /*In EFLAGS*/
+
+#define WP_FLAG 0x10000 /*In CR0*/
+
+#define CR4_VME (1 << 0)
+#define CR4_PVI (1 << 1)
+#define CR4_PSE (1 << 4)
+
+#define IOPL ((cpu_state.flags >> 12) & 3)
+
+#define IOPLp ((!(msw&1)) || (CPL<=IOPL))
+
+extern x86seg gdt, ldt, idt, tr;
+
+extern uint32_t cr2, cr3, cr4;
+extern uint32_t dr[8];
+
+
+extern uint16_t cpu_cur_status;
+
+/*The flags below must match in both cpu_cur_status and block->status for a block
+  to be valid*/
+#define CPU_STATUS_USE32   (1 << 0)
+#define CPU_STATUS_STACK32 (1 << 1)
+#define CPU_STATUS_PMODE   (1 << 2)
+#define CPU_STATUS_V86     (1 << 3)
+#define CPU_STATUS_FLAGS 0xff
+
+/*If the flags below are set in cpu_cur_status, they must be set in block->status.
+  Otherwise they are ignored*/
+#define CPU_STATUS_NOTFLATDS  (1 << 8)
+#define CPU_STATUS_NOTFLATSS  (1 << 9)
+#define CPU_STATUS_MASK 0xff00
+
+
+extern uint32_t rmdat;
+#define fetchdat rmdat
+
+extern uint32_t easeg;
+extern uint32_t *eal_r, *eal_w;
+
 extern int oldcpl;
+extern uint32_t oldss;
 
 extern int nmi_enable;
 
-extern int tempc;
-extern int output;
-extern int firstrepcycle;
+extern int trap;
 
-extern uint32_t easeg,ealimit,ealimitw;
+extern uint32_t use32;
+extern int stack32;
 
-extern int skipnextprint;
-extern int inhlt;
+extern uint8_t znptable8[256];
+extern uint16_t *mod1add[2][8];
+extern uint32_t *mod1seg[8];
 
-extern  uint8_t opcode;
-extern int noint;
+extern int cgate16, cgate32;
+extern int cpl_override;
+
+extern int x86_was_reset;
 
-extern uint16_t lastcs,lastpc;
-extern int timetolive,keyboardtimer;
+extern int insc;
+extern int fpucount;
+extern float mips,flops;
 
 #define setznp168 setznp16
 
@@ -30,12 +233,6 @@ extern int timetolive,keyboardtimer;
 #define setr16(r,v) cpu_state.regs[r].w=v
 #define setr32(r,v) cpu_state.regs[r].l=v
 
-extern uint8_t znptable8[256];
-extern uint16_t znptable16[65536];
-
-extern int use32;
-extern int stack32;
-
 #define fetchea()   { rmdat=readmemb(cs+pc); pc++;  \
                     reg=(rmdat>>3)&7;               \
                     mod=(rmdat>>6)&3;               \
@@ -49,28 +246,6 @@ extern int optype;
 #define IRET 3
 #define OPTYPE_INT 4
 
-extern 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
 {
@@ -87,22 +262,17 @@ 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 codegen_flat_ds;
+extern int codegen_flat_ss;
 
-extern int inscounts[256];
+extern uint32_t pccache;
+extern uint8_t *pccache2;
 
 void x86illegal();
 
 void x86seg_reset();
 void x86gpf(char *s, uint16_t error);
 
-extern uint16_t zero;
-
-extern int x86_was_reset;
-
 void resetx86();
 void softresetx86();
 void refreshread();
@@ -112,5 +282,19 @@ void execx86(int cycs);
 void exec386(int cycs);
 void exec386_dynarec(int cycs);
 
-extern int codegen_flat_ds;
-extern int codegen_flat_ss;
+void pmodeint(int num, int soft);
+int loadseg(uint16_t seg, x86seg *s);
+void loadcs(uint16_t seg);
+void loadcscall(uint16_t seg, uint32_t old_pc);
+void loadcsjmp(uint16_t seg, uint32_t old_pc);
+void pmoderetf(int is32, uint16_t off);
+void pmodeiret(int is32);
+
+void x86_int(int num);
+void x86_int_sw(int num);
+int x86_int_sw_rm(int num);
+
+int divl(uint32_t val);
+int idivl(int32_t val);
+
+#endif
index 87e52420427bb9657bd4aca605213a6e4e6bd071..9a99839268b45aa91b5efc42cafcc78bd73a6b34 100644 (file)
@@ -1,3 +1,5 @@
+extern int tempc;
+
 enum
 {
         FLAGS_UNKNOWN,
@@ -26,6 +28,14 @@ enum
         FLAGS_SAR16,
         FLAGS_SAR32,
 
+        FLAGS_ROL8,
+        FLAGS_ROL16,
+        FLAGS_ROL32,
+
+        FLAGS_ROR8,
+        FLAGS_ROR16,
+        FLAGS_ROR32,
+
         FLAGS_INC8,
         FLAGS_INC16,
         FLAGS_INC32,
@@ -33,6 +43,14 @@ enum
         FLAGS_DEC8,
         FLAGS_DEC16,
         FLAGS_DEC32,
+
+        FLAGS_ADC8,
+        FLAGS_ADC16,
+        FLAGS_ADC32,
+
+        FLAGS_SBC8,
+        FLAGS_SBC16,
+        FLAGS_SBC32
 };
 
 static inline int ZF_SET()
@@ -63,10 +81,22 @@ static inline int ZF_SET()
                 case FLAGS_DEC8:
                 case FLAGS_DEC16:
                 case FLAGS_DEC32:
+                case FLAGS_ADC8:
+                case FLAGS_ADC16:
+                case FLAGS_ADC32:
+                case FLAGS_SBC8:
+                case FLAGS_SBC16:
+                case FLAGS_SBC32:
                 return !cpu_state.flags_res;
                 
+                case FLAGS_ROL8:
+                case FLAGS_ROL16:
+                case FLAGS_ROL32:
+                case FLAGS_ROR8:
+                case FLAGS_ROR16:
+                case FLAGS_ROR32:
                 case FLAGS_UNKNOWN:
-                return flags & Z_FLAG;
+                return cpu_state.flags & Z_FLAG;
         }
         return 0;
 }
@@ -83,6 +113,8 @@ static inline int NF_SET()
                 case FLAGS_SAR8:
                 case FLAGS_INC8:
                 case FLAGS_DEC8:
+                case FLAGS_ADC8:
+                case FLAGS_SBC8:
                 return cpu_state.flags_res & 0x80;
                 
                 case FLAGS_ZN16:
@@ -93,6 +125,8 @@ static inline int NF_SET()
                 case FLAGS_SAR16:
                 case FLAGS_INC16:
                 case FLAGS_DEC16:
+                case FLAGS_ADC16:
+                case FLAGS_SBC16:
                 return cpu_state.flags_res & 0x8000;
                 
                 case FLAGS_ZN32:
@@ -103,10 +137,18 @@ static inline int NF_SET()
                 case FLAGS_SAR32:
                 case FLAGS_INC32:
                 case FLAGS_DEC32:
+                case FLAGS_ADC32:
+                case FLAGS_SBC32:
                 return cpu_state.flags_res & 0x80000000;
                 
+                case FLAGS_ROL8:
+                case FLAGS_ROL16:
+                case FLAGS_ROL32:
+                case FLAGS_ROR8:
+                case FLAGS_ROR16:
+                case FLAGS_ROR32:
                 case FLAGS_UNKNOWN:
-                return flags & N_FLAG;
+                return cpu_state.flags & N_FLAG;
         }
         return 0;
 }
@@ -139,10 +181,22 @@ static inline int PF_SET()
                 case FLAGS_DEC8:
                 case FLAGS_DEC16:
                 case FLAGS_DEC32:
+                case FLAGS_ADC8:
+                case FLAGS_ADC16:
+                case FLAGS_ADC32:
+                case FLAGS_SBC8:
+                case FLAGS_SBC16:
+                case FLAGS_SBC32:
                 return znptable8[cpu_state.flags_res & 0xff] & P_FLAG;
                 
+                case FLAGS_ROL8:
+                case FLAGS_ROL16:
+                case FLAGS_ROL32:
+                case FLAGS_ROR8:
+                case FLAGS_ROR16:
+                case FLAGS_ROR32:
                 case FLAGS_UNKNOWN:
-                return flags & P_FLAG;
+                return cpu_state.flags & P_FLAG;
         }
         return 0;
 }
@@ -159,22 +213,28 @@ static inline int VF_SET()
                 case FLAGS_SAR32:
                 return 0;
                 
+                case FLAGS_ADC8:
                 case FLAGS_ADD8:
                 case FLAGS_INC8:
                 return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80);
+                case FLAGS_ADC16:
                 case FLAGS_ADD16:
                 case FLAGS_INC16:
                 return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000);
+                case FLAGS_ADC32:
                 case FLAGS_ADD32:
                 case FLAGS_INC32:
                 return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000);
                                 
+                case FLAGS_SBC8:
                 case FLAGS_SUB8:
                 case FLAGS_DEC8:
                 return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80);
+                case FLAGS_SBC16:
                 case FLAGS_SUB16:
                 case FLAGS_DEC16:
                 return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000);
+                case FLAGS_SBC32:
                 case FLAGS_SUB32:
                 case FLAGS_DEC32:
                 return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000);
@@ -192,9 +252,23 @@ static inline int VF_SET()
                 return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000));
                 case FLAGS_SHR32:
                 return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000));
-                
+
+                case FLAGS_ROL8:
+                return (cpu_state.flags_res ^ (cpu_state.flags_res >> 7)) & 1;
+                case FLAGS_ROL16:
+                return (cpu_state.flags_res ^ (cpu_state.flags_res >> 15)) & 1;
+                case FLAGS_ROL32:
+                return (cpu_state.flags_res ^ (cpu_state.flags_res >> 31)) & 1;
+
+                case FLAGS_ROR8:
+                return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x40;
+                case FLAGS_ROR16:
+                return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x4000;
+                case FLAGS_ROR32:
+                return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x40000000;
+
                 case FLAGS_UNKNOWN:
-                return flags & V_FLAG;
+                return cpu_state.flags & V_FLAG;
         }
         return 0;
 }
@@ -225,6 +299,16 @@ static inline int AF_SET()
                 case FLAGS_INC32:
                 return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10;
 
+                case FLAGS_ADC8:
+                return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) ||
+                        ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xff);
+                case FLAGS_ADC16:
+                return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) ||
+                        ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xffff);
+                case FLAGS_ADC32:
+                return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) ||
+                        ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xffffffff);
+
                 case FLAGS_SUB8:
                 case FLAGS_SUB16:
                 case FLAGS_SUB32:
@@ -232,9 +316,21 @@ static inline int AF_SET()
                 case FLAGS_DEC16:
                 case FLAGS_DEC32:
                 return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10;
+
+                case FLAGS_SBC8:
+                case FLAGS_SBC16:
+                case FLAGS_SBC32:
+                return ((cpu_state.flags_op1 & 0xf) < (cpu_state.flags_op2 & 0xf)) ||
+                        ((cpu_state.flags_op1 & 0xf) == (cpu_state.flags_op2 & 0xf) && (cpu_state.flags_res & 0xf) != 0);
                 
+                case FLAGS_ROL8:
+                case FLAGS_ROL16:
+                case FLAGS_ROL32:
+                case FLAGS_ROR8:
+                case FLAGS_ROR16:
+                case FLAGS_ROR32:
                 case FLAGS_UNKNOWN:
-                return flags & A_FLAG;
+                return cpu_state.flags & A_FLAG;
         }
         return 0;
 }
@@ -244,23 +340,39 @@ static inline int CF_SET()
         switch (cpu_state.flags_op)
         {
                 case FLAGS_ADD8:
-                return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100;
+                return ((cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100) ? 1 : 0;
                 case FLAGS_ADD16:
-                return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000;
+                return ((cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000) ? 1 : 0;
                 case FLAGS_ADD32:
                 return (cpu_state.flags_res < cpu_state.flags_op1);
 
+                case FLAGS_ADC8:
+                return (cpu_state.flags_res < cpu_state.flags_op1) ||
+                        (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xff);
+                case FLAGS_ADC16:
+                return (cpu_state.flags_res < cpu_state.flags_op1) ||
+                        (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xffff);
+                case FLAGS_ADC32:
+                return (cpu_state.flags_res < cpu_state.flags_op1) ||
+                        (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xffffffff);
+
                 case FLAGS_SUB8:
                 case FLAGS_SUB16:
                 case FLAGS_SUB32:
                 return (cpu_state.flags_op1 < cpu_state.flags_op2);
-                
+
+                case FLAGS_SBC8:
+                case FLAGS_SBC16:
+                case FLAGS_SBC32:
+                return (cpu_state.flags_op1 < cpu_state.flags_op2) ||
+                        (cpu_state.flags_op1 == cpu_state.flags_op2 && cpu_state.flags_res != 0);
+
                 case FLAGS_SHL8:
-                return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80;
+                return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80) ? 1 : 0;
                 case FLAGS_SHL16:
-                return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000;
+                return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000) ? 1 : 0;
                 case FLAGS_SHL32:
-                return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000;
+                return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000) ? 1 : 0;
 
                 case FLAGS_SHR8:
                 case FLAGS_SHR16:
@@ -278,6 +390,18 @@ static inline int CF_SET()
                 case FLAGS_ZN16:
                 case FLAGS_ZN32:
                 return 0;
+
+                case FLAGS_ROL8:
+                case FLAGS_ROL16:
+                case FLAGS_ROL32:
+                return cpu_state.flags_res & 1;
+                
+                case FLAGS_ROR8:
+                return (cpu_state.flags_res & 0x80) ? 1 : 0;
+                case FLAGS_ROR16:
+                return (cpu_state.flags_res & 0x8000) ? 1 :0;
+                case FLAGS_ROR32:
+                return (cpu_state.flags_res & 0x80000000) ? 1 : 0;
                 
                 case FLAGS_DEC8:
                 case FLAGS_DEC16:
@@ -286,7 +410,7 @@ static inline int CF_SET()
                 case FLAGS_INC16:
                 case FLAGS_INC32:
                 case FLAGS_UNKNOWN:
-                return flags & C_FLAG;
+                return cpu_state.flags & C_FLAG;
         }
         return 0;
 }
@@ -309,7 +433,7 @@ static inline void flags_rebuild()
                 if (ZF_SET()) tempf |= Z_FLAG;                                
                 if (NF_SET()) tempf |= N_FLAG;
                 if (VF_SET()) tempf |= V_FLAG;
-                flags = (flags & ~0x8d5) | tempf;
+                cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf;
                 cpu_state.flags_op = FLAGS_UNKNOWN;
         }
 }
@@ -324,12 +448,21 @@ static inline void flags_rebuild_c()
         if (cpu_state.flags_op != FLAGS_UNKNOWN)
         {
                 if (CF_SET())
-                   flags |=  C_FLAG;
+                        cpu_state.flags |=  C_FLAG;
                 else
-                   flags &= ~C_FLAG;
+                        cpu_state.flags &= ~C_FLAG;
         }                
 }
 
+static inline int flags_res_valid()
+{
+        if (cpu_state.flags_op == FLAGS_UNKNOWN ||
+            (cpu_state.flags_op >= FLAGS_ROL8 && cpu_state.flags_op <= FLAGS_ROR32))
+                return 0;
+
+        return 1;
+}
+
 static inline void setznp8(uint8_t val)
 {
         cpu_state.flags_op = FLAGS_ZN8;
@@ -352,6 +485,10 @@ static inline void setznp32(uint32_t val)
         cpu_state.flags_op1 = orig;               \
         cpu_state.flags_op2 = shift;
 
+#define set_flags_rotate(op, res)               \
+        cpu_state.flags_op = op;                \
+        cpu_state.flags_res = res;
+
 static inline void setadd8(uint8_t a, uint8_t b)
 {
         cpu_state.flags_op1 = a;
@@ -447,67 +584,47 @@ static inline void setsub32nc(uint32_t a, uint32_t b)
 
 static inline void setadc8(uint8_t a, uint8_t b)
 {
-        uint16_t c=(uint16_t)a+(uint16_t)b+tempc;
-        cpu_state.flags_op = FLAGS_UNKNOWN;
-        flags&=~0x8D5;
-        flags|=znptable8[c&0xFF];
-        if (c&0x100) flags|=C_FLAG;
-        if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG;
-        if (((a&0xF)+(b&0xF))&0x10)      flags|=A_FLAG;
+        cpu_state.flags_op1 = a;
+        cpu_state.flags_op2 = b;
+        cpu_state.flags_res = (a + b + tempc) & 0xff;
+        cpu_state.flags_op = FLAGS_ADC8;
 }
 static inline void setadc16(uint16_t a, uint16_t b)
 {
-        uint32_t c=(uint32_t)a+(uint32_t)b+tempc;
-        cpu_state.flags_op = FLAGS_UNKNOWN;
-        flags&=~0x8D5;
-        flags|=znptable16[c&0xFFFF];
-        if (c&0x10000) flags|=C_FLAG;
-        if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG;
-        if (((a&0xF)+(b&0xF))&0x10)      flags|=A_FLAG;
+        cpu_state.flags_op1 = a;
+        cpu_state.flags_op2 = b;
+        cpu_state.flags_res = (a + b + tempc) & 0xffff;
+        cpu_state.flags_op = FLAGS_ADC16;
+}
+static inline void setadc32(uint32_t a, uint32_t b)
+{
+        cpu_state.flags_op1 = a;
+        cpu_state.flags_op2 = b;
+        cpu_state.flags_res = a + b + tempc;
+        cpu_state.flags_op = FLAGS_ADC32;
 }
 
 static inline void setsbc8(uint8_t a, uint8_t b)
 {
-        uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc);
-        cpu_state.flags_op = FLAGS_UNKNOWN;
-        flags&=~0x8D5;
-        flags|=znptable8[c&0xFF];
-        if (c&0x100) flags|=C_FLAG;
-        if ((a^b)&(a^c)&0x80) flags|=V_FLAG;
-        if (((a&0xF)-(b&0xF))&0x10)      flags|=A_FLAG;
+        cpu_state.flags_op1 = a;
+        cpu_state.flags_op2 = b;
+        cpu_state.flags_res = (a - (b + tempc)) & 0xff;
+        cpu_state.flags_op = FLAGS_SBC8;
 }
 static inline void setsbc16(uint16_t a, uint16_t b)
 {
-        uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc);
-        cpu_state.flags_op = FLAGS_UNKNOWN;
-        flags&=~0x8D5;
-        flags|=(znptable16[c&0xFFFF]&~4);
-        flags|=(znptable8[c&0xFF]&4);
-        if (c&0x10000) flags|=C_FLAG;
-        if ((a^b)&(a^c)&0x8000) flags|=V_FLAG;
-        if (((a&0xF)-(b&0xF))&0x10)      flags|=A_FLAG;
-}
-
-static inline void setadc32(uint32_t a, uint32_t b)
-{
-        uint32_t c=(uint32_t)a+(uint32_t)b+tempc;
-        cpu_state.flags_op = FLAGS_UNKNOWN;
-        flags&=~0x8D5;
-        flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0));
-        flags|=(znptable8[c&0xFF]&P_FLAG);
-        if ((c<a) || (c==a && tempc)) flags|=C_FLAG;
-        if (!((a^b)&0x80000000)&&((a^c)&0x80000000)) flags|=V_FLAG;
-        if (((a&0xF)+(b&0xF)+tempc)&0x10)      flags|=A_FLAG;
+        cpu_state.flags_op1 = a;
+        cpu_state.flags_op2 = b;
+        cpu_state.flags_res = (a - (b + tempc)) & 0xffff;
+        cpu_state.flags_op = FLAGS_SBC16;
 }
 static inline void setsbc32(uint32_t a, uint32_t b)
 {
-        uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc);
-        cpu_state.flags_op = FLAGS_UNKNOWN;
-        flags&=~0x8D5;
-        flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0));
-        flags|=(znptable8[c&0xFF]&P_FLAG);
-        if ((c>a) || (c==a && tempc)) flags|=C_FLAG;
-        if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG;
-        if (((a&0xF)-((b&0xF)+tempc))&0x10)      flags|=A_FLAG;
+        cpu_state.flags_op1 = a;
+        cpu_state.flags_op2 = b;
+        cpu_state.flags_res = a - (b + tempc);
+        cpu_state.flags_op = FLAGS_SBC32;
 }
 
+extern void cpu_386_flags_extract();
+extern void cpu_386_flags_rebuild();
index e79734fce7883aaa4a64bf4a2d5700de33ec52b2..ad4f0706bdfbe8a5fcaacd0c1c7a56bbe11b235d 100644 (file)
@@ -25,6 +25,7 @@ extern OpFn *x86_dynarec_opcodes_df_a16;
 extern OpFn *x86_dynarec_opcodes_df_a32;
 extern OpFn *x86_dynarec_opcodes_REPE;
 extern OpFn *x86_dynarec_opcodes_REPNE;
+extern OpFn *x86_dynarec_opcodes_3DNOW;
 
 extern OpFn dynarec_ops_286[1024];
 extern OpFn dynarec_ops_286_0f[1024];
@@ -33,6 +34,7 @@ extern OpFn dynarec_ops_386[1024];
 extern OpFn dynarec_ops_386_0f[1024];
 
 extern OpFn dynarec_ops_winchip_0f[1024];
+extern OpFn dynarec_ops_winchip2_0f[1024];
 
 extern OpFn dynarec_ops_pentium_0f[1024];
 extern OpFn dynarec_ops_pentiummmx_0f[1024];
@@ -67,6 +69,8 @@ extern OpFn dynarec_ops_fpu_686_df_a32[256];
 extern OpFn dynarec_ops_REPE[1024];
 extern OpFn dynarec_ops_REPNE[1024];
 
+extern OpFn dynarec_ops_3DNOW[256];
+
 extern OpFn *x86_opcodes;
 extern OpFn *x86_opcodes_0f;
 extern OpFn *x86_opcodes_d8_a16;
@@ -87,6 +91,7 @@ extern OpFn *x86_opcodes_df_a16;
 extern OpFn *x86_opcodes_df_a32;
 extern OpFn *x86_opcodes_REPE;
 extern OpFn *x86_opcodes_REPNE;
+extern OpFn *x86_opcodes_3DNOW;
 
 extern OpFn ops_286[1024];
 extern OpFn ops_286_0f[1024];
@@ -95,6 +100,7 @@ extern OpFn ops_386[1024];
 extern OpFn ops_386_0f[1024];
 
 extern OpFn ops_winchip_0f[1024];
+extern OpFn ops_winchip2_0f[1024];
 
 extern OpFn ops_pentium_0f[1024];
 extern OpFn ops_pentiummmx_0f[1024];
@@ -130,4 +136,6 @@ extern OpFn ops_fpu_686_df_a32[256];
 extern OpFn ops_REPE[1024];
 extern OpFn ops_REPNE[1024];
 
+extern OpFn ops_3DNOW[256];
+
 #endif /*_X86_OPS_H*/
diff --git a/pcem/x86_ops_3dnow.h b/pcem/x86_ops_3dnow.h
new file mode 100644 (file)
index 0000000..2930a68
--- /dev/null
@@ -0,0 +1,346 @@
+#include <math.h>
+
+static int opPREFETCH_a16(uint32_t fetchdat)
+{
+        fetch_ea_16(fetchdat);
+        ILLEGAL_ON(cpu_mod == 3);
+
+        CLOCK_CYCLES(1);
+        return 0;
+}
+static int opPREFETCH_a32(uint32_t fetchdat)
+{
+        fetch_ea_32(fetchdat);
+        ILLEGAL_ON(cpu_mod == 3);
+
+        CLOCK_CYCLES(1);
+        return 0;
+}
+
+static int opFEMMS(uint32_t fetchdat)
+{
+        ILLEGAL_ON(!cpu_has_feature(CPU_FEATURE_MMX));
+        if (cr0 & 0xc)
+        {
+                x86_int(7);
+                return 1;
+        }
+        x87_emms();
+        CLOCK_CYCLES(1);
+        return 0;
+}
+
+static int opPAVGUSB(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] + src.b[0] + 1) >> 1;
+        cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] + src.b[1] + 1) >> 1;
+        cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] + src.b[2] + 1) >> 1;
+        cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] + src.b[3] + 1) >> 1;
+        cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] + src.b[4] + 1) >> 1;
+        cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] + src.b[5] + 1) >> 1;
+        cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] + src.b[6] + 1) >> 1;
+        cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] + src.b[7] + 1) >> 1;
+
+        return 0;
+}
+static int opPF2ID(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].sl[0] = (int32_t)src.f[0];
+        cpu_state.MM[cpu_reg].sl[1] = (int32_t)src.f[1];
+
+        return 0;
+}
+static int opPFACC(uint32_t fetchdat)
+{
+        MMX_REG src;
+        float tempf;
+
+        MMX_GETSRC();
+
+        tempf = cpu_state.MM[cpu_reg].f[0] + cpu_state.MM[cpu_reg].f[1];
+        cpu_state.MM[cpu_reg].f[1] = src.f[0] + src.f[1];
+        cpu_state.MM[cpu_reg].f[0] = tempf;
+
+        return 0;
+}
+static int opPFADD(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].f[0] += src.f[0];
+        cpu_state.MM[cpu_reg].f[1] += src.f[1];
+
+        return 0;
+}
+static int opPFCMPEQ(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] == src.f[0]) ? 0xffffffff : 0;
+        cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] == src.f[1]) ? 0xffffffff : 0;
+
+        return 0;
+}
+static int opPFCMPGE(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] >= src.f[0]) ? 0xffffffff : 0;
+        cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] >= src.f[1]) ? 0xffffffff : 0;
+
+        return 0;
+}
+static int opPFCMPGT(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] > src.f[0]) ? 0xffffffff : 0;
+        cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] > src.f[1]) ? 0xffffffff : 0;
+
+        return 0;
+}
+static int opPFMAX(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        if (src.f[0] > cpu_state.MM[cpu_reg].f[0])
+                cpu_state.MM[cpu_reg].f[0] = src.f[0];
+        if (src.f[1] > cpu_state.MM[cpu_reg].f[1])
+                cpu_state.MM[cpu_reg].f[1] = src.f[1];
+
+        return 0;
+}
+static int opPFMIN(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        if (src.f[0] < cpu_state.MM[cpu_reg].f[0])
+                cpu_state.MM[cpu_reg].f[0] = src.f[0];
+        if (src.f[1] < cpu_state.MM[cpu_reg].f[1])
+                cpu_state.MM[cpu_reg].f[1] = src.f[1];
+
+        return 0;
+}
+static int opPFMUL(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].f[0] *= src.f[0];
+        cpu_state.MM[cpu_reg].f[1] *= src.f[1];
+
+        return 0;
+}
+static int opPFRCP(uint32_t fetchdat)
+{
+        union
+        {
+                uint32_t i;
+                float f;
+        } src;
+        
+        if (cpu_mod == 3)
+        {
+                src.f = cpu_state.MM[cpu_rm].f[0];
+                CLOCK_CYCLES(1);           
+        }                                  
+        else                               
+        {                                  
+                SEG_CHECK_READ(cpu_state.ea_seg);
+                src.i = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1;
+                CLOCK_CYCLES(2);
+        }
+
+        cpu_state.MM[cpu_reg].f[0] = 1.0/src.f;
+        cpu_state.MM[cpu_reg].f[1] = cpu_state.MM[cpu_reg].f[0];
+
+        return 0;
+}
+/*Since opPFRCP() calculates a full precision reciprocal, treat the followup iterations as MOVs*/
+static int opPFRCPIT1(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].f[0] = src.f[0];
+        cpu_state.MM[cpu_reg].f[1] = src.f[1];
+
+        return 0;
+}
+static int opPFRCPIT2(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].f[0] = src.f[0];
+        cpu_state.MM[cpu_reg].f[1] = src.f[1];
+
+        return 0;
+}
+static int opPFRSQRT(uint32_t fetchdat)
+{
+        union
+        {
+                uint32_t i;
+                float f;
+        } src;
+
+        if (cpu_mod == 3)
+        {
+                src.f = cpu_state.MM[cpu_rm].f[0];
+                CLOCK_CYCLES(1);
+        }
+        else
+        {
+                SEG_CHECK_READ(cpu_state.ea_seg);
+                src.i = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1;
+                CLOCK_CYCLES(2);
+        }
+
+        cpu_state.MM[cpu_reg].f[0] = 1.0/sqrt(src.f);
+        cpu_state.MM[cpu_reg].f[1] = cpu_state.MM[cpu_reg].f[0];
+
+        return 0;
+}
+/*Since opPFRSQRT() calculates a full precision inverse square root, treat the followup iteration as a NOP*/
+static int opPFRSQIT1(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+        UNUSED(src);
+
+        return 0;
+}
+static int opPFSUB(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].f[0] -= src.f[0];
+        cpu_state.MM[cpu_reg].f[1] -= src.f[1];
+
+        return 0;
+}
+static int opPFSUBR(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].f[0] = src.f[0] - cpu_state.MM[cpu_reg].f[0];
+        cpu_state.MM[cpu_reg].f[1] = src.f[1] - cpu_state.MM[cpu_reg].f[1];
+
+        return 0;
+}
+static int opPI2FD(uint32_t fetchdat)
+{
+        MMX_REG src;
+
+        MMX_GETSRC();
+
+        cpu_state.MM[cpu_reg].f[0] = (float)src.sl[0];
+        cpu_state.MM[cpu_reg].f[1] = (float)src.sl[1];
+
+        return 0;
+}
+static int opPMULHRW(uint32_t fetchdat)
+{
+        if (cpu_mod == 3)
+        {
+                cpu_state.MM[cpu_reg].w[0] = (((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)cpu_state.MM[cpu_rm].sw[0]) + 0x8000) >> 16;
+                cpu_state.MM[cpu_reg].w[1] = (((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)cpu_state.MM[cpu_rm].sw[1]) + 0x8000) >> 16;
+                cpu_state.MM[cpu_reg].w[2] = (((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)cpu_state.MM[cpu_rm].sw[2]) + 0x8000) >> 16;
+                cpu_state.MM[cpu_reg].w[3] = (((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)cpu_state.MM[cpu_rm].sw[3]) + 0x8000) >> 16;
+                CLOCK_CYCLES(1);
+        }
+        else
+        {
+                MMX_REG src;
+
+                SEG_CHECK_READ(cpu_state.ea_seg);
+                src.l[0] = readmeml(easeg, cpu_state.eaaddr);
+                src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0;
+                cpu_state.MM[cpu_reg].w[0] = ((int32_t)(cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + 0x8000) >> 16;
+                cpu_state.MM[cpu_reg].w[1] = ((int32_t)(cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) + 0x8000) >> 16;
+                cpu_state.MM[cpu_reg].w[2] = ((int32_t)(cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + 0x8000) >> 16;
+                cpu_state.MM[cpu_reg].w[3] = ((int32_t)(cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) + 0x8000) >> 16;
+                CLOCK_CYCLES(2);
+        }
+        return 0;
+}
+
+OpFn OP_TABLE(3DNOW)[256] =
+{
+/*      00              01              02              03              04              05              06              07              08              09              0a              0b              0c              0d              0e              0f*/
+/*00*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opPI2FD,        ILLEGAL,        ILLEGAL,
+/*10*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opPF2ID,        ILLEGAL,        ILLEGAL,
+/*20*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*30*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+
+/*40*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*50*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*60*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*70*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+
+/*80*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*90*/  opPFCMPGE,      ILLEGAL,        ILLEGAL,        ILLEGAL,        opPFMIN,        ILLEGAL,        opPFRCP,        opPFRSQRT,      ILLEGAL,        ILLEGAL,        opPFSUB,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opPFADD,        ILLEGAL,
+/*a0*/  opPFCMPGT,      ILLEGAL,        ILLEGAL,        ILLEGAL,        opPFMAX,        ILLEGAL,        opPFRCPIT1,     opPFRSQIT1,     ILLEGAL,        ILLEGAL,        opPFSUBR,       ILLEGAL,        ILLEGAL,        ILLEGAL,        opPFACC,        ILLEGAL,
+/*b0*/  opPFCMPEQ,      ILLEGAL,        ILLEGAL,        ILLEGAL,        opPFMUL,        ILLEGAL,        opPFRCPIT2,     opPMULHRW,      ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        opPAVGUSB,
+
+/*c0*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*d0*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*e0*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+/*f0*/  ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,        ILLEGAL,
+};
+
+static int op3DNOW_a16(uint32_t fetchdat)
+{
+        uint8_t opcode;
+
+        MMX_ENTER();
+
+        fetch_ea_16(fetchdat);
+        opcode = fastreadb(cs + cpu_state.pc);
+        if (cpu_state.abrt) return 1;
+        cpu_state.pc++;
+
+        return x86_opcodes_3DNOW[opcode](0);
+}
+static int op3DNOW_a32(uint32_t fetchdat)
+{
+        uint8_t opcode;
+        
+        MMX_ENTER();
+
+        fetch_ea_32(fetchdat);
+        opcode = fastreadb(cs + cpu_state.pc);
+        if (cpu_state.abrt) return 1;
+        cpu_state.pc++;
+        
+        return x86_opcodes_3DNOW[opcode](0);
+}
index 3a9f96953e8aacf50fba26887268212cc720e140..2be0e4ef1236c434e168c1a7d14471c2f84de4bf 100644 (file)
                 }                                                                               \
                 else                                                                            \
                 {                                                                               \
-                        uint8_t dst = geteab();                         if (cpu_state.abrt) return 1;     \
+                        uint8_t dst;                                                            \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                                      \
+                        dst = geteab();                         if (cpu_state.abrt) return 1;     \
                         uint8_t src = getr8(cpu_reg);                                               \
-                        seteab(operation);                              if (cpu_state.abrt) return 1;     \
+                        seteab(operation);                      if (cpu_state.abrt) return 1;     \
                         setflags ## 8 flagops;                                                  \
                         CLOCK_CYCLES(timing_mr);                                                \
                         PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 0); \
@@ -38,7 +40,9 @@
                 }                                                                               \
                 else                                                                            \
                 {                                                                               \
-                        uint8_t dst = geteab();                         if (cpu_state.abrt) return 1;     \
+                        uint8_t dst;                                                            \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                                      \
+                        dst = geteab();                         if (cpu_state.abrt) return 1;     \
                         uint8_t src = getr8(cpu_reg);                                               \
                         seteab(operation);                              if (cpu_state.abrt) return 1;     \
                         setflags ## 8 flagops;                                                  \
@@ -63,7 +67,9 @@
                 }                                                                               \
                 else                                                                            \
                 {                                                                               \
-                        uint16_t dst = geteaw();                        if (cpu_state.abrt) return 1;     \
+                        uint16_t dst;                                                           \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                                      \
+                        dst = geteaw();                         if (cpu_state.abrt) return 1;   \
                         uint16_t src = cpu_state.regs[cpu_reg].w;                                   \
                         seteaw(operation);                              if (cpu_state.abrt) return 1;     \
                         setflags ## 16 flagops;                                                 \
@@ -87,7 +93,9 @@
                 }                                                                               \
                 else                                                                            \
                 {                                                                               \
-                        uint16_t dst = geteaw();                        if (cpu_state.abrt) return 1;     \
+                        uint16_t dst;                                                           \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                                      \
+                        dst = geteaw();                         if (cpu_state.abrt) return 1;   \
                         uint16_t src = cpu_state.regs[cpu_reg].w;                                   \
                         seteaw(operation);                              if (cpu_state.abrt) return 1;     \
                         setflags ## 16 flagops;                                                 \
                 }                                                                               \
                 else                                                                            \
                 {                                                                               \
-                        uint32_t dst = geteal();                        if (cpu_state.abrt) return 1;     \
+                        uint32_t dst;                                                           \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                                      \
+                        dst = geteal();                         if (cpu_state.abrt) return 1;   \
                         uint32_t src = cpu_state.regs[cpu_reg].l;                                   \
                         seteal(operation);                              if (cpu_state.abrt) return 1;     \
                         setflags ## 32 flagops;                                                 \
                 }                                                                               \
                 else                                                                            \
                 {                                                                               \
-                        uint32_t dst = geteal();                        if (cpu_state.abrt) return 1;     \
+                        uint32_t dst;                                                           \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                                      \
+                        dst = geteal();                         if (cpu_state.abrt) return 1;   \
                         uint32_t src = cpu_state.regs[cpu_reg].l;                                   \
                         seteal(operation);                              if (cpu_state.abrt) return 1;     \
                         setflags ## 32 flagops;                                                 \
                 uint8_t dst, src;                                                               \
                 if (gettempc) tempc = CF_SET() ? 1 : 0;                                         \
                 fetch_ea_16(fetchdat);                                                          \
+                if (cpu_mod != 3)                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                       \
                 dst = getr8(cpu_reg);                                                               \
                 src = geteab();                                         if (cpu_state.abrt) return 1;     \
                 setflags ## 8 flagops;                                                          \
                 uint8_t dst, src;                                                               \
                 if (gettempc) tempc = CF_SET() ? 1 : 0;                                         \
                 fetch_ea_32(fetchdat);                                                          \
+                if (cpu_mod != 3)                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                       \
                 dst = getr8(cpu_reg);                                                               \
                 src = geteab();                                         if (cpu_state.abrt) return 1;     \
                 setflags ## 8 flagops;                                                          \
                 uint16_t dst, src;                                                              \
                 if (gettempc) tempc = CF_SET() ? 1 : 0;                                         \
                 fetch_ea_16(fetchdat);                                                          \
+                if (cpu_mod != 3)                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                       \
                 dst = cpu_state.regs[cpu_reg].w;                                                    \
                 src = geteaw();                                 if (cpu_state.abrt) return 1;             \
                 setflags ## 16 flagops;                                                         \
                 uint16_t dst, src;                                                              \
                 if (gettempc) tempc = CF_SET() ? 1 : 0;                                         \
                 fetch_ea_32(fetchdat);                                                          \
+                if (cpu_mod != 3)                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                       \
                 dst = cpu_state.regs[cpu_reg].w;                                                    \
                 src = geteaw();                                 if (cpu_state.abrt) return 1;             \
                 setflags ## 16 flagops;                                                         \
                 uint32_t dst, src;                                                              \
                 if (gettempc) tempc = CF_SET() ? 1 : 0;                                         \
                 fetch_ea_16(fetchdat);                                                          \
+                if (cpu_mod != 3)                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                       \
                 dst = cpu_state.regs[cpu_reg].l;                                                    \
                 src = geteal();                                 if (cpu_state.abrt) return 1;             \
                 setflags ## 32 flagops;                                                         \
                 uint32_t dst, src;                                                              \
                 if (gettempc) tempc = CF_SET() ? 1 : 0;                                         \
                 fetch_ea_32(fetchdat);                                                          \
+                if (cpu_mod != 3)                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                       \
                 dst = cpu_state.regs[cpu_reg].l;                                                    \
                 src = geteal();                                 if (cpu_state.abrt) return 1;             \
                 setflags ## 32 flagops;                                                         \
@@ -275,6 +299,8 @@ static int opCMP_b_rmw_a16(uint32_t fetchdat)
 {
         uint8_t dst;
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteab();                                         if (cpu_state.abrt) return 1;
         setsub8(dst, getr8(cpu_reg));
         if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2);
@@ -286,6 +312,8 @@ static int opCMP_b_rmw_a32(uint32_t fetchdat)
 {                                                                                       
         uint8_t dst;
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteab();                                         if (cpu_state.abrt) return 1;
         setsub8(dst, getr8(cpu_reg));
         if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2);
@@ -298,6 +326,8 @@ static int opCMP_w_rmw_a16(uint32_t fetchdat)
 {                                                                                       
         uint16_t dst;
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteaw();                                         if (cpu_state.abrt) return 1;
         setsub16(dst, cpu_state.regs[cpu_reg].w);
         if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2);
@@ -309,6 +339,8 @@ static int opCMP_w_rmw_a32(uint32_t fetchdat)
 {                                                                                       
         uint16_t dst;
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteaw();                                         if (cpu_state.abrt) return 1;
         setsub16(dst, cpu_state.regs[cpu_reg].w);
         if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2);
@@ -321,6 +353,8 @@ static int opCMP_l_rmw_a16(uint32_t fetchdat)
 {                                                                                       
         uint32_t dst;
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteal();                                         if (cpu_state.abrt) return 1;
         setsub32(dst, cpu_state.regs[cpu_reg].l);
         if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2);
@@ -332,6 +366,8 @@ static int opCMP_l_rmw_a32(uint32_t fetchdat)
 {                                                                                       
         uint32_t dst;
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteal();                                         if (cpu_state.abrt) return 1;
         setsub32(dst, cpu_state.regs[cpu_reg].l);
         if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2);
@@ -344,7 +380,9 @@ static int opCMP_b_rm_a16(uint32_t fetchdat)
 {                                                                                       
         uint8_t src;                                                               
         fetch_ea_16(fetchdat);                                                          
-        src = geteab();                                         if (cpu_state.abrt) return 1;     
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+        src = geteab();                                         if (cpu_state.abrt) return 1;
         setsub8(getr8(cpu_reg), src);
         CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm);
         PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0);
@@ -354,7 +392,9 @@ static int opCMP_b_rm_a32(uint32_t fetchdat)
 {                                                                                       
         uint8_t src;                                                               
         fetch_ea_32(fetchdat);                                                          
-        src = geteab();                                         if (cpu_state.abrt) return 1;     
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+        src = geteab();                                         if (cpu_state.abrt) return 1;
         setsub8(getr8(cpu_reg), src);
         CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm);
         PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1);
@@ -365,7 +405,9 @@ static int opCMP_w_rm_a16(uint32_t fetchdat)
 {                                                                                       
         uint16_t src;                                                              
         fetch_ea_16(fetchdat);                                                          
-        src = geteaw();                                 if (cpu_state.abrt) return 1;             
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+        src = geteaw();                                 if (cpu_state.abrt) return 1;
         setsub16(cpu_state.regs[cpu_reg].w, src);
         CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm);
         PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0);
@@ -375,7 +417,9 @@ static int opCMP_w_rm_a32(uint32_t fetchdat)
 {                                                                                       
         uint16_t src;                                                              
         fetch_ea_32(fetchdat);                                                          
-        src = geteaw();                                 if (cpu_state.abrt) return 1;             
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+        src = geteaw();                                 if (cpu_state.abrt) return 1;
         setsub16(cpu_state.regs[cpu_reg].w, src);
         CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm);
         PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1);
@@ -386,7 +430,9 @@ static int opCMP_l_rm_a16(uint32_t fetchdat)
 {                                                                                       
         uint32_t src;                                                              
         fetch_ea_16(fetchdat);                                                          
-        src = geteal();                                 if (cpu_state.abrt) return 1;             
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+        src = geteal();                                 if (cpu_state.abrt) return 1;
         setsub32(cpu_state.regs[cpu_reg].l, src);
         CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml);
         PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0);
@@ -396,7 +442,9 @@ static int opCMP_l_rm_a32(uint32_t fetchdat)
 {                                                                                       
         uint32_t src;
         fetch_ea_32(fetchdat);                                                          
-        src = geteal();                                 if (cpu_state.abrt) return 1;             
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+        src = geteal();                                 if (cpu_state.abrt) return 1;
         setsub32(cpu_state.regs[cpu_reg].l, src);
         CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml);
         PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1);
@@ -434,6 +482,8 @@ static int opTEST_b_a16(uint32_t fetchdat)
 {
         uint8_t temp, temp2;
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                                if (cpu_state.abrt) return 1;
         temp2 = getr8(cpu_reg);
         setznp8(temp & temp2);
@@ -446,6 +496,8 @@ static int opTEST_b_a32(uint32_t fetchdat)
 {
         uint8_t temp, temp2;
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                                if (cpu_state.abrt) return 1;
         temp2 = getr8(cpu_reg);
         setznp8(temp & temp2);
@@ -459,6 +511,8 @@ static int opTEST_w_a16(uint32_t fetchdat)
 {
         uint16_t temp, temp2;
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                                if (cpu_state.abrt) return 1;
         temp2 = cpu_state.regs[cpu_reg].w;
         setznp16(temp & temp2);
@@ -471,6 +525,8 @@ static int opTEST_w_a32(uint32_t fetchdat)
 {
         uint16_t temp, temp2;
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                                if (cpu_state.abrt) return 1;
         temp2 = cpu_state.regs[cpu_reg].w;
         setznp16(temp & temp2);
@@ -484,6 +540,8 @@ static int opTEST_l_a16(uint32_t fetchdat)
 {
         uint32_t temp, temp2;
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteal();                                if (cpu_state.abrt) return 1;
         temp2 = cpu_state.regs[cpu_reg].l;
         setznp32(temp & temp2);
@@ -496,6 +554,8 @@ static int opTEST_l_a32(uint32_t fetchdat)
 {
         uint32_t temp, temp2;
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteal();                                if (cpu_state.abrt) return 1;
         temp2 = cpu_state.regs[cpu_reg].l;
         setznp32(temp & temp2);
@@ -588,6 +648,8 @@ static int op80_a16(uint32_t fetchdat)
         uint8_t src, dst;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getbyte();                        if (cpu_state.abrt) return 1;
         ARITH_MULTI(b, 8);
         if ((rmdat & 0x38) == 0x38)
@@ -602,6 +664,8 @@ static int op80_a32(uint32_t fetchdat)
         uint8_t src, dst;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getbyte();                        if (cpu_state.abrt) return 1;
         ARITH_MULTI(b, 8);
         if ((rmdat & 0x38) == 0x38)
@@ -616,6 +680,8 @@ static int op81_w_a16(uint32_t fetchdat)
         uint16_t src, dst;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getword();                        if (cpu_state.abrt) return 1;
         ARITH_MULTI(w, 16);
         if ((rmdat & 0x38) == 0x38)
@@ -630,6 +696,8 @@ static int op81_w_a32(uint32_t fetchdat)
         uint16_t src, dst;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getword();                        if (cpu_state.abrt) return 1;
         ARITH_MULTI(w, 16);
         if ((rmdat & 0x38) == 0x38)
@@ -644,6 +712,8 @@ static int op81_l_a16(uint32_t fetchdat)
         uint32_t src, dst;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getlong();                        if (cpu_state.abrt) return 1;
         ARITH_MULTI(l, 32);
         if ((rmdat & 0x38) == 0x38)
@@ -658,6 +728,8 @@ static int op81_l_a32(uint32_t fetchdat)
         uint32_t src, dst;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getlong();                        if (cpu_state.abrt) return 1;
         ARITH_MULTI(l, 32);
         if ((rmdat & 0x38) == 0x38)
@@ -673,6 +745,8 @@ static int op83_w_a16(uint32_t fetchdat)
         uint16_t src, dst;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getbyte();                        if (cpu_state.abrt) return 1;
         if (src & 0x80) src |= 0xff00;
         ARITH_MULTI(w, 16);
@@ -688,6 +762,8 @@ static int op83_w_a32(uint32_t fetchdat)
         uint16_t src, dst;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getbyte();                        if (cpu_state.abrt) return 1;
         if (src & 0x80) src |= 0xff00;
         ARITH_MULTI(w, 16);
@@ -704,6 +780,8 @@ static int op83_l_a16(uint32_t fetchdat)
         uint32_t src, dst;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getbyte();                        if (cpu_state.abrt) return 1;
         if (src & 0x80) src |= 0xffffff00;
         ARITH_MULTI(l, 32);
@@ -719,6 +797,8 @@ static int op83_l_a32(uint32_t fetchdat)
         uint32_t src, dst;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         src = getbyte();                        if (cpu_state.abrt) return 1;
         if (src & 0x80) src |= 0xffffff00;
         ARITH_MULTI(l, 32);
index 7d90e22d1004d944088b7f43577e15f5f9107da9..4011a0aa438e40beff682a552091c40682037609 100644 (file)
@@ -8,6 +8,7 @@ static int opCMPXCHG_b_a16(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         if (AL == temp) seteab(getr8(cpu_reg));
         else            AL = temp;
@@ -26,6 +27,7 @@ static int opCMPXCHG_b_a32(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         if (AL == temp) seteab(getr8(cpu_reg));
         else            AL = temp;
@@ -45,6 +47,7 @@ static int opCMPXCHG_w_a16(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w);
         else            AX = temp;
@@ -63,6 +66,7 @@ static int opCMPXCHG_w_a32(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w);
         else            AX = temp;
@@ -82,6 +86,7 @@ static int opCMPXCHG_l_a16(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l);
         else             EAX = temp;
@@ -100,6 +105,7 @@ static int opCMPXCHG_l_a32(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l);
         else             EAX = temp;
@@ -119,6 +125,7 @@ static int opCMPXCHG8B_a16(uint32_t fetchdat)
                 return 0;
         }
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();
         temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0;
         if (EAX == temp && EDX == temp_hi)
@@ -134,9 +141,9 @@ static int opCMPXCHG8B_a16(uint32_t fetchdat)
         if (cpu_state.abrt) return 0;
         flags_rebuild();
         if (temp == temp2 && temp_hi == temp2_hi)
-                flags |= Z_FLAG;
+                cpu_state.flags |= Z_FLAG;
         else
-                flags &= ~Z_FLAG;        
+                cpu_state.flags &= ~Z_FLAG;
         cycles -= (cpu_mod == 3) ? 6 : 10;
         return 0;
 }
@@ -150,6 +157,7 @@ static int opCMPXCHG8B_a32(uint32_t fetchdat)
                 return 0;
         }
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();
         temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0;
         if (EAX == temp && EDX == temp_hi)
@@ -165,9 +173,9 @@ static int opCMPXCHG8B_a32(uint32_t fetchdat)
         if (cpu_state.abrt) return 0;
         flags_rebuild();
         if (temp == temp2 && temp_hi == temp2_hi)
-                flags |= Z_FLAG;
+                cpu_state.flags |= Z_FLAG;
         else
-                flags &= ~Z_FLAG;        
+                cpu_state.flags &= ~Z_FLAG;
         cycles -= (cpu_mod == 3) ? 6 : 10;
         return 0;
 }
@@ -182,6 +190,7 @@ static int opXADD_b_a16(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         seteab(temp + getr8(cpu_reg));              if (cpu_state.abrt) return 1;
         setadd8(temp, getr8(cpu_reg));
@@ -199,6 +208,7 @@ static int opXADD_b_a32(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         seteab(temp + getr8(cpu_reg));              if (cpu_state.abrt) return 1;
         setadd8(temp, getr8(cpu_reg));
@@ -217,6 +227,7 @@ static int opXADD_w_a16(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         seteaw(temp + cpu_state.regs[cpu_reg].w);   if (cpu_state.abrt) return 1;
         setadd16(temp, cpu_state.regs[cpu_reg].w);
@@ -234,6 +245,7 @@ static int opXADD_w_a32(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         seteaw(temp + cpu_state.regs[cpu_reg].w);   if (cpu_state.abrt) return 1;
         setadd16(temp, cpu_state.regs[cpu_reg].w);
@@ -252,6 +264,7 @@ static int opXADD_l_a16(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         seteal(temp + cpu_state.regs[cpu_reg].l);   if (cpu_state.abrt) return 1;
         setadd32(temp, cpu_state.regs[cpu_reg].l);
@@ -269,6 +282,7 @@ static int opXADD_l_a32(uint32_t fetchdat)
                 return 1;
         }
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         seteal(temp + cpu_state.regs[cpu_reg].l);   if (cpu_state.abrt) return 1;
         setadd32(temp, cpu_state.regs[cpu_reg].l);
index 241216b144ad66480fcb15e5b910d771913b9296..cd29b1405e5f4feb15f3ed914a6e8ac4a200e1ca 100644 (file)
@@ -1,14 +1,14 @@
 static int opAAA(uint32_t fetchdat)
 {
         flags_rebuild();
-        if ((flags & A_FLAG) || ((AL & 0xF) > 9))
+        if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9))
         {
                 AL += 6;
                 AH++;
-                flags |= (A_FLAG | C_FLAG);
+                cpu_state.flags |= (A_FLAG | C_FLAG);
         }
         else
-                flags &= ~(A_FLAG | C_FLAG);
+                cpu_state.flags &= ~(A_FLAG | C_FLAG);
         AL &= 0xF;
         CLOCK_CYCLES(is486 ? 3 : 4);
         PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0);
@@ -42,14 +42,14 @@ static int opAAM(uint32_t fetchdat)
 static int opAAS(uint32_t fetchdat)
 {
         flags_rebuild();
-        if ((flags & A_FLAG) || ((AL & 0xF) > 9))
+        if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9))
         {
                 AL -= 6;
                 AH--;
-                flags |= (A_FLAG | C_FLAG);
+                cpu_state.flags |= (A_FLAG | C_FLAG);
         }
         else
-                flags &= ~(A_FLAG | C_FLAG);
+                cpu_state.flags &= ~(A_FLAG | C_FLAG);
         AL &= 0xF;
         CLOCK_CYCLES(is486 ? 3 : 4);
         PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0);
@@ -61,23 +61,23 @@ static int opDAA(uint32_t fetchdat)
         uint16_t tempw;
         
         flags_rebuild();
-        if ((flags & A_FLAG) || ((AL & 0xf) > 9))
+        if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9))
         {
                 int tempi = ((uint16_t)AL) + 6;
                 AL += 6;
-                flags |= A_FLAG;
-                if (tempi & 0x100) flags |= C_FLAG;
+                cpu_state.flags |= A_FLAG;
+                if (tempi & 0x100) cpu_state.flags |= C_FLAG;
         }
-        if ((flags & C_FLAG) || (AL > 0x9f))
+        if ((cpu_state.flags & C_FLAG) || (AL > 0x9f))
         {
                 AL += 0x60;
-                flags |= C_FLAG;
+                cpu_state.flags |= C_FLAG;
         }
 
-        tempw = flags & (C_FLAG | A_FLAG);
+        tempw = cpu_state.flags & (C_FLAG | A_FLAG);
         setznp8(AL);
         flags_rebuild();
-        flags |= tempw;
+        cpu_state.flags |= tempw;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0);
         
@@ -89,23 +89,23 @@ static int opDAS(uint32_t fetchdat)
         uint16_t tempw;
 
         flags_rebuild();
-        if ((flags & A_FLAG) || ((AL & 0xf) > 9))
+        if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9))
         {
                 int tempi = ((uint16_t)AL) - 6;
                 AL -= 6;
-                flags |= A_FLAG;
-                if (tempi & 0x100) flags |= C_FLAG;
+                cpu_state.flags |= A_FLAG;
+                if (tempi & 0x100) cpu_state.flags |= C_FLAG;
         }
-        if ((flags & C_FLAG) || (AL > 0x9f))
+        if ((cpu_state.flags & C_FLAG) || (AL > 0x9f))
         {
                 AL -= 0x60;
-                flags |= C_FLAG;
+                cpu_state.flags |= C_FLAG;
         }
 
-        tempw = flags & (C_FLAG | A_FLAG);
+        tempw = cpu_state.flags & (C_FLAG | A_FLAG);
         setznp8(AL);
         flags_rebuild();
-        flags |= tempw;
+        cpu_state.flags |= tempw;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0);
         
index dc10b4f6c490db6779c38aa989a40fc4412adab9..a32c406b60f45d4c7c3a1019e4a04a45e27e8eb2 100644 (file)
@@ -3,11 +3,12 @@ static int opBT_w_r_a16(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2);     eal_r = 0;
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         flags_rebuild();
-        if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |=  C_FLAG;
-        else                                            flags &= ~C_FLAG;
+        if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |=  C_FLAG;
+        else                                                cpu_state.flags &= ~C_FLAG;
         
         CLOCK_CYCLES(3);
         PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 0);
@@ -18,11 +19,12 @@ static int opBT_w_r_a32(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2);     eal_r = 0;
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         flags_rebuild();
-        if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |=  C_FLAG;
-        else                                            flags &= ~C_FLAG;
+        if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |=  C_FLAG;
+        else                                                cpu_state.flags &= ~C_FLAG;
         
         CLOCK_CYCLES(3);
         PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 1);
@@ -33,11 +35,12 @@ static int opBT_l_r_a16(uint32_t fetchdat)
         uint32_t temp;
         
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4);     eal_r = 0;
         temp = geteal();                        if (cpu_state.abrt) return 1;
         flags_rebuild();
-        if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |=  C_FLAG;
-        else                                            flags &= ~C_FLAG;
+        if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |=  C_FLAG;
+        else                                                cpu_state.flags &= ~C_FLAG;
         
         CLOCK_CYCLES(3);
         PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 0);
@@ -48,11 +51,12 @@ static int opBT_l_r_a32(uint32_t fetchdat)
         uint32_t temp;
         
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4);     eal_r = 0;
         temp = geteal();                        if (cpu_state.abrt) return 1;
         flags_rebuild();
-        if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |=  C_FLAG;
-        else                                            flags &= ~C_FLAG;
+        if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |=  C_FLAG;
+        else                                                cpu_state.flags &= ~C_FLAG;
         
         CLOCK_CYCLES(3);
         PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 1);
@@ -66,14 +70,16 @@ static int opBT_l_r_a32(uint32_t fetchdat)
                 uint16_t temp;                                                  \
                                                                                 \
                 fetch_ea_16(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2);     eal_r = eal_w = 0;      \
                 temp = geteaw();                        if (cpu_state.abrt) return 1;     \
                 tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0;   \
                 temp operation (1 << (cpu_state.regs[cpu_reg].w & 15));             \
                 seteaw(temp);                           if (cpu_state.abrt) return 1;     \
                 flags_rebuild();                                                \
-                if (tempc) flags |=  C_FLAG;                                    \
-                else       flags &= ~C_FLAG;                                    \
+                if (tempc) cpu_state.flags |=  C_FLAG;                                    \
+                else       cpu_state.flags &= ~C_FLAG;                                    \
                                                                                 \
                 CLOCK_CYCLES(6);                                                \
                 PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 0);                          \
@@ -85,14 +91,16 @@ static int opBT_l_r_a32(uint32_t fetchdat)
                 uint16_t temp;                                                  \
                                                                                 \
                 fetch_ea_32(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2);     eal_r = eal_w = 0;      \
                 temp = geteaw();                        if (cpu_state.abrt) return 1;     \
                 tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0;   \
                 temp operation (1 << (cpu_state.regs[cpu_reg].w & 15));             \
                 seteaw(temp);                           if (cpu_state.abrt) return 1;     \
                 flags_rebuild();                                                \
-                if (tempc) flags |=  C_FLAG;                                    \
-                else       flags &= ~C_FLAG;                                    \
+                if (tempc) cpu_state.flags |=  C_FLAG;                                    \
+                else       cpu_state.flags &= ~C_FLAG;                                    \
                                                                                 \
                 CLOCK_CYCLES(6);                                                \
                 PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 1);                          \
@@ -104,14 +112,16 @@ static int opBT_l_r_a32(uint32_t fetchdat)
                 uint32_t temp;                                                  \
                                                                                 \
                 fetch_ea_16(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4);     eal_r = eal_w = 0;      \
                 temp = geteal();                        if (cpu_state.abrt) return 1;     \
                 tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0;   \
                 temp operation (1 << (cpu_state.regs[cpu_reg].l & 31));             \
                 seteal(temp);                           if (cpu_state.abrt) return 1;     \
                 flags_rebuild();                                                \
-                if (tempc) flags |=  C_FLAG;                                    \
-                else       flags &= ~C_FLAG;                                    \
+                if (tempc) cpu_state.flags |=  C_FLAG;                                    \
+                else       cpu_state.flags &= ~C_FLAG;                                    \
                                                                                 \
                 CLOCK_CYCLES(6);                                                \
                 PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 0);                          \
@@ -123,14 +133,16 @@ static int opBT_l_r_a32(uint32_t fetchdat)
                 uint32_t temp;                                                  \
                                                                                 \
                 fetch_ea_32(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4);     eal_r = eal_w = 0;      \
                 temp = geteal();                        if (cpu_state.abrt) return 1;     \
                 tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0;   \
                 temp operation (1 << (cpu_state.regs[cpu_reg].l & 31));             \
                 seteal(temp);                           if (cpu_state.abrt) return 1;     \
                 flags_rebuild();                                                \
-                if (tempc) flags |=  C_FLAG;                                    \
-                else       flags &= ~C_FLAG;                                    \
+                if (tempc) cpu_state.flags |=  C_FLAG;                                    \
+                else       cpu_state.flags &= ~C_FLAG;                                    \
                                                                                 \
                 CLOCK_CYCLES(6);                                                \
                 PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 1);                          \
@@ -147,7 +159,9 @@ static int opBA_w_a16(uint32_t fetchdat)
         uint16_t temp;
 
         fetch_ea_16(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         temp = geteaw();
         count = getbyte();                      if (cpu_state.abrt) return 1;
         tempc = temp & (1 << count);
@@ -155,8 +169,8 @@ static int opBA_w_a16(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x20: /*BT w,imm*/
-                if (tempc) flags |=  C_FLAG;
-                else       flags &= ~C_FLAG;
+                if (tempc) cpu_state.flags |=  C_FLAG;
+                else       cpu_state.flags &= ~C_FLAG;
                 CLOCK_CYCLES(3);
                 PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
                 return 0;
@@ -177,8 +191,8 @@ static int opBA_w_a16(uint32_t fetchdat)
                 break;
         }
         seteaw(temp);                           if (cpu_state.abrt) return 1;
-        if (tempc) flags |=  C_FLAG;
-        else       flags &= ~C_FLAG;
+        if (tempc) cpu_state.flags |=  C_FLAG;
+        else       cpu_state.flags &= ~C_FLAG;
         CLOCK_CYCLES(6);
         PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0);
         return 0;
@@ -189,7 +203,9 @@ static int opBA_w_a32(uint32_t fetchdat)
         uint16_t temp;
 
         fetch_ea_32(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         temp = geteaw();
         count = getbyte();                      if (cpu_state.abrt) return 1;
         tempc = temp & (1 << count);
@@ -197,8 +213,8 @@ static int opBA_w_a32(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x20: /*BT w,imm*/
-                if (tempc) flags |=  C_FLAG;
-                else       flags &= ~C_FLAG;
+                if (tempc) cpu_state.flags |=  C_FLAG;
+                else       cpu_state.flags &= ~C_FLAG;
                 CLOCK_CYCLES(3);
                 PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
                 return 0;
@@ -219,8 +235,8 @@ static int opBA_w_a32(uint32_t fetchdat)
                 break;
         }
         seteaw(temp);                           if (cpu_state.abrt) return 1;
-        if (tempc) flags |=  C_FLAG;
-        else       flags &= ~C_FLAG;
+        if (tempc) cpu_state.flags |=  C_FLAG;
+        else       cpu_state.flags &= ~C_FLAG;
         CLOCK_CYCLES(6);
         PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0);
         return 0;
@@ -232,7 +248,9 @@ static int opBA_l_a16(uint32_t fetchdat)
         uint32_t temp;
 
         fetch_ea_16(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         temp = geteal();
         count = getbyte();                      if (cpu_state.abrt) return 1;
         tempc = temp & (1 << count);
@@ -240,8 +258,8 @@ static int opBA_l_a16(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x20: /*BT w,imm*/
-                if (tempc) flags |=  C_FLAG;
-                else       flags &= ~C_FLAG;
+                if (tempc) cpu_state.flags |=  C_FLAG;
+                else       cpu_state.flags &= ~C_FLAG;
                 CLOCK_CYCLES(3);
                 PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0);
                 return 0;
@@ -262,8 +280,8 @@ static int opBA_l_a16(uint32_t fetchdat)
                 break;
         }
         seteal(temp);                           if (cpu_state.abrt) return 1;
-        if (tempc) flags |=  C_FLAG;
-        else       flags &= ~C_FLAG;
+        if (tempc) cpu_state.flags |=  C_FLAG;
+        else       cpu_state.flags &= ~C_FLAG;
         CLOCK_CYCLES(6);
         PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0);
         return 0;
@@ -274,7 +292,9 @@ static int opBA_l_a32(uint32_t fetchdat)
         uint32_t temp;
 
         fetch_ea_32(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         temp = geteal();
         count = getbyte();                      if (cpu_state.abrt) return 1;
         tempc = temp & (1 << count);
@@ -282,8 +302,8 @@ static int opBA_l_a32(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x20: /*BT w,imm*/
-                if (tempc) flags |=  C_FLAG;
-                else       flags &= ~C_FLAG;
+                if (tempc) cpu_state.flags |=  C_FLAG;
+                else       cpu_state.flags &= ~C_FLAG;
                 CLOCK_CYCLES(3);
                 PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1);
                 return 0;
@@ -304,8 +324,8 @@ static int opBA_l_a32(uint32_t fetchdat)
                 break;
         }
         seteal(temp);                           if (cpu_state.abrt) return 1;
-        if (tempc) flags |=  C_FLAG;
-        else       flags &= ~C_FLAG;
+        if (tempc) cpu_state.flags |=  C_FLAG;
+        else       cpu_state.flags &= ~C_FLAG;
         CLOCK_CYCLES(6);
         PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1);
         return 0;
index 12a8a79ad27897a43438b387e09a726bc09243b7..74f26dd38eeb974b3fef952a1b7c86fb2121e411 100644 (file)
@@ -4,7 +4,7 @@
         if (temp)                                                               \
         {                                                                       \
                 int c;                                                          \
-                flags &= ~Z_FLAG;                                               \
+                cpu_state.flags &= ~Z_FLAG;                                               \
                 for (c = start; c != end; c += dir)                             \
                 {                                                               \
                         CLOCK_CYCLES(time);                                     \
@@ -17,7 +17,7 @@
                 }                                                               \
         }                                                                       \
         else                                                                    \
-                flags |= Z_FLAG;
+                cpu_state.flags |= Z_FLAG;
 
 static int opBSF_w_a16(uint32_t fetchdat)
 {
@@ -25,6 +25,8 @@ static int opBSF_w_a16(uint32_t fetchdat)
         int instr_cycles;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         
         BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3);
@@ -40,6 +42,8 @@ static int opBSF_w_a32(uint32_t fetchdat)
         int instr_cycles;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         
         BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3);
@@ -55,6 +59,8 @@ static int opBSF_l_a16(uint32_t fetchdat)
         int instr_cycles;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         
         BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3);
@@ -70,6 +76,8 @@ static int opBSF_l_a32(uint32_t fetchdat)
         int instr_cycles;        
 
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         
         BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3);
@@ -86,6 +94,8 @@ static int opBSR_w_a16(uint32_t fetchdat)
         int instr_cycles;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         
         BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3);
@@ -101,6 +111,8 @@ static int opBSR_w_a32(uint32_t fetchdat)
         int instr_cycles;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         
         BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3);
@@ -116,6 +128,8 @@ static int opBSR_l_a16(uint32_t fetchdat)
         int instr_cycles;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         
         BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3);
@@ -131,6 +145,8 @@ static int opBSR_l_a32(uint32_t fetchdat)
         int instr_cycles;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         
         BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3);
index d1f61021cc95ad18b47f399aa0dfafac394a5285..0b7f5f0f5d13fd3d206b389cbdbaa3354ca79064 100644 (file)
@@ -1,11 +1,10 @@
 #define CALL_FAR_w(new_seg, new_pc)                                             \
         old_cs = CS;                                                            \
         old_pc = cpu_state.pc;                                                  \
-        oxpc = cpu_state.pc;                                                    \
         cpu_state.pc = new_pc;                                                  \
         optype = CALL;                                                          \
         cgate16 = cgate32 = 0;                                                  \
-        if (msw & 1) loadcscall(new_seg);                                       \
+        if (msw & 1) loadcscall(new_seg, old_pc);                               \
         else                                                                    \
         {                                                                       \
                 loadcs(new_seg);                                                \
         if (cgate32)                                                            \
         {                                                                       \
                 uint32_t old_esp = ESP;                                         \
-                PUSH_L(old_cs);                         if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; }     \
-                PUSH_L(old_pc);                         if (cpu_state.abrt) { ESP = old_esp; return 1; } \
+                PUSH_L(old_cs);                         if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; }     \
+                PUSH_L(old_pc);                         if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \
         }                                                                       \
         else                                                                    \
         {                                                                       \
                 uint32_t old_esp = ESP;                                         \
-                PUSH_W(old_cs);                         if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; }     \
-                PUSH_W(old_pc);                         if (cpu_state.abrt) { ESP = old_esp; return 1; } \
+                PUSH_W(old_cs);                         if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; }     \
+                PUSH_W(old_pc);                         if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \
         }
         
 #define CALL_FAR_l(new_seg, new_pc)                                             \
         old_cs = CS;                                                            \
         old_pc = cpu_state.pc;                                                  \
-        oxpc = cpu_state.pc;                                                    \
         cpu_state.pc = new_pc;                                                  \
         optype = CALL;                                                          \
         cgate16 = cgate32 = 0;                                                  \
-        if (msw & 1) loadcscall(new_seg);                                       \
+        if (msw & 1) loadcscall(new_seg, old_pc);                               \
         else                                                                    \
         {                                                                       \
                 loadcs(new_seg);                                                \
         if (cgate16)                                                            \
         {                                                                       \
                 uint32_t old_esp = ESP;                                         \
-                PUSH_W(old_cs);                         if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; }     \
-                PUSH_W(old_pc);                         if (cpu_state.abrt) { ESP = old_esp; return 1; } \
+                PUSH_W(old_cs);                         if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; }     \
+                PUSH_W(old_pc);                         if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \
         }                                                                       \
         else                                                                    \
         {                                                                       \
                 uint32_t old_esp = ESP;                                         \
-                PUSH_L(old_cs);                         if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; }     \
-                PUSH_L(old_pc);                         if (cpu_state.abrt) { ESP = old_esp; return 1; } \
+                PUSH_L(old_cs);                         if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; }     \
+                PUSH_L(old_pc);                         if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \
         }
         
        
@@ -104,6 +102,8 @@ static int opFF_w_a16(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x00: /*INC w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteaw();                        if (cpu_state.abrt) return 1;
                 seteaw(temp + 1);                       if (cpu_state.abrt) return 1;
                 setadd16nc(temp, 1);
@@ -111,6 +111,8 @@ static int opFF_w_a16(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0);
                 break;
                 case 0x08: /*DEC w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteaw();                        if (cpu_state.abrt) return 1;
                 seteaw(temp - 1);                       if (cpu_state.abrt) return 1;
                 setsub16nc(temp, 1);
@@ -118,6 +120,8 @@ static int opFF_w_a16(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0);
                 break;
                 case 0x10: /*CALL*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteaw();                      if (cpu_state.abrt) return 1;
                 PUSH_W(cpu_state.pc);
                 cpu_state.pc = new_pc;
@@ -128,6 +132,8 @@ static int opFF_w_a16(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x18: /*CALL far*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = readmemw(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1;
                 
@@ -137,6 +143,8 @@ static int opFF_w_a16(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x20: /*JMP*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteaw();                      if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
                 CPU_BLOCK_END();
@@ -146,16 +154,20 @@ static int opFF_w_a16(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x28: /*JMP far*/
-                oxpc = cpu_state.pc;
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
+                old_pc = cpu_state.pc;
                 new_pc = readmemw(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, cpu_state.eaaddr + 2);  if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
-                loadcsjmp(new_cs, oxpc);               if (cpu_state.abrt) return 1;
+                loadcsjmp(new_cs, old_pc);               if (cpu_state.abrt) return 1;
                 CPU_BLOCK_END();
                 PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 0);
                 PREFETCH_FLUSH();
                 break;
                 case 0x30: /*PUSH w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 temp = geteaw();                        if (cpu_state.abrt) return 1;
                 PUSH_W(temp);
                 CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5);
@@ -181,6 +193,8 @@ static int opFF_w_a32(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x00: /*INC w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteaw();                        if (cpu_state.abrt) return 1;
                 seteaw(temp + 1);                       if (cpu_state.abrt) return 1;
                 setadd16nc(temp, 1);
@@ -188,6 +202,8 @@ static int opFF_w_a32(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1);
                 break;
                 case 0x08: /*DEC w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteaw();                        if (cpu_state.abrt) return 1;
                 seteaw(temp - 1);                       if (cpu_state.abrt) return 1;
                 setsub16nc(temp, 1);
@@ -195,6 +211,8 @@ static int opFF_w_a32(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1);
                 break;
                 case 0x10: /*CALL*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteaw();                      if (cpu_state.abrt) return 1;
                 PUSH_W(cpu_state.pc);
                 cpu_state.pc = new_pc;
@@ -205,6 +223,8 @@ static int opFF_w_a32(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x18: /*CALL far*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = readmemw(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1;
                 
@@ -214,6 +234,8 @@ static int opFF_w_a32(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x20: /*JMP*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteaw();                      if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
                 CPU_BLOCK_END();
@@ -223,16 +245,20 @@ static int opFF_w_a32(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x28: /*JMP far*/
-                oxpc = cpu_state.pc;
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
+                old_pc = cpu_state.pc;
                 new_pc = readmemw(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, cpu_state.eaaddr + 2);  if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
-                loadcsjmp(new_cs, oxpc);               if (cpu_state.abrt) return 1;
+                loadcsjmp(new_cs, old_pc);               if (cpu_state.abrt) return 1;
                 CPU_BLOCK_END();
                 PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 1);
                 PREFETCH_FLUSH();
                 break;
                 case 0x30: /*PUSH w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 temp = geteaw();                        if (cpu_state.abrt) return 1;
                 PUSH_W(temp);
                 CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5);
@@ -259,6 +285,8 @@ static int opFF_l_a16(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x00: /*INC l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteal();                        if (cpu_state.abrt) return 1;
                 seteal(temp + 1);                       if (cpu_state.abrt) return 1;
                 setadd32nc(temp, 1);
@@ -266,6 +294,8 @@ static int opFF_l_a16(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0);
                 break;
                 case 0x08: /*DEC l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteal();                        if (cpu_state.abrt) return 1;
                 seteal(temp - 1);                       if (cpu_state.abrt) return 1;
                 setsub32nc(temp, 1);
@@ -273,6 +303,8 @@ static int opFF_l_a16(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0);
                 break;
                 case 0x10: /*CALL*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteal();                      if (cpu_state.abrt) return 1;
                 PUSH_L(cpu_state.pc);
                 cpu_state.pc = new_pc;
@@ -283,6 +315,8 @@ static int opFF_l_a16(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x18: /*CALL far*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = readmeml(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1;
                 
@@ -292,6 +326,8 @@ static int opFF_l_a16(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x20: /*JMP*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteal();                      if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
                 CPU_BLOCK_END();
@@ -301,16 +337,20 @@ static int opFF_l_a16(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x28: /*JMP far*/
-                oxpc = cpu_state.pc;
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
+                old_pc = cpu_state.pc;
                 new_pc = readmeml(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, cpu_state.eaaddr + 4);   if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
-                loadcsjmp(new_cs, oxpc);                if (cpu_state.abrt) return 1;
+                loadcsjmp(new_cs, old_pc);                if (cpu_state.abrt) return 1;
                 CPU_BLOCK_END();
                 PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 0);
                 PREFETCH_FLUSH();
                 break;
                 case 0x30: /*PUSH l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 temp = geteal();                        if (cpu_state.abrt) return 1;
                 PUSH_L(temp);
                 CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5);
@@ -336,6 +376,8 @@ static int opFF_l_a32(uint32_t fetchdat)
         switch (rmdat & 0x38)
         {
                 case 0x00: /*INC l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteal();                        if (cpu_state.abrt) return 1;
                 seteal(temp + 1);                       if (cpu_state.abrt) return 1;
                 setadd32nc(temp, 1);
@@ -343,6 +385,8 @@ static int opFF_l_a32(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1);
                 break;
                 case 0x08: /*DEC l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 temp = geteal();                        if (cpu_state.abrt) return 1;
                 seteal(temp - 1);                       if (cpu_state.abrt) return 1;
                 setsub32nc(temp, 1);
@@ -350,6 +394,8 @@ static int opFF_l_a32(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1);
                 break;
                 case 0x10: /*CALL*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteal();                      if (cpu_state.abrt) return 1;
                 PUSH_L(cpu_state.pc);                             if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
@@ -360,6 +406,8 @@ static int opFF_l_a32(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x18: /*CALL far*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = readmeml(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1;
                 
@@ -369,6 +417,8 @@ static int opFF_l_a32(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x20: /*JMP*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 new_pc = geteal();                      if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
                 CPU_BLOCK_END();
@@ -378,16 +428,20 @@ static int opFF_l_a32(uint32_t fetchdat)
                 PREFETCH_FLUSH();
                 break;
                 case 0x28: /*JMP far*/
-                oxpc = cpu_state.pc;
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
+                old_pc = cpu_state.pc;
                 new_pc = readmeml(easeg, cpu_state.eaaddr);
                 new_cs = readmemw(easeg, cpu_state.eaaddr + 4);   if (cpu_state.abrt) return 1;
                 cpu_state.pc = new_pc;
-                loadcsjmp(new_cs, oxpc);                if (cpu_state.abrt) return 1;
+                loadcsjmp(new_cs, old_pc);                if (cpu_state.abrt) return 1;
                 CPU_BLOCK_END();
                 PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1);
                 PREFETCH_FLUSH();
                 break;
                 case 0x30: /*PUSH l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 temp = geteal();                        if (cpu_state.abrt) return 1;
                 PUSH_L(temp);
                 PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1);
index 91fce5115bdfd4585c6578fb0667e5c6194ddcfe..d21408c8bf440d25032786b69e7d40276ac10a4c 100644 (file)
@@ -1,7 +1,7 @@
 static int opCMC(uint32_t fetchdat)
 {
         flags_rebuild();
-        flags ^= C_FLAG;
+        cpu_state.flags ^= C_FLAG;
         CLOCK_CYCLES(2);
         PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0);
         return 0;
@@ -11,14 +11,14 @@ static int opCMC(uint32_t fetchdat)
 static int opCLC(uint32_t fetchdat)
 {
         flags_rebuild();
-        flags &= ~C_FLAG;
+        cpu_state.flags &= ~C_FLAG;
         CLOCK_CYCLES(2);
         PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0);
         return 0;
 }
 static int opCLD(uint32_t fetchdat)
 {
-        flags &= ~D_FLAG;
+        cpu_state.flags &= ~D_FLAG;
         CLOCK_CYCLES(2);
         PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0);
         return 0;
@@ -27,10 +27,10 @@ static int opCLI(uint32_t fetchdat)
 {
         if (!IOPLp)
         {
-                if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || 
-                        ((eflags & VM_FLAG) && (cr4 & CR4_VME)))
+                if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) ||
+                        ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME)))
                 {
-                        eflags &= ~VIF_FLAG;
+                        cpu_state.eflags &= ~VIF_FLAG;
                 }
                 else
                 {
@@ -39,7 +39,7 @@ static int opCLI(uint32_t fetchdat)
                 }
         }
         else
-                flags &= ~I_FLAG;
+                cpu_state.flags &= ~I_FLAG;
          
         CLOCK_CYCLES(3);
         PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0);
@@ -49,14 +49,14 @@ static int opCLI(uint32_t fetchdat)
 static int opSTC(uint32_t fetchdat)
 {
         flags_rebuild();
-        flags |= C_FLAG;
+        cpu_state.flags |= C_FLAG;
         CLOCK_CYCLES(2);
         PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0);
         return 0;
 }
 static int opSTD(uint32_t fetchdat)
 {
-        flags |= D_FLAG;
+        cpu_state.flags |= D_FLAG;
         CLOCK_CYCLES(2);
         PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0);
         return 0;
@@ -65,16 +65,16 @@ static int opSTI(uint32_t fetchdat)
 {
         if (!IOPLp)
         {
-                if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || 
-                        ((eflags & VM_FLAG) && (cr4 & CR4_VME)))
+                if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) ||
+                        ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME)))
                 {
-                        if (eflags & VIP_FLAG)
+                        if (cpu_state.eflags & VIP_FLAG)
                         {
                                 x86gpf(NULL,0);
                                 return 1;
                         }
                         else
-                                eflags |= VIF_FLAG;
+                                cpu_state.eflags |= VIF_FLAG;
                 }
                 else
                 {
@@ -83,7 +83,7 @@ static int opSTI(uint32_t fetchdat)
                 }
         }
         else
-                flags |= I_FLAG;
+                cpu_state.flags |= I_FLAG;
 
         CPU_BLOCK_END();
                                 
@@ -95,7 +95,7 @@ static int opSTI(uint32_t fetchdat)
 static int opSAHF(uint32_t fetchdat)
 {
         flags_rebuild();
-        flags = (flags & 0xff00) | (AH & 0xd5) | 2;
+        cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2;
         CLOCK_CYCLES(3);
         PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0);
         
@@ -106,7 +106,7 @@ static int opSAHF(uint32_t fetchdat)
 static int opLAHF(uint32_t fetchdat)
 {
         flags_rebuild();
-        AH = flags & 0xff;
+        AH = cpu_state.flags & 0xff;
         CLOCK_CYCLES(3);
         PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0);
         return 0;
@@ -114,15 +114,15 @@ static int opLAHF(uint32_t fetchdat)
 
 static int opPUSHF(uint32_t fetchdat)
 {
-        if ((eflags & VM_FLAG) && (IOPL < 3))
+        if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3))
         {
                 if (cr4 & CR4_VME)
                 {
                         uint16_t temp;
 
                         flags_rebuild();
-                        temp = (flags & ~I_FLAG) | 0x3000;
-                        if (eflags & VIF_FLAG)
+                        temp = (cpu_state.flags & ~I_FLAG) | 0x3000;
+                        if (cpu_state.eflags & VIF_FLAG)
                                 temp |= I_FLAG;
                         PUSH_W(temp);
                 }
@@ -135,7 +135,7 @@ static int opPUSHF(uint32_t fetchdat)
         else
         {
                 flags_rebuild();
-                PUSH_W(flags);
+                PUSH_W(cpu_state.flags);
         }
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0);
@@ -144,16 +144,16 @@ static int opPUSHF(uint32_t fetchdat)
 static int opPUSHFD(uint32_t fetchdat)
 {
         uint16_t tempw;
-        if ((eflags & VM_FLAG) && (IOPL < 3))
+        if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3))
         {
                 x86gpf(NULL, 0);
                 return 1;
         }
-        if (cpu_CR4_mask & CR4_VME) tempw = eflags & 0x3c;
-        else if (CPUID)             tempw = eflags & 0x24;
-        else                        tempw = eflags & 4;
+        if (cpu_CR4_mask & CR4_VME) tempw = cpu_state.eflags & 0x3c;
+        else if (CPUID)             tempw = cpu_state.eflags & 0x24;
+        else                        tempw = cpu_state.eflags & 4;
         flags_rebuild();
-        PUSH_L(flags | (tempw << 16));
+        PUSH_L(cpu_state.flags | (tempw << 16));
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0);
         return cpu_state.abrt;
@@ -163,7 +163,7 @@ static int opPOPF_286(uint32_t fetchdat)
 {
         uint16_t tempw;
         
-        if ((eflags & VM_FLAG) && (IOPL < 3))
+        if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3))
         {
                 x86gpf(NULL, 0);
                 return 1;
@@ -171,10 +171,10 @@ static int opPOPF_286(uint32_t fetchdat)
         
         tempw = POP_W();                if (cpu_state.abrt) return 1;
 
-        if (!(msw & 1))           flags = (flags & 0x7000) | (tempw & 0x0fd5) | 2;
-        else if (!(CPL))          flags = (tempw & 0x7fd5) | 2;
-        else if (IOPLp)           flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2;
-        else                      flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2;
+        if (!(msw & 1))           cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2;
+        else if (!(CPL))          cpu_state.flags = (tempw & 0x7fd5) | 2;
+        else if (IOPLp)           cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2;
+        else                      cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2;
         flags_extract();
 
         CLOCK_CYCLES(5);
@@ -188,7 +188,7 @@ static int opPOPF(uint32_t fetchdat)
 {
         uint16_t tempw;
         
-        if ((eflags & VM_FLAG) && (IOPL < 3))
+        if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3))
         {
                 if (cr4 & CR4_VME)
                 {
@@ -201,17 +201,17 @@ static int opPOPF(uint32_t fetchdat)
                                 return 1;
                         }
 
-                        if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (eflags & VIP_FLAG)))
+                        if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (cpu_state.eflags & VIP_FLAG)))
                         {
                                 ESP = old_esp;
                                 x86gpf(NULL, 0);
                                 return 1;
                         }
                         if (tempw & I_FLAG)
-                                eflags |= VIF_FLAG;
+                                cpu_state.eflags |= VIF_FLAG;
                         else
-                                eflags &= ~VIF_FLAG;
-                        flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2;
+                                cpu_state.eflags &= ~VIF_FLAG;
+                        cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2;
                 }
                 else
                 {
@@ -226,11 +226,11 @@ static int opPOPF(uint32_t fetchdat)
                         return 1;
 
                 if (!(CPL) || !(msw & 1))
-                        flags = (tempw & 0x7fd5) | 2;
+                        cpu_state.flags = (tempw & 0x7fd5) | 2;
                 else if (IOPLp)
-                        flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2;
+                        cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2;
                 else
-                        flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2;
+                        cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2;
         }
         flags_extract();
 
@@ -245,7 +245,7 @@ static int opPOPFD(uint32_t fetchdat)
 {
         uint32_t templ;
         
-        if ((eflags & VM_FLAG) && (IOPL < 3))
+        if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3))
         {
                 x86gpf(NULL, 0);
                 return 1;
@@ -253,16 +253,16 @@ static int opPOPFD(uint32_t fetchdat)
         
         templ = POP_L();                if (cpu_state.abrt) return 1;
 
-        if (!(CPL) || !(msw & 1)) flags = (templ & 0x7fd5) | 2;
-        else if (IOPLp)           flags = (flags & 0x3000) | (templ & 0x4fd5) | 2;
-        else                      flags = (flags & 0x3200) | (templ & 0x4dd5) | 2;
+        if (!(CPL) || !(msw & 1)) cpu_state.flags = (templ & 0x7fd5) | 2;
+        else if (IOPLp)           cpu_state.flags = (cpu_state.flags & 0x3000) | (templ & 0x4fd5) | 2;
+        else                      cpu_state.flags = (cpu_state.flags & 0x3200) | (templ & 0x4dd5) | 2;
         
         templ &= is486 ? 0x3c0000 : 0;
-        templ |= ((eflags&3) << 16);
-        if (cpu_CR4_mask & CR4_VME) eflags = (templ >> 16) & 0x3f;
-        else if (CPUID)             eflags = (templ >> 16) & 0x27;
-        else if (is486)             eflags = (templ >> 16) & 7;
-        else                        eflags = (templ >> 16) & 3;
+        templ |= ((cpu_state.eflags&3) << 16);
+        if (cpu_CR4_mask & CR4_VME) cpu_state.eflags = (templ >> 16) & 0x3f;
+        else if (CPUID)             cpu_state.eflags = (templ >> 16) & 0x27;
+        else if (is486)             cpu_state.eflags = (templ >> 16) & 7;
+        else                        cpu_state.eflags = (templ >> 16) & 3;
         
         flags_extract();
 
index 56293c7bfa9a3bbaae03c742f38706f6a7513fdf..d14bae863871748c1b9e8a51aa6394909ccc2ed9 100644 (file)
@@ -50,6 +50,8 @@ static int opINCDEC_b_a16(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_16(fetchdat);       
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp=geteab();                  if (cpu_state.abrt) return 1;
 
         if (rmdat&0x38)
@@ -71,6 +73,8 @@ static int opINCDEC_b_a32(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_32(fetchdat);       
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp=geteab();                  if (cpu_state.abrt) return 1;
 
         if (rmdat&0x38)
index ff8830ee6fea3a34de49e772bc42a1590ee1a65e..97793405ce007b39b56fe41334968e07799be176 100644 (file)
@@ -1,7 +1,7 @@
 static int opINT3(uint32_t fetchdat)
 {
         int cycles_old = cycles; UNUSED(cycles_old);
-        if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
+        if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3))
         {
                 x86gpf(NULL,0);
                 return 1;
@@ -15,7 +15,7 @@ static int opINT3(uint32_t fetchdat)
 static int opINT1(uint32_t fetchdat)
 {
         int cycles_old = cycles; UNUSED(cycles_old);
-        if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
+        if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3))
         {
                 x86gpf(NULL,0);
                 return 1;
@@ -31,7 +31,7 @@ static int opINT(uint32_t fetchdat)
         int cycles_old = cycles; UNUSED(cycles_old);
         uint8_t temp = getbytef();
 
-        if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
+        if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3))
         {
                 if (cr4 & CR4_VME)
                 {
@@ -104,7 +104,7 @@ static int opINTO(uint32_t fetchdat)
 {
         int cycles_old = cycles; UNUSED(cycles_old);
         
-        if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
+        if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3))
         {
                 x86gpf(NULL,0);
                 return 1;
index 93987633e06a7b9e68448f00b961b2d3d74b53c6..4b4a1c3bde7d3030a408bb1c5a33fe836d389699 100644 (file)
@@ -23,6 +23,8 @@
                 if (cond_ ## condition)                 \
                 {                                       \
                         cpu_state.pc += offset;         \
+                        if (!(cpu_state.op32 & 0x100))  \
+                                cpu_state.pc &= 0xffff; \
                         CLOCK_CYCLES_ALWAYS(timing_bt); \
                         CPU_BLOCK_END();                \
                         PREFETCH_RUN(timing_bt+timing_bnt, 2, -1, 0,0,0,0, 0); \
@@ -40,6 +42,7 @@
                 if (cond_ ## condition)                 \
                 {                                       \
                         cpu_state.pc += offset;         \
+                        cpu_state.pc &= 0xffff;         \
                         CLOCK_CYCLES_ALWAYS(timing_bt); \
                         CPU_BLOCK_END();                \
                         PREFETCH_RUN(timing_bt+timing_bnt, 3, -1, 0,0,0,0, 0); \
@@ -95,6 +98,8 @@ static int opLOOPNE_w(uint32_t fetchdat)
         if (CX && !ZF_SET())
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CPU_BLOCK_END();
                 PREFETCH_FLUSH();
                 return 1;
@@ -110,6 +115,8 @@ static int opLOOPNE_l(uint32_t fetchdat)
         if (ECX && !ZF_SET()) 
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CPU_BLOCK_END();
                 PREFETCH_FLUSH();
                 return 1;
@@ -126,6 +133,8 @@ static int opLOOPE_w(uint32_t fetchdat)
         if (CX && ZF_SET())
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CPU_BLOCK_END();
                 PREFETCH_FLUSH();
                 return 1;
@@ -141,6 +150,8 @@ static int opLOOPE_l(uint32_t fetchdat)
         if (ECX && ZF_SET())
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CPU_BLOCK_END();
                 PREFETCH_FLUSH();
                 return 1;
@@ -157,6 +168,8 @@ static int opLOOP_w(uint32_t fetchdat)
         if (CX)
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CPU_BLOCK_END();
                 PREFETCH_FLUSH();
                 return 1;
@@ -172,6 +185,8 @@ static int opLOOP_l(uint32_t fetchdat)
         if (ECX)
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CPU_BLOCK_END();
                 PREFETCH_FLUSH();
                 return 1;
@@ -186,6 +201,8 @@ static int opJCXZ(uint32_t fetchdat)
         if (!CX)
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CLOCK_CYCLES(4);
                 CPU_BLOCK_END();
                 PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0);
@@ -202,6 +219,8 @@ static int opJECXZ(uint32_t fetchdat)
         if (!ECX)
         {
                 cpu_state.pc += offset;
+                if (!(cpu_state.op32 & 0x100))
+                        cpu_state.pc &= 0xffff;
                 CLOCK_CYCLES(4);
                 CPU_BLOCK_END();
                 PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0);
@@ -217,6 +236,8 @@ static int opJMP_r8(uint32_t fetchdat)
 {
         int8_t offset = (int8_t)getbytef();
         cpu_state.pc += offset;
+        if (!(cpu_state.op32 & 0x100))
+                cpu_state.pc &= 0xffff;
         CPU_BLOCK_END();
         CLOCK_CYCLES((is486) ? 3 : 7);
         PREFETCH_RUN(7, 2, -1, 0,0,0,0, 0);
@@ -227,6 +248,7 @@ static int opJMP_r16(uint32_t fetchdat)
 {
         int16_t offset = (int16_t)getwordf();
         cpu_state.pc += offset;
+        cpu_state.pc &= 0xffff;
         CPU_BLOCK_END();
         CLOCK_CYCLES((is486) ? 3 : 7);
         PREFETCH_RUN(7, 3, -1, 0,0,0,0, 0);
@@ -248,9 +270,9 @@ static int opJMP_far_a16(uint32_t fetchdat)
 {
         uint16_t addr = getwordf();
         uint16_t seg = getword();                       if (cpu_state.abrt) return 1;
-        uint32_t oxpc = cpu_state.pc;
+        uint32_t old_pc = cpu_state.pc;
         cpu_state.pc = addr;
-        loadcsjmp(seg, oxpc);
+        loadcsjmp(seg, old_pc);
         CPU_BLOCK_END();
         PREFETCH_RUN(11, 5, -1, 0,0,0,0, 0);
         PREFETCH_FLUSH();
@@ -260,9 +282,9 @@ static int opJMP_far_a32(uint32_t fetchdat)
 {
         uint32_t addr = getlong();
         uint16_t seg = getword();                       if (cpu_state.abrt) return 1;
-        uint32_t oxpc = cpu_state.pc;
+        uint32_t old_pc = cpu_state.pc;
         cpu_state.pc = addr;
-        loadcsjmp(seg, oxpc);
+        loadcsjmp(seg, old_pc);
         CPU_BLOCK_END();
         PREFETCH_RUN(11, 7, -1, 0,0,0,0, 0);
         PREFETCH_FLUSH();
@@ -274,6 +296,7 @@ static int opCALL_r16(uint32_t fetchdat)
         int16_t addr = (int16_t)getwordf();
         PUSH_W(cpu_state.pc);
         cpu_state.pc += addr;
+        cpu_state.pc &= 0xffff;
         CPU_BLOCK_END();
         CLOCK_CYCLES((is486) ? 3 : 7);
         PREFETCH_RUN(7, 3, -1, 0,0,1,0, 0);
index 1e0410ac0bdc56505088409db1a18c23b8a04612..9e281f2e540d55ef08c19531198980ac7eb06bbf 100644 (file)
@@ -54,6 +54,7 @@ static int opF6_a16(uint32_t fetchdat)
         fetch_ea_16(fetchdat);
         if (cpu_mod != 3)
         {
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
         }
         dst = geteab();                 if (cpu_state.abrt) return 1;
@@ -68,11 +69,15 @@ static int opF6_a16(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
                 break;
                 case 0x10: /*NOT b*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteab(~dst);                           if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0);
                 break;
                 case 0x18: /*NEG b*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteab(0 - dst);                        if (cpu_state.abrt) return 1;
                 setsub8(0, dst);
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
@@ -81,8 +86,8 @@ static int opF6_a16(uint32_t fetchdat)
                 case 0x20: /*MUL AL,b*/
                 AX = AL * dst;
                 flags_rebuild();
-                if (AH) flags |=  (C_FLAG | V_FLAG);
-                else    flags &= ~(C_FLAG | V_FLAG);
+                if (AH) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else    cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(13);
                 PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
                 break;
@@ -90,8 +95,8 @@ static int opF6_a16(uint32_t fetchdat)
                 tempws = (int)((int8_t)AL) * (int)((int8_t)dst);
                 AX = tempws & 0xffff;
                 flags_rebuild();
-                if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |=  (C_FLAG | V_FLAG);
-                else                                                     flags &= ~(C_FLAG | V_FLAG);
+                if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else                                                     cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(14);
                 PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
                 break;
@@ -105,8 +110,8 @@ static int opF6_a16(uint32_t fetchdat)
                         if (!cpu_iscyrix) 
                         {
                                 flags_rebuild();
-                                flags |= 0x8D5; /*Not a Cyrix*/
-                                flags &= ~1;
+                                cpu_state.flags |= 0x8D5; /*Not a Cyrix*/
+                                cpu_state.flags &= ~1;
                         }
                 }
                 else
@@ -128,8 +133,8 @@ static int opF6_a16(uint32_t fetchdat)
                         if (!cpu_iscyrix) 
                         {
                                 flags_rebuild();
-                                flags|=0x8D5; /*Not a Cyrix*/
-                                flags &= ~1;
+                                cpu_state.flags|=0x8D5; /*Not a Cyrix*/
+                                cpu_state.flags &= ~1;
                         }
                 }
                 else
@@ -156,6 +161,8 @@ static int opF6_a32(uint32_t fetchdat)
         int8_t temps;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteab();                 if (cpu_state.abrt) return 1;
         switch (rmdat & 0x38)
         {
@@ -168,11 +175,15 @@ static int opF6_a32(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
                 break;
                 case 0x10: /*NOT b*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteab(~dst);                           if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1);
                 break;
                 case 0x18: /*NEG b*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteab(0 - dst);                        if (cpu_state.abrt) return 1;
                 setsub8(0, dst);
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
@@ -181,8 +192,8 @@ static int opF6_a32(uint32_t fetchdat)
                 case 0x20: /*MUL AL,b*/
                 AX = AL * dst;
                 flags_rebuild();
-                if (AH) flags |=  (C_FLAG | V_FLAG);
-                else    flags &= ~(C_FLAG | V_FLAG);
+                if (AH) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else    cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(13);
                 PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
                 break;
@@ -190,8 +201,8 @@ static int opF6_a32(uint32_t fetchdat)
                 tempws = (int)((int8_t)AL) * (int)((int8_t)dst);
                 AX = tempws & 0xffff;
                 flags_rebuild();
-                if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |=  (C_FLAG | V_FLAG);
-                else                                                     flags &= ~(C_FLAG | V_FLAG);
+                if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else                                                     cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(14);
                 PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
                 break;
@@ -205,8 +216,8 @@ static int opF6_a32(uint32_t fetchdat)
                         if (!cpu_iscyrix) 
                         {
                                 flags_rebuild();
-                                flags |= 0x8D5; /*Not a Cyrix*/
-                                flags &= ~1;
+                                cpu_state.flags |= 0x8D5; /*Not a Cyrix*/
+                                cpu_state.flags &= ~1;
                         }
                 }
                 else
@@ -228,8 +239,8 @@ static int opF6_a32(uint32_t fetchdat)
                         if (!cpu_iscyrix) 
                         {
                                 flags_rebuild();
-                                flags|=0x8D5; /*Not a Cyrix*/
-                                flags &= ~1;
+                                cpu_state.flags |= 0x8D5; /*Not a Cyrix*/
+                                cpu_state.flags &= ~1;
                         }
                 }
                 else
@@ -259,6 +270,8 @@ static int opF7_w_a16(uint32_t fetchdat)
         uint16_t src, dst;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteaw();        if (cpu_state.abrt) return 1;
         switch (rmdat & 0x38)
         {
@@ -271,11 +284,15 @@ static int opF7_w_a16(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
                 break;
                 case 0x10: /*NOT w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(~dst);           if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0);
                 break;
                 case 0x18: /*NEG w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(0 - dst);        if (cpu_state.abrt) return 1;
                 setsub16(0, dst);
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
@@ -286,8 +303,8 @@ static int opF7_w_a16(uint32_t fetchdat)
                 AX = templ & 0xFFFF;
                 DX = templ >> 16;
                 flags_rebuild();
-                if (DX)    flags |=  (C_FLAG | V_FLAG);
-                else       flags &= ~(C_FLAG | V_FLAG);
+                if (DX)    cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else       cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(21);
                 PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
                 break;
@@ -296,8 +313,8 @@ static int opF7_w_a16(uint32_t fetchdat)
                 AX = templ & 0xFFFF;
                 DX = templ >> 16;
                 flags_rebuild();
-                if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |=  (C_FLAG | V_FLAG);
-                else                                                             flags &= ~(C_FLAG | V_FLAG);
+                if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else                                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(22);
                 PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
                 break;
@@ -353,6 +370,8 @@ static int opF7_w_a32(uint32_t fetchdat)
         uint16_t src, dst;
 
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteaw();        if (cpu_state.abrt) return 1;
         switch (rmdat & 0x38)
         {
@@ -365,11 +384,15 @@ static int opF7_w_a32(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
                 break;
                 case 0x10: /*NOT w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(~dst);           if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1);
                 break;
                 case 0x18: /*NEG w*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(0 - dst);        if (cpu_state.abrt) return 1;
                 setsub16(0, dst);
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm);
@@ -380,8 +403,8 @@ static int opF7_w_a32(uint32_t fetchdat)
                 AX = templ & 0xFFFF;
                 DX = templ >> 16;
                 flags_rebuild();
-                if (DX)    flags |=  (C_FLAG | V_FLAG);
-                else       flags &= ~(C_FLAG | V_FLAG);
+                if (DX)    cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else       cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(21);
                 PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
                 break;
@@ -390,8 +413,8 @@ static int opF7_w_a32(uint32_t fetchdat)
                 AX = templ & 0xFFFF;
                 DX = templ >> 16;
                 flags_rebuild();
-                if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |=  (C_FLAG | V_FLAG);
-                else                                                             flags &= ~(C_FLAG | V_FLAG);
+                if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else                                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(22);
                 PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
                 break;
@@ -446,6 +469,8 @@ static int opF7_l_a16(uint32_t fetchdat)
         uint32_t src, dst;
 
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteal();                 if (cpu_state.abrt) return 1;
 
         switch (rmdat & 0x38)
@@ -459,11 +484,15 @@ static int opF7_l_a16(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0);
                 break;
                 case 0x10: /*NOT l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteal(~dst);           if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml);
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0);
                 break;
                 case 0x18: /*NEG l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteal(0 - dst);        if (cpu_state.abrt) return 1;
                 setsub32(0, dst);
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml);
@@ -474,8 +503,8 @@ static int opF7_l_a16(uint32_t fetchdat)
                 EAX = temp64 & 0xffffffff;
                 EDX = temp64 >> 32;
                 flags_rebuild();
-                if (EDX) flags |=  (C_FLAG|V_FLAG);
-                else     flags &= ~(C_FLAG|V_FLAG);
+                if (EDX) cpu_state.flags |=  (C_FLAG|V_FLAG);
+                else     cpu_state.flags &= ~(C_FLAG|V_FLAG);
                 CLOCK_CYCLES(21);
                 PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0);
                 break;
@@ -484,8 +513,8 @@ static int opF7_l_a16(uint32_t fetchdat)
                 EAX = temp64 & 0xffffffff;
                 EDX = temp64 >> 32;
                 flags_rebuild();
-                if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |=  (C_FLAG | V_FLAG);
-                else                                                               flags &= ~(C_FLAG | V_FLAG);
+                if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else                                                               cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(38);
                 PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0);
                 break;
@@ -516,6 +545,8 @@ static int opF7_l_a32(uint32_t fetchdat)
         uint32_t src, dst;
 
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         dst = geteal();                 if (cpu_state.abrt) return 1;
 
         switch (rmdat & 0x38)
@@ -529,11 +560,15 @@ static int opF7_l_a32(uint32_t fetchdat)
                 PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1);
                 break;
                 case 0x10: /*NOT l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteal(~dst);           if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml);
                 PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1);
                 break;
                 case 0x18: /*NEG l*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteal(0 - dst);        if (cpu_state.abrt) return 1;
                 setsub32(0, dst);
                 CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml);
@@ -544,8 +579,8 @@ static int opF7_l_a32(uint32_t fetchdat)
                 EAX = temp64 & 0xffffffff;
                 EDX = temp64 >> 32;
                 flags_rebuild();
-                if (EDX) flags |=  (C_FLAG|V_FLAG);
-                else     flags &= ~(C_FLAG|V_FLAG);
+                if (EDX) cpu_state.flags |=  (C_FLAG|V_FLAG);
+                else     cpu_state.flags &= ~(C_FLAG|V_FLAG);
                 CLOCK_CYCLES(21);
                 PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1);
                 break;
@@ -554,8 +589,8 @@ static int opF7_l_a32(uint32_t fetchdat)
                 EAX = temp64 & 0xffffffff;
                 EDX = temp64 >> 32;
                 flags_rebuild();
-                if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |=  (C_FLAG | V_FLAG);
-                else                                                               flags &= ~(C_FLAG | V_FLAG);
+                if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |=  (C_FLAG | V_FLAG);
+                else                                                               cpu_state.flags &= ~(C_FLAG | V_FLAG);
                 CLOCK_CYCLES(38);
                 PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1);
                 break;
@@ -584,12 +619,12 @@ static int opF7_l_a32(uint32_t fetchdat)
 
 static int opHLT(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 x86gpf(NULL,0);
                 return 1;
         }
-        if (!((flags&I_FLAG) && pic_intpending))
+        if (!((cpu_state.flags & I_FLAG) && pic_intpending))
         {
                 CLOCK_CYCLES_ALWAYS(100);
                 cpu_state.pc--;
@@ -625,6 +660,7 @@ static int opBOUND_w_a16(uint32_t fetchdat)
         
         fetch_ea_16(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         low = geteaw();
         high = readmemw(easeg, cpu_state.eaaddr + 2);     if (cpu_state.abrt) return 1;
         
@@ -644,6 +680,7 @@ static int opBOUND_w_a32(uint32_t fetchdat)
         
         fetch_ea_32(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         low = geteaw();
         high = readmemw(easeg, cpu_state.eaaddr + 2);     if (cpu_state.abrt) return 1;
         
@@ -664,6 +701,7 @@ static int opBOUND_l_a16(uint32_t fetchdat)
         
         fetch_ea_16(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         low = geteal();
         high = readmeml(easeg, cpu_state.eaaddr + 4);     if (cpu_state.abrt) return 1;
         
@@ -683,6 +721,7 @@ static int opBOUND_l_a32(uint32_t fetchdat)
         
         fetch_ea_32(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         low = geteal();
         high = readmeml(easeg, cpu_state.eaaddr + 4);     if (cpu_state.abrt) return 1;
         
@@ -700,7 +739,7 @@ static int opBOUND_l_a32(uint32_t fetchdat)
 
 static int opCLTS(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't CLTS\n");
                 x86gpf(NULL,0);
@@ -743,7 +782,7 @@ static int opLOADALL(uint32_t fetchdat)
                 return 1;
         }
         msw = (msw & 1) | readmemw(0, 0x806);
-        flags = (readmemw(0, 0x818) & 0xffd5) | 2;
+        cpu_state.flags = (readmemw(0, 0x818) & 0xffd5) | 2;
         flags_extract();
         tr.seg = readmemw(0, 0x816);
         cpu_state.pc = readmemw(0, 0x81A);
@@ -761,22 +800,22 @@ static int opLOADALL(uint32_t fetchdat)
         CX = readmemw(0, 0x832);
         AX = readmemw(0, 0x834);
         es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16);
-        _es.access = readmemb(0, 0x839);
-        _es.limit = readmemw(0, 0x83A);
+        cpu_state.seg_es.access = readmemb(0, 0x839);
+        cpu_state.seg_es.limit = readmemw(0, 0x83A);
         cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16);
-        _cs.access = readmemb(0, 0x83F);
-        _cs.limit = readmemw(0, 0x840);
+        cpu_state.seg_cs.access = readmemb(0, 0x83F);
+        cpu_state.seg_cs.limit = readmemw(0, 0x840);
         ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16);
-        _ss.access = readmemb(0, 0x845);
-        _ss.limit = readmemw(0, 0x846);
-        if (_ss.base == 0 && _ss.limit_low == 0 && _ss.limit_high == 0xffffffff)
+        cpu_state.seg_ss.access = readmemb(0, 0x845);
+        cpu_state.seg_ss.limit = readmemw(0, 0x846);
+        if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && cpu_state.seg_ss.limit_high == 0xffffffff)
                 cpu_cur_status &= ~CPU_STATUS_NOTFLATSS;
         else
                 cpu_cur_status |= CPU_STATUS_NOTFLATSS;
         ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16);
-        _ds.access = readmemb(0, 0x84B);
-        _ds.limit = readmemw(0, 0x84C);
-        if (_ds.base == 0 && _ds.limit_low == 0 && _ds.limit_high == 0xffffffff)
+        cpu_state.seg_ds.access = readmemb(0, 0x84B);
+        cpu_state.seg_ds.limit = readmemw(0, 0x84C);
+        if (cpu_state.seg_ds.base == 0 && cpu_state.seg_ds.limit_low == 0 && cpu_state.seg_ds.limit_high == 0xffffffff)
                 cpu_cur_status &= ~CPU_STATUS_NOTFLATDS;
         else
                 cpu_cur_status |= CPU_STATUS_NOTFLATDS;
@@ -817,8 +856,11 @@ static void loadall_load_segment(uint32_t addr, x86seg *s)
        s->base = readmeml(0, addr + 4);
        s->limit = readmeml(0, addr + 8);
 
-       if (s == &_cs)  use32 = (segdat3 & 0x40) ? 0x300 : 0;
-       if (s == &_ss)  stack32 = (segdat3 & 0x40) ? 1 : 0;
+       if (s == &cpu_state.seg_cs)
+                use32 = (segdat3 & 0x40) ? 0x300 : 0;
+       if (s == &cpu_state.seg_ss)
+                stack32 = (segdat3 & 0x40) ? 1 : 0;
+                
        cpu_cur_status &= ~(CPU_STATUS_USE32 | CPU_STATUS_STACK32);
        if (use32)
               cpu_cur_status |= CPU_STATUS_USE32;
@@ -827,14 +869,14 @@ static void loadall_load_segment(uint32_t addr, x86seg *s)
 
        set_segment_limit(s, segdat3);
 
-        if (s == &_ds)
+        if (s == &cpu_state.seg_ds)
         {
                 if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff)
                         cpu_cur_status &= ~CPU_STATUS_NOTFLATDS;
                 else
                         cpu_cur_status |= CPU_STATUS_NOTFLATDS;
         }
-        if (s == &_ss)
+        if (s == &cpu_state.seg_ss)
         {
                 if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff)
                         cpu_cur_status &= ~CPU_STATUS_NOTFLATSS;
@@ -848,8 +890,8 @@ static int opLOADALL386(uint32_t fetchdat)
        uint32_t la_addr = es + EDI;
 
        cr0 = readmeml(0, la_addr);
-        flags = readmemw(0, la_addr + 4);
-        eflags = readmemw(0, la_addr + 6);
+        cpu_state.flags = readmemw(0, la_addr + 4);
+        cpu_state.eflags = readmemw(0, la_addr + 6);
         flags_extract();
         cpu_state.pc = readmeml(0, la_addr + 8);
        EDI = readmeml(0, la_addr + 0xC);
@@ -875,14 +917,15 @@ static int opLOADALL386(uint32_t fetchdat)
        loadall_load_segment(la_addr + 0x60, &idt);
        loadall_load_segment(la_addr + 0x6c, &gdt);
        loadall_load_segment(la_addr + 0x78, &ldt);
-       loadall_load_segment(la_addr + 0x84, &_gs);
-       loadall_load_segment(la_addr + 0x90, &_fs);
-       loadall_load_segment(la_addr + 0x9c, &_ds);
-       loadall_load_segment(la_addr + 0xa8, &_ss);
-       loadall_load_segment(la_addr + 0xb4, &_cs);
-       loadall_load_segment(la_addr + 0xc0, &_es);
+       loadall_load_segment(la_addr + 0x84, &cpu_state.seg_gs);
+       loadall_load_segment(la_addr + 0x90, &cpu_state.seg_fs);
+       loadall_load_segment(la_addr + 0x9c, &cpu_state.seg_ds);
+       loadall_load_segment(la_addr + 0xa8, &cpu_state.seg_ss);
+       loadall_load_segment(la_addr + 0xb4, &cpu_state.seg_cs);
+       loadall_load_segment(la_addr + 0xc0, &cpu_state.seg_es);
 
        if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+       oldcpl = CPL;
 
        CLOCK_CYCLES(350);
         return 0;
@@ -903,7 +946,7 @@ static int opCPUID(uint32_t fetchdat)
 
 static int opRDMSR(uint32_t fetchdat)
 {
-        if (cpu_hasMSR)
+        if (cpu_has_feature(CPU_FEATURE_MSR))
         {
                 cpu_RDMSR();
                 CLOCK_CYCLES(9);
@@ -916,7 +959,7 @@ static int opRDMSR(uint32_t fetchdat)
 
 static int opWRMSR(uint32_t fetchdat)
 {
-        if (cpu_hasMSR)
+        if (cpu_has_feature(CPU_FEATURE_MSR))
         {
                 cpu_WRMSR();
                 CLOCK_CYCLES(9);
index 1af186d0b28c75d516f17e3a70f52c3c267eb4fc..f9a7f93577bee6a53a00f91c4212fdd6d204c873 100644 (file)
         }                                                                       \
         else                                                                    \
         {                                                                       \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
                 src.q = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1;            \
                 CLOCK_CYCLES(2);                                                \
         }
 
 #define MMX_ENTER()                                                     \
-        if (!cpu_hasMMX)                                                \
+        if (!cpu_has_feature(CPU_FEATURE_MMX))                          \
         {                                                               \
                 cpu_state.pc = cpu_state.oldpc;                                   \
                 x86illegal();                                           \
 
 static int opEMMS(uint32_t fetchdat)
 {
-        if (!cpu_hasMMX)
+        if (!cpu_has_feature(CPU_FEATURE_MMX))
         {
                 cpu_state.pc = cpu_state.oldpc;
                 x86illegal();
                 return 1;
         }
-        if (cr0 & 4)
+        if (cr0 & 0xc)
         {
                 x86_int(7);
                 return 1;
index 302a44eaa0569681d58c5b0fc7316e577f4b8ac7..22c34c73806f7fd5b87d1f28179a6796d9199642 100644 (file)
@@ -293,7 +293,8 @@ static int opPMULLW_a16(uint32_t fetchdat)
         else
         {
                 MMX_REG src;
-        
+
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 src.l[0] = readmeml(easeg, cpu_state.eaaddr);
                 src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0;
                 cpu_state.MM[cpu_reg].w[0] *= src.w[0];
@@ -321,6 +322,7 @@ static int opPMULLW_a32(uint32_t fetchdat)
         {
                 MMX_REG src;
         
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 src.l[0] = readmeml(easeg, cpu_state.eaaddr);
                 src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0;
                 cpu_state.MM[cpu_reg].w[0] *= src.w[0];
@@ -349,6 +351,7 @@ static int opPMULHW_a16(uint32_t fetchdat)
         {
                 MMX_REG src;
         
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 src.l[0] = readmeml(easeg, cpu_state.eaaddr);
                 src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0;
                 cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16;
@@ -376,6 +379,7 @@ static int opPMULHW_a32(uint32_t fetchdat)
         {
                 MMX_REG src;
         
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 src.l[0] = readmeml(easeg, cpu_state.eaaddr);
                 src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0;
                 cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16;
index eb401b83fba71f34a87e03492fa748aa7dba5b03..0fee959238679d088dbac4c8ac11965ced435c72 100644 (file)
@@ -166,7 +166,7 @@ static int opPCMPEQD_a32(uint32_t fetchdat)
         
         MMX_ENTER();
         
-        fetch_ea_16(fetchdat);
+        fetch_ea_32(fetchdat);
         MMX_GETSRC();
 
         cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0;
@@ -195,7 +195,7 @@ static int opPCMPGTD_a32(uint32_t fetchdat)
         
         MMX_ENTER();
         
-        fetch_ea_16(fetchdat);
+        fetch_ea_32(fetchdat);
         MMX_GETSRC();
 
         cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0;
index d96df747b89d7dca9f9feb9f87710ddec811488b..f598d5b24ed6218eaafee0097d2cb33aff69df10 100644 (file)
@@ -12,7 +12,8 @@ static int opMOVD_l_mm_a16(uint32_t fetchdat)
         else
         {
                 uint32_t dst;
-        
+
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1;
                 cpu_state.MM[cpu_reg].l[0] = dst;
                 cpu_state.MM[cpu_reg].l[1] = 0;
@@ -35,7 +36,8 @@ static int opMOVD_l_mm_a32(uint32_t fetchdat)
         else
         {
                 uint32_t dst;
-        
+
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1;
                 cpu_state.MM[cpu_reg].l[0] = dst;
                 cpu_state.MM[cpu_reg].l[1] = 0;
@@ -57,6 +59,7 @@ static int opMOVD_mm_l_a16(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3);
                 writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES(2);
@@ -75,6 +78,7 @@ static int opMOVD_mm_l_a32(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3);
                 writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES(2);
@@ -96,6 +100,7 @@ static int opMOVQ_q_mm_a16(uint32_t fetchdat)
         {
                 uint64_t dst;
         
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1;
                 cpu_state.MM[cpu_reg].q = dst;
                 CLOCK_CYCLES(2);
@@ -116,6 +121,7 @@ static int opMOVQ_q_mm_a32(uint32_t fetchdat)
         {
                 uint64_t dst;
         
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1;
                 cpu_state.MM[cpu_reg].q = dst;
                 CLOCK_CYCLES(2);
@@ -135,6 +141,7 @@ static int opMOVQ_mm_q_a16(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7);
                 writememq(easeg, cpu_state.eaaddr,     cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES(2);
@@ -153,6 +160,7 @@ static int opMOVQ_mm_q_a32(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7);
                 writememq(easeg, cpu_state.eaaddr,     cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1;
                 CLOCK_CYCLES(2);
index 50b813cb3dc7bc5b676a0911ab23cbe3255b4f6a..b03ef842ebe6d0ec2a3b7b68573ff7636e8512ef 100644 (file)
@@ -12,6 +12,7 @@ static int opPUNPCKLDQ_a16(uint32_t fetchdat)
         {
                 uint32_t src;
         
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0;
                 cpu_state.MM[cpu_reg].l[1] = src;
 
@@ -32,7 +33,8 @@ static int opPUNPCKLDQ_a32(uint32_t fetchdat)
         else
         {
                 uint32_t src;
-        
+
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0;
                 cpu_state.MM[cpu_reg].l[1] = src;
 
index 429347598327df9356194413422e00a308cb774f..7b8c377f8bb6cee5abfe55dde81f4e61e620b83b 100644 (file)
@@ -6,6 +6,7 @@
         }                                                               \
         else                                                            \
         {                                                               \
+                SEG_CHECK_READ(cpu_state.ea_seg);                       \
                 shift = readmemb(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0;    \
                 CLOCK_CYCLES(2);                                        \
         }
index 718db28a1f420a65db2a8ce71467e52d21f8ac91..5cb28c1e5c9697e6f3d42e0ce276ddfc0f7309f8 100644 (file)
@@ -182,6 +182,7 @@ static int opMOV_b_imm_a16(uint32_t fetchdat)
         uint8_t temp;
         fetch_ea_16(fetchdat);
         ILLEGAL_ON((rmdat & 0x38) != 0);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = readmemb(cs,cpu_state.pc); cpu_state.pc++;               if (cpu_state.abrt) return 1;
         CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
         seteab(temp);
@@ -194,6 +195,7 @@ static int opMOV_b_imm_a32(uint32_t fetchdat)
         uint8_t temp;
         fetch_ea_32(fetchdat);
         ILLEGAL_ON((rmdat & 0x38) != 0);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = getbyte();               if (cpu_state.abrt) return 1;
         seteab(temp);
         CLOCK_CYCLES(timing_rr);
@@ -206,6 +208,7 @@ static int opMOV_w_imm_a16(uint32_t fetchdat)
         uint16_t temp;
         fetch_ea_16(fetchdat);
         ILLEGAL_ON((rmdat & 0x38) != 0);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = getword();               if (cpu_state.abrt) return 1;
         seteaw(temp);
         CLOCK_CYCLES(timing_rr);
@@ -217,6 +220,7 @@ static int opMOV_w_imm_a32(uint32_t fetchdat)
         uint16_t temp;
         fetch_ea_32(fetchdat);
         ILLEGAL_ON((rmdat & 0x38) != 0);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = getword();               if (cpu_state.abrt) return 1;
         seteaw(temp);
         CLOCK_CYCLES(timing_rr);
@@ -228,6 +232,7 @@ static int opMOV_l_imm_a16(uint32_t fetchdat)
         uint32_t temp;
         fetch_ea_16(fetchdat);
         ILLEGAL_ON((rmdat & 0x38) != 0);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = getlong();               if (cpu_state.abrt) return 1;
         seteal(temp);
         CLOCK_CYCLES(timing_rr);
@@ -239,6 +244,7 @@ static int opMOV_l_imm_a32(uint32_t fetchdat)
         uint32_t temp;
         fetch_ea_32(fetchdat);
         ILLEGAL_ON((rmdat & 0x38) != 0);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = getlong();               if (cpu_state.abrt) return 1;
         seteal(temp);
         CLOCK_CYCLES(timing_rr);
@@ -251,6 +257,7 @@ static int opMOV_AL_a16(uint32_t fetchdat)
 {
         uint16_t addr = getwordf();
         uint8_t temp;
+        SEG_CHECK_READ(cpu_state.ea_seg);
         CHECK_READ(cpu_state.ea_seg, addr, addr);
         temp = readmemb(cpu_state.ea_seg->base, addr);      if (cpu_state.abrt) return 1;
         AL = temp;
@@ -262,6 +269,7 @@ static int opMOV_AL_a32(uint32_t fetchdat)
 {
         uint32_t addr = getlong();
         uint8_t temp;
+        SEG_CHECK_READ(cpu_state.ea_seg);
         CHECK_READ(cpu_state.ea_seg, addr, addr);
         temp = readmemb(cpu_state.ea_seg->base, addr);      if (cpu_state.abrt) return 1;
         AL = temp;
@@ -273,6 +281,7 @@ static int opMOV_AX_a16(uint32_t fetchdat)
 {
         uint16_t addr = getwordf();
         uint16_t temp;
+        SEG_CHECK_READ(cpu_state.ea_seg);
         CHECK_READ(cpu_state.ea_seg, addr, addr+1);
         temp = readmemw(cpu_state.ea_seg->base, addr);     if (cpu_state.abrt) return 1;
         AX = temp;
@@ -284,6 +293,7 @@ static int opMOV_AX_a32(uint32_t fetchdat)
 {
         uint32_t addr = getlong();
         uint16_t temp;
+        SEG_CHECK_READ(cpu_state.ea_seg);
         CHECK_READ(cpu_state.ea_seg, addr, addr+1);
         temp = readmemw(cpu_state.ea_seg->base, addr);     if (cpu_state.abrt) return 1;
         AX = temp;
@@ -295,6 +305,7 @@ static int opMOV_EAX_a16(uint32_t fetchdat)
 {
         uint16_t addr = getwordf();
         uint32_t temp;
+        SEG_CHECK_READ(cpu_state.ea_seg);
         CHECK_READ(cpu_state.ea_seg, addr, addr+3);
         temp = readmeml(cpu_state.ea_seg->base, addr);     if (cpu_state.abrt) return 1;
         EAX = temp;
@@ -306,6 +317,7 @@ static int opMOV_EAX_a32(uint32_t fetchdat)
 {
         uint32_t addr = getlong();
         uint32_t temp;
+        SEG_CHECK_READ(cpu_state.ea_seg);
         CHECK_READ(cpu_state.ea_seg, addr, addr+3);
         temp = readmeml(cpu_state.ea_seg->base, addr);     if (cpu_state.abrt) return 1;
         EAX = temp;
@@ -317,6 +329,7 @@ static int opMOV_EAX_a32(uint32_t fetchdat)
 static int opMOV_a16_AL(uint32_t fetchdat)
 {
         uint16_t addr = getwordf();
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         writememb(cpu_state.ea_seg->base, addr, AL);
         CLOCK_CYCLES((is486) ? 1 : 2);
         PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0);
@@ -325,6 +338,7 @@ static int opMOV_a16_AL(uint32_t fetchdat)
 static int opMOV_a32_AL(uint32_t fetchdat)
 {
         uint32_t addr = getlong();
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         writememb(cpu_state.ea_seg->base, addr, AL);
         CLOCK_CYCLES((is486) ? 1 : 2);
         PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1);
@@ -333,6 +347,7 @@ static int opMOV_a32_AL(uint32_t fetchdat)
 static int opMOV_a16_AX(uint32_t fetchdat)
 {
         uint16_t addr = getwordf();
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         writememw(cpu_state.ea_seg->base, addr, AX);
         CLOCK_CYCLES((is486) ? 1 : 2);
         PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0);
@@ -341,6 +356,7 @@ static int opMOV_a16_AX(uint32_t fetchdat)
 static int opMOV_a32_AX(uint32_t fetchdat)
 {
         uint32_t addr = getlong();             if (cpu_state.abrt) return 1;
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         writememw(cpu_state.ea_seg->base, addr, AX);
         CLOCK_CYCLES((is486) ? 1 : 2);
         PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1);
@@ -349,6 +365,7 @@ static int opMOV_a32_AX(uint32_t fetchdat)
 static int opMOV_a16_EAX(uint32_t fetchdat)
 {
         uint16_t addr = getwordf();
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         writememl(cpu_state.ea_seg->base, addr, EAX);
         CLOCK_CYCLES((is486) ? 1 : 2);
         PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0);
@@ -357,6 +374,7 @@ static int opMOV_a16_EAX(uint32_t fetchdat)
 static int opMOV_a32_EAX(uint32_t fetchdat)
 {
         uint32_t addr = getlong();             if (cpu_state.abrt) return 1;
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         writememl(cpu_state.ea_seg->base, addr, EAX);
         CLOCK_CYCLES((is486) ? 1 : 2);
         PREFETCH_RUN(2, 5, -1, 0,0,0,1, 1);
@@ -407,7 +425,10 @@ static int opLEA_l_a32(uint32_t fetchdat)
 static int opXLAT_a16(uint32_t fetchdat)
 {
         uint32_t addr = (BX + AL)&0xFFFF;
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+        
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1;
         AL = temp;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0);
@@ -416,7 +437,10 @@ static int opXLAT_a16(uint32_t fetchdat)
 static int opXLAT_a32(uint32_t fetchdat)
 {
         uint32_t addr = EBX + AL;
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+        
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1;
         AL = temp;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1);
@@ -434,6 +458,7 @@ static int opMOV_b_r_a16(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
                 seteab(getr8(cpu_reg));
                 CLOCK_CYCLES(is486 ? 1 : 2);
@@ -452,6 +477,7 @@ static int opMOV_b_r_a32(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
                 seteab(getr8(cpu_reg));
                 CLOCK_CYCLES(is486 ? 1 : 2);
@@ -470,6 +496,7 @@ static int opMOV_w_r_a16(uint32_t fetchdat)
         }
         else
         { 
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1);
                 seteaw(cpu_state.regs[cpu_reg].w);
                 CLOCK_CYCLES(is486 ? 1 : 2);
@@ -488,6 +515,7 @@ static int opMOV_w_r_a32(uint32_t fetchdat)
         }
         else
         { 
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1);
                 seteaw(cpu_state.regs[cpu_reg].w);
                 CLOCK_CYCLES(is486 ? 1 : 2);
@@ -506,6 +534,7 @@ static int opMOV_l_r_a16(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3);
                 seteal(cpu_state.regs[cpu_reg].l);
                 CLOCK_CYCLES(is486 ? 1 : 2);
@@ -524,6 +553,7 @@ static int opMOV_l_r_a32(uint32_t fetchdat)
         }
         else
         {
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
                 CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3);
                 seteal(cpu_state.regs[cpu_reg].l);
                 CLOCK_CYCLES(is486 ? 1 : 2);
@@ -544,6 +574,7 @@ static int opMOV_r_b_a16(uint32_t fetchdat)
         else
         {
                 uint8_t temp;
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
                 temp = geteab();                if (cpu_state.abrt) return 1;
                 setr8(cpu_reg, temp);
@@ -564,6 +595,7 @@ static int opMOV_r_b_a32(uint32_t fetchdat)
         else
         {
                 uint8_t temp;
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
                 temp = geteab();                if (cpu_state.abrt) return 1;
                 setr8(cpu_reg, temp);
@@ -584,6 +616,7 @@ static int opMOV_r_w_a16(uint32_t fetchdat)
         else
         {
                 uint16_t temp;
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1);
                 temp = geteaw();                if (cpu_state.abrt) return 1;
                 cpu_state.regs[cpu_reg].w = temp;
@@ -604,6 +637,7 @@ static int opMOV_r_w_a32(uint32_t fetchdat)
         else
         {
                 uint16_t temp;
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1);
                 temp = geteaw();                if (cpu_state.abrt) return 1;
                 cpu_state.regs[cpu_reg].w = temp;
@@ -624,6 +658,7 @@ static int opMOV_r_l_a16(uint32_t fetchdat)
         else
         {
                 uint32_t temp;
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3);
                 temp = geteal();                if (cpu_state.abrt) return 1;
                 cpu_state.regs[cpu_reg].l = temp;
@@ -644,6 +679,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat)
         else
         {
                 uint32_t temp;
+                SEG_CHECK_READ(cpu_state.ea_seg);
                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3);
                 temp = geteal();                if (cpu_state.abrt) return 1;
                 cpu_state.regs[cpu_reg].l = temp;
@@ -664,6 +700,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat)
                         else                                                            \
                         {                                                               \
                                 uint16_t temp;                                          \
+                                SEG_CHECK_READ(cpu_state.ea_seg);                       \
                                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1);                   \
                                 temp = geteaw();                if (cpu_state.abrt) return 1;     \
                                 cpu_state.regs[cpu_reg].w = temp;                           \
@@ -682,6 +719,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat)
                         else                                                            \
                         {                                                               \
                                 uint16_t temp;                                          \
+                                SEG_CHECK_READ(cpu_state.ea_seg);                       \
                                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1);                   \
                                 temp = geteaw();                if (cpu_state.abrt) return 1;     \
                                 cpu_state.regs[cpu_reg].w = temp;                           \
@@ -700,6 +738,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat)
                         else                                                            \
                         {                                                               \
                                 uint32_t temp;                                          \
+                                SEG_CHECK_READ(cpu_state.ea_seg);                       \
                                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3);                   \
                                 temp = geteal();                if (cpu_state.abrt) return 1;     \
                                 cpu_state.regs[cpu_reg].l = temp;                           \
@@ -719,6 +758,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat)
                         {                                                               \
                                 uint32_t temp;                                          \
                                 CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3);                   \
+                                SEG_CHECK_READ(cpu_state.ea_seg);                       \
                                 temp = geteal();                if (cpu_state.abrt) return 1;     \
                                 cpu_state.regs[cpu_reg].l = temp;                           \
                         }                                                               \
index 3a522a6526687bc5a4dec7bab192062757458cf7..923bb571bd061e4a4791d9b4a7cb995799b6e384 100644 (file)
@@ -1,6 +1,6 @@
 static int opMOV_r_CRx_a16(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load from CRx\n");
                 x86gpf(NULL, 0);
@@ -21,7 +21,7 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat)
                 cpu_state.regs[cpu_rm].l = cr3;
                 break;
                 case 4:
-                if (cpu_hasCR4)
+                if (cpu_has_feature(CPU_FEATURE_CR4))
                 {
                         cpu_state.regs[cpu_rm].l = cr4;
                         break;
@@ -38,7 +38,7 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat)
 }
 static int opMOV_r_CRx_a32(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load from CRx\n");
                 x86gpf(NULL, 0);
@@ -59,7 +59,7 @@ static int opMOV_r_CRx_a32(uint32_t fetchdat)
                 cpu_state.regs[cpu_rm].l = cr3;
                 break;
                 case 4:
-                if (cpu_hasCR4)
+                if (cpu_has_feature(CPU_FEATURE_CR4))
                 {
                         cpu_state.regs[cpu_rm].l = cr4;
                         break;
@@ -77,7 +77,7 @@ static int opMOV_r_CRx_a32(uint32_t fetchdat)
 
 static int opMOV_r_DRx_a16(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load from DRx\n");
                 x86gpf(NULL, 0);
@@ -91,7 +91,7 @@ static int opMOV_r_DRx_a16(uint32_t fetchdat)
 }
 static int opMOV_r_DRx_a32(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load from DRx\n");
                 x86gpf(NULL, 0);
@@ -108,7 +108,7 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat)
 {
         uint32_t old_cr0 = cr0;
         
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load CRx\n");
                 x86gpf(NULL,0);
@@ -144,7 +144,7 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat)
                 flushmmucache();
                 break;
                 case 4:
-                if (cpu_hasCR4)
+                if (cpu_has_feature(CPU_FEATURE_CR4))
                 {
                         cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask;
                         break;
@@ -164,7 +164,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat)
 {
         uint32_t old_cr0 = cr0;
         
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load CRx\n");
                 x86gpf(NULL,0);
@@ -200,7 +200,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat)
                 flushmmucache();
                 break;
                 case 4:
-                if (cpu_hasCR4)
+                if (cpu_has_feature(CPU_FEATURE_CR4))
                 {
                         cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask;
                         break;
@@ -219,7 +219,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat)
 
 static int opMOV_DRx_r_a16(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load DRx\n");
                 x86gpf(NULL, 0);
@@ -233,7 +233,7 @@ static int opMOV_DRx_r_a16(uint32_t fetchdat)
 }
 static int opMOV_DRx_r_a32(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load DRx\n");
                 x86gpf(NULL, 0);
@@ -248,7 +248,7 @@ static int opMOV_DRx_r_a32(uint32_t fetchdat)
 
 static int opMOV_r_TRx_a16(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load from TRx\n");
                 x86gpf(NULL, 0);
@@ -262,7 +262,7 @@ static int opMOV_r_TRx_a16(uint32_t fetchdat)
 }
 static int opMOV_r_TRx_a32(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load from TRx\n");
                 x86gpf(NULL, 0);
@@ -277,7 +277,7 @@ static int opMOV_r_TRx_a32(uint32_t fetchdat)
 
 static int opMOV_TRx_r_a16(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load TRx\n");
                 x86gpf(NULL, 0);
@@ -290,7 +290,7 @@ static int opMOV_TRx_r_a16(uint32_t fetchdat)
 }
 static int opMOV_TRx_r_a32(uint32_t fetchdat)
 {
-        if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
+        if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))
         {
                 pclog("Can't load TRx\n");
                 x86gpf(NULL, 0);
index 1e2f654b111133d5a9f1976757a03ce554547d86..da7727143ea6c9c059586070b4cfd85bdfcdb105 100644 (file)
@@ -1,7 +1,9 @@
 static int opMOV_w_seg_a16(uint32_t fetchdat)
 {
         fetch_ea_16(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         switch (rmdat & 0x38)
         {
                 case 0x00: /*ES*/
@@ -31,7 +33,9 @@ static int opMOV_w_seg_a16(uint32_t fetchdat)
 static int opMOV_w_seg_a32(uint32_t fetchdat)
 {
         fetch_ea_32(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         switch (rmdat & 0x38)
         {
                 case 0x00: /*ES*/
@@ -62,7 +66,9 @@ static int opMOV_w_seg_a32(uint32_t fetchdat)
 static int opMOV_l_seg_a16(uint32_t fetchdat)
 {
         fetch_ea_16(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         switch (rmdat & 0x38)
         {
                 case 0x00: /*ES*/
@@ -98,7 +104,9 @@ static int opMOV_l_seg_a16(uint32_t fetchdat)
 static int opMOV_l_seg_a32(uint32_t fetchdat)
 {
         fetch_ea_32(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+
         switch (rmdat & 0x38)
         {
                 case 0x00: /*ES*/
@@ -137,34 +145,35 @@ static int opMOV_seg_w_a16(uint32_t fetchdat)
         uint16_t new_seg;
         
         fetch_ea_16(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         new_seg=geteaw();         if (cpu_state.abrt) return 1;
         
         switch (rmdat & 0x38)
         {
                 case 0x00: /*ES*/
-                loadseg(new_seg, &_es);
+                loadseg(new_seg, &cpu_state.seg_es);
                 break;
                 case 0x18: /*DS*/
-                loadseg(new_seg, &_ds);
+                loadseg(new_seg, &cpu_state.seg_ds);
                 break;
                 case 0x10: /*SS*/
-                loadseg(new_seg, &_ss);
+                loadseg(new_seg, &cpu_state.seg_ss);
                 if (cpu_state.abrt) return 1;
                 cpu_state.oldpc = cpu_state.pc;
                 cpu_state.op32 = use32;
                 cpu_state.ssegs = 0;
-                cpu_state.ea_seg = &_ds;
+                cpu_state.ea_seg = &cpu_state.seg_ds;
                 fetchdat = fastreadl(cs + cpu_state.pc);
                 cpu_state.pc++;
                 if (cpu_state.abrt) return 1;
                 x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
                 return 1;
                 case 0x20: /*FS*/
-                loadseg(new_seg, &_fs);
+                loadseg(new_seg, &cpu_state.seg_fs);
                 break;
                 case 0x28: /*GS*/
-                loadseg(new_seg, &_gs);
+                loadseg(new_seg, &cpu_state.seg_gs);
                 break;
         }
                         
@@ -177,34 +186,35 @@ static int opMOV_seg_w_a32(uint32_t fetchdat)
         uint16_t new_seg;
         
         fetch_ea_32(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         new_seg=geteaw();         if (cpu_state.abrt) return 1;
         
         switch (rmdat & 0x38)
         {
                 case 0x00: /*ES*/
-                loadseg(new_seg, &_es);
+                loadseg(new_seg, &cpu_state.seg_es);
                 break;
                 case 0x18: /*DS*/
-                loadseg(new_seg, &_ds);
+                loadseg(new_seg, &cpu_state.seg_ds);
                 break;
                 case 0x10: /*SS*/
-                loadseg(new_seg, &_ss);
+                loadseg(new_seg, &cpu_state.seg_ss);
                 if (cpu_state.abrt) return 1;
                 cpu_state.oldpc = cpu_state.pc;
                 cpu_state.op32 = use32;
                 cpu_state.ssegs = 0;
-                cpu_state.ea_seg = &_ds;
+                cpu_state.ea_seg = &cpu_state.seg_ds;
                 fetchdat = fastreadl(cs + cpu_state.pc);
                 cpu_state.pc++;
                 if (cpu_state.abrt) return 1;
                 x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
                 return 1;
                 case 0x20: /*FS*/
-                loadseg(new_seg, &_fs);
+                loadseg(new_seg, &cpu_state.seg_fs);
                 break;
                 case 0x28: /*GS*/
-                loadseg(new_seg, &_gs);
+                loadseg(new_seg, &cpu_state.seg_gs);
                 break;
         }
                         
@@ -220,9 +230,10 @@ static int opLDS_w_a16(uint32_t fetchdat)
 
         fetch_ea_16(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmemw(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 2);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ds);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ds);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = addr;
  
         CLOCK_CYCLES(7);
@@ -235,9 +246,10 @@ static int opLDS_w_a32(uint32_t fetchdat)
 
         fetch_ea_32(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmemw(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 2);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ds);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ds);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = addr;
  
         CLOCK_CYCLES(7);
@@ -251,9 +263,10 @@ static int opLDS_l_a16(uint32_t fetchdat)
 
         fetch_ea_16(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmeml(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 4);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ds);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ds);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = addr;
  
         CLOCK_CYCLES(7);
@@ -267,9 +280,10 @@ static int opLDS_l_a32(uint32_t fetchdat)
 
         fetch_ea_32(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmeml(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 4);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ds);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ds);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = addr;
  
         CLOCK_CYCLES(7);
@@ -283,9 +297,10 @@ static int opLSS_w_a16(uint32_t fetchdat)
 
         fetch_ea_16(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmemw(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 2);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ss);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ss);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = addr;
  
         CLOCK_CYCLES(7);
@@ -298,9 +313,10 @@ static int opLSS_w_a32(uint32_t fetchdat)
 
         fetch_ea_32(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmemw(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 2);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ss);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ss);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = addr;
  
         CLOCK_CYCLES(7);
@@ -314,9 +330,10 @@ static int opLSS_l_a16(uint32_t fetchdat)
 
         fetch_ea_16(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmeml(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 4);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ss);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ss);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = addr;
  
         CLOCK_CYCLES(7);
@@ -330,9 +347,10 @@ static int opLSS_l_a32(uint32_t fetchdat)
 
         fetch_ea_32(fetchdat);
         ILLEGAL_ON(cpu_mod == 3);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         addr = readmeml(easeg, cpu_state.eaaddr);
         seg = readmemw(easeg, cpu_state.eaaddr + 4);      if (cpu_state.abrt) return 1;
-        loadseg(seg, &_ss);                     if (cpu_state.abrt) return 1;
+        loadseg(seg, &cpu_state.seg_ss);                  if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = addr;
  
         CLOCK_CYCLES(7);
@@ -346,6 +364,7 @@ static int opLSS_l_a32(uint32_t fetchdat)
                 uint16_t addr, seg;                                             \
                                                                                 \
                 fetch_ea_16(fetchdat);                                          \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
                 ILLEGAL_ON(cpu_mod == 3);                                           \
                 addr = readmemw(easeg, cpu_state.eaaddr);                                 \
                 seg = readmemw(easeg, cpu_state.eaaddr + 2);      if (cpu_state.abrt) return 1;     \
@@ -362,6 +381,7 @@ static int opLSS_l_a32(uint32_t fetchdat)
                 uint16_t addr, seg;                                             \
                                                                                 \
                 fetch_ea_32(fetchdat);                                          \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
                 ILLEGAL_ON(cpu_mod == 3);                                           \
                 addr = readmemw(easeg, cpu_state.eaaddr);                                 \
                 seg = readmemw(easeg, cpu_state.eaaddr + 2);      if (cpu_state.abrt) return 1;     \
@@ -379,6 +399,7 @@ static int opLSS_l_a32(uint32_t fetchdat)
                 uint16_t seg;                                                   \
                                                                                 \
                 fetch_ea_16(fetchdat);                                          \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
                 ILLEGAL_ON(cpu_mod == 3);                                           \
                 addr = readmeml(easeg, cpu_state.eaaddr);                                 \
                 seg = readmemw(easeg, cpu_state.eaaddr + 4);      if (cpu_state.abrt) return 1;     \
@@ -396,6 +417,7 @@ static int opLSS_l_a32(uint32_t fetchdat)
                 uint16_t seg;                                                   \
                                                                                 \
                 fetch_ea_32(fetchdat);                                          \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
                 ILLEGAL_ON(cpu_mod == 3);                                           \
                 addr = readmeml(easeg, cpu_state.eaaddr);                                 \
                 seg = readmemw(easeg, cpu_state.eaaddr + 4);      if (cpu_state.abrt) return 1;     \
@@ -407,6 +429,6 @@ static int opLSS_l_a32(uint32_t fetchdat)
                 return 0;                                                       \
         }
         
-opLsel(ES, _es)
-opLsel(FS, _fs)
-opLsel(GS, _gs)
+opLsel(ES, cpu_state.seg_es)
+opLsel(FS, cpu_state.seg_fs)
+opLsel(GS, cpu_state.seg_gs)
index 2175a63c36c4ed3d8b35ffa31a3534d8397242a9..2e4fa20011d0f80cbab039fd7c79876a14239e44 100644 (file)
@@ -3,6 +3,8 @@ static int opMOVZX_w_b_a16(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = (uint16_t)temp;
         
@@ -15,6 +17,8 @@ static int opMOVZX_w_b_a32(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = (uint16_t)temp;
         
@@ -27,6 +31,8 @@ static int opMOVZX_l_b_a16(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         
@@ -39,6 +45,8 @@ static int opMOVZX_l_b_a32(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         
@@ -51,6 +59,8 @@ static int opMOVZX_w_w_a16(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = temp;
         
@@ -63,6 +73,8 @@ static int opMOVZX_w_w_a32(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = temp;
         
@@ -75,6 +87,8 @@ static int opMOVZX_l_w_a16(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         
@@ -87,6 +101,8 @@ static int opMOVZX_l_w_a32(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         
@@ -100,6 +116,8 @@ static int opMOVSX_w_b_a16(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = (uint16_t)temp;
         if (temp & 0x80)        
@@ -114,6 +132,8 @@ static int opMOVSX_w_b_a32(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = (uint16_t)temp;
         if (temp & 0x80)        
@@ -128,6 +148,8 @@ static int opMOVSX_l_b_a16(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         if (temp & 0x80)        
@@ -142,6 +164,8 @@ static int opMOVSX_l_b_a32(uint32_t fetchdat)
         uint8_t temp;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         if (temp & 0x80)        
@@ -156,6 +180,8 @@ static int opMOVSX_l_w_a16(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         if (temp & 0x8000)
@@ -170,6 +196,8 @@ static int opMOVSX_l_w_a32(uint32_t fetchdat)
         uint16_t temp;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = (uint32_t)temp;
         if (temp & 0x8000)
index a7331674582fa8c57fec511ec589af20b5cecf3e..2a8bdcf4c86bf69df8a56693e53f1b081d0c5ef7 100644 (file)
@@ -1,6 +1,6 @@
 static int opRDTSC(uint32_t fetchdat)
 {
-        if (!cpu_hasrdtsc)
+        if (!cpu_has_feature(CPU_FEATURE_RDTSC))
         {
                 cpu_state.pc = cpu_state.oldpc;
                 x86illegal();
index 98cf254cc8e0ffe6e4e818e24beb11ffa26cef02..f3e10e5a0848ed1cbc65e6e70a617cca9cbf24d9 100644 (file)
@@ -4,14 +4,16 @@ static int opIMUL_w_iw_a16(uint32_t fetchdat)
         int16_t tempw, tempw2; 
         
         fetch_ea_16(fetchdat);
-                        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         tempw = geteaw();               if (cpu_state.abrt) return 1;
         tempw2 = getword();             if (cpu_state.abrt) return 1;
         
         templ = ((int)tempw) * ((int)tempw2);
         flags_rebuild();
-        if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                           flags &= ~(C_FLAG | V_FLAG);
+        if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                           cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].w = templ & 0xffff;
 
         CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17);
@@ -24,14 +26,16 @@ static int opIMUL_w_iw_a32(uint32_t fetchdat)
         int16_t tempw, tempw2;
         
         fetch_ea_32(fetchdat);
-                        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         tempw = geteaw();               if (cpu_state.abrt) return 1;
         tempw2 = getword();             if (cpu_state.abrt) return 1;
         
         templ = ((int)tempw) * ((int)tempw2);
         flags_rebuild();
-        if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                           flags &= ~(C_FLAG | V_FLAG);
+        if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                           cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].w = templ & 0xffff;
 
         CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17);
@@ -45,14 +49,16 @@ static int opIMUL_l_il_a16(uint32_t fetchdat)
         int32_t templ, templ2;
         
         fetch_ea_16(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         templ = geteal();               if (cpu_state.abrt) return 1;
         templ2 = getlong();             if (cpu_state.abrt) return 1;
         
         temp64 = ((int64_t)templ) * ((int64_t)templ2);
         flags_rebuild();
-        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                             flags &= ~(C_FLAG | V_FLAG);
+        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff;
         
         CLOCK_CYCLES(25);
@@ -65,14 +71,16 @@ static int opIMUL_l_il_a32(uint32_t fetchdat)
         int32_t templ, templ2;
         
         fetch_ea_32(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         templ = geteal();               if (cpu_state.abrt) return 1;
         templ2 = getlong();             if (cpu_state.abrt) return 1;
         
         temp64 = ((int64_t)templ) * ((int64_t)templ2);
         flags_rebuild();
-        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                             flags &= ~(C_FLAG | V_FLAG);
+        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff;
         
         CLOCK_CYCLES(25);
@@ -86,15 +94,17 @@ static int opIMUL_w_ib_a16(uint32_t fetchdat)
         int16_t tempw, tempw2;
         
         fetch_ea_16(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         tempw = geteaw();               if (cpu_state.abrt) return 1;
         tempw2 = getbyte();             if (cpu_state.abrt) return 1;
         if (tempw2 & 0x80) tempw2 |= 0xff00;
         
         templ = ((int)tempw) * ((int)tempw2);
         flags_rebuild();
-        if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                           flags &= ~(C_FLAG | V_FLAG);
+        if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                           cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].w = templ & 0xffff;
         
         CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17);
@@ -107,15 +117,17 @@ static int opIMUL_w_ib_a32(uint32_t fetchdat)
         int16_t tempw, tempw2;
         
         fetch_ea_32(fetchdat);
-        
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         tempw = geteaw();               if (cpu_state.abrt) return 1;
         tempw2 = getbyte();             if (cpu_state.abrt) return 1;
         if (tempw2 & 0x80) tempw2 |= 0xff00;
         
         templ = ((int)tempw) * ((int)tempw2);
         flags_rebuild();
-        if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                           flags &= ~(C_FLAG | V_FLAG);
+        if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                           cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].w = templ & 0xffff;
         
         CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17);
@@ -129,14 +141,17 @@ static int opIMUL_l_ib_a16(uint32_t fetchdat)
         int32_t templ, templ2;
 
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         templ = geteal();               if (cpu_state.abrt) return 1;
         templ2 = getbyte();             if (cpu_state.abrt) return 1;
         if (templ2 & 0x80) templ2 |= 0xffffff00;
         
         temp64 = ((int64_t)templ)*((int64_t)templ2);
         flags_rebuild();
-        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                             flags &= ~(C_FLAG | V_FLAG);
+        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff;
         
         CLOCK_CYCLES(20);
@@ -149,14 +164,17 @@ static int opIMUL_l_ib_a32(uint32_t fetchdat)
         int32_t templ, templ2;
 
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         templ = geteal();               if (cpu_state.abrt) return 1;
         templ2 = getbyte();             if (cpu_state.abrt) return 1;
         if (templ2 & 0x80) templ2 |= 0xffffff00;
         
         temp64 = ((int64_t)templ)*((int64_t)templ2);
         flags_rebuild();
-        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                             flags &= ~(C_FLAG | V_FLAG);
+        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
         cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff;
         
         CLOCK_CYCLES(20);
@@ -171,12 +189,15 @@ static int opIMUL_w_w_a16(uint32_t fetchdat)
         int32_t templ;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw();
         if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = templ & 0xFFFF;
         flags_rebuild();
-        if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                           flags &= ~(C_FLAG | V_FLAG);
+        if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                           cpu_state.flags &= ~(C_FLAG | V_FLAG);
         
         CLOCK_CYCLES(18);
         PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 0);
@@ -187,12 +208,15 @@ static int opIMUL_w_w_a32(uint32_t fetchdat)
         int32_t templ;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw();
         if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = templ & 0xFFFF;
         flags_rebuild();
-        if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                           flags &= ~(C_FLAG | V_FLAG);
+        if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                           cpu_state.flags &= ~(C_FLAG | V_FLAG);
         
         CLOCK_CYCLES(18);
         PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 1);
@@ -204,12 +228,15 @@ static int opIMUL_l_l_a16(uint32_t fetchdat)
         int64_t temp64;
 
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal();
         if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF;
         flags_rebuild();
-        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                             flags &= ~(C_FLAG | V_FLAG);
+        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
         
         CLOCK_CYCLES(30);
         PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 0);
@@ -220,12 +247,15 @@ static int opIMUL_l_l_a32(uint32_t fetchdat)
         int64_t temp64;
 
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_READ(cpu_state.ea_seg);
+
         temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal();
         if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF;
         flags_rebuild();
-        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |=   C_FLAG | V_FLAG;
-        else                                             flags &= ~(C_FLAG | V_FLAG);
+        if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |=   C_FLAG | V_FLAG;
+        else                                             cpu_state.flags &= ~(C_FLAG | V_FLAG);
         
         CLOCK_CYCLES(30);
         PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 1);
index 0b5a3e8a514c8bff71bf2e8ddb371de6ae205593..7afd6c8bfeac2888cb63ebde73938c488d3c541e 100644 (file)
@@ -4,6 +4,8 @@ static int opARPL_a16(uint32_t fetchdat)
         
         NOTRM
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         pclog("ARPL_a16\n");
         temp_seg = geteaw();            if (cpu_state.abrt) return 1;
         
@@ -12,10 +14,10 @@ static int opARPL_a16(uint32_t fetchdat)
         {
                 temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3);
                 seteaw(temp_seg);       if (cpu_state.abrt) return 1;
-                flags |= Z_FLAG;
+                cpu_state.flags |= Z_FLAG;
         }
         else
-                flags &= ~Z_FLAG;
+                cpu_state.flags &= ~Z_FLAG;
         
         CLOCK_CYCLES(is486 ? 9 : 20);
         PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 0);
@@ -27,7 +29,9 @@ static int opARPL_a32(uint32_t fetchdat)
         
         NOTRM
         fetch_ea_32(fetchdat);
-        pclog("ARPL_a32\n");        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
+        pclog("ARPL_a32\n");
         temp_seg = geteaw();            if (cpu_state.abrt) return 1;
         
         flags_rebuild();
@@ -35,10 +39,10 @@ static int opARPL_a32(uint32_t fetchdat)
         {
                 temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3);
                 seteaw(temp_seg);       if (cpu_state.abrt) return 1;
-                flags |= Z_FLAG;
+                cpu_state.flags |= Z_FLAG;
         }
         else
-                flags &= ~Z_FLAG;
+                cpu_state.flags &= ~Z_FLAG;
         
         CLOCK_CYCLES(is486 ? 9 : 20);
         PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 1);
@@ -53,11 +57,13 @@ static int opARPL_a32(uint32_t fetchdat)
                                                                                                                 \
                 NOTRM                                                                                           \
                 fetch_ea(fetchdat);                                                                             \
+                if (cpu_mod != 3)                                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                                       \
                                                                                                                 \
                 sel = geteaw();                 if (cpu_state.abrt) return 1;                                             \
                                                                                                                 \
                 flags_rebuild();                                                                                \
-                if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/                          \
+                if (!(sel & 0xfffc)) { cpu_state.flags &= ~Z_FLAG; return 0; } /*Null selector*/                          \
                 valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);                                       \
                 if (valid)                                                                                      \
                 {                                                                                               \
@@ -65,7 +71,7 @@ static int opARPL_a32(uint32_t fetchdat)
                         desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4);                 \
                         cpl_override = 0;       if (cpu_state.abrt) return 1;                                             \
                 }                                                                                               \
-                flags &= ~Z_FLAG;                                                                               \
+                cpu_state.flags &= ~Z_FLAG;                                                                               \
                 if ((desc & 0x1f00) == 0x000) valid = 0;                                                        \
                 if ((desc & 0x1f00) == 0x800) valid = 0;                                                        \
                 if ((desc & 0x1f00) == 0xa00) valid = 0;                                                        \
@@ -77,7 +83,7 @@ static int opARPL_a32(uint32_t fetchdat)
                 }                                                                                               \
                 if (valid)                                                                                      \
                 {                                                                                               \
-                        flags |= Z_FLAG;                                                                        \
+                        cpu_state.flags |= Z_FLAG;                                                                        \
                         cpl_override = 1;                                                                       \
                         if (is32)                                                                               \
                                 cpu_state.regs[cpu_reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00;       \
@@ -103,10 +109,12 @@ opLAR(l_a32, fetch_ea_32, 1, 1)
                                                                                                                 \
                 NOTRM                                                                                           \
                 fetch_ea(fetchdat);                                                                             \
+                if (cpu_mod != 3)                                                                               \
+                        SEG_CHECK_READ(cpu_state.ea_seg);                                                       \
                                                                                                                 \
                 sel = geteaw();                 if (cpu_state.abrt) return 1;                                             \
                 flags_rebuild();                                                                                \
-                flags &= ~Z_FLAG;                                                                               \
+                cpu_state.flags &= ~Z_FLAG;                                                                               \
                 if (!(sel & 0xfffc)) return 0; /*Null selector*/                                                \
                 valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);                                       \
                 if (valid)                                                                                      \
@@ -125,7 +133,7 @@ opLAR(l_a32, fetch_ea_32, 1, 1)
                 }                                                                                               \
                 if (valid)                                                                                      \
                 {                                                                                               \
-                        flags |= Z_FLAG;                                                                        \
+                        cpu_state.flags |= Z_FLAG;                                                                        \
                         cpl_override = 1;                                                                       \
                         if (is32)                                                                               \
                         {                                                                                       \
@@ -163,22 +171,28 @@ static int op0F00_common(uint32_t fetchdat, int ea32)
         switch (rmdat & 0x38)
         {
                 case 0x00: /*SLDT*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(ldt.seg);
                 CLOCK_CYCLES(4);
                 PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32);
                 break;
                 case 0x08: /*STR*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(tr.seg);
                 CLOCK_CYCLES(4);
                 PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32);
                 break;
                 case 0x10: /*LLDT*/
-                if ((CPL || eflags&VM_FLAG) && (cr0&1))
+                if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1))
                 {
                         pclog("Invalid LLDT!\n");
                         x86gpf(NULL,0);
                         return 1;
                 }
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 sel = geteaw(); if (cpu_state.abrt) return 1;
                 addr = (sel & ~7) + gdt.base;
                 limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16);
@@ -199,12 +213,14 @@ static int op0F00_common(uint32_t fetchdat, int ea32)
                 PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32);
                 break;
                 case 0x18: /*LTR*/
-                if ((CPL || eflags&VM_FLAG) && (cr0&1))
+                if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1))
                 {
                         pclog("Invalid LTR!\n");
                         x86gpf(NULL,0);
                         break;
                 }
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 sel = geteaw(); if (cpu_state.abrt) return 1;
                 addr = (sel & ~7) + gdt.base;
                 limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16);
@@ -228,9 +244,11 @@ static int op0F00_common(uint32_t fetchdat, int ea32)
                 PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32);
                 break;
                 case 0x20: /*VERR*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 sel = geteaw();                 if (cpu_state.abrt) return 1;
                 flags_rebuild();
-                flags &= ~Z_FLAG;
+                cpu_state.flags &= ~Z_FLAG;
                 if (!(sel & 0xfffc)) return 0; /*Null selector*/
                 cpl_override = 1;
                 valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);
@@ -243,14 +261,16 @@ static int op0F00_common(uint32_t fetchdat, int ea32)
                         if (dpl < CPL || dpl < (sel & 3)) valid = 0;
                 }
                 if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/
-                if (valid) flags |= Z_FLAG;
+                if (valid) cpu_state.flags |= Z_FLAG;
                 CLOCK_CYCLES(20);
                 PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32);
                 break;
                 case 0x28: /*VERW*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 sel = geteaw();                 if (cpu_state.abrt) return 1;
                 flags_rebuild();
-                flags &= ~Z_FLAG;
+                cpu_state.flags &= ~Z_FLAG;
                 if (!(sel & 0xfffc)) return 0; /*Null selector*/
                 cpl_override = 1;
                 valid  = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);
@@ -261,7 +281,7 @@ static int op0F00_common(uint32_t fetchdat, int ea32)
                 if (dpl < CPL || dpl < (sel & 3)) valid = 0;
                 if (desc & 0x0800) valid = 0; /*Code*/
                 if (!(desc & 0x0200)) valid = 0; /*Read-only data*/
-                if (valid) flags |= Z_FLAG;
+                if (valid) cpu_state.flags |= Z_FLAG;
                 CLOCK_CYCLES(20);
                 PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32);
                 break;
@@ -300,6 +320,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32)
         switch (rmdat & 0x38)
         {
                 case 0x00: /*SGDT*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(gdt.limit);
                 base = gdt.base; //is32 ? gdt.base : (gdt.base & 0xffffff);
                 if (is286)
@@ -309,6 +331,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32)
                 PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32);
                 break;
                 case 0x08: /*SIDT*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 seteaw(idt.limit);
                 base = idt.base;
                 if (is286)
@@ -318,12 +342,14 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32)
                 PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32);
                 break;
                 case 0x10: /*LGDT*/
-                if ((CPL || eflags&VM_FLAG) && (cr0&1))
+                if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1))
                 {
                         pclog("Invalid LGDT!\n");
                         x86gpf(NULL,0);
                         break;
                 }
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
 //                pclog("LGDT %08X:%08X\n", easeg, eaaddr);
                 limit = geteaw();
                 base = readmeml(0, easeg + cpu_state.eaaddr + 2);         if (cpu_state.abrt) return 1;
@@ -335,12 +361,14 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32)
                 PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32);
                 break;
                 case 0x18: /*LIDT*/
-                if ((CPL || eflags&VM_FLAG) && (cr0&1))
+                if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1))
                 {
                         pclog("Invalid LIDT!\n");
                         x86gpf(NULL,0);
                         break;
                 }
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
 //                pclog("LIDT %08X:%08X\n", easeg, eaaddr);
                 limit = geteaw();
                 base = readmeml(0, easeg + cpu_state.eaaddr + 2);         if (cpu_state.abrt) return 1;
@@ -353,6 +381,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32)
                 break;
 
                 case 0x20: /*SMSW*/
+                if (cpu_mod != 3)
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);
                 if (is486)      seteaw(msw);
                 else if (is386) seteaw(msw | 0xFF00);
                 else            seteaw(msw | 0xFFF0);
@@ -360,12 +390,14 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32)
                 PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32);
                 break;
                 case 0x30: /*LMSW*/
-                if ((CPL || eflags&VM_FLAG) && (msw&1))
+                if ((CPL || cpu_state.eflags&VM_FLAG) && (msw&1))
                 {
                         pclog("LMSW - ring not zero!\n");
                         x86gpf(NULL, 0);
                         break;
                 }
+                if (cpu_mod != 3)
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                 tempw = geteaw();                                       if (cpu_state.abrt) return 1;
                 if (msw & 1) tempw |= 1;
                 if (is386)
@@ -385,12 +417,13 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32)
                 case 0x38: /*INVLPG*/
                 if (is486)
                 {
-                        if ((CPL || eflags&VM_FLAG) && (cr0&1))
+                        if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1))
                         {
                                 pclog("Invalid INVLPG!\n");
                                 x86gpf(NULL, 0);
                                 break;
                         }
+                        SEG_CHECK_READ(cpu_state.ea_seg);
                         mmu_invalidate(ds + cpu_state.eaaddr);
                         CLOCK_CYCLES(12);
                         PREFETCH_RUN(12, 2, rmdat, 0,0,0,0, ea32);
index 8265c19f145332817d4d57eaf7564b014c7dcd64..8d191103d1aa464b99315ef162ca7c82897424d9 100644 (file)
@@ -63,26 +63,26 @@ static int op ## name ## _l_a32(uint32_t fetchdat)              \
         return normal_opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \
 }
 
-op_seg(CS, _cs, x86_opcodes, x86_opcodes)
-op_seg(DS, _ds, x86_opcodes, x86_opcodes)
-op_seg(ES, _es, x86_opcodes, x86_opcodes)
-op_seg(FS, _fs, x86_opcodes, x86_opcodes)
-op_seg(GS, _gs, x86_opcodes, x86_opcodes)
-op_seg(SS, _ss, x86_opcodes, x86_opcodes)
+op_seg(CS, cpu_state.seg_cs, x86_opcodes, x86_opcodes)
+op_seg(DS, cpu_state.seg_ds, x86_opcodes, x86_opcodes)
+op_seg(ES, cpu_state.seg_es, x86_opcodes, x86_opcodes)
+op_seg(FS, cpu_state.seg_fs, x86_opcodes, x86_opcodes)
+op_seg(GS, cpu_state.seg_gs, x86_opcodes, x86_opcodes)
+op_seg(SS, cpu_state.seg_ss, x86_opcodes, x86_opcodes)
 
-op_seg(CS_REPE, _cs, x86_opcodes_REPE, x86_opcodes)
-op_seg(DS_REPE, _ds, x86_opcodes_REPE, x86_opcodes)
-op_seg(ES_REPE, _es, x86_opcodes_REPE, x86_opcodes)
-op_seg(FS_REPE, _fs, x86_opcodes_REPE, x86_opcodes)
-op_seg(GS_REPE, _gs, x86_opcodes_REPE, x86_opcodes)
-op_seg(SS_REPE, _ss, x86_opcodes_REPE, x86_opcodes)
+op_seg(CS_REPE, cpu_state.seg_cs, x86_opcodes_REPE, x86_opcodes)
+op_seg(DS_REPE, cpu_state.seg_ds, x86_opcodes_REPE, x86_opcodes)
+op_seg(ES_REPE, cpu_state.seg_es, x86_opcodes_REPE, x86_opcodes)
+op_seg(FS_REPE, cpu_state.seg_fs, x86_opcodes_REPE, x86_opcodes)
+op_seg(GS_REPE, cpu_state.seg_gs, x86_opcodes_REPE, x86_opcodes)
+op_seg(SS_REPE, cpu_state.seg_ss, x86_opcodes_REPE, x86_opcodes)
 
-op_seg(CS_REPNE, _cs, x86_opcodes_REPNE, x86_opcodes)
-op_seg(DS_REPNE, _ds, x86_opcodes_REPNE, x86_opcodes)
-op_seg(ES_REPNE, _es, x86_opcodes_REPNE, x86_opcodes)
-op_seg(FS_REPNE, _fs, x86_opcodes_REPNE, x86_opcodes)
-op_seg(GS_REPNE, _gs, x86_opcodes_REPNE, x86_opcodes)
-op_seg(SS_REPNE, _ss, x86_opcodes_REPNE, x86_opcodes)
+op_seg(CS_REPNE, cpu_state.seg_cs, x86_opcodes_REPNE, x86_opcodes)
+op_seg(DS_REPNE, cpu_state.seg_ds, x86_opcodes_REPNE, x86_opcodes)
+op_seg(ES_REPNE, cpu_state.seg_es, x86_opcodes_REPNE, x86_opcodes)
+op_seg(FS_REPNE, cpu_state.seg_fs, x86_opcodes_REPNE, x86_opcodes)
+op_seg(GS_REPNE, cpu_state.seg_gs, x86_opcodes_REPNE, x86_opcodes)
+op_seg(SS_REPNE, cpu_state.seg_ss, x86_opcodes_REPNE, x86_opcodes)
 
 static int op_66(uint32_t fetchdat) /*Data size select*/
 {
index 065695706535d6d6587ac266f4e05a8617ae2111..e696f513e169c19a030f43995e0ef5140e6e5452 100644 (file)
@@ -1,5 +1,3 @@
-extern int trap;
-
 #define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \
 static int opREP_INSB_ ## size(uint32_t fetchdat)                               \
 {                                                                               \
@@ -9,12 +7,13 @@ static int opREP_INSB_ ## size(uint32_t fetchdat)
         {                                                                       \
                 uint8_t temp;                                                   \
                                                                                 \
-                check_io_perm(DX);                                               \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
+                check_io_perm(DX);                                              \
                 temp = inb(DX);                                                 \
                 writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1;    \
                                                                                 \
-                if (flags & D_FLAG) DEST_REG--;                                 \
-                else                DEST_REG++;                                 \
+                if (cpu_state.flags & D_FLAG) DEST_REG--;                                 \
+                else                          DEST_REG++;                                 \
                 CNT_REG--;                                                      \
                 cycles -= 15;                                                   \
                 reads++; writes++; total_cycles += 15;                          \
@@ -36,13 +35,14 @@ static int opREP_INSW_ ## size(uint32_t fetchdat)
         {                                                                       \
                 uint16_t temp;                                                  \
                                                                                 \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
                 check_io_perm(DX);                                               \
                 check_io_perm(DX+1);                                             \
                 temp = inw(DX);                                                 \
                 writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1;       \
                                                                                 \
-                if (flags & D_FLAG) DEST_REG -= 2;                              \
-                else                DEST_REG += 2;                              \
+                if (cpu_state.flags & D_FLAG) DEST_REG -= 2;                              \
+                else                          DEST_REG += 2;                              \
                 CNT_REG--;                                                      \
                 cycles -= 15;                                                   \
                 reads++; writes++; total_cycles += 15;                          \
@@ -64,6 +64,7 @@ static int opREP_INSL_ ## size(uint32_t fetchdat)
         {                                                                       \
                 uint32_t temp;                                                  \
                                                                                 \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
                 check_io_perm(DX);                                               \
                 check_io_perm(DX+1);                                             \
                 check_io_perm(DX+2);                                             \
@@ -71,8 +72,8 @@ static int opREP_INSL_ ## size(uint32_t fetchdat)
                 temp = inl(DX);                                                 \
                 writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1;       \
                                                                                 \
-                if (flags & D_FLAG) DEST_REG -= 4;                              \
-                else                DEST_REG += 4;                              \
+                if (cpu_state.flags & D_FLAG) DEST_REG -= 4;                              \
+                else                          DEST_REG += 4;                              \
                 CNT_REG--;                                                      \
                 cycles -= 15;                                                   \
                 reads++; writes++; total_cycles += 15;                          \
@@ -93,11 +94,13 @@ static int opREP_OUTSB_ ## size(uint32_t fetchdat)
                                                                                 \
         if (CNT_REG > 0)                                                        \
         {                                                                       \
-                uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;    \
+                uint8_t temp;                                                   \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;    \
                 check_io_perm(DX);                                               \
                 outb(DX, temp);                                                 \
-                if (flags & D_FLAG) SRC_REG--;                                  \
-                else                SRC_REG++;                                  \
+                if (cpu_state.flags & D_FLAG) SRC_REG--;                                  \
+                else                          SRC_REG++;                                  \
                 CNT_REG--;                                                      \
                 cycles -= 14;                                                   \
                 reads++; writes++; total_cycles += 14;                          \
@@ -117,12 +120,14 @@ static int opREP_OUTSW_ ## size(uint32_t fetchdat)
                                                                                 \
         if (CNT_REG > 0)                                                        \
         {                                                                       \
-                uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;   \
+                uint16_t temp;                                                  \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;   \
                 check_io_perm(DX);                                               \
                 check_io_perm(DX+1);                                             \
                 outw(DX, temp);                                                 \
-                if (flags & D_FLAG) SRC_REG -= 2;                               \
-                else                SRC_REG += 2;                               \
+                if (cpu_state.flags & D_FLAG) SRC_REG -= 2;                               \
+                else                          SRC_REG += 2;                               \
                 CNT_REG--;                                                      \
                 cycles -= 14;                                                   \
                 reads++; writes++; total_cycles += 14;                          \
@@ -142,14 +147,16 @@ static int opREP_OUTSL_ ## size(uint32_t fetchdat)
                                                                                 \
         if (CNT_REG > 0)                                                        \
         {                                                                       \
-                uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;   \
+                uint32_t temp;                                                  \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;   \
                 check_io_perm(DX);                                               \
                 check_io_perm(DX+1);                                             \
                 check_io_perm(DX+2);                                             \
                 check_io_perm(DX+3);                                             \
                 outl(DX, temp);                                                 \
-                if (flags & D_FLAG) SRC_REG -= 4;                               \
-                else                SRC_REG += 4;                               \
+                if (cpu_state.flags & D_FLAG) SRC_REG -= 4;                               \
+                else                          SRC_REG += 4;                               \
                 CNT_REG--;                                                      \
                 cycles -= 14;                                                   \
                 reads++; writes++; total_cycles += 14;                          \
@@ -170,16 +177,21 @@ static int opREP_MOVSB_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+        {                                                                       \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
+        }                                                                       \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
                 uint8_t temp;                                                   \
                                                                                 \
-                CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG);                      \
+                CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG);         \
                 temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;    \
                 writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1;       \
                                                                                 \
-                if (flags & D_FLAG) { DEST_REG--; SRC_REG--; }                  \
-                else                { DEST_REG++; SRC_REG++; }                  \
+                if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; }                  \
+                else                          { DEST_REG++; SRC_REG++; }                  \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 3 : 4;                                        \
                 ins++;                                                          \
@@ -203,16 +215,21 @@ static int opREP_MOVSW_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+        {                                                                       \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
+        }                                                                       \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
                 uint16_t temp;                                                  \
                                                                                 \
-                CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG);                      \
+                CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG);         \
                 temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;    \
                 writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1;       \
                                                                                 \
-                if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; }            \
-                else                { DEST_REG += 2; SRC_REG += 2; }            \
+                if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; }            \
+                else                          { DEST_REG += 2; SRC_REG += 2; }            \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 3 : 4;                                        \
                 ins++;                                                          \
@@ -236,16 +253,21 @@ static int opREP_MOVSL_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+        {                                                                       \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
+        }                                                                       \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
                 uint32_t temp;                                                  \
                                                                                 \
-                CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG);                      \
+                CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG);         \
                 temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;    \
                 writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1;       \
                                                                                 \
-                if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; }            \
-                else                { DEST_REG += 4; SRC_REG += 4; }            \
+                if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; }            \
+                else                          { DEST_REG += 4; SRC_REG += 4; }            \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 3 : 4;                                        \
                 ins++;                                                          \
@@ -271,12 +293,14 @@ static int opREP_STOSB_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
-                CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG);                      \
+                CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG);         \
                 writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1;         \
-                if (flags & D_FLAG) DEST_REG--;                                 \
-                else                DEST_REG++;                                 \
+                if (cpu_state.flags & D_FLAG) DEST_REG--;                                 \
+                else                          DEST_REG++;                                 \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 4 : 5;                                        \
                 writes++; total_cycles += is486 ? 4 : 5;                        \
@@ -299,12 +323,14 @@ static int opREP_STOSW_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
-                CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG+1);                    \
+                CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG+1);       \
                 writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1;         \
-                if (flags & D_FLAG) DEST_REG -= 2;                              \
-                else                DEST_REG += 2;                              \
+                if (cpu_state.flags & D_FLAG) DEST_REG -= 2;                              \
+                else                          DEST_REG += 2;                              \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 4 : 5;                                        \
                 writes++; total_cycles += is486 ? 4 : 5;                        \
@@ -327,12 +353,14 @@ static int opREP_STOSL_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+                SEG_CHECK_WRITE(&cpu_state.seg_es);                             \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
-                CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG+3);                    \
+                CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG+3);       \
                 writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1;        \
-                if (flags & D_FLAG) DEST_REG -= 4;                              \
-                else                DEST_REG += 4;                              \
+                if (cpu_state.flags & D_FLAG) DEST_REG -= 4;                              \
+                else                          DEST_REG += 4;                              \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 4 : 5;                                        \
                 writes++; total_cycles += is486 ? 4 : 5;                        \
@@ -356,11 +384,13 @@ static int opREP_LODSB_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
                 AL = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;      \
-                if (flags & D_FLAG) SRC_REG--;                                  \
-                else                SRC_REG++;                                  \
+                if (cpu_state.flags & D_FLAG) SRC_REG--;                                  \
+                else                          SRC_REG++;                                  \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 4 : 5;                                        \
                 reads++; total_cycles += is486 ? 4 : 5;                         \
@@ -383,11 +413,13 @@ static int opREP_LODSW_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
                 AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;      \
-                if (flags & D_FLAG) SRC_REG -= 2;                               \
-                else                SRC_REG += 2;                               \
+                if (cpu_state.flags & D_FLAG) SRC_REG -= 2;                               \
+                else                          SRC_REG += 2;                               \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 4 : 5;                                        \
                 reads++; total_cycles += is486 ? 4 : 5;                         \
@@ -410,11 +442,13 @@ static int opREP_LODSL_ ## size(uint32_t fetchdat)
         int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100);    \
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
+        if (CNT_REG > 0)                                                        \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
         while (CNT_REG > 0)                                                     \
         {                                                                       \
                 EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1;     \
-                if (flags & D_FLAG) SRC_REG -= 4;                               \
-                else                SRC_REG += 4;                               \
+                if (cpu_state.flags & D_FLAG) SRC_REG -= 4;                               \
+                else                          SRC_REG += 4;                               \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 4 : 5;                                        \
                 reads++; total_cycles += is486 ? 4 : 5;                         \
@@ -441,11 +475,14 @@ static int opREP_CMPSB_ ## size(uint32_t fetchdat)
         tempz = FV;                                                             \
         if ((CNT_REG > 0) && (FV == tempz))                                     \
         {                                                                       \
-                uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG);       \
-                uint8_t temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1;      \
+                uint8_t temp, temp2;                                            \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                SEG_CHECK_READ(&cpu_state.seg_es);                              \
+                temp = readmemb(cpu_state.ea_seg->base, SRC_REG);               \
+                temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1;   \
                                                                                 \
-                if (flags & D_FLAG) { DEST_REG--; SRC_REG--; }                  \
-                else                { DEST_REG++; SRC_REG++; }                  \
+                if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; }                  \
+                else                          { DEST_REG++; SRC_REG++; }                  \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 7 : 9;                                        \
                 reads += 2; total_cycles += is486 ? 7 : 9;                      \
@@ -468,11 +505,14 @@ static int opREP_CMPSW_ ## size(uint32_t fetchdat)
         tempz = FV;                                                             \
         if ((CNT_REG > 0) && (FV == tempz))                                     \
         {                                                                       \
-                uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG);      \
-                uint16_t temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1;     \
+                uint16_t temp, temp2;                                           \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                SEG_CHECK_READ(&cpu_state.seg_es);                              \
+                temp = readmemw(cpu_state.ea_seg->base, SRC_REG);               \
+                temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1;   \
                                                                                 \
-                if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; }            \
-                else                { DEST_REG += 2; SRC_REG += 2; }            \
+                if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; }            \
+                else                          { DEST_REG += 2; SRC_REG += 2; }            \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 7 : 9;                                        \
                 reads += 2; total_cycles += is486 ? 7 : 9;                      \
@@ -495,11 +535,14 @@ static int opREP_CMPSL_ ## size(uint32_t fetchdat)
         tempz = FV;                                                             \
         if ((CNT_REG > 0) && (FV == tempz))                                     \
         {                                                                       \
-                uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG);      \
-                uint32_t temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1;     \
+                uint32_t temp, temp2;                                           \
+                SEG_CHECK_READ(cpu_state.ea_seg);                               \
+                SEG_CHECK_READ(&cpu_state.seg_es);                              \
+                temp = readmeml(cpu_state.ea_seg->base, SRC_REG);               \
+                temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1;   \
                                                                                 \
-                if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; }            \
-                else                { DEST_REG += 4; SRC_REG += 4; }            \
+                if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; }            \
+                else                          { DEST_REG += 4; SRC_REG += 4; }            \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 7 : 9;                                        \
                 reads += 2; total_cycles += is486 ? 7 : 9;                      \
@@ -523,13 +566,15 @@ static int opREP_SCASB_ ## size(uint32_t fetchdat)
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
         tempz = FV;                                                             \
+        if ((CNT_REG > 0) && (FV == tempz))                                     \
+                SEG_CHECK_READ(&cpu_state.seg_es);                              \
         while ((CNT_REG > 0) && (FV == tempz))                                  \
         {                                                                       \
                 uint8_t temp = readmemb(es, DEST_REG); if (cpu_state.abrt) break;\
                 setsub8(AL, temp);                                              \
                 tempz = (ZF_SET()) ? 1 : 0;                                     \
-                if (flags & D_FLAG) DEST_REG--;                                 \
-                else                DEST_REG++;                                 \
+                if (cpu_state.flags & D_FLAG) DEST_REG--;                                 \
+                else                          DEST_REG++;                                 \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 5 : 8;                                        \
                 reads++; total_cycles += is486 ? 5 : 8;                         \
@@ -554,13 +599,15 @@ static int opREP_SCASW_ ## size(uint32_t fetchdat)
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
         tempz = FV;                                                             \
+        if ((CNT_REG > 0) && (FV == tempz))                                     \
+                SEG_CHECK_READ(&cpu_state.seg_es);                              \
         while ((CNT_REG > 0) && (FV == tempz))                                  \
         {                                                                       \
                 uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\
                 setsub16(AX, temp);                                             \
                 tempz = (ZF_SET()) ? 1 : 0;                                     \
-                if (flags & D_FLAG) DEST_REG -= 2;                              \
-                else                DEST_REG += 2;                              \
+                if (cpu_state.flags & D_FLAG) DEST_REG -= 2;                              \
+                else                          DEST_REG += 2;                              \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 5 : 8;                                        \
                 reads++; total_cycles += is486 ? 5 : 8;                         \
@@ -585,13 +632,15 @@ static int opREP_SCASL_ ## size(uint32_t fetchdat)
         if (trap)                                                               \
                 cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/     \
         tempz = FV;                                                             \
+        if ((CNT_REG > 0) && (FV == tempz))                                     \
+                SEG_CHECK_READ(&cpu_state.seg_es);                              \
         while ((CNT_REG > 0) && (FV == tempz))                                  \
         {                                                                       \
                 uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\
                 setsub32(EAX, temp);                                            \
                 tempz = (ZF_SET()) ? 1 : 0;                                     \
-                if (flags & D_FLAG) DEST_REG -= 4;                              \
-                else                DEST_REG += 4;                              \
+                if (cpu_state.flags & D_FLAG) DEST_REG -= 4;                              \
+                else                          DEST_REG += 4;                              \
                 CNT_REG--;                                                      \
                 cycles -= is486 ? 5 : 8;                                        \
                 reads++; total_cycles += is486 ? 5 : 8;                         \
index 71d1bb7c7869aaf2fe3808fbc85d96f9a09cabd1..271da6e575c4dd43532ff3f0321f95100cb08ac3 100644 (file)
@@ -1,10 +1,9 @@
 #define RETF_a16(stack_offset)                                  \
-                if ((msw&1) && !(eflags&VM_FLAG))               \
+                if ((msw&1) && !(cpu_state.eflags&VM_FLAG))     \
                 {                                               \
                         pmoderetf(0, stack_offset);             \
                         return 1;                               \
                 }                                               \
-                oxpc = cpu_state.pc;                            \
                 if (stack32)                                    \
                 {                                               \
                         cpu_state.pc = readmemw(ss, ESP);       \
                 cycles -= timing_retf_rm;
 
 #define RETF_a32(stack_offset)                                  \
-                if ((msw&1) && !(eflags&VM_FLAG))               \
+                if ((msw&1) && !(cpu_state.eflags&VM_FLAG))     \
                 {                                               \
                         pmoderetf(1, stack_offset);             \
                         return 1;                               \
                 }                                               \
-                oxpc = cpu_state.pc;                            \
                 if (stack32)                                    \
                 {                                               \
                         cpu_state.pc = readmeml(ss, ESP);       \
@@ -94,7 +92,7 @@ static int opIRET_286(uint32_t fetchdat)
 {
         int cycles_old = cycles; UNUSED(cycles_old);
         
-        if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
+        if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3))
         {
                 x86gpf(NULL,0);
                 return 1;
@@ -108,19 +106,18 @@ static int opIRET_286(uint32_t fetchdat)
         else
         {
                 uint16_t new_cs;
-                oxpc = cpu_state.pc;
                 if (stack32)
                 {
                         cpu_state.pc = readmemw(ss, ESP);
                         new_cs = readmemw(ss, ESP + 2);
-                        flags = (flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2;
+                        cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2;
                         ESP += 6;
                 }
                 else
                 {
                         cpu_state.pc = readmemw(ss, SP);
                         new_cs = readmemw(ss, ((SP + 2) & 0xffff));
-                        flags = (flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2;
+                        cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2;
                         SP += 6;
                 }
                 loadcs(new_cs);
@@ -139,7 +136,7 @@ static int opIRET(uint32_t fetchdat)
 {
         int cycles_old = cycles; UNUSED(cycles_old);
         
-        if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
+        if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3))
         {
                 if (cr4 & CR4_VME)
                 {
@@ -151,17 +148,17 @@ static int opIRET(uint32_t fetchdat)
                         if (cpu_state.abrt)
                                 return 1;
 
-                        if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (eflags & VIP_FLAG)))
+                        if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (cpu_state.eflags & VIP_FLAG)))
                         {
                                 x86gpf(NULL, 0);
                                 return 1;
                         }
                         SP += 6;
                         if (new_flags & I_FLAG)
-                                eflags |= VIF_FLAG;
+                                cpu_state.eflags |= VIF_FLAG;
                         else
-                                eflags &= ~VIF_FLAG;
-                        flags = (flags & 0x3300) | (new_flags & 0x4cd5) | 2;
+                                cpu_state.eflags &= ~VIF_FLAG;
+                        cpu_state.flags = (cpu_state.flags & 0x3300) | (new_flags & 0x4cd5) | 2;
                         loadcs(new_cs);
                         cpu_state.pc = new_pc;
 
@@ -184,19 +181,18 @@ static int opIRET(uint32_t fetchdat)
                 else
                 {
                         uint16_t new_cs;
-                        oxpc = cpu_state.pc;
                         if (stack32)
                         {
                                 cpu_state.pc = readmemw(ss, ESP);
                                 new_cs = readmemw(ss, ESP + 2);
-                                flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2;
+                                cpu_state.flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2;
                                 ESP += 6;
                         }
                         else
                         {
                                 cpu_state.pc = readmemw(ss, SP);
                                 new_cs = readmemw(ss, ((SP + 2) & 0xffff));
-                                flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2;
+                                cpu_state.flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2;
                                 SP += 6;
                         }
                         loadcs(new_cs);
@@ -216,7 +212,7 @@ static int opIRETD(uint32_t fetchdat)
 {
         int cycles_old = cycles; UNUSED(cycles_old);
         
-        if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
+        if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3))
         {
                 x86gpf(NULL,0);
                 return 1;
@@ -230,21 +226,20 @@ static int opIRETD(uint32_t fetchdat)
         else
         {
                 uint16_t new_cs;
-                oxpc = cpu_state.pc;
                 if (stack32)
                 {
                         cpu_state.pc = readmeml(ss, ESP);
                         new_cs = readmemw(ss, ESP + 4);
-                        flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2;
-                        eflags = readmemw(ss, ESP + 10);
+                        cpu_state.flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2;
+                        cpu_state.eflags = readmemw(ss, ESP + 10);
                         ESP += 12;
                 }
                 else
                 {
                         cpu_state.pc = readmeml(ss, SP);
                         new_cs = readmemw(ss, ((SP + 4) & 0xffff));
-                        flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2;
-                        eflags = readmemw(ss, (SP + 10) & 0xffff);
+                        cpu_state.flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2;
+                        cpu_state.eflags = readmemw(ss, (SP + 10) & 0xffff);
                         SP += 12;
                 }
                 loadcs(new_cs);
index 0094b85d46c4c6fb3511aad70d5a0c5879758199..f6fd50e6937bd9b5265186007f1e31ffcc08809d 100644 (file)
@@ -2,6 +2,8 @@
         static int opSET ## condition ## _a16(uint32_t fetchdat)        \
         {                                                               \
                 fetch_ea_16(fetchdat);                                  \
+                if (cpu_mod != 3)                                       \
+                        SEG_CHECK_READ(cpu_state.ea_seg);               \
                 seteab((cond_ ## condition) ? 1 : 0);                   \
                 CLOCK_CYCLES(4);                                        \
                 return cpu_state.abrt;                                            \
@@ -10,6 +12,8 @@
         static int opSET ## condition ## _a32(uint32_t fetchdat)        \
         {                                                               \
                 fetch_ea_32(fetchdat);                                  \
+                if (cpu_mod != 3)                                       \
+                        SEG_CHECK_READ(cpu_state.ea_seg);               \
                 seteab((cond_ ## condition) ? 1 : 0);                   \
                 CLOCK_CYCLES(4);                                        \
                 return cpu_state.abrt;                                            \
index 495a1bf471dd85b350841b34c45d6ddd21062596..16e9c6151a7661c8f96f861c2a1e4006a9f15294 100644 (file)
@@ -6,36 +6,21 @@
                 switch (rmdat & 0x38)                                                   \
                 {                                                                       \
                         case 0x00: /*ROL b, c*/                                         \
-                        while (c > 0)                                                   \
-                        {                                                               \
-                                temp2 = (temp & 0x80) ? 1 : 0;                          \
-                                temp = (temp << 1) | temp2;                             \
-                                c--;                                                    \
-                        }                                                               \
-                        seteab(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG;            \
+                        temp = (temp << (c & 7)) | (temp >> (8-(c & 7)));               \
+                        seteab(temp);      if (cpu_state.abrt) return 1;                     \
+                        set_flags_rotate(FLAGS_ROL8, temp);                             \
                         CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                                 \
                         PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                         case 0x08: /*ROR b,CL*/                                         \
-                        while (c > 0)                                                   \
-                        {                                                               \
-                                temp2 = temp & 1;                                       \
-                                temp >>= 1;                                             \
-                                if (temp2) temp |= 0x80;                                \
-                                c--;                                                    \
-                        }                                                               \
-                        seteab(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG;               \
+                        temp = (temp >> (c & 7)) | (temp << (8-(c & 7)));               \
+                        seteab(temp);      if (cpu_state.abrt) return 1;                \
+                        set_flags_rotate(FLAGS_ROR8, temp);                             \
                         CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                                 \
                         PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                         case 0x10: /*RCL b,CL*/                                         \
-                        temp2 = flags & C_FLAG;                                         \
+                        temp2 = cpu_state.flags & C_FLAG;                                         \
                         if (is486) CLOCK_CYCLES_ALWAYS(c);                              \
                         while (c > 0)                                                   \
                         {                                                               \
                                 c--;                                                    \
                         }                                                               \
                         seteab(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG;            \
+                        cpu_state.flags &= ~(C_FLAG | V_FLAG);                                    \
+                        if (temp2) cpu_state.flags |= C_FLAG;                                     \
+                        if ((cpu_state.flags & C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG;            \
                         CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10);                                \
                         PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                         case 0x18: /*RCR b,CL*/                                         \
-                        temp2 = flags & C_FLAG;                                         \
+                        temp2 = cpu_state.flags & C_FLAG;                                         \
                         if (is486) CLOCK_CYCLES_ALWAYS(c);                              \
                         while (c > 0)                                                   \
                         {                                                               \
@@ -62,9 +47,9 @@
                                 c--;                                                    \
                         }                                                               \
                         seteab(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG;               \
+                        cpu_state.flags &= ~(C_FLAG | V_FLAG);                                    \
+                        if (temp2) cpu_state.flags |= C_FLAG;                                     \
+                        if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG;               \
                         CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10);                                \
                         PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                 switch (rmdat & 0x38)                                                   \
                 {                                                                       \
                         case 0x00: /*ROL w, c*/                                         \
-                        while (c > 0)                                                   \
-                        {                                                               \
-                                temp2 = (temp & 0x8000) ? 1 : 0;                        \
-                                temp = (temp << 1) | temp2;                             \
-                                c--;                                                    \
-                        }                                                               \
-                        seteaw(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG;           \
-                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                                 \
+                        temp = (temp << (c & 15)) | (temp >> (16-(c & 15)));            \
+                        seteaw(temp);      if (cpu_state.abrt) return 1;                \
+                        set_flags_rotate(FLAGS_ROL16, temp);                            \
+                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                           \
                         PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
-                        case 0x08: /*ROR w, c*/                                         \
-                        while (c > 0)                                                   \
-                        {                                                               \
-                                temp2 = temp & 1;                                       \
-                                temp >>= 1;                                             \
-                                if (temp2) temp |= 0x8000;                              \
-                                c--;                                                    \
-                        }                                                               \
-                        seteaw(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG;             \
-                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                                 \
+                        case 0x08: /*ROR w,CL*/                                         \
+                        temp = (temp >> (c & 15)) | (temp << (16-(c & 15)));            \
+                        seteaw(temp);      if (cpu_state.abrt) return 1;                \
+                        set_flags_rotate(FLAGS_ROR16, temp);                            \
+                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                           \
                         PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                         case 0x10: /*RCL w, c*/                                         \
-                        temp2 = flags & C_FLAG;                                         \
+                        temp2 = cpu_state.flags & C_FLAG;                                         \
                         if (is486) CLOCK_CYCLES_ALWAYS(c);                              \
                         while (c > 0)                                                   \
                         {                                                               \
                                 c--;                                                    \
                         }                                                               \
                         seteaw(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG;           \
+                        cpu_state.flags &= ~(C_FLAG | V_FLAG);                                    \
+                        if (temp2) cpu_state.flags |= C_FLAG;                                     \
+                        if ((cpu_state.flags & C_FLAG) ^ (temp >> 15)) cpu_state.flags |= V_FLAG;           \
                         CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10);                                \
                         PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                         case 0x18: /*RCR w, c*/                                         \
-                        temp2 = flags & C_FLAG;                                         \
+                        temp2 = cpu_state.flags & C_FLAG;                                         \
                         if (is486) CLOCK_CYCLES_ALWAYS(c);                              \
                         while (c > 0)                                                   \
                         {                                                               \
                                 c--;                                                    \
                         }                                                               \
                         seteaw(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG;             \
+                        cpu_state.flags &= ~(C_FLAG | V_FLAG);                                    \
+                        if (temp2) cpu_state.flags |= C_FLAG;                                     \
+                        if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG;             \
                         CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10);                                \
                         PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                 switch (rmdat & 0x38)                                                   \
                 {                                                                       \
                         case 0x00: /*ROL l, c*/                                         \
-                        while (c > 0)                                                   \
-                        {                                                               \
-                                temp2 = (temp & 0x80000000) ? 1 : 0;                    \
-                                temp = (temp << 1) | temp2;                             \
-                                c--;                                                    \
-                        }                                                               \
-                        seteal(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG;           \
-                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                                 \
-                        PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \
+                        temp = (temp << c) | (temp >> (32-c));                          \
+                        seteal(temp);      if (cpu_state.abrt) return 1;                \
+                        set_flags_rotate(FLAGS_ROL32, temp);                            \
+                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                           \
+                        PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
-                        case 0x08: /*ROR l, c*/                                         \
-                        while (c > 0)                                                   \
-                        {                                                               \
-                                temp2 = temp & 1;                                       \
-                                temp >>= 1;                                             \
-                                if (temp2) temp |= 0x80000000;                          \
-                                c--;                                                    \
-                        }                                                               \
-                        seteal(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG;         \
-                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                                 \
-                        PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \
+                        case 0x08: /*ROR l,CL*/                                         \
+                        temp = (temp >> c) | (temp << (32-c));                          \
+                        seteal(temp);      if (cpu_state.abrt) return 1;                \
+                        set_flags_rotate(FLAGS_ROR32, temp);                            \
+                        CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7);                           \
+                        PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \
                         break;                                                          \
                         case 0x10: /*RCL l, c*/                                         \
                         temp2 = CF_SET();                                               \
                                 c--;                                                    \
                         }                                                               \
                         seteal(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG;           \
+                        cpu_state.flags &= ~(C_FLAG | V_FLAG);                                    \
+                        if (temp2) cpu_state.flags |= C_FLAG;                                     \
+                        if ((cpu_state.flags & C_FLAG) ^ (temp >> 31)) cpu_state.flags |= V_FLAG;           \
                         CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10);                                \
                         PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \
                         break;                                                          \
                         case 0x18: /*RCR l, c*/                                         \
-                        temp2 = flags & C_FLAG;                                         \
+                        temp2 = cpu_state.flags & C_FLAG;                                         \
                         if (is486) CLOCK_CYCLES_ALWAYS(c);                              \
                         while (c > 0)                                                   \
                         {                                                               \
                                 c--;                                                    \
                         }                                                               \
                         seteal(temp);           if (cpu_state.abrt) return 1;                     \
-                        flags &= ~(C_FLAG | V_FLAG);                                    \
-                        if (temp2) flags |= C_FLAG;                                     \
-                        if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG;         \
+                        cpu_state.flags &= ~(C_FLAG | V_FLAG);                                    \
+                        if (temp2) cpu_state.flags |= C_FLAG;                                     \
+                        if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG;         \
                         CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10);                                \
                         PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \
                         break;                                                          \
@@ -281,6 +236,8 @@ static int opC0_a16(uint32_t fetchdat)
         uint8_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++;
         PREFETCH_PREFIX();
         temp = geteab();                if (cpu_state.abrt) return 1;
@@ -294,6 +251,8 @@ static int opC0_a32(uint32_t fetchdat)
         uint8_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++;
         PREFETCH_PREFIX();
         temp = geteab();                if (cpu_state.abrt) return 1;
@@ -307,6 +266,8 @@ static int opC1_w_a16(uint32_t fetchdat)
         uint16_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++;
         PREFETCH_PREFIX();
         temp = geteaw();                if (cpu_state.abrt) return 1;
@@ -320,6 +281,8 @@ static int opC1_w_a32(uint32_t fetchdat)
         uint16_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++;
         PREFETCH_PREFIX();
         temp = geteaw();                if (cpu_state.abrt) return 1;
@@ -333,6 +296,8 @@ static int opC1_l_a16(uint32_t fetchdat)
         uint32_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++;
         PREFETCH_PREFIX();
         temp = geteal();                if (cpu_state.abrt) return 1;
@@ -346,6 +311,8 @@ static int opC1_l_a32(uint32_t fetchdat)
         uint32_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++;
         PREFETCH_PREFIX();
         temp = geteal();                if (cpu_state.abrt) return 1;
@@ -360,6 +327,8 @@ static int opD0_a16(uint32_t fetchdat)
         uint8_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                if (cpu_state.abrt) return 1;
         OP_SHIFT_b(c, 0);
         return 0;
@@ -371,6 +340,8 @@ static int opD0_a32(uint32_t fetchdat)
         uint8_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                if (cpu_state.abrt) return 1;
         OP_SHIFT_b(c, 1);
         return 0;
@@ -382,6 +353,8 @@ static int opD1_w_a16(uint32_t fetchdat)
         uint16_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                if (cpu_state.abrt) return 1;
         OP_SHIFT_w(c, 0);
         return 0;
@@ -393,6 +366,8 @@ static int opD1_w_a32(uint32_t fetchdat)
         uint16_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                if (cpu_state.abrt) return 1;
         OP_SHIFT_w(c, 1);
         return 0;
@@ -404,6 +379,8 @@ static int opD1_l_a16(uint32_t fetchdat)
         uint32_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                if (cpu_state.abrt) return 1;
         OP_SHIFT_l(c, 0);
         return 0;
@@ -415,6 +392,8 @@ static int opD1_l_a32(uint32_t fetchdat)
         uint32_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                if (cpu_state.abrt) return 1;
         OP_SHIFT_l(c, 1);
         return 0;
@@ -427,6 +406,8 @@ static int opD2_a16(uint32_t fetchdat)
         uint8_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = CL & 31;
         temp = geteab();                if (cpu_state.abrt) return 1;
         OP_SHIFT_b(c, 0);
@@ -439,6 +420,8 @@ static int opD2_a32(uint32_t fetchdat)
         uint8_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = CL & 31;
         temp = geteab();                if (cpu_state.abrt) return 1;
         OP_SHIFT_b(c, 1);
@@ -451,6 +434,8 @@ static int opD3_w_a16(uint32_t fetchdat)
         uint16_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = CL & 31;
         temp = geteaw();                if (cpu_state.abrt) return 1;
         OP_SHIFT_w(c, 0);
@@ -463,6 +448,8 @@ static int opD3_w_a32(uint32_t fetchdat)
         uint16_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = CL & 31;
         temp = geteaw();                if (cpu_state.abrt) return 1;
         OP_SHIFT_w(c, 1);
@@ -475,6 +462,8 @@ static int opD3_l_a16(uint32_t fetchdat)
         uint32_t temp, temp2;
         
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = CL & 31;
         temp = geteal();                if (cpu_state.abrt) return 1;
         OP_SHIFT_l(c, 0);
@@ -487,6 +476,8 @@ static int opD3_l_a32(uint32_t fetchdat)
         uint32_t temp, temp2;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         c = CL & 31;
         temp = geteal();                if (cpu_state.abrt) return 1;
         OP_SHIFT_l(c, 1);
@@ -505,7 +496,7 @@ static int opD3_l_a32(uint32_t fetchdat)
                 seteaw(tempw);                  if (cpu_state.abrt) return 1;             \
                 setznp16(tempw);                                                \
                 flags_rebuild();                                                \
-                if (tempc) flags |= C_FLAG;                                     \
+                if (tempc) cpu_state.flags |= C_FLAG;                                     \
         }
 
 #define SHLD_l()                                                                \
@@ -517,7 +508,7 @@ static int opD3_l_a32(uint32_t fetchdat)
                 seteal(templ);                  if (cpu_state.abrt) return 1;             \
                 setznp32(templ);                                                \
                 flags_rebuild();                                                \
-                if (tempc) flags |= C_FLAG;                                     \
+                if (tempc) cpu_state.flags |= C_FLAG;                                     \
         }
 
 
@@ -531,7 +522,7 @@ static int opD3_l_a32(uint32_t fetchdat)
                 seteaw(tempw);                  if (cpu_state.abrt) return 1;             \
                 setznp16(tempw);                                                \
                 flags_rebuild();                                                \
-                if (tempc) flags |= C_FLAG;                                     \
+                if (tempc) cpu_state.flags |= C_FLAG;                                     \
         }
 
 #define SHRD_l()                                                                \
@@ -543,7 +534,7 @@ static int opD3_l_a32(uint32_t fetchdat)
                 seteal(templ);                  if (cpu_state.abrt) return 1;             \
                 setznp32(templ);                                                \
                 flags_rebuild();                                                \
-                if (tempc) flags |= C_FLAG;                                     \
+                if (tempc) cpu_state.flags |= C_FLAG;                                     \
         }
 
 #define opSHxD(operation)                                                       \
@@ -552,6 +543,8 @@ static int opD3_l_a32(uint32_t fetchdat)
                 int count;                                                      \
                                                                                 \
                 fetch_ea_16(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 count = getbyte() & 31;                                         \
                 operation();                                                    \
                                                                                 \
@@ -564,6 +557,8 @@ static int opD3_l_a32(uint32_t fetchdat)
                 int count;                                                      \
                                                                                 \
                 fetch_ea_16(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 count = CL & 31;                                                \
                 operation();                                                    \
                                                                                 \
@@ -576,6 +571,8 @@ static int opD3_l_a32(uint32_t fetchdat)
                 int count;                                                      \
                                                                                 \
                 fetch_ea_32(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 count = getbyte() & 31;                                         \
                 operation();                                                    \
                                                                                 \
@@ -588,6 +585,8 @@ static int opD3_l_a32(uint32_t fetchdat)
                 int count;                                                      \
                                                                                 \
                 fetch_ea_32(fetchdat);                                          \
+                if (cpu_mod != 3)                                               \
+                        SEG_CHECK_WRITE(cpu_state.ea_seg);                      \
                 count = CL & 31;                                                \
                 operation();                                                    \
                                                                                 \
index 86daf52aad777603621ad0d8ea97613ee5a5e1bb..fb55e364b110f1287c9717047e46631970294f9e 100644 (file)
@@ -236,6 +236,8 @@ static int opPOPW_a16(uint32_t fetchdat)
         temp = POP_W();                                 if (cpu_state.abrt) return 1;
 
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         seteaw(temp);
         if (cpu_state.abrt)
         {
@@ -255,6 +257,8 @@ static int opPOPW_a32(uint32_t fetchdat)
         temp = POP_W();                                 if (cpu_state.abrt) return 1;
         
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         seteaw(temp);
         if (cpu_state.abrt)
         {
@@ -275,6 +279,8 @@ static int opPOPL_a16(uint32_t fetchdat)
         temp = POP_L();                                 if (cpu_state.abrt) return 1;
 
         fetch_ea_16(fetchdat);        
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         seteal(temp);
         if (cpu_state.abrt)
         {
@@ -294,6 +300,8 @@ static int opPOPL_a32(uint32_t fetchdat)
         temp = POP_L();                                 if (cpu_state.abrt) return 1;
 
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         seteal(temp);
         if (cpu_state.abrt)
         {
@@ -462,10 +470,10 @@ PUSH_SEG_OPS(FS);
 PUSH_SEG_OPS(GS);
 PUSH_SEG_OPS(SS);
 
-POP_SEG_OPS(DS, &_ds);
-POP_SEG_OPS(ES, &_es);
-POP_SEG_OPS(FS, &_fs);
-POP_SEG_OPS(GS, &_gs);
+POP_SEG_OPS(DS, &cpu_state.seg_ds);
+POP_SEG_OPS(ES, &cpu_state.seg_es);
+POP_SEG_OPS(FS, &cpu_state.seg_fs);
+POP_SEG_OPS(GS, &cpu_state.seg_gs);
 
 
 static int opPOP_SS_w(uint32_t fetchdat)
@@ -473,14 +481,14 @@ static int opPOP_SS_w(uint32_t fetchdat)
         uint16_t temp_seg;
         uint32_t temp_esp = ESP;
         temp_seg = POP_W();                     if (cpu_state.abrt) return 1;
-        loadseg(temp_seg, &_ss);                if (cpu_state.abrt) { ESP = temp_esp; return 1; }
+        loadseg(temp_seg, &cpu_state.seg_ss);   if (cpu_state.abrt) { ESP = temp_esp; return 1; }
         CLOCK_CYCLES(is486 ? 3 : 7);
         PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0);
                         
         cpu_state.oldpc = cpu_state.pc;
         cpu_state.op32 = use32;
         cpu_state.ssegs = 0;
-        cpu_state.ea_seg = &_ds;
+        cpu_state.ea_seg = &cpu_state.seg_ds;
         fetchdat = fastreadl(cs + cpu_state.pc);
         cpu_state.pc++;
         if (cpu_state.abrt) return 1;
@@ -493,14 +501,14 @@ static int opPOP_SS_l(uint32_t fetchdat)
         uint32_t temp_seg;
         uint32_t temp_esp = ESP;
         temp_seg = POP_L();                     if (cpu_state.abrt) return 1;
-        loadseg(temp_seg & 0xffff, &_ss);       if (cpu_state.abrt) { ESP = temp_esp; return 1; }
+        loadseg(temp_seg & 0xffff, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; }
         CLOCK_CYCLES(is486 ? 3 : 7);
         PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0);
 
         cpu_state.oldpc = cpu_state.pc;
         cpu_state.op32 = use32;
         cpu_state.ssegs = 0;
-        cpu_state.ea_seg = &_ds;
+        cpu_state.ea_seg = &cpu_state.seg_ds;
         fetchdat = fastreadl(cs + cpu_state.pc);
         cpu_state.pc++;
         if (cpu_state.abrt) return 1;
index 8c8ba6816a19f24dd06d77e83011f52d1bf2bdf0..c02725138dfacfb3685bf1c202ebee80fd0043bb 100644 (file)
@@ -1,19 +1,27 @@
 static int opMOVSB_a16(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
+        temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         writememb(es, DI, temp);                if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) { DI--; SI--; }
-        else                { DI++; SI++; }
+        if (cpu_state.flags & D_FLAG) { DI--; SI--; }
+        else                          { DI++; SI++; }
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0);
         return 0;
 }
 static int opMOVSB_a32(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
+        temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         writememb(es, EDI, temp);               if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) { EDI--; ESI--; }
-        else                { EDI++; ESI++; }
+        if (cpu_state.flags & D_FLAG) { EDI--; ESI--; }
+        else                          { EDI++; ESI++; }
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1);
         return 0;
@@ -21,20 +29,28 @@ static int opMOVSB_a32(uint32_t fetchdat)
 
 static int opMOVSW_a16(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
+        temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         writememw(es, DI, temp);                if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) { DI -= 2; SI -= 2; }
-        else                { DI += 2; SI += 2; }
+        if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; }
+        else                          { DI += 2; SI += 2; }
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0);
         return 0;
 }
 static int opMOVSW_a32(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
+        temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         writememw(es, EDI, temp);               if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) { EDI -= 2; ESI -= 2; }
-        else                { EDI += 2; ESI += 2; }
+        if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; }
+        else                          { EDI += 2; ESI += 2; }
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1);
         return 0;
@@ -42,20 +58,28 @@ static int opMOVSW_a32(uint32_t fetchdat)
 
 static int opMOVSL_a16(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
+        temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         writememl(es, DI, temp);                if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) { DI -= 4; SI -= 4; }
-        else                { DI += 4; SI += 4; }
+        if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; }
+        else                          { DI += 4; SI += 4; }
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 0,1,0,1, 0);
         return 0;
 }
 static int opMOVSL_a32(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
+        temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         writememl(es, EDI, temp);               if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) { EDI -= 4; ESI -= 4; }
-        else                { EDI += 4; ESI += 4; }
+        if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; }
+        else                          { EDI += 4; ESI += 4; }
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 0,1,0,1, 1);
         return 0;
@@ -64,22 +88,30 @@ static int opMOVSL_a32(uint32_t fetchdat)
 
 static int opCMPSB_a16(uint32_t fetchdat)
 {
-        uint8_t src = readmemb(cpu_state.ea_seg->base, SI);
-        uint8_t dst = readmemb(es, DI);         if (cpu_state.abrt) return 1;
+        uint8_t src, dst;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        src = readmemb(cpu_state.ea_seg->base, SI);
+        dst = readmemb(es, DI);         if (cpu_state.abrt) return 1;
         setsub8(src, dst);
-        if (flags & D_FLAG) { DI--; SI--; }
-        else                { DI++; SI++; }
+        if (cpu_state.flags & D_FLAG) { DI--; SI--; }
+        else                          { DI++; SI++; }
         CLOCK_CYCLES((is486) ? 8 : 10);
         PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0);
         return 0;
 }
 static int opCMPSB_a32(uint32_t fetchdat)
 {
-        uint8_t src = readmemb(cpu_state.ea_seg->base, ESI);
-        uint8_t dst = readmemb(es, EDI);        if (cpu_state.abrt) return 1;
+        uint8_t src, dst;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        src = readmemb(cpu_state.ea_seg->base, ESI);
+        dst = readmemb(es, EDI);        if (cpu_state.abrt) return 1;
         setsub8(src, dst);
-        if (flags & D_FLAG) { EDI--; ESI--; }
-        else                { EDI++; ESI++; }
+        if (cpu_state.flags & D_FLAG) { EDI--; ESI--; }
+        else                          { EDI++; ESI++; }
         CLOCK_CYCLES((is486) ? 8 : 10);
         PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1);
         return 0;
@@ -87,22 +119,30 @@ static int opCMPSB_a32(uint32_t fetchdat)
 
 static int opCMPSW_a16(uint32_t fetchdat)
 {
-        uint16_t src = readmemw(cpu_state.ea_seg->base, SI);
-        uint16_t dst = readmemw(es, DI);        if (cpu_state.abrt) return 1;
+        uint16_t src, dst;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        src = readmemw(cpu_state.ea_seg->base, SI);
+        dst = readmemw(es, DI);        if (cpu_state.abrt) return 1;
         setsub16(src, dst);
-        if (flags & D_FLAG) { DI -= 2; SI -= 2; }
-        else                { DI += 2; SI += 2; }
+        if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; }
+        else                          { DI += 2; SI += 2; }
         CLOCK_CYCLES((is486) ? 8 : 10);
         PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0);
         return 0;
 }
 static int opCMPSW_a32(uint32_t fetchdat)
 {
-        uint16_t src = readmemw(cpu_state.ea_seg->base, ESI);
-        uint16_t dst = readmemw(es, EDI);        if (cpu_state.abrt) return 1;
+        uint16_t src, dst;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        src = readmemw(cpu_state.ea_seg->base, ESI);
+        dst = readmemw(es, EDI);        if (cpu_state.abrt) return 1;
         setsub16(src, dst);
-        if (flags & D_FLAG) { EDI -= 2; ESI -= 2; }
-        else                { EDI += 2; ESI += 2; }
+        if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; }
+        else                          { EDI += 2; ESI += 2; }
         CLOCK_CYCLES((is486) ? 8 : 10);
         PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1);
         return 0;
@@ -110,22 +150,30 @@ static int opCMPSW_a32(uint32_t fetchdat)
 
 static int opCMPSL_a16(uint32_t fetchdat)
 {
-        uint32_t src = readmeml(cpu_state.ea_seg->base, SI);
-        uint32_t dst = readmeml(es, DI);        if (cpu_state.abrt) return 1;
+        uint32_t src, dst;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        src = readmeml(cpu_state.ea_seg->base, SI);
+        dst = readmeml(es, DI);        if (cpu_state.abrt) return 1;
         setsub32(src, dst);
-        if (flags & D_FLAG) { DI -= 4; SI -= 4; }
-        else                { DI += 4; SI += 4; }
+        if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; }
+        else                          { DI += 4; SI += 4; }
         CLOCK_CYCLES((is486) ? 8 : 10);
         PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 0);
         return 0;
 }
 static int opCMPSL_a32(uint32_t fetchdat)
 {
-        uint32_t src = readmeml(cpu_state.ea_seg->base, ESI);
-        uint32_t dst = readmeml(es, EDI);        if (cpu_state.abrt) return 1;
+        uint32_t src, dst;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        src = readmeml(cpu_state.ea_seg->base, ESI);
+        dst = readmeml(es, EDI);        if (cpu_state.abrt) return 1;
         setsub32(src, dst);
-        if (flags & D_FLAG) { EDI -= 4; ESI -= 4; }
-        else                { EDI += 4; ESI += 4; }
+        if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; }
+        else                          { EDI += 4; ESI += 4; }
         CLOCK_CYCLES((is486) ? 8 : 10);
         PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 1);
         return 0;
@@ -133,18 +181,20 @@ static int opCMPSL_a32(uint32_t fetchdat)
 
 static int opSTOSB_a16(uint32_t fetchdat)
 {
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         writememb(es, DI, AL);                  if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) DI--;
-        else                DI++;
+        if (cpu_state.flags & D_FLAG) DI--;
+        else                          DI++;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0);
         return 0;
 }
 static int opSTOSB_a32(uint32_t fetchdat)
 {
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         writememb(es, EDI, AL);                 if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) EDI--;
-        else                EDI++;
+        if (cpu_state.flags & D_FLAG) EDI--;
+        else                          EDI++;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1);
         return 0;
@@ -152,18 +202,20 @@ static int opSTOSB_a32(uint32_t fetchdat)
 
 static int opSTOSW_a16(uint32_t fetchdat)
 {
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         writememw(es, DI, AX);                  if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) DI -= 2;
-        else                DI += 2;
+        if (cpu_state.flags & D_FLAG) DI -= 2;
+        else                          DI += 2;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0);
         return 0;
 }
 static int opSTOSW_a32(uint32_t fetchdat)
 {
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         writememw(es, EDI, AX);                 if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) EDI -= 2;
-        else                EDI += 2;
+        if (cpu_state.flags & D_FLAG) EDI -= 2;
+        else                          EDI += 2;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1);
         return 0;
@@ -171,18 +223,20 @@ static int opSTOSW_a32(uint32_t fetchdat)
 
 static int opSTOSL_a16(uint32_t fetchdat)
 {
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         writememl(es, DI, EAX);                 if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) DI -= 4;
-        else                DI += 4;
+        if (cpu_state.flags & D_FLAG) DI -= 4;
+        else                          DI += 4;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0);
         return 0;
 }
 static int opSTOSL_a32(uint32_t fetchdat)
 {
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         writememl(es, EDI, EAX);                if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) EDI -= 4;
-        else                EDI += 4;
+        if (cpu_state.flags & D_FLAG) EDI -= 4;
+        else                          EDI += 4;
         CLOCK_CYCLES(4);
         PREFETCH_RUN(4, 1, -1, 0,0,0,1, 1);
         return 0;
@@ -191,20 +245,26 @@ static int opSTOSL_a32(uint32_t fetchdat)
 
 static int opLODSB_a16(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         AL = temp;
-        if (flags & D_FLAG) SI--;
-        else                SI++;
+        if (cpu_state.flags & D_FLAG) SI--;
+        else                          SI++;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0);
         return 0;
 }
 static int opLODSB_a32(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         AL = temp;
-        if (flags & D_FLAG) ESI--;
-        else                ESI++;
+        if (cpu_state.flags & D_FLAG) ESI--;
+        else                          ESI++;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1);
         return 0;
@@ -212,20 +272,26 @@ static int opLODSB_a32(uint32_t fetchdat)
 
 static int opLODSW_a16(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         AX = temp;
-        if (flags & D_FLAG) SI -= 2;
-        else                SI += 2;
+        if (cpu_state.flags & D_FLAG) SI -= 2;
+        else                          SI += 2;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0);
         return 0;
 }
 static int opLODSW_a32(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         AX = temp;
-        if (flags & D_FLAG) ESI -= 2;
-        else                ESI += 2;
+        if (cpu_state.flags & D_FLAG) ESI -= 2;
+        else                          ESI += 2;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1);
         return 0;
@@ -233,20 +299,26 @@ static int opLODSW_a32(uint32_t fetchdat)
 
 static int opLODSL_a16(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         EAX = temp;
-        if (flags & D_FLAG) SI -= 4;
-        else                SI += 4;
+        if (cpu_state.flags & D_FLAG) SI -= 4;
+        else                          SI += 4;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0);
         return 0;
 }
 static int opLODSL_a32(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         EAX = temp;
-        if (flags & D_FLAG) ESI -= 4;
-        else                ESI += 4;
+        if (cpu_state.flags & D_FLAG) ESI -= 4;
+        else                          ESI += 4;
         CLOCK_CYCLES(5);
         PREFETCH_RUN(5, 1, -1, 0,1,0,0, 1);
         return 0;
@@ -255,20 +327,26 @@ static int opLODSL_a32(uint32_t fetchdat)
 
 static int opSCASB_a16(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(es, DI);        if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        temp = readmemb(es, DI);        if (cpu_state.abrt) return 1;
         setsub8(AL, temp);
-        if (flags & D_FLAG) DI--;
-        else                DI++;
+        if (cpu_state.flags & D_FLAG) DI--;
+        else                          DI++;
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0);
         return 0;
 }
 static int opSCASB_a32(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(es, EDI);       if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        temp = readmemb(es, EDI);       if (cpu_state.abrt) return 1;
         setsub8(AL, temp);
-        if (flags & D_FLAG) EDI--;
-        else                EDI++;
+        if (cpu_state.flags & D_FLAG) EDI--;
+        else                          EDI++;
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1);
         return 0;
@@ -276,20 +354,26 @@ static int opSCASB_a32(uint32_t fetchdat)
 
 static int opSCASW_a16(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(es, DI);       if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        temp = readmemw(es, DI);       if (cpu_state.abrt) return 1;
         setsub16(AX, temp);
-        if (flags & D_FLAG) DI -= 2;
-        else                DI += 2;
+        if (cpu_state.flags & D_FLAG) DI -= 2;
+        else                          DI += 2;
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0);
         return 0;
 }
 static int opSCASW_a32(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(es, EDI);      if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        temp = readmemw(es, EDI);      if (cpu_state.abrt) return 1;
         setsub16(AX, temp);
-        if (flags & D_FLAG) EDI -= 2;
-        else                EDI += 2;
+        if (cpu_state.flags & D_FLAG) EDI -= 2;
+        else                          EDI += 2;
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1);
         return 0;
@@ -297,20 +381,26 @@ static int opSCASW_a32(uint32_t fetchdat)
 
 static int opSCASL_a16(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(es, DI);       if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        temp = readmeml(es, DI);       if (cpu_state.abrt) return 1;
         setsub32(EAX, temp);
-        if (flags & D_FLAG) DI -= 4;
-        else                DI += 4;
+        if (cpu_state.flags & D_FLAG) DI -= 4;
+        else                          DI += 4;
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 0,1,0,0, 0);
         return 0;
 }
 static int opSCASL_a32(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(es, EDI);      if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(&cpu_state.seg_es);
+        temp = readmeml(es, EDI);      if (cpu_state.abrt) return 1;
         setsub32(EAX, temp);
-        if (flags & D_FLAG) EDI -= 4;
-        else                EDI += 4;
+        if (cpu_state.flags & D_FLAG) EDI -= 4;
+        else                          EDI += 4;
         CLOCK_CYCLES(7);
         PREFETCH_RUN(7, 1, -1, 0,1,0,0, 1);
         return 0;
@@ -319,11 +409,13 @@ static int opSCASL_a32(uint32_t fetchdat)
 static int opINSB_a16(uint32_t fetchdat)
 {
         uint8_t temp;
+
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         check_io_perm(DX);
         temp = inb(DX);
         writememb(es, DI, temp);                if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) DI--;
-        else                DI++;
+        if (cpu_state.flags & D_FLAG) DI--;
+        else                          DI++;
         CLOCK_CYCLES(15);
         PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0);
         return 0;
@@ -331,11 +423,13 @@ static int opINSB_a16(uint32_t fetchdat)
 static int opINSB_a32(uint32_t fetchdat)
 {
         uint8_t temp;
+
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         check_io_perm(DX);
         temp = inb(DX);
         writememb(es, EDI, temp);               if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) EDI--;
-        else                EDI++;
+        if (cpu_state.flags & D_FLAG) EDI--;
+        else                          EDI++;
         CLOCK_CYCLES(15);
         PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1);
         return 0;
@@ -344,12 +438,14 @@ static int opINSB_a32(uint32_t fetchdat)
 static int opINSW_a16(uint32_t fetchdat)
 {
         uint16_t temp;
+
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         check_io_perm(DX);
         check_io_perm(DX + 1);
         temp = inw(DX);
         writememw(es, DI, temp);                if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) DI -= 2;
-        else                DI += 2;
+        if (cpu_state.flags & D_FLAG) DI -= 2;
+        else                          DI += 2;
         CLOCK_CYCLES(15);
         PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0);
         return 0;
@@ -357,12 +453,14 @@ static int opINSW_a16(uint32_t fetchdat)
 static int opINSW_a32(uint32_t fetchdat)
 {
         uint16_t temp;
+
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         check_io_perm(DX);
         check_io_perm(DX + 1);
         temp = inw(DX);
         writememw(es, EDI, temp);               if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) EDI -= 2;
-        else                EDI += 2;
+        if (cpu_state.flags & D_FLAG) EDI -= 2;
+        else                          EDI += 2;
         CLOCK_CYCLES(15);
         PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1);
         return 0;
@@ -371,14 +469,16 @@ static int opINSW_a32(uint32_t fetchdat)
 static int opINSL_a16(uint32_t fetchdat)
 {
         uint32_t temp;
+
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         check_io_perm(DX);
         check_io_perm(DX + 1);
         check_io_perm(DX + 2);
         check_io_perm(DX + 3);
         temp = inl(DX);
         writememl(es, DI, temp);                if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) DI -= 4;
-        else                DI += 4;
+        if (cpu_state.flags & D_FLAG) DI -= 4;
+        else                          DI += 4;
         CLOCK_CYCLES(15);
         PREFETCH_RUN(15, 1, -1, 0,1,0,1, 0);
         return 0;
@@ -386,14 +486,16 @@ static int opINSL_a16(uint32_t fetchdat)
 static int opINSL_a32(uint32_t fetchdat)
 {
         uint32_t temp;
+
+        SEG_CHECK_WRITE(&cpu_state.seg_es);
         check_io_perm(DX);
         check_io_perm(DX + 1);
         check_io_perm(DX + 2);
         check_io_perm(DX + 3);
         temp = inl(DX);
         writememl(es, EDI, temp);               if (cpu_state.abrt) return 1;
-        if (flags & D_FLAG) EDI -= 4;
-        else                EDI += 4;
+        if (cpu_state.flags & D_FLAG) EDI -= 4;
+        else                          EDI += 4;
         CLOCK_CYCLES(15);
         PREFETCH_RUN(15, 1, -1, 0,1,0,1, 1);
         return 0;
@@ -401,10 +503,13 @@ static int opINSL_a32(uint32_t fetchdat)
 
 static int opOUTSB_a16(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         check_io_perm(DX);
-        if (flags & D_FLAG) SI--;
-        else                SI++;
+        if (cpu_state.flags & D_FLAG) SI--;
+        else                          SI++;
         outb(DX, temp);
         CLOCK_CYCLES(14);
         PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0);
@@ -412,10 +517,13 @@ static int opOUTSB_a16(uint32_t fetchdat)
 }
 static int opOUTSB_a32(uint32_t fetchdat)
 {
-        uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint8_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         check_io_perm(DX);
-        if (flags & D_FLAG) ESI--;
-        else                ESI++;
+        if (cpu_state.flags & D_FLAG) ESI--;
+        else                          ESI++;
         outb(DX, temp);
         CLOCK_CYCLES(14);
         PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1);
@@ -424,11 +532,14 @@ static int opOUTSB_a32(uint32_t fetchdat)
 
 static int opOUTSW_a16(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         check_io_perm(DX);
         check_io_perm(DX + 1);
-        if (flags & D_FLAG) SI -= 2;
-        else                SI += 2;
+        if (cpu_state.flags & D_FLAG) SI -= 2;
+        else                          SI += 2;
         outw(DX, temp);
         CLOCK_CYCLES(14);
         PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0);
@@ -436,11 +547,14 @@ static int opOUTSW_a16(uint32_t fetchdat)
 }
 static int opOUTSW_a32(uint32_t fetchdat)
 {
-        uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint16_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         check_io_perm(DX);
         check_io_perm(DX + 1);
-        if (flags & D_FLAG) ESI -= 2;
-        else                ESI += 2;
+        if (cpu_state.flags & D_FLAG) ESI -= 2;
+        else                          ESI += 2;
         outw(DX, temp);
         CLOCK_CYCLES(14);
         PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1);
@@ -449,13 +563,16 @@ static int opOUTSW_a32(uint32_t fetchdat)
 
 static int opOUTSL_a16(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1;
         check_io_perm(DX);
         check_io_perm(DX + 1);
         check_io_perm(DX + 2);
         check_io_perm(DX + 3);
-        if (flags & D_FLAG) SI -= 4;
-        else                SI += 4;
+        if (cpu_state.flags & D_FLAG) SI -= 4;
+        else                          SI += 4;
         outl(EDX, temp);
         CLOCK_CYCLES(14);
         PREFETCH_RUN(14, 1, -1, 0,1,0,1, 0);
@@ -463,13 +580,16 @@ static int opOUTSL_a16(uint32_t fetchdat)
 }
 static int opOUTSL_a32(uint32_t fetchdat)
 {
-        uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
+        uint32_t temp;
+
+        SEG_CHECK_READ(cpu_state.ea_seg);
+        temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1;
         check_io_perm(DX);
         check_io_perm(DX + 1);
         check_io_perm(DX + 2);
         check_io_perm(DX + 3);
-        if (flags & D_FLAG) ESI -= 4;
-        else                ESI += 4;
+        if (cpu_state.flags & D_FLAG) ESI -= 4;
+        else                          ESI += 4;
         outl(EDX, temp);
         CLOCK_CYCLES(14);
         PREFETCH_RUN(14, 1, -1, 0,1,0,1, 1);
index 77191ae43d7bc65fb9ca865d398470ff1f0a4fec..6a787273e98e319769fc2327f475d09af91d927c 100644 (file)
@@ -1,7 +1,10 @@
 static int opXCHG_b_a16(uint32_t fetchdat)
 {
         uint8_t temp;
+        
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         seteab(getr8(cpu_reg));                     if (cpu_state.abrt) return 1;
         setr8(cpu_reg, temp);
@@ -12,7 +15,10 @@ static int opXCHG_b_a16(uint32_t fetchdat)
 static int opXCHG_b_a32(uint32_t fetchdat)
 {
         uint8_t temp;
+
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteab();                        if (cpu_state.abrt) return 1;
         seteab(getr8(cpu_reg));                     if (cpu_state.abrt) return 1;
         setr8(cpu_reg, temp);
@@ -24,7 +30,10 @@ static int opXCHG_b_a32(uint32_t fetchdat)
 static int opXCHG_w_a16(uint32_t fetchdat)
 {
         uint16_t temp;
+
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         seteaw(cpu_state.regs[cpu_reg].w);          if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = temp;
@@ -35,7 +44,10 @@ static int opXCHG_w_a16(uint32_t fetchdat)
 static int opXCHG_w_a32(uint32_t fetchdat)
 {
         uint16_t temp;
+
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteaw();                        if (cpu_state.abrt) return 1;
         seteaw(cpu_state.regs[cpu_reg].w);          if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].w = temp;
@@ -47,7 +59,10 @@ static int opXCHG_w_a32(uint32_t fetchdat)
 static int opXCHG_l_a16(uint32_t fetchdat)
 {
         uint32_t temp;
+
         fetch_ea_16(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         seteal(cpu_state.regs[cpu_reg].l);          if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = temp;
@@ -58,7 +73,10 @@ static int opXCHG_l_a16(uint32_t fetchdat)
 static int opXCHG_l_a32(uint32_t fetchdat)
 {
         uint32_t temp;
+
         fetch_ea_32(fetchdat);
+        if (cpu_mod != 3)
+                SEG_CHECK_WRITE(cpu_state.ea_seg);
         temp = geteal();                        if (cpu_state.abrt) return 1;
         seteal(cpu_state.regs[cpu_reg].l);          if (cpu_state.abrt) return 1;
         cpu_state.regs[cpu_reg].l = temp;
index c1924c341a0172e219c3aeb7edd22cdd3ff37bcc..9999fde67692a8d22e1d9d03778a1cd399735e60 100644 (file)
@@ -5,7 +5,7 @@
 #include "ibm.h"
 #include "mem.h"
 #include "x86.h"
-#include "386.h"
+#include "x86_flags.h"
 #include "386_common.h"
 #include "cpu.h"
 #include "config.h"
@@ -32,8 +32,6 @@ int intgatesize;
 void taskswitch286(uint16_t seg, uint16_t *segdat, int is32);
 void taskswitch386(uint16_t seg, uint16_t *segdat);
 
-extern int output;
-
 /*NOT PRESENT is INT 0B
   GPF is INT 0D*/
 
@@ -45,7 +43,7 @@ void x86abort(const char *format, ...)
         if (!pclogf)
         {
                 strcpy(buf, logs_path);
-                //put_backslash(buf);
+                put_backslash(buf);
                 strcat(buf, "pcem.log");
                 pclogf=fopen(buf, "wt");
         }
@@ -60,15 +58,13 @@ void x86abort(const char *format, ...)
         exit(-1);
 }
 
-uint8_t opcode2;
-
 static void seg_reset(x86seg *s)
 {
         s->access = (0 << 5) | 2;
         s->limit = 0xFFFF;
         s->limit_low = 0;
         s->limit_high = 0xffff;
-        if (s == &_cs)
+        if (s == &cpu_state.seg_cs)
         {
                 // TODO - When the PC is reset, initialization of the CS descriptor must be like the annotated line below.
                 //s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0;
@@ -84,20 +80,19 @@ static void seg_reset(x86seg *s)
 
 void x86seg_reset()
 {
-        seg_reset(&_cs);
-        seg_reset(&_ds);
-        seg_reset(&_es);
-        seg_reset(&_fs);
-        seg_reset(&_gs);
-        seg_reset(&_ss);
+        seg_reset(&cpu_state.seg_cs);
+        seg_reset(&cpu_state.seg_ds);
+        seg_reset(&cpu_state.seg_es);
+        seg_reset(&cpu_state.seg_fs);
+        seg_reset(&cpu_state.seg_gs);
+        seg_reset(&cpu_state.seg_ss);
 }
 
 void x86_doabrt(int x86_abrt)
 {
 //        ingpf = 1;
-        CS = oldcs;
         cpu_state.pc = cpu_state.oldpc;
-        _cs.access = oldcpl << 5;
+        cpu_state.seg_cs.access = oldcpl << 5;
 //        pclog("x86_doabrt - %02X %08X  %04X:%08X  %i\n", x86_abrt, abrt_error, CS, pc, ins);
         
 /*        if (CS == 0x3433 && pc == 0x000006B0)
@@ -115,22 +110,21 @@ void x86_doabrt(int x86_abrt)
                 uint32_t addr = (x86_abrt << 2) + idt.base;
                 if (stack32)
                 {
-                        writememw(ss,ESP-2,flags);
+                        writememw(ss,ESP-2,cpu_state.flags);
                         writememw(ss,ESP-4,CS);
                         writememw(ss,ESP-6,cpu_state.pc);
                         ESP-=6;
                 }
                 else
                 {
-                        writememw(ss,((SP-2)&0xFFFF),flags);
+                        writememw(ss,((SP-2)&0xFFFF),cpu_state.flags);
                         writememw(ss,((SP-4)&0xFFFF),CS);
                         writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
                         SP-=6;
                 }
 
-                flags&=~I_FLAG;
-                flags&=~T_FLAG;
-                oxpc=cpu_state.pc;
+                cpu_state.flags &= ~I_FLAG;
+                cpu_state.flags &= ~T_FLAG;
                 cpu_state.pc=readmemw(0,addr);
                 loadcs(readmemw(0,addr+2));
                 return;
@@ -164,8 +158,6 @@ void x86_doabrt(int x86_abrt)
                         SP-=4;
                 }
         }
-//        ingpf = 0;
-//        abrt = gpf = 1;
 }
 void x86gpf(char *s, uint16_t error)
 {
@@ -238,14 +230,14 @@ static void do_seg_load(x86seg *s, uint16_t *segdat)
         }
 //        if (output) pclog("SEG : base=%08x limit=%08x low=%08x high=%08x\n", s->base, s->limit, s->limit_low, s->limit_high);
 
-        if (s == &_ds)
+        if (s == &cpu_state.seg_ds)
         {
                 if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff)
                         cpu_cur_status &= ~CPU_STATUS_NOTFLATDS;
                 else
                         cpu_cur_status |= CPU_STATUS_NOTFLATDS;
         }
-        if (s == &_ss)
+        if (s == &cpu_state.seg_ss)
         {
                 if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff)
                         cpu_cur_status &= ~CPU_STATUS_NOTFLATSS;
@@ -309,22 +301,22 @@ static void check_seg_valid(x86seg *s)
                 loadseg(0, s);
 }
 
-void loadseg(uint16_t seg, x86seg *s)
+int loadseg(uint16_t seg, x86seg *s)
 {
         uint16_t segdat[4];
         uint32_t addr;
         int dpl;
 
-        if (msw&1 && !(eflags&VM_FLAG))
+        if (msw&1 && !(cpu_state.eflags&VM_FLAG))
         {
 //                intcount++;
                 if (!(seg&~3))
                 {
-                        if (s==&_ss)
+                        if (s==&cpu_state.seg_ss)
                         {
                                 pclog("SS selector = NULL!\n");
                                 x86ss(NULL,0);
-                                return;
+                                return 1;
 //                                dumpregs();
 //                                exit(-1);
                         }
@@ -332,10 +324,10 @@ void loadseg(uint16_t seg, x86seg *s)
                         s->seg=0;
                         s->access = 0;
                         s->base=-1;
-                        if (s == &_ds)
+                        if (s == &cpu_state.seg_ds)
                                 cpu_cur_status |= CPU_STATUS_NOTFLATDS;
 //                        pclog("NULL selector %s%s%s%s %04X(%06X):%06X\n",(s==&_ds)?"DS":"",(s==&_es)?"ES":"",(s==&_fs)?"FS":"",(s==&_gs)?"GS":"",CS,cs,pc);
-                        return;
+                        return 0;
                 }
 //                if (s==&_ss) pclog("Load SS %04X\n",seg);
 //                pclog("Protected mode seg load!\n");
@@ -344,12 +336,12 @@ void loadseg(uint16_t seg, x86seg *s)
                 {
                         if (addr>=ldt.limit)
                         {
-                                pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n",seg,ldt.limit, opcode, opcode2, 0/*rmdat*/);
+                                pclog("Bigger than LDT limit %04X %04X %02X\n",seg,ldt.limit, 0/*rmdat*/);
 //                                dumppic();
 //                                dumpregs();
 //                                exit(-1);
                                 x86gpf(NULL,seg&~3);
-                                return;
+                                return 1;
                         }
                         addr+=ldt.base;
                 }
@@ -361,7 +353,7 @@ void loadseg(uint16_t seg, x86seg *s)
 //                                dumpregs();
 //                                exit(-1);
                                 x86gpf(NULL,seg&~3);
-                                return;
+                                return 1;
                         }
                         addr+=gdt.base;
                 }
@@ -369,22 +361,22 @@ void loadseg(uint16_t seg, x86seg *s)
                 segdat[0]=readmemw(0,addr);
                 segdat[1]=readmemw(0,addr+2);
                 segdat[2]=readmemw(0,addr+4);
-                segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return;
+                segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return 1;
                 dpl=(segdat[2]>>13)&3;
-                if (s==&_ss)
+                if (s==&cpu_state.seg_ss)
                 {
                         if (!(seg&~3))
                         {
                                 pclog("Load SS null selector\n");
                                 x86gpf(NULL,seg&~3);
-                                return;
+                                return 1;
                         }
                         if ((seg&3)!=CPL || dpl!=CPL)
                         {
                                 pclog("Invalid SS permiss\n");
                                 x86gpf(NULL,seg&~3);
 //                                x86abort("Invalid SS permiss for %04X!\n",seg&0xFFFC);
-                                return;
+                                return 1;
                         }
                         switch ((segdat[2]>>8)&0x1F)
                         {
@@ -394,18 +386,18 @@ void loadseg(uint16_t seg, x86seg *s)
                                 pclog("Invalid SS type\n");
                                 x86gpf(NULL,seg&~3);
 //                                x86abort("Invalid SS segment type for %04X!\n",seg&0xFFFC);
-                                return;
+                                return 1;
                         }
                         if (!(segdat[2]&0x8000))
                         {
                                 pclog("Load SS not present!\n");
                                 x86ss(NULL,seg&~3);
-                                return;
+                                return 1;
                         }
                         set_stack32((segdat[3] & 0x40) ? 1 : 0);
 //                        pclog("Load SS  %04x %04x %04x %04x\n", segdat[0], segdat[1], segdat[2], segdat[3]);
                 }
-                else if (s!=&_cs)
+                else if (s!=&cpu_state.seg_cs)
                 {
                         if (output) pclog("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]);
                         if (output) pclog("Seg type %03X\n",segdat[2]&0x1F00);
@@ -420,7 +412,7 @@ void loadseg(uint16_t seg, x86seg *s)
                                         pclog("Data seg fail - %04X:%08X %04X %i %04X\n",CS,cpu_state.pc,seg,dpl,segdat[2]);
                                         x86gpf(NULL,seg&~3);
 //                                        x86abort("Data segment load - level too low!\n",seg&0xFFFC);
-                                        return;
+                                        return 1;
                                 }
                                 break;
                                 case 0x1E: case 0x1F: /*Readable conforming code*/
@@ -428,14 +420,14 @@ void loadseg(uint16_t seg, x86seg *s)
                                 default:
                                 pclog("Invalid segment type for %04X! %04X\n",seg&0xFFFC,segdat[2]);
                                 x86gpf(NULL,seg&~3);
-                                return;
+                                return 1;
                         }
                 }
 
                 if (!(segdat[2] & 0x8000))
                 {
                         x86np("Load data seg not present", seg & 0xfffc);
-                        return;
+                        return 1;
                 }
                 s->seg = seg;
                 do_seg_load(s, segdat);
@@ -453,9 +445,9 @@ void loadseg(uint16_t seg, x86seg *s)
                 }
 #endif
                 s->checked = 0;
-                if (s == &_ds)
+                if (s == &cpu_state.seg_ds)
                         codegen_flat_ds = 0;
-                if (s == &_ss)
+                if (s == &cpu_state.seg_ss)
                         codegen_flat_ss = 0;
         }
         else
@@ -463,29 +455,31 @@ void loadseg(uint16_t seg, x86seg *s)
                 s->access = (3 << 5) | 2;
                 s->base = seg << 4;
                 s->seg = seg;
-                if (s == &_ss)
-                        set_stack32(0);
                 s->checked = 1;
-                if (s == &_ds)
+                if (s == &cpu_state.seg_ds)
                         codegen_flat_ds = 0;
-                if (s == &_ss)
+                if (s == &cpu_state.seg_ss)
                         codegen_flat_ss = 0;
+                if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG))
+                        set_stack32(0);
         }
         
-        if (s == &_ds)
+        if (s == &cpu_state.seg_ds)
         {
                 if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff)
                         cpu_cur_status &= ~CPU_STATUS_NOTFLATDS;
                 else
                         cpu_cur_status |= CPU_STATUS_NOTFLATDS;
         }
-        if (s == &_ss)
+        if (s == &cpu_state.seg_ss)
         {
                 if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff)
                         cpu_cur_status &= ~CPU_STATUS_NOTFLATSS;
                 else
                         cpu_cur_status |= CPU_STATUS_NOTFLATSS;        
         }
+        
+        return cpu_state.abrt;
 }
 
 #define DPL ((segdat[2]>>13)&3)
@@ -497,7 +491,7 @@ void loadcs(uint16_t seg)
         uint16_t segdat[4];
         uint32_t addr;
         if (output) pclog("Load CS %04X\n",seg);
-        if (msw&1 && !(eflags&VM_FLAG))
+        if (msw&1 && !(cpu_state.eflags&VM_FLAG))
         {
 //                intcount++;
 //                flushmmucache();
@@ -547,7 +541,7 @@ void loadcs(uint16_t seg)
                                 if ((seg&3)>CPL)
                                 {
                                         x86gpf(NULL,seg&~3);
-                                        pclog("loadcs RPL > CPL %04X %04X %i %02X\n",segdat[2],seg,CPL,opcode);
+                                        pclog("loadcs RPL > CPL %04X %04X %i\n",segdat[2],seg,CPL);
                                         return;
                                 }
                                 if (CPL != DPL)
@@ -568,9 +562,10 @@ void loadcs(uint16_t seg)
                         }
                         set_use32(segdat[3] & 0x40);
                         CS=(seg&~3)|CPL;
-                        do_seg_load(&_cs, segdat);
+                        do_seg_load(&cpu_state.seg_cs, segdat);
                         use32=(segdat[3]&0x40)?0x300:0;
                         if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                        oldcpl = CPL;
 
 #ifdef CS_ACCESSED                        
                         cpl_override = 1;
@@ -590,7 +585,7 @@ void loadcs(uint16_t seg)
                         switch (segdat[2]&0xF00)
                         {
                                 default:
-                                pclog("Bad CS %02X %02X %i special descriptor %03X %04X\n",opcode,0/*rmdat*/,optype,segdat[2]&0xF00,seg);
+                                pclog("Bad CS %02X %i special descriptor %03X %04X\n",0/*rmdat*/,optype,segdat[2]&0xF00,seg);
                                 x86gpf(NULL,seg&~3);
                                 return;
                         }
@@ -601,25 +596,26 @@ void loadcs(uint16_t seg)
         }
         else
         {
-                _cs.base=seg<<4;
-                _cs.limit=0xFFFF;
-                _cs.limit_low = 0;
-                _cs.limit_high = 0xffff;
+                cpu_state.seg_cs.base=seg<<4;
+                cpu_state.seg_cs.limit=0xFFFF;
+                cpu_state.seg_cs.limit_low = 0;
+                cpu_state.seg_cs.limit_high = 0xffff;
                 CS=seg;
-                if (eflags&VM_FLAG) _cs.access=(3<<5) | 2;
-                else                _cs.access=(0<<5) | 2;
+                if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2;
+                else                          cpu_state.seg_cs.access=(0<<5) | 2;
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
         }
 }
 
-void loadcsjmp(uint16_t seg, uint32_t oxpc)
+void loadcsjmp(uint16_t seg, uint32_t old_pc)
 {
         uint16_t segdat[4];
         uint32_t addr;
         uint16_t type,seg2;
         uint32_t newpc;
 //        pclog("Load CS JMP %04X\n",seg);
-        if (msw&1 && !(eflags&VM_FLAG))
+        if (msw&1 && !(cpu_state.eflags&VM_FLAG))
         {
                 if (!(seg&~3))
                 {
@@ -693,8 +689,9 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc)
                         CS = (seg & ~3) | CPL;
                         segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8));
 
-                        do_seg_load(&_cs, segdat);
+                        do_seg_load(&cpu_state.seg_cs, segdat);
                         if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                        oldcpl = CPL;
 /*                        if (segdat[3]&0x40) 
                         {
                                 use32=0x300;
@@ -725,7 +722,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc)
 //                                pclog("Call gate\n");
                                 cgate32=(type&0x800);
                                 cgate16=!cgate32;
-                                oldcs=CS;
                                 cpu_state.oldpc = cpu_state.pc;
                                 if ((DPL < CPL) || (DPL < (seg&3)))
                                 {
@@ -797,8 +793,9 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc)
                                         }
                                         case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/
                                         CS=seg2;
-                                        do_seg_load(&_cs, segdat);
+                                        do_seg_load(&cpu_state.seg_cs, segdat);
                                         if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                                        oldcpl = CPL;
                                         set_use32(segdat[3]&0x40);
                                         cpu_state.pc=newpc;
 
@@ -821,11 +818,11 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc)
                                 case 0x100: /*286 Task gate*/
                                 case 0x900: /*386 Task gate*/
 //                                pclog("Task gate\n");
-                                cpu_state.pc=oxpc;
+                                cpu_state.pc = old_pc;
                                 optype=JMP;
                                 cpl_override=1;
                                 taskswitch286(seg,segdat,segdat[2]&0x800);
-                                flags &= ~NT_FLAG;
+                                cpu_state.flags &= ~NT_FLAG;
                                 cpl_override=0;
 //                                case 0xB00: /*386 Busy task gate*/
 //                                if (optype==JMP) pclog("Task switch!\n");
@@ -833,7 +830,7 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc)
                                 return;
 
                                 default:
-                                pclog("Bad JMP CS %02X %02X %i special descriptor %03X %04X\n",opcode,0/*rmdat*/,optype,segdat[2]&0xF00,seg);
+                                pclog("Bad JMP CS %02X %i special descriptor %03X %04X\n",0/*rmdat*/,optype,segdat[2]&0xF00,seg);
                                 x86gpf(NULL,0);
                                 return;
 //                                dumpregs();
@@ -846,14 +843,15 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc)
         }
         else
         {
-                _cs.base=seg<<4;
-                _cs.limit=0xFFFF;
-                _cs.limit_low = 0;
-                _cs.limit_high = 0xffff;
+                cpu_state.seg_cs.base=seg<<4;
+                cpu_state.seg_cs.limit=0xFFFF;
+                cpu_state.seg_cs.limit_low = 0;
+                cpu_state.seg_cs.limit_high = 0xffff;
                 CS=seg;
-                if (eflags&VM_FLAG) _cs.access=(3<<5) | 2;
-                else                _cs.access=(0<<5) | 2;
+                if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2;
+                else                          cpu_state.seg_cs.access=(0<<5) | 2;
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
                 cycles -= timing_jmp_rm;
         }
 }
@@ -926,7 +924,7 @@ uint32_t POPL()
         return templ;
 }
 
-void loadcscall(uint16_t seg)
+void loadcscall(uint16_t seg, uint32_t old_pc)
 {
         uint16_t seg2;
         uint16_t segdat[4],segdat2[4],newss;
@@ -939,7 +937,7 @@ void loadcscall(uint16_t seg)
         
         int csout = output;
         
-        if (msw&1 && !(eflags&VM_FLAG))
+        if (msw&1 && !(cpu_state.eflags&VM_FLAG))
         {
                 //flushmmucache();
                 if (csout) pclog("Protected mode CS load! %04X\n",seg);
@@ -1028,8 +1026,9 @@ void loadcscall(uint16_t seg)
                         else /*On non-conforming segments, set RPL = CPL*/
                                 seg = (seg & ~3) | CPL;
                         CS=seg;
-                        do_seg_load(&_cs, segdat);
+                        do_seg_load(&cpu_state.seg_cs, segdat);
                         if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                        oldcpl = CPL;
 /*                        if (segdat[3]&0x40) 
                         {
                                 use32=0x300;
@@ -1125,6 +1124,7 @@ void loadcscall(uint16_t seg)
                                         case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/
                                         if (DPL < CPL)
                                         {
+                                                uint16_t oldcs = CS;
                                                 oaddr = addr;
                                                 /*Load new stack*/
                                                 oldss=SS;
@@ -1205,7 +1205,7 @@ void loadcscall(uint16_t seg)
                                                 if (stack32) ESP=newsp;
                                                 else         SP=newsp;
                                                 
-                                                do_seg_load(&_ss, segdat2);
+                                                do_seg_load(&cpu_state.seg_ss, segdat2);
 
                                                 if (output) pclog("Set access 1\n");
 
@@ -1216,8 +1216,9 @@ void loadcscall(uint16_t seg)
 #endif
                                                 
                                                 CS=seg2;
-                                                do_seg_load(&_cs, segdat);
+                                                do_seg_load(&cpu_state.seg_cs, segdat);
                                                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                                                oldcpl = CPL;
                                                 set_use32(segdat[3]&0x40);
                                                 cpu_state.pc=newpc;
                                                 
@@ -1239,6 +1240,7 @@ void loadcscall(uint16_t seg)
                                                                 pclog("ABRT PUSHL\n");
                                                                 SS = oldss;
                                                                 ESP = oldsp2;
+                                                                CS = oldcs;
                                                                 return;
                                                         }
 //                                                        if (output) pclog("Stack now %04X:%08X\n",SS,ESP);
@@ -1253,13 +1255,12 @@ void loadcscall(uint16_t seg)
                                                                                 pclog("ABRT COPYL\n");
                                                                                 SS = oldss;
                                                                                 ESP = oldsp2;
+                                                                                CS = oldcs;
                                                                                 return;
                                                                         }
                                                                 }
                                                         }
 //                                                                x86abort("Call gate with count %i\n",count);
-//                                                        PUSHL(oldcs);
-//                                                        PUSHL(oldpc); if (cpu_state.abrt) return;
                                                 }
                                                 else
                                                 {
@@ -1272,6 +1273,7 @@ void loadcscall(uint16_t seg)
                                                                 pclog("ABRT PUSHW\n");
                                                                 SS = oldss;
                                                                 ESP = oldsp2;
+                                                                CS = oldcs;
                                                                 return;
                                                         }
                                                         if (output) pclog("Write SP to %04X:%04X\n",SS,SP);
@@ -1290,14 +1292,13 @@ void loadcscall(uint16_t seg)
                                                                                 pclog("ABRT COPYW\n");
                                                                                 SS = oldss;
                                                                                 ESP = oldsp2;
+                                                                                CS = oldcs;
                                                                                 return;
                                                                         }
                                                                 }
                                                         }
 //                                                        if (output) pclog("Stack %04X\n",SP);
 //                                                        if (count) x86abort("Call gate with count\n");
-//                                                        PUSHW(oldcs);
-//                                                       PUSHW(oldpc); if (cpu_state.abrt) return;
                                                 }
                                                 cycles -= timing_call_pm_gate_inner;
                                                 break;
@@ -1309,19 +1310,10 @@ void loadcscall(uint16_t seg)
                                                 return;
                                         }
                                         case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/
-/*                                        if (type==0xC00)
-                                        {
-                                                PUSHL(oldcs);
-                                                PUSHL(oldpc); if (cpu_state.abrt) return;
-                                        }
-                                        else
-                                        {
-                                                PUSHW(oldcs);
-                                                PUSHW(oldpc); if (cpu_state.abrt) return;
-                                        }*/
                                         CS=seg2;
-                                        do_seg_load(&_cs, segdat);
+                                        do_seg_load(&cpu_state.seg_cs, segdat);
                                         if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                                        oldcpl = CPL;
                                         set_use32(segdat[3]&0x40);
                                         cpu_state.pc=newpc;
 
@@ -1343,7 +1335,7 @@ void loadcscall(uint16_t seg)
                                 case 0x100: /*286 Task gate*/
                                 case 0x900: /*386 Task gate*/
 //                                pclog("Task gate\n");
-                                cpu_state.pc=oxpc;
+                                cpu_state.pc = old_pc;
                                 cpl_override=1;
                                 taskswitch286(seg,segdat,segdat[2]&0x800);
                                 cpl_override=0;
@@ -1363,14 +1355,15 @@ void loadcscall(uint16_t seg)
         }
         else
         {
-                _cs.base=seg<<4;
-                _cs.limit=0xFFFF;
-                _cs.limit_low = 0;
-                _cs.limit_high = 0xffff;
+                cpu_state.seg_cs.base=seg<<4;
+                cpu_state.seg_cs.limit=0xFFFF;
+                cpu_state.seg_cs.limit_low = 0;
+                cpu_state.seg_cs.limit_high = 0xffff;
                 CS=seg;
-                if (eflags&VM_FLAG) _cs.access=(3<<5) | 2;
-                else                _cs.access=(0<<5) | 2;
+                if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2;
+                else                          cpu_state.seg_cs.access=(0<<5) | 2;
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
         }
 }
 
@@ -1381,7 +1374,7 @@ void pmoderetf(int is32, uint16_t off)
         uint32_t addr, oaddr;
         uint16_t segdat[4],segdat2[4],seg,newss;
         uint32_t oldsp=ESP;
-        if (output) pclog("RETF %i %04X:%04X  %08X %04X\n",is32,CS,cpu_state.pc,cr0,eflags);
+        if (output) pclog("RETF %i %04X:%04X  %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags);
         if (is32)
         {
                 newpc=POPL();
@@ -1495,9 +1488,10 @@ void pmoderetf(int is32, uint16_t off)
                 if (segdat[2] & 0x400)
                    segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8));
                 CS = seg;
-                do_seg_load(&_cs, segdat);
-                _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5);
+                do_seg_load(&cpu_state.seg_cs, segdat);
+                cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5);
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
                 set_use32(segdat[3] & 0x40);
                 
 //                pclog("CPL=RPL return to %04X:%08X\n",CS,pc);
@@ -1630,7 +1624,7 @@ void pmoderetf(int is32, uint16_t off)
                 set_stack32((segdat2[3] & 0x40) ? 1 : 0);
                 if (stack32) ESP=newsp;
                 else         SP=newsp;
-                do_seg_load(&_ss, segdat2);
+                do_seg_load(&cpu_state.seg_ss, segdat2);
 
 #ifdef SEL_ACCESSED
                 cpl_override = 1;
@@ -1647,27 +1641,23 @@ void pmoderetf(int is32, uint16_t off)
 
                 cpu_state.pc=newpc;
                 CS=seg;
-                do_seg_load(&_cs, segdat);
+                do_seg_load(&cpu_state.seg_cs, segdat);
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
                 set_use32(segdat[3] & 0x40);
                 
                 if (stack32) ESP+=off;
                 else         SP+=off;
                 
-                check_seg_valid(&_ds);
-                check_seg_valid(&_es);
-                check_seg_valid(&_fs);
-                check_seg_valid(&_gs);
+                check_seg_valid(&cpu_state.seg_ds);
+                check_seg_valid(&cpu_state.seg_es);
+                check_seg_valid(&cpu_state.seg_fs);
+                check_seg_valid(&cpu_state.seg_gs);
 //                pclog("CPL<RPL return to %04X:%08X %04X:%08X\n",CS,pc,SS,ESP);
                 cycles -= timing_retf_pm_outer;
         }
 }
 
-void restore_stack()
-{
-        ss=oldss; _ss.limit=oldsslimit;
-}
-
 void pmodeint(int num, int soft)
 {
         uint16_t segdat[4],segdat2[4],segdat3[4];
@@ -1681,7 +1671,7 @@ void pmodeint(int num, int soft)
         
 //        if (!num) pclog("Pmode int 0 at %04X(%06X):%08X\n",CS,cs,pc);
 //        pclog("Pmode int %02X %i %04X:%08X %04X:%08X %i\n",num,soft,CS,pc, SS, ESP, abrt);
-        if (eflags&VM_FLAG && IOPL!=3 && soft)
+        if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft)
         {
                 if (output) pclog("V86 banned int\n");
                 pclog("V86 banned int!\n");
@@ -1804,7 +1794,7 @@ void pmodeint(int num, int soft)
                                                 x86np("Int gate CS not present\n", segdat[1] & 0xfffc);
                                                 return;
                                         }
-                                        if ((eflags&VM_FLAG) && DPL2)
+                                        if ((cpu_state.eflags & VM_FLAG) && DPL2)
                                         {
                                                 pclog("V86 calling int gate, DPL != 0\n");
                                                 x86gpf(NULL,segdat[1]&0xFFFC);
@@ -1881,7 +1871,7 @@ void pmodeint(int num, int soft)
                                         set_stack32((segdat3[3] & 0x40) ? 1 : 0);
                                         if (stack32) ESP=newsp;
                                         else         SP=newsp;
-                                        do_seg_load(&_ss, segdat3);
+                                        do_seg_load(&cpu_state.seg_ss, segdat3);
 
 #ifdef CS_ACCESSED                                        
                                         cpl_override = 1;
@@ -1894,20 +1884,20 @@ void pmodeint(int num, int soft)
                                         if (type>=0x800)
                                         {
 //                                                if (output) pclog("Push 32 %i\n",eflags&VM_FLAG);
-                                                if (eflags & VM_FLAG)
+                                                if (cpu_state.eflags & VM_FLAG)
                                                 {
                                                         PUSHL(GS);
                                                         PUSHL(FS);
                                                         PUSHL(DS);
                                                         PUSHL(ES); if (cpu_state.abrt) return;
-                                                        loadseg(0,&_ds);
-                                                        loadseg(0,&_es);
-                                                        loadseg(0,&_fs);
-                                                        loadseg(0,&_gs);
+                                                        loadseg(0,&cpu_state.seg_ds);
+                                                        loadseg(0,&cpu_state.seg_es);
+                                                        loadseg(0,&cpu_state.seg_fs);
+                                                        loadseg(0,&cpu_state.seg_gs);
                                                 }
                                                 PUSHL(oldss);
                                                 PUSHL(oldsp);
-                                                PUSHL(flags|(eflags<<16));
+                                                PUSHL(cpu_state.flags | (cpu_state.eflags << 16));
 //                                                if (soft) pclog("Pushl CS %08X\n", CS);
                                                 PUSHL(CS);
 //                                                if (soft) pclog("Pushl PC %08X\n", pc);                                                
@@ -1919,7 +1909,7 @@ void pmodeint(int num, int soft)
 //                                                if (output) pclog("Push 16\n");
                                                 PUSHW(oldss);
                                                 PUSHW(oldsp);
-                                                PUSHW(flags);
+                                                PUSHW(cpu_state.flags);
 //                                                if (soft) pclog("Pushw CS %04X\n", CS);                                                
                                                 PUSHW(CS);
 //                                                if (soft) pclog("Pushw pc %04X\n", pc);                                                
@@ -1927,7 +1917,7 @@ void pmodeint(int num, int soft)
 //                                                if (output) pclog("16Stack %04X:%08X\n",SS,ESP);
                                         }
                                         cpl_override=0;
-                                        _cs.access=0;
+                                        cpu_state.seg_cs.access=0;
                                         cycles -= timing_int_pm_outer - timing_int_pm;
 //                                        pclog("Non-confirming int gate, CS = %04X\n");
                                         break;
@@ -1945,7 +1935,7 @@ void pmodeint(int num, int soft)
                                         x86np("Int gate CS not present\n", segdat[1] & 0xfffc);
                                         return;
                                 }
-                                if ((eflags & VM_FLAG) && DPL2<CPL)
+                                if ((cpu_state.eflags & VM_FLAG) && DPL2<CPL)
                                 {
                                         pclog("Int gate V86 mode DPL2<CPL\n");
                                         x86gpf(NULL,seg&~3);
@@ -1954,7 +1944,7 @@ void pmodeint(int num, int soft)
 //                                if (!stack_changed && ssegs) restore_stack();
                                 if (type>0x800)
                                 {
-                                        PUSHL(flags|(eflags<<16));
+                                        PUSHL(cpu_state.flags | (cpu_state.eflags << 16));
 //                                        if (soft) pclog("Pushlc CS %08X\n", CS);
                                         PUSHL(CS);
 //                                        if (soft) pclog("Pushlc PC %08X\n", pc);
@@ -1962,7 +1952,7 @@ void pmodeint(int num, int soft)
                                 }
                                 else
                                 {
-                                        PUSHW(flags);
+                                        PUSHW(cpu_state.flags);
 //                                        if (soft) pclog("Pushwc CS %04X\n", CS);
                                         PUSHW(CS);
 //                                        if (soft) pclog("Pushwc PC %04X\n", pc);
@@ -1975,11 +1965,12 @@ void pmodeint(int num, int soft)
                                 x86gpf(NULL,seg&~3);
                                 return;
                         }
-                do_seg_load(&_cs, segdat2);
+                do_seg_load(&cpu_state.seg_cs, segdat2);
                 CS = (seg & ~3) | new_cpl;
-                _cs.access = (_cs.access & ~(3 << 5)) | (new_cpl << 5);
+                cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5);
 //                pclog("New CS = %04X\n",CS);
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
                 if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16);
                 else            cpu_state.pc=segdat[0];
                 set_use32(segdat2[3]&0x40);
@@ -1991,14 +1982,14 @@ void pmodeint(int num, int soft)
                 cpl_override = 0;
 #endif
                         
-                eflags&=~VM_FLAG;
+                cpu_state.eflags &= ~VM_FLAG;
                 cpu_cur_status &= ~CPU_STATUS_V86;
                 if (!(type&0x100))
                 {
-                        flags&=~I_FLAG;
+                        cpu_state.flags &= ~I_FLAG;
 //                        pclog("INT %02X disabling interrupts %i\n",num,soft);
                 }
-                flags&=~(T_FLAG|NT_FLAG);
+                cpu_state.flags &= ~(T_FLAG|NT_FLAG);
 //                if (output) pclog("Final Stack %04X:%08X\n",SS,ESP);
                 cycles -= timing_int_pm;
                 break;
@@ -2063,7 +2054,7 @@ void pmodeiret(int is32)
         uint16_t seg = 0;
         uint32_t addr, oaddr;
         uint32_t oldsp=ESP;
-        if (is386 && (eflags&VM_FLAG))
+        if (is386 && (cpu_state.eflags & VM_FLAG))
         {
 //                if (output) pclog("V86 IRET\n");
                 if (IOPL!=3)
@@ -2072,7 +2063,6 @@ void pmodeiret(int is32)
                         x86gpf(NULL,0);
                         return;
                 }
-                oxpc=cpu_state.pc;
                 if (is32)
                 {
                         newpc=POPL();
@@ -2086,12 +2076,12 @@ void pmodeiret(int is32)
                         tempflags=POPW(); if (cpu_state.abrt) return;
                 }
                 cpu_state.pc=newpc;
-                _cs.base=seg<<4;
-                _cs.limit=0xFFFF;
-                _cs.limit_low = 0;
-                _cs.limit_high = 0xffff;
+                cpu_state.seg_cs.base=seg<<4;
+                cpu_state.seg_cs.limit=0xFFFF;
+                cpu_state.seg_cs.limit_low = 0;
+                cpu_state.seg_cs.limit_high = 0xffff;
                 CS=seg;
-                flags=(flags&0x3000)|(tempflags&0xCFD5)|2;
+                cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xCFD5) | 2;
                 cycles -= timing_iret_rm;
                 return;
         }
@@ -2100,7 +2090,7 @@ void pmodeiret(int is32)
         //flushmmucache();
 //        if (output) pclog("Pmode IRET %04X:%04X ",CS,pc);
 
-        if (flags&NT_FLAG)
+        if (cpu_state.flags & NT_FLAG)
         {
 //                pclog("NT IRET\n");
                 seg=readmemw(tr.base,0);
@@ -2130,7 +2120,6 @@ void pmodeiret(int is32)
                 cpl_override=0;
                 return;
         }
-        oxpc=cpu_state.pc;
         flagmask=0xFFFF;
         if (CPL) flagmask&=~0x3000;
         if (IOPL<CPL) flagmask&=~0x200;
@@ -2153,37 +2142,38 @@ void pmodeiret(int is32)
                         segs[2]=POPL();
                         segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; }
 //                        pclog("Pop stack %04X:%04X\n",newss,newsp);
-                        eflags=tempflags>>16;
+                        cpu_state.eflags = tempflags>>16;
                         cpu_cur_status |= CPU_STATUS_V86;
-                        loadseg(segs[0],&_es);
-                        do_seg_v86_init(&_es);
-                        loadseg(segs[1],&_ds);
-                        do_seg_v86_init(&_ds);
+                        loadseg(segs[0],&cpu_state.seg_es);
+                        do_seg_v86_init(&cpu_state.seg_es);
+                        loadseg(segs[1],&cpu_state.seg_ds);
+                        do_seg_v86_init(&cpu_state.seg_ds);
                         cpu_cur_status |= CPU_STATUS_NOTFLATDS;
-                        loadseg(segs[2],&_fs);
-                        do_seg_v86_init(&_fs);
-                        loadseg(segs[3],&_gs);
-                        do_seg_v86_init(&_gs);                        
+                        loadseg(segs[2],&cpu_state.seg_fs);
+                        do_seg_v86_init(&cpu_state.seg_fs);
+                        loadseg(segs[3],&cpu_state.seg_gs);
+                        do_seg_v86_init(&cpu_state.seg_gs);
                         
 //                        pclog("V86 IRET %04X:%08X\n",SS,ESP);
 //                        output=3;
                         
-                        cpu_state.pc=newpc;
-                        _cs.base=seg<<4;
-                        _cs.limit=0xFFFF;
-                        _cs.limit_low = 0;
-                        _cs.limit_high = 0xffff;
+                        cpu_state.pc = newpc & 0xffff;
+                        cpu_state.seg_cs.base=seg<<4;
+                        cpu_state.seg_cs.limit=0xFFFF;
+                        cpu_state.seg_cs.limit_low = 0;
+                        cpu_state.seg_cs.limit_high = 0xffff;
                         CS=seg;
-                        _cs.access=(3<<5) | 2;
+                        cpu_state.seg_cs.access=(3<<5) | 2;
                         if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                        oldcpl = CPL;
 
                         ESP=newsp;
-                        loadseg(newss,&_ss);
-                        do_seg_v86_init(&_ss);
+                        loadseg(newss,&cpu_state.seg_ss);
+                        do_seg_v86_init(&cpu_state.seg_ss);
                         cpu_cur_status |= CPU_STATUS_NOTFLATSS;
                         use32=0;
                         cpu_cur_status &= ~CPU_STATUS_USE32;
-                        flags=(tempflags&0xFFD5)|2;
+                        cpu_state.flags = (tempflags&0xFFD5)|2;
                         cycles -= timing_iret_v86;
 //                        pclog("V86 IRET to %04X:%04X  %04X:%04X  %04X %04X %04X %04X %i\n",CS,pc,SS,SP,DS,ES,FS,GS,abrt);
   //                      if (CS==0xFFFF && pc==0xFFFFFFFF) timetolive=12;
@@ -2292,9 +2282,10 @@ void pmodeiret(int is32)
         {
 //                pclog("Same level\n");
                 CS=seg;
-                do_seg_load(&_cs, segdat);
-                _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5);
+                do_seg_load(&cpu_state.seg_cs, segdat);
+                cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5);
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
                 set_use32(segdat[3]&0x40);
 
 #ifdef CS_ACCESSED                
@@ -2392,7 +2383,7 @@ void pmodeiret(int is32)
                 set_stack32((segdat2[3] & 0x40) ? 1 : 0);
                 if (stack32) ESP=newsp;
                 else         SP=newsp;
-                do_seg_load(&_ss, segdat2);
+                do_seg_load(&cpu_state.seg_ss, segdat2);
 
 #ifdef SEL_ACCESSED
                 cpl_override = 1;
@@ -2408,20 +2399,21 @@ void pmodeiret(int is32)
                            segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8));
 
                 CS=seg;
-                do_seg_load(&_cs, segdat);
-                _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5);
+                do_seg_load(&cpu_state.seg_cs, segdat);
+                cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5);
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
                 set_use32(segdat[3] & 0x40);
                         
-                check_seg_valid(&_ds);
-                check_seg_valid(&_es);
-                check_seg_valid(&_fs);
-                check_seg_valid(&_gs);
+                check_seg_valid(&cpu_state.seg_ds);
+                check_seg_valid(&cpu_state.seg_es);
+                check_seg_valid(&cpu_state.seg_fs);
+                check_seg_valid(&cpu_state.seg_gs);
                 cycles -= timing_iret_pm_outer;
         }
         cpu_state.pc=newpc;
-        flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2;
-        if (is32) eflags=tempflags>>16;
+        cpu_state.flags = (cpu_state.flags&~flagmask) | (tempflags&flagmask&0xFFD5)|2;
+        if (is32) cpu_state.eflags = tempflags>>16;
 //        pclog("done\n");
 }
 
@@ -2475,13 +2467,13 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
                 }
                 if (cpu_state.abrt) return;
 
-                if (optype==IRET) flags&=~NT_FLAG;
+                if (optype==IRET) cpu_state.flags&=~NT_FLAG;
                 
 //                if (output) pclog("Write PC %08X %08X\n",tr.base,pc);
                 cpu_386_flags_rebuild();
                 writememl(tr.base,0x1C,cr3);
                 writememl(tr.base,0x20,cpu_state.pc);
-                writememl(tr.base,0x24,flags|(eflags<<16));
+                writememl(tr.base,0x24,cpu_state.flags | (cpu_state.eflags<<16));
                 
                 writememl(tr.base,0x28,EAX);
                 writememl(tr.base,0x2C,ECX);
@@ -2554,8 +2546,8 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
                 
                 cpu_state.pc=new_pc;
 //                if (output) pclog("New pc %08X\n",new_pc);
-                flags=new_flags;
-                eflags=new_flags>>16;
+                cpu_state.flags = new_flags;
+                cpu_state.eflags = new_flags>>16;
                 cpu_386_flags_extract();
 
 //                if (output) pclog("Load LDT %04X\n",new_ldt);
@@ -2572,7 +2564,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
 //                if (output) pclog("Limit %04X Base %08X\n",ldt.limit,ldt.base);
 
 
-                if (eflags & VM_FLAG)
+                if (cpu_state.eflags & VM_FLAG)
                 {
                         loadcs(new_cs);
                         set_use32(0);
@@ -2643,8 +2635,9 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
 
 //                if (output) pclog("new_cs %04X\n",new_cs);
                         CS=new_cs;
-                        do_seg_load(&_cs, segdat2);
+                        do_seg_load(&cpu_state.seg_cs, segdat2);
                         if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                        oldcpl = CPL;
                         set_use32(segdat2[3] & 0x40);
                         cpu_cur_status &= ~CPU_STATUS_V86;
                 }
@@ -2659,15 +2652,15 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
                 EDI=new_edi;
 
                 if (output) pclog("Load ES %04X\n",new_es);
-                loadseg(new_es,&_es);
+                loadseg(new_es,&cpu_state.seg_es);
                 if (output) pclog("Load SS %04X\n",new_ss);
-                loadseg(new_ss,&_ss);
+                loadseg(new_ss,&cpu_state.seg_ss);
                 if (output) pclog("Load DS %04X\n",new_ds);
-                loadseg(new_ds,&_ds);
+                loadseg(new_ds,&cpu_state.seg_ds);
                 if (output) pclog("Load FS %04X\n",new_fs);
-                loadseg(new_fs,&_fs);
+                loadseg(new_fs,&cpu_state.seg_fs);
                 if (output) pclog("Load GS %04X\n",new_gs);
-                loadseg(new_gs,&_gs);
+                loadseg(new_gs,&cpu_state.seg_gs);
 
                 if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc);
         }
@@ -2693,12 +2686,13 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
                 }
                 if (cpu_state.abrt) return;
 
-                if (optype==IRET) flags&=~NT_FLAG;
+                if (optype == IRET)
+                        cpu_state.flags &= ~NT_FLAG;
                 
 //                if (output) pclog("Write PC %08X %08X\n",tr.base,pc);
                 cpu_386_flags_rebuild();
                 writememw(tr.base,0x0E,cpu_state.pc);
-                writememw(tr.base,0x10,flags);
+                writememw(tr.base,0x10,cpu_state.flags);
                 
                 writememw(tr.base,0x12,AX);
                 writememw(tr.base,0x14,CX);
@@ -2758,7 +2752,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
                
                 cpu_state.pc=new_pc;
 //                if (output) pclog("New pc %08X\n",new_pc);
-                flags=new_flags;
+                cpu_state.flags = new_flags;
                 cpu_386_flags_extract();
 
 //                if (output) pclog("Load LDT %04X\n",new_ldt);
@@ -2842,8 +2836,9 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
 
 //                if (output) pclog("new_cs %04X\n",new_cs);
                 CS=new_cs;
-                do_seg_load(&_cs, segdat2);
+                do_seg_load(&cpu_state.seg_cs, segdat2);
                 if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
+                oldcpl = CPL;
                 set_use32(0);
 
                 EAX=new_eax | 0xFFFF0000;
@@ -2856,15 +2851,15 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
                 EDI=new_edi | 0xFFFF0000;
 
                 if (output) pclog("Load ES %04X\n",new_es);
-                loadseg(new_es,&_es);
+                loadseg(new_es,&cpu_state.seg_es);
                 if (output) pclog("Load SS %04X\n",new_ss);
-                loadseg(new_ss,&_ss);
+                loadseg(new_ss,&cpu_state.seg_ss);
                 if (output) pclog("Load DS %04X\n",new_ds);
-                loadseg(new_ds,&_ds);
+                loadseg(new_ds,&cpu_state.seg_ds);
                 if (is386)
                 {
-                        loadseg(0,&_fs);
-                        loadseg(0,&_gs);
+                        loadseg(0,&cpu_state.seg_fs);
+                        loadseg(0,&cpu_state.seg_gs);
                 }
 
                 if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc);
index 547e5609162495b37b3c80ff05d8db705b286e0f..7581fc30aa9348f5665d0c0c5bbf12eada3dd620 100644 (file)
 #include "x87.h"
 #include "386_common.h"
 
+#define X87_TAG_VALID   0
+#define X87_TAG_ZERO    1
+#define X87_TAG_INVALID 2
+#define X87_TAG_EMPTY   3
+
 uint16_t x87_gettag()
 {
         uint16_t ret = 0;
@@ -26,10 +31,14 @@ uint16_t x87_gettag()
         
         for (c = 0; c < 8; c++)
         {
-                if (cpu_state.tag[c] & TAG_UINT64)
+                if (cpu_state.tag[c] == TAG_EMPTY)
+                        ret |= X87_TAG_EMPTY << (c * 2);
+                else if (cpu_state.tag[c] & TAG_UINT64)
                         ret |= 2 << (c*2);
+                else if (cpu_state.ST[c] == 0.0 && !cpu_state.ismmx)
+                        ret |= X87_TAG_ZERO << (c * 2);
                 else
-                        ret |= (cpu_state.tag[c] << (c*2));
+                        ret |= X87_TAG_VALID << (c * 2);
         }
 
         return ret;
@@ -37,14 +46,19 @@ uint16_t x87_gettag()
 
 void x87_settag(uint16_t new_tag)
 {
-        cpu_state.tag[0] = new_tag & 3;
-        cpu_state.tag[1] = (new_tag >> 2) & 3;
-        cpu_state.tag[2] = (new_tag >> 4) & 3;
-        cpu_state.tag[3] = (new_tag >> 6) & 3;
-        cpu_state.tag[4] = (new_tag >> 8) & 3;
-        cpu_state.tag[5] = (new_tag >> 10) & 3;
-        cpu_state.tag[6] = (new_tag >> 12) & 3;
-        cpu_state.tag[7] = (new_tag >> 14) & 3;
+        int c;
+        
+        for (c = 0; c < 8; c++)
+        {
+                int tag = (new_tag >> (c * 2)) & 3;
+                
+                if (tag == X87_TAG_EMPTY)
+                        cpu_state.tag[c] = TAG_EMPTY;
+                else if (tag == 2)
+                        cpu_state.tag[c] = TAG_VALID | TAG_UINT64;
+                else
+                        cpu_state.tag[c] = TAG_VALID;
+        }
 }
 
 void x87_dumpregs()
@@ -56,7 +70,7 @@ void x87_dumpregs()
         }
         else
         {
-                pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",cpu_state.ST[cpu_state.TOP],cpu_state.ST[(cpu_state.TOP+1)&7],cpu_state.ST[(cpu_state.TOP+2)&7],cpu_state.ST[(cpu_state.TOP+3)&7]);
+                pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",cpu_state.ST[cpu_state.TOP&7],cpu_state.ST[(cpu_state.TOP+1)&7],cpu_state.ST[(cpu_state.TOP+2)&7],cpu_state.ST[(cpu_state.TOP+3)&7]);
                 pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",cpu_state.ST[(cpu_state.TOP+4)&7],cpu_state.ST[(cpu_state.TOP+5)&7],cpu_state.ST[(cpu_state.TOP+6)&7],cpu_state.ST[(cpu_state.TOP+7)&7]);
         }
         pclog("Status = %04X  Control = %04X  Tag = %04X\n", cpu_state.npxs, cpu_state.npxc, x87_gettag());
index b85e8c5916e172192a4eca3f9330c8563bbddf4d..2d61c14aed9523cddb156f615048cb1c4df43ec8 100644 (file)
@@ -1,16 +1,21 @@
-extern uint32_t x87_pc_off,x87_op_off;
-extern uint16_t x87_pc_seg,x87_op_seg;
+#define C0 (1<<8)
+#define C1 (1<<9)
+#define C2 (1<<10)
+#define C3 (1<<14)
+
+uint32_t x87_pc_off,x87_op_off;
+uint16_t x87_pc_seg,x87_op_seg;
 
 static inline void x87_set_mmx()
 {
         cpu_state.TOP = 0;
-        *(uint64_t *)cpu_state.tag = 0;
+        *(uint64_t *)cpu_state.tag = 0x0101010101010101ull;
         cpu_state.ismmx = 1;
 }
 
 static inline void x87_emms()
 {
-        *(uint64_t *)cpu_state.tag = 0x0303030303030303ll;
+        *(uint64_t *)cpu_state.tag = 0;
         cpu_state.ismmx = 0;
 }
 
@@ -19,5 +24,14 @@ void x87_settag(uint16_t new_tag);
 void x87_dumpregs();
 void x87_reset();
 
+#define TAG_EMPTY  0
+#define TAG_VALID  (1 << 0)
 /*Hack for FPU copy. If set then MM[].q contains the 64-bit integer loaded by FILD*/
-#define TAG_UINT64 (1 << 2)
+#define TAG_UINT64 (1 << 7)
+
+#define X87_ROUNDING_NEAREST 0
+#define X87_ROUNDING_DOWN    1
+#define X87_ROUNDING_UP      2
+#define X87_ROUNDING_CHOP    3
+
+void codegen_set_rounding_mode(int mode);
index 0202afacec9f277b9079d02e8f6dfa3cc7d8a827..73a231e940dc969ebe95dfad17c767e513e4f6a2 100644 (file)
@@ -1,5 +1,6 @@
 #include <math.h>
 #include <fenv.h>
+#include "x87_timings.h"
 
 #define fplog 0
 
@@ -7,26 +8,23 @@ static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZ
 
 #define ST(x) cpu_state.ST[((cpu_state.TOP+(x))&7)]
 
-#define C0 (1<<8)
-#define C1 (1<<9)
-#define C2 (1<<10)
-#define C3 (1<<14)
-
 #define STATUS_ZERODIVIDE 4
 
+#define FPCW_DISI (1 << 7)
+
 #define x87_div(dst, src1, src2) do                             \
         {                                                       \
                 if (((double)src2) == 0.0)                      \
                 {                                               \
-                        cpu_state.npxs |= STATUS_ZERODIVIDE;              \
-                        if (cpu_state.npxc & STATUS_ZERODIVIDE)           \
+                        cpu_state.npxs |= STATUS_ZERODIVIDE;    \
+                        if (cpu_state.npxc & STATUS_ZERODIVIDE) \
                                 dst = src1 / (double)src2;      \
                         else                                    \
                         {                                       \
                                 pclog("FPU : divide by zero\n"); \
                                 picint(1 << 13);                \
+                                return 1;                       \
                         }                                       \
-                        return 1;                               \
                 }                                               \
                 else                                            \
                         dst = src1 / (double)src2;              \
@@ -38,9 +36,9 @@ static inline void x87_checkexceptions()
 
 static inline void x87_push(double i)
 {
-        cpu_state.TOP=(cpu_state.TOP-1)&7;
-        cpu_state.ST[cpu_state.TOP] = i;
-        cpu_state.tag[cpu_state.TOP&7] = (i == 0.0) ? 1 : 0;
+        cpu_state.TOP--;
+        cpu_state.ST[cpu_state.TOP&7] = i;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
 }
 
 static inline void x87_push_u64(uint64_t i)
@@ -53,16 +51,16 @@ static inline void x87_push_u64(uint64_t i)
                 
         td.ll = i;
 
-        cpu_state.TOP=(cpu_state.TOP-1)&7;
-        cpu_state.ST[cpu_state.TOP] = td.d;
-        cpu_state.tag[cpu_state.TOP&7] = (td.d == 0.0) ? 1 : 0;
+        cpu_state.TOP--;
+        cpu_state.ST[cpu_state.TOP&7] = td.d;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
 }
 
 static inline double x87_pop()
 {
-        double t = cpu_state.ST[cpu_state.TOP];
-        cpu_state.tag[cpu_state.TOP&7] = 3;
-        cpu_state.TOP=(cpu_state.TOP+1)&7;
+        double t = cpu_state.ST[cpu_state.TOP&7];
+        cpu_state.tag[cpu_state.TOP&7] = TAG_EMPTY;
+        cpu_state.TOP++;
         return t;
 }
 
@@ -186,13 +184,15 @@ static inline void x87_ld_frstor(int reg)
         cpu_state.MM[reg].q = readmemq(easeg, cpu_state.eaaddr);
         cpu_state.MM_w4[reg] = readmemw(easeg, cpu_state.eaaddr + 8);
 
-        if (cpu_state.MM_w4[reg] == 0x5555 && cpu_state.tag[reg] == 2)
+        if ((cpu_state.MM_w4[reg] == 0x5555) && (cpu_state.tag[reg] & TAG_UINT64))
         {
-                cpu_state.tag[reg] = TAG_UINT64;
                 cpu_state.ST[reg] = (double)cpu_state.MM[reg].q;
         }
         else
+        {
+                cpu_state.tag[reg] &= ~TAG_UINT64;
                 cpu_state.ST[reg] = x87_ld80();
+        }
 }
 
 static inline void x87_ldmmx(MMX_REG *r, uint16_t *w4)
@@ -211,7 +211,7 @@ static inline void x87_stmmx(MMX_REG r)
 
 static inline uint16_t x87_compare(double a, double b)
 {
-#if 0 //defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32
+#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__
         uint32_t out;
         
         /* Memory barrier, to force GCC to write to the input parameters
@@ -245,7 +245,7 @@ static inline uint16_t x87_compare(double a, double b)
 
 static inline uint16_t x87_ucompare(double a, double b)
 {
-#if 0 //defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32
+#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__
         uint32_t out;
         
         /* Memory barrier, to force GCC to write to the input parameters
@@ -289,6 +289,9 @@ typedef union
         uint64_t i;
 } x87_td;
 
+#ifdef X8087
+#define FP_ENTER() fpucount++
+#else
 #define FP_ENTER() do                   \
         {                               \
                 if (cr0 & 0xc)          \
@@ -298,6 +301,7 @@ typedef union
                 }                       \
                 fpucount++;             \
         } while (0)
+#endif
 
 #include "x87_ops_arith.h"
 #include "x87_ops_misc.h"
@@ -637,7 +641,7 @@ OpFn OP_TABLE(fpu_db_a16)[256] =
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
-        ILLEGAL,       opFNOP,        opFCLEX,       opFINIT,       opFNOP,        opFNOP,        ILLEGAL,       ILLEGAL,
+        opFENI,        opFDISI,       opFCLEX,       opFINIT,       opFNOP,        opFNOP,        ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
@@ -677,7 +681,7 @@ OpFn OP_TABLE(fpu_db_a32)[256] =
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
-        ILLEGAL,       opFNOP,        opFCLEX,       opFINIT,       opFNOP,        opFNOP,        ILLEGAL,       ILLEGAL,
+        opFENI,        opFDISI,       opFCLEX,       opFINIT,       opFNOP,        opFNOP,        ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
         ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,       ILLEGAL,
index 48a141e2f9ea5421be04a42608915809e5b695a5..c00f9780290ede7473b1e8bd5520a7f99e0c9f39 100644 (file)
@@ -1,17 +1,18 @@
-#define opFPU(name, optype, a_size, load_var, get, use_var)     \
+#define opFPU(name, optype, a_size, load_var, get, use_var, cycle_postfix)     \
 static int opFADD ## name ## _a ## a_size(uint32_t fetchdat)    \
 {                                                               \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         if ((cpu_state.npxc >> 10) & 3)                                   \
                 fesetround(rounding_modes[(cpu_state.npxc >> 10) & 3]);   \
         ST(0) += use_var;                                       \
         if ((cpu_state.npxc >> 10) & 3)                                   \
                 fesetround(FE_TONEAREST);                       \
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;                                \
-        CLOCK_CYCLES(8);                                        \
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;             \
+        CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix);        \
         return 0;                                               \
 }                                                               \
 static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat)    \
@@ -19,10 +20,11 @@ static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat)    \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         cpu_state.npxs &= ~(C0|C2|C3);                                    \
         cpu_state.npxs |= x87_compare(ST(0), (double)use_var);            \
-        CLOCK_CYCLES(4);                                        \
+        CLOCK_CYCLES(x87_timings.fcom ## cycle_postfix);        \
         return 0;                                               \
 }                                                               \
 static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat)   \
@@ -30,11 +32,12 @@ static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat)   \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         cpu_state.npxs &= ~(C0|C2|C3);                                    \
         cpu_state.npxs |= x87_compare(ST(0), (double)use_var);            \
         x87_pop();                                              \
-        CLOCK_CYCLES(4);                                        \
+        CLOCK_CYCLES(x87_timings.fcom ## cycle_postfix);        \
         return 0;                                               \
 }                                                               \
 static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat)    \
@@ -42,10 +45,11 @@ static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat)    \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         x87_div(ST(0), ST(0), use_var);                         \
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;                                \
-        CLOCK_CYCLES(73);                                       \
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;             \
+        CLOCK_CYCLES(x87_timings.fdiv ## cycle_postfix);        \
         return 0;                                               \
 }                                                               \
 static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat)   \
@@ -53,10 +57,11 @@ static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat)   \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         x87_div(ST(0), use_var, ST(0));                         \
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;                                \
-        CLOCK_CYCLES(73);                                       \
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;             \
+        CLOCK_CYCLES(x87_timings.fdiv ## cycle_postfix);        \
         return 0;                                               \
 }                                                               \
 static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat)    \
@@ -64,10 +69,11 @@ static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat)    \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         ST(0) *= use_var;                                       \
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;                                \
-        CLOCK_CYCLES(11);                                       \
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;             \
+        CLOCK_CYCLES(x87_timings.fmul ## cycle_postfix);        \
         return 0;                                               \
 }                                                               \
 static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat)    \
@@ -75,10 +81,11 @@ static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat)    \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         ST(0) -= use_var;                                       \
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;                                \
-        CLOCK_CYCLES(8);                                        \
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;             \
+        CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix);        \
         return 0;                                               \
 }                                                               \
 static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat)   \
@@ -86,23 +93,24 @@ static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat)   \
         optype t;                                               \
         FP_ENTER();                                             \
         fetch_ea_ ## a_size(fetchdat);                          \
+        SEG_CHECK_READ(cpu_state.ea_seg);                       \
         load_var = get(); if (cpu_state.abrt) return 1;                   \
         ST(0) = use_var - ST(0);                                \
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;                                \
-        CLOCK_CYCLES(8);                                        \
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;             \
+        CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix);        \
         return 0;                                               \
 }
 
 
-opFPU(s, x87_ts, 16, t.i, geteal, t.s)
-opFPU(s, x87_ts, 32, t.i, geteal, t.s)
-opFPU(d, x87_td, 16, t.i, geteaq, t.d)
-opFPU(d, x87_td, 32, t.i, geteaq, t.d)
+opFPU(s, x87_ts, 16, t.i, geteal, t.s, _32)
+opFPU(s, x87_ts, 32, t.i, geteal, t.s, _32)
+opFPU(d, x87_td, 16, t.i, geteaq, t.d, _64)
+opFPU(d, x87_td, 32, t.i, geteaq, t.d, _64)
 
-opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t)
-opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t)
-opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t)
-opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t)
+opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t, _i16)
+opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t, _i16)
+opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t, _i32)
+opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t, _i32)
 
 
 
@@ -113,8 +121,8 @@ static int opFADD(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FADD\n");
         ST(0) = ST(0) + ST(fetchdat & 7);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(8);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 static int opFADDr(uint32_t fetchdat)
@@ -123,8 +131,8 @@ static int opFADDr(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FADD\n");
         ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
-        CLOCK_CYCLES(8);
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 static int opFADDP(uint32_t fetchdat)
@@ -133,9 +141,9 @@ static int opFADDP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FADDP\n");
         ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 
@@ -147,7 +155,7 @@ static int opFCOM(uint32_t fetchdat)
         cpu_state.npxs &= ~(C0|C2|C3);
         if (ST(0) == ST(fetchdat & 7))     cpu_state.npxs |= C3;
         else if (ST(0) < ST(fetchdat & 7)) cpu_state.npxs |= C0;
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 
@@ -159,7 +167,7 @@ static int opFCOMP(uint32_t fetchdat)
         cpu_state.npxs &= ~(C0|C2|C3);
         cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7));
         x87_pop();
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 
@@ -176,7 +184,7 @@ static int opFCOMPP(uint32_t fetchdat)
 
         x87_pop();
         x87_pop();
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 static int opFUCOMPP(uint32_t fetchdat)
@@ -188,7 +196,7 @@ static int opFUCOMPP(uint32_t fetchdat)
         cpu_state.npxs |= x87_ucompare(ST(0), ST(1));
         x87_pop();
         x87_pop();
-        CLOCK_CYCLES(5);
+        CLOCK_CYCLES(x87_timings.fucom);
         return 0;
 }
 
@@ -198,10 +206,10 @@ static int opFCOMI(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FICOM\n");
         flags_rebuild();
-        flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
-        if (ST(0) == ST(fetchdat & 7))     flags |= Z_FLAG;
-        else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG;
-        CLOCK_CYCLES(4);
+        cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
+        if (ST(0) == ST(fetchdat & 7))     cpu_state.flags |= Z_FLAG;
+        else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG;
+        CLOCK_CYCLES(x87_timings.fcom);
         return 0;
 }
 static int opFCOMIP(uint32_t fetchdat)
@@ -210,11 +218,11 @@ static int opFCOMIP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FICOMP\n");
         flags_rebuild();
-        flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
-        if (ST(0) == ST(fetchdat & 7))     flags |= Z_FLAG;
-        else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG;
+        cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
+        if (ST(0) == ST(fetchdat & 7))     cpu_state.flags |= Z_FLAG;
+        else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG;
         x87_pop();
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fcom);
         return 0;
 }
 
@@ -224,8 +232,8 @@ static int opFDIV(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FDIV\n");
         x87_div(ST(0), ST(0), ST(fetchdat & 7));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(73);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fdiv);
         return 0;
 }
 static int opFDIVr(uint32_t fetchdat)
@@ -234,8 +242,8 @@ static int opFDIVr(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FDIV\n");
         x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0));
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
-        CLOCK_CYCLES(73);
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fdiv);
         return 0;
 }
 static int opFDIVP(uint32_t fetchdat)
@@ -244,9 +252,9 @@ static int opFDIVP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FDIVP\n");
         x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0));
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(73);
+        CLOCK_CYCLES(x87_timings.fdiv);
         return 0;
 }
 
@@ -256,8 +264,8 @@ static int opFDIVR(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FDIVR\n");
         x87_div(ST(0), ST(fetchdat&7), ST(0));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(73);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fdiv);
         return 0;
 }
 static int opFDIVRr(uint32_t fetchdat)
@@ -266,8 +274,8 @@ static int opFDIVRr(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FDIVR\n");
         x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7));
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
-        CLOCK_CYCLES(73);
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fdiv);
         return 0;
 }
 static int opFDIVRP(uint32_t fetchdat)
@@ -276,9 +284,9 @@ static int opFDIVRP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FDIVR\n");
         x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7));
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(73);
+        CLOCK_CYCLES(x87_timings.fdiv);
         return 0;
 }
 
@@ -288,8 +296,8 @@ static int opFMUL(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FMUL\n");
         ST(0) = ST(0) * ST(fetchdat & 7);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(16);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fmul);
         return 0;
 }
 static int opFMULr(uint32_t fetchdat)
@@ -298,8 +306,8 @@ static int opFMULr(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FMUL\n");
         ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
-        CLOCK_CYCLES(16);
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fmul);
         return 0;
 }
 static int opFMULP(uint32_t fetchdat)
@@ -308,9 +316,9 @@ static int opFMULP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FMULP\n");
         ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(16);
+        CLOCK_CYCLES(x87_timings.fmul);
         return 0;
 }
 
@@ -320,8 +328,8 @@ static int opFSUB(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSUB\n");
         ST(0) = ST(0) - ST(fetchdat & 7);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(8);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 static int opFSUBr(uint32_t fetchdat)
@@ -330,8 +338,8 @@ static int opFSUBr(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSUB\n");
         ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
-        CLOCK_CYCLES(8);
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 static int opFSUBP(uint32_t fetchdat)
@@ -340,9 +348,9 @@ static int opFSUBP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSUBP\n");
         ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 
@@ -352,8 +360,8 @@ static int opFSUBR(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSUBR\n");
         ST(0) = ST(fetchdat & 7) - ST(0);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(8);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 static int opFSUBRr(uint32_t fetchdat)
@@ -362,8 +370,8 @@ static int opFSUBRr(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSUBR\n");
         ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
-        CLOCK_CYCLES(8);
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 static int opFSUBRP(uint32_t fetchdat)
@@ -372,9 +380,9 @@ static int opFSUBRP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSUBRP\n");
         ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7);
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fadd);
         return 0;
 }
 
@@ -385,7 +393,7 @@ static int opFUCOM(uint32_t fetchdat)
         if (fplog) pclog("FUCOM\n");
         cpu_state.npxs &= ~(C0|C2|C3);
         cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7));
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fucom);
         return 0;
 }
 
@@ -397,7 +405,7 @@ static int opFUCOMP(uint32_t fetchdat)
         cpu_state.npxs &= ~(C0|C2|C3);
         cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7));
         x87_pop();
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fucom);
         return 0;
 }
 
@@ -407,10 +415,10 @@ static int opFUCOMI(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FUCOMI\n");
         flags_rebuild();
-        flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
-        if (ST(0) == ST(fetchdat & 7))     flags |= Z_FLAG;
-        else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG;
-        CLOCK_CYCLES(4);
+        cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
+        if (ST(0) == ST(fetchdat & 7))     cpu_state.flags |= Z_FLAG;
+        else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG;
+        CLOCK_CYCLES(x87_timings.fucom);
         return 0;
 }
 static int opFUCOMIP(uint32_t fetchdat)
@@ -419,10 +427,10 @@ static int opFUCOMIP(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FUCOMIP\n");
         flags_rebuild();
-        flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
-        if (ST(0) == ST(fetchdat & 7))     flags |= Z_FLAG;
-        else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG;
+        cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG);
+        if (ST(0) == ST(fetchdat & 7))     cpu_state.flags |= Z_FLAG;
+        else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG;
         x87_pop();
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fucom);
         return 0;
 }
index ed083b9215c3b0dddc529755c6f20475828eecdc..6b8c050c8b6af96280dce3f3d65d9a2ab4f9e0f7 100644 (file)
@@ -3,11 +3,12 @@ static int opFILDiw_a16(uint32_t fetchdat)
         int16_t temp;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp = geteaw(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", (double)temp);
         x87_push((double)temp);
-        CLOCK_CYCLES(13);
+        CLOCK_CYCLES(x87_timings.fild_16);
         return 0;
 }
 static int opFILDiw_a32(uint32_t fetchdat)
@@ -15,11 +16,12 @@ static int opFILDiw_a32(uint32_t fetchdat)
         int16_t temp;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp = geteaw(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", (double)temp);
         x87_push((double)temp);
-        CLOCK_CYCLES(13);
+        CLOCK_CYCLES(x87_timings.fild_16);
         return 0;
 }
 
@@ -28,12 +30,13 @@ static int opFISTiw_a16(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 32767 || temp64 < -32768)
                            fatal("FISTw overflow %i\n", temp64);*/
         seteaw((int16_t)temp64);
-        CLOCK_CYCLES(29);
+        CLOCK_CYCLES(x87_timings.fist_16);
         return cpu_state.abrt;
 }
 static int opFISTiw_a32(uint32_t fetchdat)
@@ -41,12 +44,13 @@ static int opFISTiw_a32(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 32767 || temp64 < -32768)
                            fatal("FISTw overflow %i\n", temp64);*/
         seteaw((int16_t)temp64);
-        CLOCK_CYCLES(29);
+        CLOCK_CYCLES(x87_timings.fist_16);
         return cpu_state.abrt;
 }
 
@@ -55,13 +59,14 @@ static int opFISTPiw_a16(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 32767 || temp64 < -32768)
                            fatal("FISTw overflow %i\n", temp64);*/
         seteaw((int16_t)temp64); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(29);
+        CLOCK_CYCLES(x87_timings.fist_16);
         return 0;
 }
 static int opFISTPiw_a32(uint32_t fetchdat)
@@ -69,13 +74,14 @@ static int opFISTPiw_a32(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 32767 || temp64 < -32768)
                            fatal("FISTw overflow %i\n", temp64);*/
         seteaw((int16_t)temp64); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(29);
+        CLOCK_CYCLES(x87_timings.fist_16);
         return 0;
 }
 
@@ -84,14 +90,15 @@ static int opFILDiq_a16(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = geteaq(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f  %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4));
         x87_push((double)temp64);
-        cpu_state.MM[cpu_state.TOP].q = temp64;
-        cpu_state.tag[cpu_state.TOP] |= TAG_UINT64;
+        cpu_state.MM[cpu_state.TOP&7].q = temp64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64;
 
-        CLOCK_CYCLES(10);
+        CLOCK_CYCLES(x87_timings.fild_64);
         return 0;
 }
 static int opFILDiq_a32(uint32_t fetchdat)
@@ -99,14 +106,15 @@ static int opFILDiq_a32(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = geteaq(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f  %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4));
         x87_push((double)temp64);
-        cpu_state.MM[cpu_state.TOP].q = temp64;
-        cpu_state.tag[cpu_state.TOP] |= TAG_UINT64;
+        cpu_state.MM[cpu_state.TOP&7].q = temp64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64;
 
-        CLOCK_CYCLES(10);
+        CLOCK_CYCLES(x87_timings.fild_64);
         return 0;
 }
 
@@ -116,6 +124,7 @@ static int FBSTP_a16(uint32_t fetchdat)
         int c;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr);
         tempd = ST(0);
         if (tempd < 0.0) 
@@ -134,6 +143,7 @@ static int FBSTP_a16(uint32_t fetchdat)
         if (ST(0) < 0.0) tempc |= 0x80;
         writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1;
         x87_pop();
+        CLOCK_CYCLES(x87_timings.fbstp);
         return 0;
 }
 static int FBSTP_a32(uint32_t fetchdat)
@@ -142,6 +152,7 @@ static int FBSTP_a32(uint32_t fetchdat)
         int c;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr);
         tempd = ST(0);
         if (tempd < 0.0) 
@@ -160,6 +171,7 @@ static int FBSTP_a32(uint32_t fetchdat)
         if (ST(0) < 0.0) tempc |= 0x80;
         writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1;
         x87_pop();
+        CLOCK_CYCLES(x87_timings.fbstp);
         return 0;
 }
 
@@ -168,14 +180,15 @@ static int FISTPiq_a16(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr);
-        if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64)
-                temp64 = cpu_state.MM[cpu_state.TOP].q;
+        if (cpu_state.tag[cpu_state.TOP&7] & TAG_UINT64)
+                temp64 = cpu_state.MM[cpu_state.TOP&7].q;
         else
                 temp64 = x87_fround(ST(0));
         seteaq(temp64); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(29);
+        CLOCK_CYCLES(x87_timings.fist_64);
         return 0;
 }
 static int FISTPiq_a32(uint32_t fetchdat)
@@ -183,14 +196,15 @@ static int FISTPiq_a32(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr);
-        if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64)
-                temp64 = cpu_state.MM[cpu_state.TOP].q;
+        if (cpu_state.tag[cpu_state.TOP&7] & TAG_UINT64)
+                temp64 = cpu_state.MM[cpu_state.TOP&7].q;
         else
                 temp64 = x87_fround(ST(0));
         seteaq(temp64); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(29);
+        CLOCK_CYCLES(x87_timings.fist_64);
         return 0;
 }
 
@@ -199,11 +213,12 @@ static int opFILDil_a16(uint32_t fetchdat)
         int32_t templ;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr);
         templ = geteal(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f %08X %i\n", (double)templ, templ, templ);
         x87_push((double)templ);
-        CLOCK_CYCLES(9);
+        CLOCK_CYCLES(x87_timings.fild_32);
         return 0;
 }
 static int opFILDil_a32(uint32_t fetchdat)
@@ -211,11 +226,12 @@ static int opFILDil_a32(uint32_t fetchdat)
         int32_t templ;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr);
         templ = geteal(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f %08X %i\n", (double)templ, templ, templ);
         x87_push((double)templ);
-        CLOCK_CYCLES(9);
+        CLOCK_CYCLES(x87_timings.fild_32);
         return 0;
 }
 
@@ -224,12 +240,13 @@ static int opFISTil_a16(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 2147483647 || temp64 < -2147483647)
                            fatal("FISTl out of range! %i\n", temp64);*/
         seteal((int32_t)temp64);
-        CLOCK_CYCLES(28);
+        CLOCK_CYCLES(x87_timings.fist_32);
         return cpu_state.abrt;
 }
 static int opFISTil_a32(uint32_t fetchdat)
@@ -237,12 +254,13 @@ static int opFISTil_a32(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 2147483647 || temp64 < -2147483647)
                            fatal("FISTl out of range! %i\n", temp64);*/
         seteal((int32_t)temp64);
-        CLOCK_CYCLES(28);
+        CLOCK_CYCLES(x87_timings.fist_32);
         return cpu_state.abrt;
 }
 
@@ -251,13 +269,14 @@ static int opFISTPil_a16(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 2147483647 || temp64 < -2147483647)
                            fatal("FISTl out of range! %i\n", temp64);*/
         seteal((int32_t)temp64); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(28);
+        CLOCK_CYCLES(x87_timings.fist_32);
         return 0;
 }
 static int opFISTPil_a32(uint32_t fetchdat)
@@ -265,13 +284,14 @@ static int opFISTPil_a32(uint32_t fetchdat)
         int64_t temp64;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         temp64 = x87_fround(ST(0));
 /*                        if (temp64 > 2147483647 || temp64 < -2147483647)
                            fatal("FISTl out of range! %i\n", temp64);*/
         seteal((int32_t)temp64); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(28);
+        CLOCK_CYCLES(x87_timings.fist_32);
         return 0;
 }
 
@@ -280,11 +300,12 @@ static int opFLDe_a16(uint32_t fetchdat)
         double t;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr);                        
         t=x87_ld80(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", t);
         x87_push(t);
-        CLOCK_CYCLES(6);
+        CLOCK_CYCLES(x87_timings.fld_80);
         return 0;
 }
 static int opFLDe_a32(uint32_t fetchdat)
@@ -292,11 +313,12 @@ static int opFLDe_a32(uint32_t fetchdat)
         double t;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr);                        
         t=x87_ld80(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", t);
         x87_push(t);
-        CLOCK_CYCLES(6);
+        CLOCK_CYCLES(x87_timings.fld_80);
         return 0;
 }
 
@@ -304,20 +326,22 @@ static int opFSTPe_a16(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr);
         x87_st80(ST(0)); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(6);
+        CLOCK_CYCLES(x87_timings.fst_80);
         return 0;
 }
 static int opFSTPe_a32(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr);
         x87_st80(ST(0)); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(6);
+        CLOCK_CYCLES(x87_timings.fst_80);
         return 0;
 }
 
@@ -326,11 +350,12 @@ static int opFLDd_a16(uint32_t fetchdat)
         x87_td t;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr);
         t.i = geteaq(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", t.d);                        
         x87_push(t.d);
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fld_64);
         return 0;
 }
 static int opFLDd_a32(uint32_t fetchdat)
@@ -338,11 +363,12 @@ static int opFLDd_a32(uint32_t fetchdat)
         x87_td t;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr);
         t.i = geteaq(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", t.d);                        
         x87_push(t.d);
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fld_64);
         return 0;
 }
 
@@ -351,10 +377,11 @@ static int opFSTd_a16(uint32_t fetchdat)
         x87_td t;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr);
         t.d = ST(0);
         seteaq(t.i);
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fst_64);
         return cpu_state.abrt;
 }
 static int opFSTd_a32(uint32_t fetchdat)
@@ -362,10 +389,11 @@ static int opFSTd_a32(uint32_t fetchdat)
         x87_td t;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr);
         t.d = ST(0);
         seteaq(t.i);
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fst_64);
         return cpu_state.abrt;
 }
 
@@ -374,12 +402,13 @@ static int opFSTPd_a16(uint32_t fetchdat)
         x87_td t;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7);
         if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr);
         t.d = ST(0);
         seteaq(t.i); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fst_64);
         return 0;
 }
 static int opFSTPd_a32(uint32_t fetchdat)
@@ -387,12 +416,13 @@ static int opFSTPd_a32(uint32_t fetchdat)
         x87_td t;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7);
         if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr);
         t.d = ST(0);
         seteaq(t.i); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fst_64);
         return 0;
 }
 
@@ -401,11 +431,12 @@ static int opFLDs_a16(uint32_t fetchdat)
         x87_ts ts;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr);                        
         ts.i = geteal(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", ts.s);
         x87_push((double)ts.s);
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fld_32);
         return 0;
 }
 static int opFLDs_a32(uint32_t fetchdat)
@@ -413,11 +444,12 @@ static int opFLDs_a32(uint32_t fetchdat)
         x87_ts ts;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr);                        
         ts.i = geteal(); if (cpu_state.abrt) return 1;
         if (fplog) pclog("  %f\n", ts.s);
         x87_push((double)ts.s);
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fld_32);
         return 0;
 }
 
@@ -426,10 +458,11 @@ static int opFSTs_a16(uint32_t fetchdat)
         x87_ts ts;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         ts.s = (float)ST(0);
         seteal(ts.i);
-        CLOCK_CYCLES(7);
+        CLOCK_CYCLES(x87_timings.fst_32);
         return cpu_state.abrt;
 }
 static int opFSTs_a32(uint32_t fetchdat)
@@ -437,10 +470,11 @@ static int opFSTs_a32(uint32_t fetchdat)
         x87_ts ts;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         ts.s = (float)ST(0);
         seteal(ts.i);
-        CLOCK_CYCLES(7);
+        CLOCK_CYCLES(x87_timings.fst_32);
         return cpu_state.abrt;
 }
 
@@ -449,11 +483,12 @@ static int opFSTPs_a16(uint32_t fetchdat)
         x87_ts ts;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         ts.s = (float)ST(0);
         seteal(ts.i); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(7);
+        CLOCK_CYCLES(x87_timings.fst_32);
         return 0;
 }
 static int opFSTPs_a32(uint32_t fetchdat)
@@ -461,10 +496,11 @@ static int opFSTPs_a32(uint32_t fetchdat)
         x87_ts ts;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr);
         ts.s = (float)ST(0);
         seteal(ts.i); if (cpu_state.abrt) return 1;
         x87_pop();
-        CLOCK_CYCLES(7);
+        CLOCK_CYCLES(x87_timings.fst_32);
         return 0;
 }
index bd00f9eb172a9d6efd83c9611148715120e944d0..61a9919a753d0319df8b43a06fc0a87fdb22f965 100644 (file)
@@ -1,10 +1,37 @@
+static int opFDISI(uint32_t fetchdat)
+{
+        FP_ENTER();
+        cpu_state.pc++;
+        if (fpu_type == FPU_8087)
+        {
+                cpu_state.npxc |= FPCW_DISI;
+                CLOCK_CYCLES(x87_timings.fdisi_eni);
+        }
+        else
+                CLOCK_CYCLES(x87_timings.fnop);
+        return 0;
+}
+static int opFENI(uint32_t fetchdat)
+{
+        FP_ENTER();
+        cpu_state.pc++;
+        if (fpu_type == FPU_8087)
+        {
+                cpu_state.npxc &= ~FPCW_DISI;
+                CLOCK_CYCLES(x87_timings.fdisi_eni);
+        }
+        else
+                CLOCK_CYCLES(x87_timings.fnop);
+        return 0;
+}
+
 static int opFSTSW_AX(uint32_t fetchdat)
 {
         FP_ENTER();
         cpu_state.pc++;
         if (fplog) pclog("FSTSW\n");
         AX = cpu_state.npxs;
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fstcw_sw);
         return 0;
 }
 
@@ -14,7 +41,7 @@ static int opFNOP(uint32_t fetchdat)
 {
         FP_ENTER();
         cpu_state.pc++;
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fnop);
         return 0;
 }
 
@@ -23,7 +50,7 @@ static int opFCLEX(uint32_t fetchdat)
         FP_ENTER();
         cpu_state.pc++;
         cpu_state.npxs &= 0xff00;
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fclex);
         return 0;
 }
 
@@ -31,13 +58,17 @@ static int opFINIT(uint32_t fetchdat)
 {
         FP_ENTER();
         cpu_state.pc++;
-        cpu_state.npxc = 0x37F;
-        cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00);
+        if (fpu_type == FPU_8087)
+                cpu_state.npxc = 0x3ff;
+        else
+                cpu_state.npxc = 0x37f;
+        codegen_set_rounding_mode(X87_ROUNDING_NEAREST);
         cpu_state.npxs = 0;
-        *(uint64_t *)cpu_state.tag = 0x0303030303030303ll;
+        *(uint64_t *)cpu_state.tag = 0;
         cpu_state.TOP = 0;
         cpu_state.ismmx = 0;
-        CLOCK_CYCLES(17);
+        CLOCK_CYCLES(x87_timings.finit);
+        CPU_BLOCK_END();
         return 0;
 }
 
@@ -47,8 +78,8 @@ static int opFFREE(uint32_t fetchdat)
         FP_ENTER();
         cpu_state.pc++;
         if (fplog) pclog("FFREE\n");
-        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3;
-        CLOCK_CYCLES(3);
+        cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_EMPTY;
+        CLOCK_CYCLES(x87_timings.ffree);
         return 0;
 }
 
@@ -59,7 +90,7 @@ static int opFST(uint32_t fetchdat)
         if (fplog) pclog("FST\n");
         ST(fetchdat & 7) = ST(0);
         cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7];
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fst);
         return 0;
 }
 
@@ -71,7 +102,7 @@ static int opFSTP(uint32_t fetchdat)
         ST(fetchdat & 7) = ST(0);
         cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7];
         x87_pop();
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fst);
         return 0;
 }
 
@@ -86,7 +117,7 @@ static int FSTOR()
                 case 0x000: /*16-bit real mode*/
                 case 0x001: /*16-bit protected mode*/
                 cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
-                cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
+                codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3);
                 cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2);
                 x87_settag(readmemw(easeg, cpu_state.eaaddr+4));
                 cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
@@ -95,7 +126,7 @@ static int FSTOR()
                 case 0x100: /*32-bit real mode*/
                 case 0x101: /*32-bit protected mode*/
                 cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
-                cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
+                codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3);
                 cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4);
                 x87_settag(readmemw(easeg, cpu_state.eaaddr+8));
                 cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
@@ -116,10 +147,10 @@ static int FSTOR()
           something like this is needed*/
         if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff &&
             cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff &&
-            !cpu_state.TOP && !(*(uint64_t *)cpu_state.tag))
-        cpu_state.ismmx = 1;
+            !cpu_state.TOP && (*(uint64_t *)cpu_state.tag == 0x0101010101010101ull))
+                cpu_state.ismmx = 1;
 
-        CLOCK_CYCLES((cr0 & 1) ? 34 : 44);
+        CLOCK_CYCLES(x87_timings.frstor);
         if (fplog) pclog("FRSTOR %08X:%08X %i %i %04X\n", easeg, cpu_state.eaaddr, cpu_state.ismmx, cpu_state.TOP, x87_gettag());
         return cpu_state.abrt;
 }
@@ -127,6 +158,7 @@ static int opFSTOR_a16(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         FSTOR();
         return cpu_state.abrt;
 }
@@ -134,6 +166,7 @@ static int opFSTOR_a32(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         FSTOR();
         return cpu_state.abrt;
 }
@@ -142,7 +175,7 @@ static int FSAVE()
 {
         FP_ENTER();
         if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, cpu_state.eaaddr, cpu_state.ismmx);
-        cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | (cpu_state.TOP << 11);
+        cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | ((cpu_state.TOP & 7) << 11);
 
         switch ((cr0 & 1) | (cpu_state.op32 & 0x100))
         {
@@ -274,19 +307,20 @@ static int FSAVE()
         }
 
         cpu_state.npxc = 0x37F;
-        cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00);
+        codegen_set_rounding_mode(X87_ROUNDING_NEAREST);
         cpu_state.npxs = 0;
-        *(uint64_t *)cpu_state.tag = 0x0303030303030303ll;
+        *(uint64_t *)cpu_state.tag = 0;
         cpu_state.TOP = 0;
         cpu_state.ismmx = 0;
 
-        CLOCK_CYCLES((cr0 & 1) ? 56 : 67);
+        CLOCK_CYCLES(x87_timings.fsave);
         return cpu_state.abrt;
 }
 static int opFSAVE_a16(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         FSAVE();
         return cpu_state.abrt;
 }
@@ -294,6 +328,7 @@ static int opFSAVE_a32(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         FSAVE();
         return cpu_state.abrt;
 }
@@ -302,18 +337,20 @@ static int opFSTSW_a16(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr);
-        seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11));
-        CLOCK_CYCLES(3);
+        seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11));
+        CLOCK_CYCLES(x87_timings.fstcw_sw);
         return cpu_state.abrt;
 }
 static int opFSTSW_a32(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr);
-        seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11));
-        CLOCK_CYCLES(3);
+        seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11));
+        CLOCK_CYCLES(x87_timings.fstcw_sw);
         return cpu_state.abrt;
 }
 
@@ -329,9 +366,9 @@ static int opFLD(uint32_t fetchdat)
         old_tag = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7];
         old_i64 = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q;
         x87_push(ST(fetchdat&7));
-        cpu_state.tag[cpu_state.TOP] = old_tag;
-        cpu_state.MM[cpu_state.TOP].q = old_i64;
-        CLOCK_CYCLES(4);
+        cpu_state.tag[cpu_state.TOP&7] = old_tag;
+        cpu_state.MM[cpu_state.TOP&7].q = old_i64;
+        CLOCK_CYCLES(x87_timings.fld);
         return 0;
 }
 
@@ -346,14 +383,14 @@ static int opFXCH(uint32_t fetchdat)
         td = ST(0);
         ST(0) = ST(fetchdat&7);
         ST(fetchdat&7) = td;
-        old_tag = cpu_state.tag[cpu_state.TOP];
-        cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7];
+        old_tag = cpu_state.tag[cpu_state.TOP&7];
+        cpu_state.tag[cpu_state.TOP&7] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7];
         cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = old_tag;
-        old_i64 = cpu_state.MM[cpu_state.TOP].q;
-        cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q;
+        old_i64 = cpu_state.MM[cpu_state.TOP&7].q;
+        cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q;
         cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q = old_i64;
         
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fxch);
         return 0;
 }
 
@@ -363,8 +400,8 @@ static int opFCHS(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FCHS\n");
         ST(0) = -ST(0);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(6);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fchs);
         return 0;
 }
 
@@ -374,8 +411,8 @@ static int opFABS(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FABS %f\n", ST(0));
         ST(0) = fabs(ST(0));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(3);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fabs);
         return 0;
 }
 
@@ -387,7 +424,7 @@ static int opFTST(uint32_t fetchdat)
         cpu_state.npxs &= ~(C0|C2|C3);
         if (ST(0) == 0.0)     cpu_state.npxs |= C3;
         else if (ST(0) < 0.0) cpu_state.npxs |= C0;
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.ftst);
         return 0;
 }
 
@@ -397,11 +434,11 @@ static int opFXAM(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FXAM %i %f\n", cpu_state.tag[cpu_state.TOP&7], ST(0));
         cpu_state.npxs &= ~(C0|C1|C2|C3);
-        if (cpu_state.tag[cpu_state.TOP&7] == 3)   cpu_state.npxs |= (C0|C3);
+        if (cpu_state.tag[cpu_state.TOP&7] == TAG_EMPTY)   cpu_state.npxs |= (C0|C3);
         else if (ST(0) == 0.0) cpu_state.npxs |= C3;
         else                   cpu_state.npxs |= C2;
         if (ST(0) < 0.0)       cpu_state.npxs |= C1;
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fxam);
         return 0;
 }
 
@@ -411,7 +448,7 @@ static int opFLD1(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FLD1\n");
         x87_push(1.0);
-        CLOCK_CYCLES(4);
+        CLOCK_CYCLES(x87_timings.fld_z1);
         return 0;
 }
 
@@ -421,7 +458,7 @@ static int opFLDL2T(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FLDL2T\n");
         x87_push(3.3219280948873623);
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fld_const);
         return 0;
 }
 
@@ -431,7 +468,7 @@ static int opFLDL2E(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FLDL2E\n");
         x87_push(1.4426950408889634);
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fld_const);
         return 0;
 }
 
@@ -441,7 +478,7 @@ static int opFLDPI(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FLDPI\n");
         x87_push(3.141592653589793);
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fld_const);
         return 0;
 }
 
@@ -451,7 +488,7 @@ static int opFLDEG2(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FLDEG2\n");
         x87_push(0.3010299956639812);
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fld_const);
         return 0;
 }
 
@@ -461,7 +498,7 @@ static int opFLDLN2(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FLDLN2\n");
         x87_push_u64(0x3fe62e42fefa39f0ull);
-        CLOCK_CYCLES(8);
+        CLOCK_CYCLES(x87_timings.fld_const);
         return 0;
 }
  
@@ -471,8 +508,8 @@ static int opFLDZ(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FLDZ\n");
         x87_push(0.0);
-        cpu_state.tag[cpu_state.TOP&7] = 1;
-        CLOCK_CYCLES(4);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fld_z1);
         return 0;
 }
 
@@ -482,8 +519,8 @@ static int opF2XM1(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("F2XM1\n");
         ST(0) = pow(2.0, ST(0)) - 1.0;
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(200);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.f2xm1);
         return 0;
 }
 
@@ -493,9 +530,9 @@ static int opFYL2X(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FYL2X\n");
         ST(1) = ST(1) * (log(ST(0)) / log(2.0));
-        cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(250);
+        CLOCK_CYCLES(x87_timings.fyl2x);
         return 0;
 }
 
@@ -505,9 +542,9 @@ static int opFYL2XP1(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FYL2XP1\n");
         ST(1) = ST(1) * (log(ST(0)+1.0) / log(2.0));
-        cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(250);
+        CLOCK_CYCLES(x87_timings.fyl2xp1);
         return 0;
 }
 
@@ -517,10 +554,10 @@ static int opFPTAN(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FPTAN\n");
         ST(0) = tan(ST(0));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
         x87_push(1.0);
         cpu_state.npxs &= ~C2;
-        CLOCK_CYCLES(235);
+        CLOCK_CYCLES(x87_timings.fptan);
         return 0;
 }
 
@@ -530,9 +567,9 @@ static int opFPATAN(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FPATAN\n");
         ST(1) = atan2(ST(1), ST(0));
-        cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64;
+        cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID;
         x87_pop();
-        CLOCK_CYCLES(250);
+        CLOCK_CYCLES(x87_timings.fpatan);
         return 0;
 }
 
@@ -541,8 +578,8 @@ static int opFDECSTP(uint32_t fetchdat)
         FP_ENTER();
         cpu_state.pc++;
         if (fplog) pclog("FDECSTP\n");
-        cpu_state.TOP = (cpu_state.TOP - 1) & 7;
-        CLOCK_CYCLES(4);
+        cpu_state.TOP--;
+        CLOCK_CYCLES(x87_timings.fincdecstp);
         return 0;
 }
 
@@ -551,8 +588,8 @@ static int opFINCSTP(uint32_t fetchdat)
         FP_ENTER();
         cpu_state.pc++;
         if (fplog) pclog("FDECSTP\n");
-        cpu_state.TOP = (cpu_state.TOP + 1) & 7;
-        CLOCK_CYCLES(4);
+        cpu_state.TOP++;
+        CLOCK_CYCLES(x87_timings.fincdecstp);
         return 0;
 }
 
@@ -564,13 +601,13 @@ static int opFPREM(uint32_t fetchdat)
         if (fplog) pclog("FPREM %f %f  ", ST(0), ST(1));
         temp64 = (int64_t)(ST(0) / ST(1));
         ST(0) = ST(0) - (ST(1) * (double)temp64);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
         if (fplog) pclog("%f\n", ST(0));
         cpu_state.npxs &= ~(C0|C1|C2|C3);
         if (temp64 & 4) cpu_state.npxs|=C0;
         if (temp64 & 2) cpu_state.npxs|=C3;
         if (temp64 & 1) cpu_state.npxs|=C1;
-        CLOCK_CYCLES(100);
+        CLOCK_CYCLES(x87_timings.fprem);
         return 0;
 }
 static int opFPREM1(uint32_t fetchdat)
@@ -581,13 +618,13 @@ static int opFPREM1(uint32_t fetchdat)
         if (fplog) pclog("FPREM1 %f %f  ", ST(0), ST(1));
         temp64 = (int64_t)(ST(0) / ST(1));
         ST(0) = ST(0) - (ST(1) * (double)temp64);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
         if (fplog) pclog("%f\n", ST(0));
         cpu_state.npxs &= ~(C0|C1|C2|C3);
         if (temp64 & 4) cpu_state.npxs|=C0;
         if (temp64 & 2) cpu_state.npxs|=C3;
         if (temp64 & 1) cpu_state.npxs|=C1;
-        CLOCK_CYCLES(100);
+        CLOCK_CYCLES(x87_timings.fprem1);
         return 0;
 }
 
@@ -597,8 +634,8 @@ static int opFSQRT(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSQRT\n");
         ST(0) = sqrt(ST(0));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(83);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fsqrt);
         return 0;
 }
 
@@ -610,10 +647,10 @@ static int opFSINCOS(uint32_t fetchdat)
         if (fplog) pclog("FSINCOS\n");
         td = ST(0);
         ST(0) = sin(td);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
         x87_push(cos(td));
         cpu_state.npxs &= ~C2;
-        CLOCK_CYCLES(330);
+        CLOCK_CYCLES(x87_timings.fsincos);
         return 0;
 }
 
@@ -623,9 +660,9 @@ static int opFRNDINT(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FRNDINT %g ", ST(0));
         ST(0) = (double)x87_fround(ST(0));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
         if (fplog) pclog("%g\n", ST(0));
-        CLOCK_CYCLES(21);
+        CLOCK_CYCLES(x87_timings.frndint);
         return 0;
 }
 
@@ -637,8 +674,8 @@ static int opFSCALE(uint32_t fetchdat)
         if (fplog) pclog("FSCALE\n");
         temp64 = (int64_t)ST(1);
         ST(0) = ST(0) * pow(2.0, (double)temp64);
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
-        CLOCK_CYCLES(30);
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
+        CLOCK_CYCLES(x87_timings.fscale);
         return 0;
 }
 
@@ -648,9 +685,9 @@ static int opFSIN(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FSIN\n");
         ST(0) = sin(ST(0));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
         cpu_state.npxs &= ~C2;
-        CLOCK_CYCLES(300);
+        CLOCK_CYCLES(x87_timings.fsin_cos);
         return 0;
 }
 
@@ -660,9 +697,9 @@ static int opFCOS(uint32_t fetchdat)
         cpu_state.pc++;
         if (fplog) pclog("FCOS\n");
         ST(0) = cos(ST(0));
-        cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64;
+        cpu_state.tag[cpu_state.TOP&7] = TAG_VALID;
         cpu_state.npxs &= ~C2;
-        CLOCK_CYCLES(300);
+        CLOCK_CYCLES(x87_timings.fsin_cos);
         return 0;
 }
 
@@ -676,7 +713,7 @@ static int FLDENV()
                 case 0x000: /*16-bit real mode*/
                 case 0x001: /*16-bit protected mode*/
                 cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
-                cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
+                codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3);
                 cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2);
                 x87_settag(readmemw(easeg, cpu_state.eaaddr+4));
                 cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
@@ -684,13 +721,13 @@ static int FLDENV()
                 case 0x100: /*32-bit real mode*/
                 case 0x101: /*32-bit protected mode*/
                 cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
-                cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
+                codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3);
                 cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4);
                 x87_settag(readmemw(easeg, cpu_state.eaaddr+8));
                 cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
                 break;
         }
-        CLOCK_CYCLES((cr0 & 1) ? 34 : 44);
+        CLOCK_CYCLES(x87_timings.fldenv);
         return cpu_state.abrt;
 }
 
@@ -698,6 +735,7 @@ static int opFLDENV_a16(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         FLDENV();
         return cpu_state.abrt;
 }
@@ -705,6 +743,7 @@ static int opFLDENV_a32(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         FLDENV();
         return cpu_state.abrt;
 }
@@ -714,12 +753,13 @@ static int opFLDCW_a16(uint32_t fetchdat)
         uint16_t tempw;
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr);                        
         tempw = geteaw();
         if (cpu_state.abrt) return 1;
         cpu_state.npxc = tempw;
-        cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
-        CLOCK_CYCLES(4);
+        codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3);
+        CLOCK_CYCLES(x87_timings.fldcw);
         return 0;
 }
 static int opFLDCW_a32(uint32_t fetchdat)
@@ -727,12 +767,13 @@ static int opFLDCW_a32(uint32_t fetchdat)
         uint16_t tempw;
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_READ(cpu_state.ea_seg);
         if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr);                        
         tempw = geteaw();
         if (cpu_state.abrt) return 1;
         cpu_state.npxc = tempw;
-        cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
-        CLOCK_CYCLES(4);
+        codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3);
+        CLOCK_CYCLES(x87_timings.fldcw);
         return 0;
 }
 
@@ -776,7 +817,7 @@ static int FSTENV()
                 writememl(easeg,cpu_state.eaaddr+24,x87_op_seg);
                 break;
         }
-        CLOCK_CYCLES((cr0 & 1) ? 56 : 67);
+        CLOCK_CYCLES(x87_timings.fstenv);
         return cpu_state.abrt;
 }
 
@@ -784,6 +825,7 @@ static int opFSTENV_a16(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         FSTENV();
         return cpu_state.abrt;
 }
@@ -791,6 +833,7 @@ static int opFSTENV_a32(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         FSTENV();
         return cpu_state.abrt;
 }
@@ -799,18 +842,20 @@ static int opFSTCW_a16(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_16(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr);
         seteaw(cpu_state.npxc);
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fstcw_sw);
         return cpu_state.abrt;
 }
 static int opFSTCW_a32(uint32_t fetchdat)
 {
         FP_ENTER();
         fetch_ea_32(fetchdat);
+        SEG_CHECK_WRITE(cpu_state.ea_seg);
         if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr);
         seteaw(cpu_state.npxc);
-        CLOCK_CYCLES(3);
+        CLOCK_CYCLES(x87_timings.fstcw_sw);
         return cpu_state.abrt;
 }
 
@@ -822,8 +867,8 @@ static int opFSTCW_a32(uint32_t fetchdat)
                 if (fplog) pclog("FCMOV %f\n", ST(fetchdat & 7));                       \
                 if (cond_ ## condition)                                                 \
                 {                                                                       \
-                        cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7];                           \
-                        cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q;                     \
+                        cpu_state.tag[cpu_state.TOP&7] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7];                           \
+                        cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q;                     \
                         ST(0) = ST(fetchdat & 7);                                       \
                 }                                                                       \
                 CLOCK_CYCLES(4);                                                        \
diff --git a/pcem/x87_timings.cpp b/pcem/x87_timings.cpp
new file mode 100644 (file)
index 0000000..cc60e1b
--- /dev/null
@@ -0,0 +1,309 @@
+#include "ibm.h"
+#include "x87_timings.h"
+
+x87_timings_t x87_timings;
+
+const x87_timings_t x87_timings_8087 =
+{
+        .f2xm1      = (310 + 630) / 2,
+        .fabs       = (10 + 17) / 2,
+        .fadd       = (70 + 100) / 2,
+        .fadd_32    = (90 + 120) / 2,
+        .fadd_64    = (95 + 125) / 2,
+        .fbld       = (290 + 310) / 2,
+        .fbstp      = (520 + 540) / 2,
+        .fchs       = (10 + 17) / 2,
+        .fclex      = (2 + 8) / 2,
+        .fcom       = (40 + 50) / 2,
+        .fcom_32    = (60 + 70) / 2,
+        .fcom_64    = (65 + 75) / 2,
+        .fcos       = 0, /*387+*/
+        .fincdecstp = (6 + 12) / 2,
+        .fdisi_eni  = (6 + 12) / 2,
+        .fdiv       = (193 + 203) / 2,
+        .fdiv_32    = (215 + 225) / 2,
+        .fdiv_64    = (220 + 230) / 2,
+        .ffree      = (9 + 16) / 2,
+        .fadd_i16   = (102 + 137) / 2,
+        .fadd_i32   = (108 + 143) / 2,
+        .fcom_i16   = (72 + 86) / 2,
+        .fcom_i32   = (78 + 91) / 2,
+        .fdiv_i16   = (224 + 238) / 2,
+        .fdiv_i32   = (230 + 243) / 2,
+        .fild_16    = (46 + 54) / 2,
+        .fild_32    = (50 + 60) / 2,
+        .fild_64    = (60 + 68) / 2,
+        .fmul_i16   = (124 + 138) / 2,
+        .fmul_i32   = (130 + 144) / 2,
+        .finit      = (2 + 8) / 2,
+        .fist_16    = (80 + 90) / 2,
+        .fist_32    = (82 + 92) / 2,
+        .fist_64    = (94 + 105) / 2,
+        .fld        = (17 + 22) / 2,
+        .fld_32     = (38 + 56) / 2,
+        .fld_64     = (40 + 60) / 2,
+        .fld_80     = (53 + 65) / 2,
+        .fld_z1     = (11 + 21) / 2,
+        .fld_const  = (15 + 24) / 2,
+        .fldcw      = (7 + 14) / 2,
+        .fldenv     = (35 + 45) / 2,
+        .fmul       = (90 + 145) / 2,
+        .fmul_32    = (110 + 125) / 2,
+        .fmul_64    = (154 + 168) / 2,
+        .fnop       = (10 + 16) / 2,
+        .fpatan     = (250 + 800) / 2,
+        .fprem      = (15 + 190) / 2,
+        .fprem1     = 0, /*387+*/
+        .fptan      = (30 + 540) / 2,
+        .frndint    = (16 + 50) / 2,
+        .frstor     = (197 + 207) / 2,
+        .fsave      = (197 + 207) / 2,
+        .fscale     = (32 + 38) / 2,
+        .fsetpm     = 0, /*287+*/
+        .fsin_cos   = 0, /*387+*/
+        .fsincos    = 0, /*387+*/
+        .fsqrt      = (180 + 186) / 2,
+        .fst        = (15 + 22) / 2,
+        .fst_32     = (84 + 90) / 2,
+        .fst_64     = (96 + 104) / 2,
+        .fst_80     = (52 + 58) / 2,
+        .fstcw_sw   = (12 + 18) / 2,
+        .fstenv     = (40 + 50) / 2,
+        .ftst       = (38 + 48) / 2,
+        .fucom      = 0, /*387+*/
+        .fwait      = 4,
+        .fxam       = (12 + 23) / 2,
+        .fxch       = (10 + 15) / 2,
+        .fxtract    = (27 + 55) / 2,
+        .fyl2x      = (900 + 1100) / 2,
+        .fyl2xp1    = (700 + 1000) / 2
+};
+
+/*Mostly the same as 8087*/
+const x87_timings_t x87_timings_287 =
+{
+        .f2xm1      = (310 + 630) / 2,
+        .fabs       = (10 + 17) / 2,
+        .fadd       = (70 + 100) / 2,
+        .fadd_32    = (90 + 120) / 2,
+        .fadd_64    = (95 + 125) / 2,
+        .fbld       = (290 + 310) / 2,
+        .fbstp      = (520 + 540) / 2,
+        .fchs       = (10 + 17) / 2,
+        .fclex      = (2 + 8) / 2,
+        .fcom       = (40 + 50) / 2,
+        .fcom_32    = (60 + 70) / 2,
+        .fcom_64    = (65 + 75) / 2,
+        .fcos       = 0, /*387+*/
+        .fincdecstp = (6 + 12) / 2,
+        .fdisi_eni  = 2,
+        .fdiv       = (193 + 203) / 2,
+        .fdiv_32    = (215 + 225) / 2,
+        .fdiv_64    = (220 + 230) / 2,
+        .ffree      = (9 + 16) / 2,
+        .fadd_i16   = (102 + 137) / 2,
+        .fadd_i32   = (108 + 143) / 2,
+        .fcom_i16   = (72 + 86) / 2,
+        .fcom_i32   = (78 + 91) / 2,
+        .fdiv_i16   = (224 + 238) / 2,
+        .fdiv_i32   = (230 + 243) / 2,
+        .fild_16    = (46 + 54) / 2,
+        .fild_32    = (50 + 60) / 2,
+        .fild_64    = (60 + 68) / 2,
+        .fmul_i16   = (124 + 138) / 2,
+        .fmul_i32   = (130 + 144) / 2,
+        .finit      = (2 + 8) / 2,
+        .fist_16    = (80 + 90) / 2,
+        .fist_32    = (82 + 92) / 2,
+        .fist_64    = (94 + 105) / 2,
+        .fld        = (17 + 22) / 2,
+        .fld_32     = (38 + 56) / 2,
+        .fld_64     = (40 + 60) / 2,
+        .fld_80     = (53 + 65) / 2,
+        .fld_z1     = (11 + 21) / 2,
+        .fld_const  = (15 + 24) / 2,
+        .fldcw      = (7 + 14) / 2,
+        .fldenv     = (35 + 45) / 2,
+        .fmul       = (90 + 145) / 2,
+        .fmul_32    = (110 + 125) / 2,
+        .fmul_64    = (154 + 168) / 2,
+        .fnop       = (10 + 16) / 2,
+        .fpatan     = (250 + 800) / 2,
+        .fprem      = (15 + 190) / 2,
+        .fprem1     = 0, /*387+*/
+        .fptan      = (30 + 540) / 2,
+        .frndint    = (16 + 50) / 2,
+        .frstor     = (197 + 207) / 2,
+        .fsave      = (197 + 207) / 2,
+        .fscale     = (32 + 38) / 2,
+        .fsetpm     = (2 + 8) / 2, /*287+*/
+        .fsin_cos   = 0, /*387+*/
+        .fsincos    = 0, /*387+*/
+        .fsqrt      = (180 + 186) / 2,
+        .fst        = (15 + 22) / 2,
+        .fst_32     = (84 + 90) / 2,
+        .fst_64     = (96 + 104) / 2,
+        .fst_80     = (52 + 58) / 2,
+        .fstcw_sw   = (12 + 18) / 2,
+        .fstenv     = (40 + 50) / 2,
+        .ftst       = (38 + 48) / 2,
+        .fucom      = 0, /*387+*/
+        .fwait      = 3,
+        .fxam       = (12 + 23) / 2,
+        .fxch       = (10 + 15) / 2,
+        .fxtract    = (27 + 55) / 2,
+        .fyl2x      = (900 + 1100) / 2,
+        .fyl2xp1    = (700 + 1000) / 2
+};
+
+const x87_timings_t x87_timings_387 =
+{
+        .f2xm1      = (211 + 476) / 2,
+        .fabs       = 22,
+        .fadd       = (23 + 34) / 2,
+        .fadd_32    = (24 + 32) / 2,
+        .fadd_64    = (29 + 37) / 2,
+        .fbld       = (266 + 275) / 2,
+        .fbstp      = (512 + 534) / 2,
+        .fchs       = (24 + 25) / 2,
+        .fclex      = 11,
+        .fcom       = 24,
+        .fcom_32    = 26,
+        .fcom_64    = 31,
+        .fcos       = (122 + 772) / 2,
+        .fincdecstp = 22,
+        .fdisi_eni  = 2,
+        .fdiv       = (88 + 91) / 2,
+        .fdiv_32    = 89,
+        .fdiv_64    = 94,
+        .ffree      = 18,
+        .fadd_i16   = (71 + 85) / 2,
+        .fadd_i32   = (57 + 72) / 2,
+        .fcom_i16   = (71 + 75) / 2,
+        .fcom_i32   = (56 + 63) / 2,
+        .fdiv_i16   = (136 + 140) / 2,
+        .fdiv_i32   = (120 + 127) / 2,
+        .fild_16    = (61 + 65) / 2,
+        .fild_32    = (45 + 52) / 2,
+        .fild_64    = (56 + 67) / 2,
+        .fmul_i16   = (76 + 87) / 2,
+        .fmul_i32   = (61 + 82) / 2,
+        .finit      = 33,
+        .fist_16    = (82 + 95) / 2,
+        .fist_32    = (79 + 93) / 2,
+        .fist_64    = (80 + 97) / 2,
+        .fld        = 14,
+        .fld_32     = 20,
+        .fld_64     = 25,
+        .fld_80     = 44,
+        .fld_z1     = (20 + 24) / 2,
+        .fld_const  = 40,
+        .fldcw      = 19,
+        .fldenv     = 71,
+        .fmul       = (29 + 57) / 2,
+        .fmul_32    = (27 + 35) / 2,
+        .fmul_64    = (32 + 57) / 2,
+        .fnop       = 12,
+        .fpatan     = (314 + 487) / 2,
+        .fprem      = (74 + 155) / 2,
+        .fprem1     = (95 + 185) / 2,
+        .fptan      = (191 + 497) / 2,
+        .frndint    = (66 + 80) / 2,
+        .frstor     = 308,
+        .fsave      = 375,
+        .fscale     = (67 + 86) / 2,
+        .fsetpm     = 12,
+        .fsin_cos   = (122 + 771) / 2,
+        .fsincos    = (194 + 809) / 2,
+        .fsqrt      = (122 + 129) / 2,
+        .fst        = 11,
+        .fst_32     = 44,
+        .fst_64     = 45,
+        .fst_80     = 53,
+        .fstcw_sw   = 15,
+        .fstenv     = 103,
+        .ftst       = 28,
+        .fucom      = 24,
+        .fwait      = 6,
+        .fxam       = (30 + 38) / 2,
+        .fxch       = 18,
+        .fxtract    = (70 + 76) / 2,
+        .fyl2x      = (120 + 538) / 2,
+        .fyl2xp1    = (257 + 547) / 2
+};
+
+const x87_timings_t x87_timings_486 =
+{
+        .f2xm1      = (140 + 270) / 2,
+        .fabs       = 3,
+        .fadd       = (8 + 20) / 2,
+        .fadd_32    = (8 + 20) / 2,
+        .fadd_64    = (8 + 20) / 2,
+        .fbld       = (70 + 103) / 2,
+        .fbstp      = (172 + 176) / 2,
+        .fchs       = 6,
+        .fclex      = 7,
+        .fcom       = 4,
+        .fcom_32    = 4,
+        .fcom_64    = 4,
+        .fcos       = (257 + 354) / 2,
+        .fincdecstp = 3,
+        .fdisi_eni  = 3,
+        .fdiv       = 73,
+        .fdiv_32    = 73,
+        .fdiv_64    = 73,
+        .ffree      = 3,
+        .fadd_i16   = (20 + 35) / 2,
+        .fadd_i32   = (19 + 32) / 2,
+        .fcom_i16   = (16 + 20) / 2,
+        .fcom_i32   = (15 + 17) / 2,
+        .fdiv_i16   = (85 + 89) / 2,
+        .fdiv_i32   = (84 + 86) / 2,
+        .fild_16    = (13 + 16) / 2,
+        .fild_32    = (9 + 12) / 2,
+        .fild_64    = (10 + 18) / 2,
+        .fmul_i16   = (23 + 27) / 2,
+        .fmul_i32   = (22 + 24) / 2,
+        .finit      = 17,
+        .fist_16    = (29 + 34) / 2,
+        .fist_32    = (28 + 34) / 2,
+        .fist_64    = (29 + 34) / 2,
+        .fld        = 4,
+        .fld_32     = 3,
+        .fld_64     = 3,
+        .fld_80     = 6,
+        .fld_z1     = 4,
+        .fld_const  = 8,
+        .fldcw      = 4,
+        .fldenv     = 34,
+        .fmul       = 16,
+        .fmul_32    = 11,
+        .fmul_64    = 14,
+        .fnop       = 3,
+        .fpatan     = (218 + 303) / 2,
+        .fprem      = (70 + 138) / 2,
+        .fprem1     = (72 + 167) / 2,
+        .fptan      = (200 + 273) / 2,
+        .frndint    = (21 + 30) / 2,
+        .frstor     = 120,
+        .fsave      = 143,
+        .fscale     = (30 + 32) / 2,
+        .fsetpm     = 3,
+        .fsin_cos   = (257 + 354) / 2,
+        .fsincos    = (292 + 365) / 2,
+        .fsqrt      = (83 + 87) / 2,
+        .fst        = 3,
+        .fst_32     = 7,
+        .fst_64     = 8,
+        .fst_80     = 6,
+        .fstcw_sw   = 3,
+        .fstenv     = 56,
+        .ftst       = 4,
+        .fucom      = 4,
+        .fwait      = (1 + 3) / 2,
+        .fxam       = 8,
+        .fxch       = 4,
+        .fxtract    = (16 + 20) / 2,
+        .fyl2x      = (196 + 329) / 2,
+        .fyl2xp1    = (171 + 326) / 2
+};
diff --git a/pcem/x87_timings.h b/pcem/x87_timings.h
new file mode 100644 (file)
index 0000000..0e7363d
--- /dev/null
@@ -0,0 +1,56 @@
+typedef struct
+{
+        int f2xm1;
+        int fabs;
+        int fadd, fadd_32, fadd_64;
+        int fbld;
+        int fbstp;
+        int fchs;
+        int fclex;
+        int fcom, fcom_32, fcom_64;
+        int fcos;
+        int fincdecstp;
+        int fdisi_eni;
+        int fdiv, fdiv_32, fdiv_64;
+        int ffree;
+        int fadd_i16, fadd_i32;
+        int fcom_i16, fcom_i32;
+        int fdiv_i16, fdiv_i32;
+        int fild_16, fild_32, fild_64;
+        int fmul_i16, fmul_i32;
+        int finit;
+        int fist_16, fist_32, fist_64;
+        int fld, fld_32, fld_64, fld_80;
+        int fld_z1, fld_const;
+        int fldcw;
+        int fldenv;
+        int fmul, fmul_32, fmul_64;
+        int fnop;
+        int fpatan;
+        int fprem, fprem1;
+        int fptan;
+        int frndint;
+        int frstor;
+        int fsave;
+        int fscale;
+        int fsetpm;
+        int fsin_cos, fsincos;
+        int fsqrt;
+        int fst, fst_32, fst_64, fst_80;
+        int fstcw_sw;
+        int fstenv;
+        int ftst;
+        int fucom;
+        int fwait;
+        int fxam;
+        int fxch;
+        int fxtract;
+        int fyl2x, fyl2xp1;
+} x87_timings_t;
+
+extern const x87_timings_t x87_timings_8087;
+extern const x87_timings_t x87_timings_287;
+extern const x87_timings_t x87_timings_387;
+extern const x87_timings_t x87_timings_486;
+
+extern x87_timings_t x87_timings;