From d45be21c891811213e3290510c7301e77b121f16 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 29 Aug 2020 19:56:46 +0300 Subject: [PATCH] PCem v16 merge. Original files. --- pcem/386.cpp | 139 +- pcem/386.h | 13 - pcem/386_common.cpp | 249 ++ pcem/386_common.h | 100 +- pcem/386_dynarec.cpp | 932 +++---- pcem/386_dynarec_ops.cpp | 58 + pcem/386_ops.h | 128 +- pcem/8087.h | 98 + pcem/808x.cpp | 1149 ++++---- pcem/codegen.h | 308 ++- pcem/codegen_backend.h | 43 + pcem/codegen_backend_x86-64.h | 12 + pcem/codegen_backend_x86-64_defs.h | 67 + pcem/codegen_backend_x86.h | 12 + pcem/codegen_backend_x86_defs.h | 50 + pcem/codegen_x86-64.h | 23 - pcem/codegen_x86.h | 42 - pcem/config.h | 27 + pcem/cpu.cpp | 974 ++++--- pcem/cpu.h | 75 +- pcem/fdc.h | 11 + pcem/ibm.h | 336 +-- pcem/keyboard.cpp | 621 +++-- pcem/keyboard.h | 12 +- pcem/keyboard_at.cpp | 220 +- pcem/mca.h | 3 +- pcem/mem.cpp | 819 +++--- pcem/mem.h | 62 +- pcem/model.h | 1 + pcem/mouse_ps2.cpp | 24 +- pcem/mouse_serial.cpp | 8 +- pcem/{pcemnvr.cpp => nvr.cpp} | 199 +- pcem/nvr.h | 8 +- pcem/pcemglue.cpp | 732 ++++- pcem/pcemglue.h | 1 - pcem/pic.cpp | 20 +- pcem/pit.cpp | 194 +- pcem/pit.h | 2 +- pcem/plat-keyboard.h | 21 + pcem/plat-midi.h | 7 +- pcem/plat-mouse.h | 14 +- pcem/rom.h | 20 + pcem/serial.cpp | 21 +- pcem/serial.h | 13 +- pcem/sound.h | 37 +- pcem/sound_cms.cpp | 5 +- pcem/sound_dbopl.cpp | 4 +- pcem/sound_dbopl.h | 6 + pcem/sound_emu8k.h | 4 + pcem/sound_mpu401_uart.cpp | 49 +- pcem/sound_mpu401_uart.h | 15 +- pcem/sound_opl.cpp | 47 +- pcem/sound_opl.h | 3 +- pcem/sound_sb.cpp | 155 +- pcem/sound_sb.h | 114 + pcem/sound_sb_dsp.cpp | 239 +- pcem/sound_sb_dsp.h | 27 +- pcem/thread.h | 18 + pcem/timer.cpp | 203 +- pcem/timer.h | 172 +- pcem/vid_cl5429.cpp | 2384 ++++++++++++++++ pcem/vid_cl5429.h | 11 + pcem/vid_s3.cpp | 3069 ++++++++++++++++++++ pcem/vid_s3.h | 4 + pcem/vid_s3_virge.cpp | 4150 ++++++++++++++++++++++++++++ pcem/vid_s3_virge.h | 2 + pcem/vid_sdac_ramdac.cpp | 187 ++ pcem/vid_sdac_ramdac.h | 16 + pcem/vid_svga.cpp | 1554 +++++++++++ pcem/vid_svga.h | 185 ++ pcem/vid_svga_render.cpp | 782 ++++++ pcem/vid_svga_render.h | 34 + pcem/vid_unk_ramdac.h | 8 + pcem/vid_vga.h | 8 + pcem/video.h | 20 +- pcem/x86.h | 286 +- pcem/x86_flags.h | 247 +- pcem/x86_ops.h | 8 + pcem/x86_ops_3dnow.h | 346 +++ pcem/x86_ops_arith.h | 106 +- pcem/x86_ops_atomic.h | 22 +- pcem/x86_ops_bcd.h | 40 +- pcem/x86_ops_bit.h | 92 +- pcem/x86_ops_bitscan.h | 20 +- pcem/x86_ops_call.h | 94 +- pcem/x86_ops_flag.h | 94 +- pcem/x86_ops_inc_dec.h | 4 + pcem/x86_ops_int.h | 8 +- pcem/x86_ops_jump.h | 31 +- pcem/x86_ops_misc.h | 163 +- pcem/x86_ops_mmx.h | 7 +- pcem/x86_ops_mmx_arith.h | 6 +- pcem/x86_ops_mmx_cmp.h | 4 +- pcem/x86_ops_mmx_mov.h | 12 +- pcem/x86_ops_mmx_pack.h | 4 +- pcem/x86_ops_mmx_shift.h | 1 + pcem/x86_ops_mov.h | 44 +- pcem/x86_ops_mov_ctrl.h | 32 +- pcem/x86_ops_mov_seg.h | 80 +- pcem/x86_ops_movx.h | 28 + pcem/x86_ops_msr.h | 2 +- pcem/x86_ops_mul.h | 90 +- pcem/x86_ops_pmode.h | 73 +- pcem/x86_ops_prefix.h | 36 +- pcem/x86_ops_rep.h | 169 +- pcem/x86_ops_ret.h | 39 +- pcem/x86_ops_set.h | 4 + pcem/x86_ops_shift.h | 195 +- pcem/x86_ops_stack.h | 24 +- pcem/x86_ops_string.h | 360 ++- pcem/x86_ops_xchg.h | 18 + pcem/x86seg.cpp | 381 ++- pcem/x87.cpp | 36 +- pcem/x87.h | 24 +- pcem/x87_ops.h | 50 +- pcem/x87_ops_arith.h | 170 +- pcem/x87_ops_loadstore.h | 116 +- pcem/x87_ops_misc.h | 223 +- pcem/x87_timings.cpp | 309 +++ pcem/x87_timings.h | 56 + 120 files changed, 20751 insertions(+), 4783 deletions(-) delete mode 100644 pcem/386.h create mode 100644 pcem/386_common.cpp create mode 100644 pcem/386_dynarec_ops.cpp create mode 100644 pcem/8087.h create mode 100644 pcem/codegen_backend.h create mode 100644 pcem/codegen_backend_x86-64.h create mode 100644 pcem/codegen_backend_x86-64_defs.h create mode 100644 pcem/codegen_backend_x86.h create mode 100644 pcem/codegen_backend_x86_defs.h delete mode 100644 pcem/codegen_x86-64.h delete mode 100644 pcem/codegen_x86.h rename pcem/{pcemnvr.cpp => nvr.cpp} (73%) create mode 100644 pcem/thread.h create mode 100644 pcem/vid_cl5429.cpp create mode 100644 pcem/vid_cl5429.h create mode 100644 pcem/vid_s3.cpp create mode 100644 pcem/vid_s3.h create mode 100644 pcem/vid_s3_virge.cpp create mode 100644 pcem/vid_s3_virge.h create mode 100644 pcem/vid_sdac_ramdac.cpp create mode 100644 pcem/vid_sdac_ramdac.h create mode 100644 pcem/vid_svga.cpp create mode 100644 pcem/vid_svga.h create mode 100644 pcem/vid_svga_render.cpp create mode 100644 pcem/vid_svga_render.h create mode 100644 pcem/vid_unk_ramdac.h create mode 100644 pcem/vid_vga.h create mode 100644 pcem/x86_ops_3dnow.h create mode 100644 pcem/x87_timings.cpp create mode 100644 pcem/x87_timings.h diff --git a/pcem/386.cpp b/pcem/386.cpp index 9a07a2af..e99ef1f6 100644 --- a/pcem/386.cpp +++ b/pcem/386.cpp @@ -2,7 +2,6 @@ #include #include #include "ibm.h" -#include "386.h" #include "x86.h" #include "x87.h" #include "mem.h" @@ -13,56 +12,15 @@ #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 index eada519a..00000000 --- a/pcem/386.h +++ /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 index 00000000..8919652e --- /dev/null +++ b/pcem/386_common.cpp @@ -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(); +} diff --git a/pcem/386_common.h b/pcem/386_common.h index c8bbd6e8..c01b9c70 100644 --- a/pcem/386_common.h +++ b/pcem/386_common.h @@ -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(easeg, cpu_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 diff --git a/pcem/386_dynarec.cpp b/pcem/386_dynarec.cpp index e0c068ff..b7ab1bfd 100644 --- a/pcem/386_dynarec.cpp +++ b/pcem/386_dynarec.cpp @@ -2,12 +2,12 @@ #include #include #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" @@ -18,59 +18,18 @@ #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 index 00000000..e1bbfe1d --- /dev/null +++ b/pcem/386_dynarec_ops.cpp @@ -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" diff --git a/pcem/386_ops.h b/pcem/386_ops.h index 47407503..5c73ccb4 100644 --- a/pcem/386_ops.h +++ b/pcem/386_ops.h @@ -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 index 00000000..42f64d59 --- /dev/null +++ b/pcem/8087.h @@ -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 diff --git a/pcem/808x.cpp b/pcem/808x.cpp index 69e59bc1..d81ee335 100644 --- a/pcem/808x.cpp +++ b/pcem/808x.cpp @@ -25,45 +25,49 @@ #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)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 index 00000000..afe27682 --- /dev/null +++ b/pcem/codegen_backend.h @@ -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 index 00000000..70e953a6 --- /dev/null +++ b/pcem/codegen_backend_x86-64.h @@ -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 index 00000000..8955773c --- /dev/null +++ b/pcem/codegen_backend_x86-64_defs.h @@ -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 index 00000000..a5aec727 --- /dev/null +++ b/pcem/codegen_backend_x86.h @@ -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 index 00000000..25964ba3 --- /dev/null +++ b/pcem/codegen_backend_x86_defs.h @@ -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 index f0c22e40..00000000 --- a/pcem/codegen_x86-64.h +++ /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 index 92e35913..00000000 --- a/pcem/codegen_x86.h +++ /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; diff --git a/pcem/config.h b/pcem/config.h index e69de29b..5913377a 100644 --- a/pcem/config.h +++ b/pcem/config.h @@ -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 diff --git a/pcem/cpu.cpp b/pcem/cpu.cpp index 5619bb53..7490db11 100644 --- a/pcem/cpu.cpp +++ b/pcem/cpu.cpp @@ -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() diff --git a/pcem/cpu.h b/pcem/cpu.h index cd31b483..b4dc2b66 100644 --- a/pcem/cpu.h +++ b/pcem/cpu.h @@ -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 diff --git a/pcem/fdc.h b/pcem/fdc.h index 85d6d7e1..8d804aa3 100644 --- a/pcem/fdc.h +++ b/pcem/fdc.h @@ -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 +}; diff --git a/pcem/ibm.h b/pcem/ibm.h index 1a5ed65a..da0f39fe 100644 --- a/pcem/ibm.h +++ b/pcem/ibm.h @@ -2,6 +2,8 @@ #include #include +#include "timer.h" + #ifdef ABS #undef ABS #endif @@ -17,40 +19,27 @@ #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*/ diff --git a/pcem/keyboard.cpp b/pcem/keyboard.cpp index a346a4a2..7c2c63c7 100644 --- a/pcem/keyboard.cpp +++ b/pcem/keyboard.cpp @@ -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++]); + } +} diff --git a/pcem/keyboard.h b/pcem/keyboard.h index 9430617c..fb47b314 100644 --- a/pcem/keyboard.h +++ b/pcem/keyboard.h @@ -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); diff --git a/pcem/keyboard_at.cpp b/pcem/keyboard_at.cpp index c56c14e0..b2fd23b3 100644 --- a/pcem/keyboard_at.cpp +++ b/pcem/keyboard_at.cpp @@ -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; } diff --git a/pcem/mca.h b/pcem/mca.h index 90d7f07e..0f1e6aef 100644 --- a/pcem/mca.h +++ b/pcem/mca.h @@ -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); diff --git a/pcem/mem.cpp b/pcem/mem.cpp index 425500a6..89bbff8d 100644 --- a/pcem/mem.cpp +++ b/pcem/mem.cpp @@ -22,18 +22,10 @@ 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; } } diff --git a/pcem/mem.h b/pcem/mem.h index 7ea6f6f1..41fe23f3 100644 --- a/pcem/mem.h +++ b/pcem/mem.h @@ -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 diff --git a/pcem/model.h b/pcem/model.h index e8fab563..6834e439 100644 --- a/pcem/model.h +++ b/pcem/model.h @@ -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(); diff --git a/pcem/mouse_ps2.cpp b/pcem/mouse_ps2.cpp index 551d20b0..b1c219df 100644 --- a/pcem/mouse_ps2.cpp +++ b/pcem/mouse_ps2.cpp @@ -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; diff --git a/pcem/mouse_serial.cpp b/pcem/mouse_serial.cpp index f975d00e..2d81dea4 100644 --- a/pcem/mouse_serial.cpp +++ b/pcem/mouse_serial.cpp @@ -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; } diff --git a/pcem/pcemnvr.cpp b/pcem/nvr.cpp similarity index 73% rename from pcem/pcemnvr.cpp rename to pcem/nvr.cpp index 406364db..ccb7f9f0 100644 --- a/pcem/pcemnvr.cpp +++ b/pcem/nvr.cpp @@ -1,5 +1,7 @@ #include +#include #include "ibm.h" +#include "device.h" #include "io.h" #include "nvr.h" #include "nvr_tc8521.h" @@ -11,19 +13,24 @@ #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 +}; diff --git a/pcem/nvr.h b/pcem/nvr.h index dd769a8a..c545f848 100644 --- a/pcem/nvr.h +++ b/pcem/nvr.h @@ -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; diff --git a/pcem/pcemglue.cpp b/pcem/pcemglue.cpp index a8161bcd..fe33dc26 100644 --- a/pcem/pcemglue.cpp +++ b/pcem/pcemglue.cpp @@ -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 @@ -21,6 +22,15 @@ #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); +} + diff --git a/pcem/pcemglue.h b/pcem/pcemglue.h index 41cea2c9..8c5ed7aa 100644 --- a/pcem/pcemglue.h +++ b/pcem/pcemglue.h @@ -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]; diff --git a/pcem/pic.cpp b/pcem/pic.cpp index e21d0650..e6bf6791 100644 --- a/pcem/pic.cpp +++ b/pcem/pic.cpp @@ -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; diff --git a/pcem/pit.cpp b/pcem/pit.cpp index 078f1c01..6e7ef6ed 100644 --- a/pcem/pit.cpp +++ b/pcem/pit.cpp @@ -21,7 +21,12 @@ //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); diff --git a/pcem/pit.h b/pcem/pit.h index 2b54da4b..3bcf2029 100644 --- a/pcem/pit.h +++ b/pcem/pit.h @@ -1,4 +1,4 @@ -extern double PITCONST; +extern uint64_t PITCONST; void pit_init(); void pit_ps2_init(); void pit_reset(); diff --git a/pcem/plat-keyboard.h b/pcem/plat-keyboard.h index e69de29b..ad027f99 100644 --- a/pcem/plat-keyboard.h +++ b/pcem/plat-keyboard.h @@ -0,0 +1,21 @@ +#ifdef __cplusplus +extern "C" { +#endif + #include + + 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 + diff --git a/pcem/plat-midi.h b/pcem/plat-midi.h index befdba90..ff7d2640 100644 --- a/pcem/plat-midi.h +++ b/pcem/plat-midi.h @@ -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); diff --git a/pcem/plat-mouse.h b/pcem/plat-mouse.h index 79224d6c..e9323027 100644 --- a/pcem/plat-mouse.h +++ b/pcem/plat-mouse.h @@ -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 diff --git a/pcem/rom.h b/pcem/rom.h index 551acf24..18e8cf8e 100644 --- a/pcem/rom.h +++ b/pcem/rom.h @@ -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 diff --git a/pcem/serial.cpp b/pcem/serial.cpp index b8b1c2b2..8d2947bb 100644 --- a/pcem/serial.cpp +++ b/pcem/serial.cpp @@ -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) { diff --git a/pcem/serial.h b/pcem/serial.h index b4261231..85ae2592 100644 --- a/pcem/serial.h +++ b/pcem/serial.h @@ -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); diff --git a/pcem/sound.h b/pcem/sound.h index 98236804..9d532e9a 100644 --- a/pcem/sound.h +++ b/pcem/sound.h @@ -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) diff --git a/pcem/sound_cms.cpp b/pcem/sound_cms.cpp index 39a4f1d2..c649a625 100644 --- a/pcem/sound_cms.cpp +++ b/pcem/sound_cms.cpp @@ -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 diff --git a/pcem/sound_dbopl.cpp b/pcem/sound_dbopl.cpp index 165ed84a..fd9f6c7e 100644 --- a/pcem/sound_dbopl.cpp +++ b/pcem/sound_dbopl.cpp @@ -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) { diff --git a/pcem/sound_dbopl.h b/pcem/sound_dbopl.h index b86040b1..80c15bbd 100644 --- a/pcem/sound_dbopl.h +++ b/pcem/sound_dbopl.h @@ -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 diff --git a/pcem/sound_emu8k.h b/pcem/sound_emu8k.h index 97b4528c..290a1b53 100644 --- a/pcem/sound_emu8k.h +++ b/pcem/sound_emu8k.h @@ -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 */ diff --git a/pcem/sound_mpu401_uart.cpp b/pcem/sound_mpu401_uart.cpp index 5d70b542..99a7f8a9 100644 --- a/pcem/sound_mpu401_uart.cpp +++ b/pcem/sound_mpu401_uart.cpp @@ -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; +} + diff --git a/pcem/sound_mpu401_uart.h b/pcem/sound_mpu401_uart.h index 893c53fc..dd00612f 100644 --- a/pcem/sound_mpu401_uart.h +++ b/pcem/sound_mpu401_uart.h @@ -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 */ diff --git a/pcem/sound_opl.cpp b/pcem/sound_opl.cpp index 9d4d48d5..44c1af7d 100644 --- a/pcem/sound_opl.cpp +++ b/pcem/sound_opl.cpp @@ -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); } diff --git a/pcem/sound_opl.h b/pcem/sound_opl.h index d2aa3654..7ce62278 100644 --- a/pcem/sound_opl.h +++ b/pcem/sound_opl.h @@ -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]; diff --git a/pcem/sound_sb.cpp b/pcem/sound_sb.cpp index 2da4d22d..2c308c5e 100644 --- a/pcem/sound_sb.cpp +++ b/pcem/sound_sb.cpp @@ -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 diff --git a/pcem/sound_sb.h b/pcem/sound_sb.h index 4a0b974b..0f0902e5 100644 --- a/pcem/sound_sb.h +++ b/pcem/sound_sb.h @@ -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 */ diff --git a/pcem/sound_sb_dsp.cpp b/pcem/sound_sb_dsp.cpp index edcad06f..ce88db91 100644 --- a/pcem/sound_sb_dsp.cpp +++ b/pcem/sound_sb_dsp.cpp @@ -10,13 +10,16 @@ #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); } diff --git a/pcem/sound_sb_dsp.h b/pcem/sound_sb_dsp.h index cf21e82f..f728400c 100644 --- a/pcem/sound_sb_dsp.h +++ b/pcem/sound_sb_dsp.h @@ -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 index 00000000..c8bcd0b4 --- /dev/null +++ b/pcem/thread.h @@ -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); diff --git a/pcem/timer.cpp b/pcem/timer.cpp index a8f65dda..565e51da 100644 --- a/pcem/timer.cpp +++ b/pcem/timer.cpp @@ -1,117 +1,134 @@ #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); } diff --git a/pcem/timer.h b/pcem/timer.h index 50c83e55..ddcd9c00 100644 --- a/pcem/timer.h +++ b/pcem/timer.h @@ -3,56 +3,140 @@ #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 index 00000000..76c54fe3 --- /dev/null +++ b/pcem/vid_cl5429.cpp @@ -0,0 +1,2384 @@ +/*Cirrus Logic CL-GD5429 emulation*/ +#include +#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 index 00000000..70b03215 --- /dev/null +++ b/pcem/vid_cl5429.h @@ -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 index 00000000..338b39a9 --- /dev/null +++ b/pcem/vid_s3.cpp @@ -0,0 +1,3069 @@ +/*S3 emulation*/ +#include +#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 index 00000000..ee040396 --- /dev/null +++ b/pcem/vid_s3.h @@ -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 index 00000000..33e85fd7 --- /dev/null +++ b/pcem/vid_s3_virge.cpp @@ -0,0 +1,4150 @@ +/*S3 ViRGE emulation*/ +#include +#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 index 00000000..dce1a249 --- /dev/null +++ b/pcem/vid_s3_virge.h @@ -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 index 00000000..08288ac0 --- /dev/null +++ b/pcem/vid_sdac_ramdac.cpp @@ -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 index 00000000..48126f7b --- /dev/null +++ b/pcem/vid_sdac_ramdac.h @@ -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 index 00000000..314c4d71 --- /dev/null +++ b/pcem/vid_svga.cpp @@ -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 +#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 index 00000000..219eb6b3 --- /dev/null +++ b/pcem/vid_svga.h @@ -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 index 00000000..505f362a --- /dev/null +++ b/pcem/vid_svga_render.cpp @@ -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 index 00000000..be8105f7 --- /dev/null +++ b/pcem/vid_svga_render.h @@ -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 index 00000000..0f92848f --- /dev/null +++ b/pcem/vid_unk_ramdac.h @@ -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 index 00000000..329195b8 --- /dev/null +++ b/pcem/vid_vga.h @@ -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; diff --git a/pcem/video.h b/pcem/video.h index 939b19d6..3fc28622 100644 --- a/pcem/video.h +++ b/pcem/video.h @@ -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(); diff --git a/pcem/x86.h b/pcem/x86.h index a55adc1f..7bcd75b9 100644 --- a/pcem/x86.h +++ b/pcem/x86.h @@ -1,23 +1,226 @@ -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 diff --git a/pcem/x86_flags.h b/pcem/x86_flags.h index 87e52420..9a998392 100644 --- a/pcem/x86_flags.h +++ b/pcem/x86_flags.h @@ -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 ((ca) || (c==a && tempc)) flags|=C_FLAG; - if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; - if (((a&0xF)-((b&0xF)+tempc))&0x10) flags|=A_FLAG; + 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(); diff --git a/pcem/x86_ops.h b/pcem/x86_ops.h index e79734fc..ad4f0706 100644 --- a/pcem/x86_ops.h +++ b/pcem/x86_ops.h @@ -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 index 00000000..2930a68a --- /dev/null +++ b/pcem/x86_ops_3dnow.h @@ -0,0 +1,346 @@ +#include + +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); +} diff --git a/pcem/x86_ops_arith.h b/pcem/x86_ops_arith.h index 3a9f9695..2be0e4ef 100644 --- a/pcem/x86_ops_arith.h +++ b/pcem/x86_ops_arith.h @@ -14,9 +14,11 @@ } \ 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; \ @@ -112,7 +120,9 @@ } \ 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; \ @@ -136,7 +146,9 @@ } \ 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; \ @@ -151,6 +163,8 @@ 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; \ @@ -164,6 +178,8 @@ 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; \ @@ -178,6 +194,8 @@ 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; \ @@ -191,6 +209,8 @@ 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; \ @@ -205,6 +225,8 @@ 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; \ @@ -218,6 +240,8 @@ 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); diff --git a/pcem/x86_ops_atomic.h b/pcem/x86_ops_atomic.h index 7d90e22d..4011a0aa 100644 --- a/pcem/x86_ops_atomic.h +++ b/pcem/x86_ops_atomic.h @@ -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); diff --git a/pcem/x86_ops_bcd.h b/pcem/x86_ops_bcd.h index 241216b1..cd29b140 100644 --- a/pcem/x86_ops_bcd.h +++ b/pcem/x86_ops_bcd.h @@ -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); diff --git a/pcem/x86_ops_bit.h b/pcem/x86_ops_bit.h index dc10b4f6..a32c406b 100644 --- a/pcem/x86_ops_bit.h +++ b/pcem/x86_ops_bit.h @@ -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; diff --git a/pcem/x86_ops_bitscan.h b/pcem/x86_ops_bitscan.h index 12a8a79a..74f26dd3 100644 --- a/pcem/x86_ops_bitscan.h +++ b/pcem/x86_ops_bitscan.h @@ -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); diff --git a/pcem/x86_ops_call.h b/pcem/x86_ops_call.h index d1f61021..0b7f5f0f 100644 --- a/pcem/x86_ops_call.h +++ b/pcem/x86_ops_call.h @@ -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); \ @@ -17,24 +16,23 @@ 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); \ @@ -46,14 +44,14 @@ 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); diff --git a/pcem/x86_ops_flag.h b/pcem/x86_ops_flag.h index 91fce511..d21408c8 100644 --- a/pcem/x86_ops_flag.h +++ b/pcem/x86_ops_flag.h @@ -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(); diff --git a/pcem/x86_ops_inc_dec.h b/pcem/x86_ops_inc_dec.h index 56293c7b..d14bae86 100644 --- a/pcem/x86_ops_inc_dec.h +++ b/pcem/x86_ops_inc_dec.h @@ -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) diff --git a/pcem/x86_ops_int.h b/pcem/x86_ops_int.h index ff8830ee..97793405 100644 --- a/pcem/x86_ops_int.h +++ b/pcem/x86_ops_int.h @@ -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; diff --git a/pcem/x86_ops_jump.h b/pcem/x86_ops_jump.h index 93987633..4b4a1c3b 100644 --- a/pcem/x86_ops_jump.h +++ b/pcem/x86_ops_jump.h @@ -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); diff --git a/pcem/x86_ops_misc.h b/pcem/x86_ops_misc.h index 1e0410ac..9e281f2e 100644 --- a/pcem/x86_ops_misc.h +++ b/pcem/x86_ops_misc.h @@ -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); diff --git a/pcem/x86_ops_mmx.h b/pcem/x86_ops_mmx.h index 1af186d0..f9a7f935 100644 --- a/pcem/x86_ops_mmx.h +++ b/pcem/x86_ops_mmx.h @@ -11,12 +11,13 @@ } \ 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(); \ @@ -31,13 +32,13 @@ 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; diff --git a/pcem/x86_ops_mmx_arith.h b/pcem/x86_ops_mmx_arith.h index 302a44ea..22c34c73 100644 --- a/pcem/x86_ops_mmx_arith.h +++ b/pcem/x86_ops_mmx_arith.h @@ -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; diff --git a/pcem/x86_ops_mmx_cmp.h b/pcem/x86_ops_mmx_cmp.h index eb401b83..0fee9592 100644 --- a/pcem/x86_ops_mmx_cmp.h +++ b/pcem/x86_ops_mmx_cmp.h @@ -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; diff --git a/pcem/x86_ops_mmx_mov.h b/pcem/x86_ops_mmx_mov.h index d96df747..f598d5b2 100644 --- a/pcem/x86_ops_mmx_mov.h +++ b/pcem/x86_ops_mmx_mov.h @@ -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); diff --git a/pcem/x86_ops_mmx_pack.h b/pcem/x86_ops_mmx_pack.h index 50b813cb..b03ef842 100644 --- a/pcem/x86_ops_mmx_pack.h +++ b/pcem/x86_ops_mmx_pack.h @@ -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; diff --git a/pcem/x86_ops_mmx_shift.h b/pcem/x86_ops_mmx_shift.h index 42934759..7b8c377f 100644 --- a/pcem/x86_ops_mmx_shift.h +++ b/pcem/x86_ops_mmx_shift.h @@ -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); \ } diff --git a/pcem/x86_ops_mov.h b/pcem/x86_ops_mov.h index 718db28a..5cb28c1e 100644 --- a/pcem/x86_ops_mov.h +++ b/pcem/x86_ops_mov.h @@ -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; \ } \ diff --git a/pcem/x86_ops_mov_ctrl.h b/pcem/x86_ops_mov_ctrl.h index 3a522a65..923bb571 100644 --- a/pcem/x86_ops_mov_ctrl.h +++ b/pcem/x86_ops_mov_ctrl.h @@ -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); diff --git a/pcem/x86_ops_mov_seg.h b/pcem/x86_ops_mov_seg.h index 1e2f654b..da772714 100644 --- a/pcem/x86_ops_mov_seg.h +++ b/pcem/x86_ops_mov_seg.h @@ -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) diff --git a/pcem/x86_ops_movx.h b/pcem/x86_ops_movx.h index 2175a63c..2e4fa200 100644 --- a/pcem/x86_ops_movx.h +++ b/pcem/x86_ops_movx.h @@ -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) diff --git a/pcem/x86_ops_msr.h b/pcem/x86_ops_msr.h index a7331674..2a8bdcf4 100644 --- a/pcem/x86_ops_msr.h +++ b/pcem/x86_ops_msr.h @@ -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(); diff --git a/pcem/x86_ops_mul.h b/pcem/x86_ops_mul.h index 98cf254c..f3e10e5a 100644 --- a/pcem/x86_ops_mul.h +++ b/pcem/x86_ops_mul.h @@ -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); diff --git a/pcem/x86_ops_pmode.h b/pcem/x86_ops_pmode.h index 0b5a3e8a..7afd6c8b 100644 --- a/pcem/x86_ops_pmode.h +++ b/pcem/x86_ops_pmode.h @@ -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); diff --git a/pcem/x86_ops_prefix.h b/pcem/x86_ops_prefix.h index 8265c19f..8d191103 100644 --- a/pcem/x86_ops_prefix.h +++ b/pcem/x86_ops_prefix.h @@ -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*/ { diff --git a/pcem/x86_ops_rep.h b/pcem/x86_ops_rep.h index 06569570..e696f513 100644 --- a/pcem/x86_ops_rep.h +++ b/pcem/x86_ops_rep.h @@ -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; \ diff --git a/pcem/x86_ops_ret.h b/pcem/x86_ops_ret.h index 71d1bb7c..271da6e5 100644 --- a/pcem/x86_ops_ret.h +++ b/pcem/x86_ops_ret.h @@ -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); \ @@ -21,12 +20,11 @@ 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); diff --git a/pcem/x86_ops_set.h b/pcem/x86_ops_set.h index 0094b85d..f6fd50e6 100644 --- a/pcem/x86_ops_set.h +++ b/pcem/x86_ops_set.h @@ -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; \ diff --git a/pcem/x86_ops_shift.h b/pcem/x86_ops_shift.h index 495a1bf4..16e9c615 100644 --- a/pcem/x86_ops_shift.h +++ b/pcem/x86_ops_shift.h @@ -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) \ { \ @@ -45,14 +30,14 @@ 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; \ @@ -98,36 +83,21 @@ 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) \ { \ @@ -137,14 +107,14 @@ 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) \ { \ @@ -154,9 +124,9 @@ 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; \ @@ -190,33 +160,18 @@ 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(); \ @@ -229,14 +184,14 @@ 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) \ { \ @@ -246,9 +201,9 @@ 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(); \ \ diff --git a/pcem/x86_ops_stack.h b/pcem/x86_ops_stack.h index 86daf52a..fb55e364 100644 --- a/pcem/x86_ops_stack.h +++ b/pcem/x86_ops_stack.h @@ -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; diff --git a/pcem/x86_ops_string.h b/pcem/x86_ops_string.h index 8c8ba681..c0272513 100644 --- a/pcem/x86_ops_string.h +++ b/pcem/x86_ops_string.h @@ -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); diff --git a/pcem/x86_ops_xchg.h b/pcem/x86_ops_xchg.h index 77191ae4..6a787273 100644 --- a/pcem/x86_ops_xchg.h +++ b/pcem/x86_ops_xchg.h @@ -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; diff --git a/pcem/x86seg.cpp b/pcem/x86seg.cpp index c1924c34..9999fde6 100644 --- a/pcem/x86seg.cpp +++ b/pcem/x86seg.cpp @@ -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=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) && DPL20x800) { - 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>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); diff --git a/pcem/x87.cpp b/pcem/x87.cpp index 547e5609..7581fc30 100644 --- a/pcem/x87.cpp +++ b/pcem/x87.cpp @@ -19,6 +19,11 @@ #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()); diff --git a/pcem/x87.h b/pcem/x87.h index b85e8c59..2d61c14a 100644 --- a/pcem/x87.h +++ b/pcem/x87.h @@ -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); diff --git a/pcem/x87_ops.h b/pcem/x87_ops.h index 0202afac..73a231e9 100644 --- a/pcem/x87_ops.h +++ b/pcem/x87_ops.h @@ -1,5 +1,6 @@ #include #include +#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, diff --git a/pcem/x87_ops_arith.h b/pcem/x87_ops_arith.h index 48a141e2..c00f9780 100644 --- a/pcem/x87_ops_arith.h +++ b/pcem/x87_ops_arith.h @@ -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; } diff --git a/pcem/x87_ops_loadstore.h b/pcem/x87_ops_loadstore.h index ed083b92..6b8c050c 100644 --- a/pcem/x87_ops_loadstore.h +++ b/pcem/x87_ops_loadstore.h @@ -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; } diff --git a/pcem/x87_ops_misc.h b/pcem/x87_ops_misc.h index bd00f9eb..61a9919a 100644 --- a/pcem/x87_ops_misc.h +++ b/pcem/x87_ops_misc.h @@ -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 index 00000000..cc60e1b6 --- /dev/null +++ b/pcem/x87_timings.cpp @@ -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 index 00000000..0e7363da --- /dev/null +++ b/pcem/x87_timings.h @@ -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; -- 2.47.3