diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 0b5b113..49e3972 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -87,7 +87,7 @@ int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, int inrecomp = 0; int cpu_block_end = 0; -int nmi_enable = 1; +//int nmi_enable = 1; 808x.c int cpl_override=0; int fpucount=0; diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 72752f3..a02d144 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -8,23 +8,16 @@ * * 808x CPU emulation. * - * SHR AX,1 + * Version: @(#)808x.c 1.0.8 2019/02/08 * - * 4 clocks - fetch opcode - * 4 clocks - fetch mod/rm - * 2 clocks - execute 2 clocks - fetch opcode 1 - * 2 clocks - fetch opcode 2 - * 4 clocks - fetch mod/rm - * 2 clocks - fetch opcode 1 2 clocks - execute - * 2 clocks - fetch opcode 2 etc - * - * Version: @(#)808x.c 1.0.6 2018/10/05 - * - * Authors: Sarah Walker, - * Miran Grca, + * Authors: Miran Grca, + * Andrew Jenner, + * Sarah Walker, * + * Copyright 2016-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2015-2018 Andrew Jenner. * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,6 +40,7 @@ #include #include #include +#include #include #include "../emu.h" #include "cpu.h" @@ -61,424 +55,480 @@ #include "../plat.h" -int xt_cpu_multi; -int nmi = 0; -int nmi_auto_clear = 0; -int nextcyc = 0; -int cycdiff; -int is8086 = 0; -int nopageerrors = 0; -uint16_t oldcs; -int oldcpl; -int tempc; -uint8_t opcode; -uint16_t pc2, - pc3; -int noint = 0; -int output = 0; -int ins = 0; -int fetchcycles = 0, - memcycs, - fetchclocks; -uint8_t prefetchqueue[6]; -uint16_t prefetchpc; -int prefetchw = 0; +/* Misc */ +int use32, stack32; +int oldcpl; -int use32; -int stack32; +/* The previous value of the CS segment register. */ +uint16_t oldcs; + +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The tables to speed up the setting of the Z, N, and P flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +int rmdat; + +/* XT CPU multiplier. */ +int xt_cpu_multi; + +/* Is the CPU 8088 or 8086. */ +int is8086 = 0; + +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; +int nmi_enable = 1; + +/* Was the CPU ever reset? */ +int x86_was_reset = 0; + +/* Variables used elsewhere in the emulator. */ +int tempc; + +/* Amount of instructions executed - used to calculate the % shown in the title bar. */ +int ins = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; + + +/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ +static uint8_t pfq[6]; + +/* Variables to aid with the prefetch queue operation. */ +static int fetchcycles = 0; +static int fetchclocks, pfq_pos = 0; + +/* The IP equivalent of the current prefetch queue position. */ +static uint16_t pfq_ip; + +/* Where is this even used?! */ +static int nextcyc = 0; + +/* Pointer tables needed for segment overrides. */ +static uint32_t *opseg[4]; +static x86seg *_opseg[4]; + +static int takeint = 0, noint = 0; +static int in_lock = 0, halt = 0; +static int cpu_alu_op, pfq_size; + +static uint16_t cpu_src = 0, cpu_dest = 0; +static uint16_t cpu_data = 0; + +static uint32_t *ovr_seg = NULL; + + +int indump = 0; + + +void +dumpregs(int force) +{ + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + int c; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + INFO("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, flags); + INFO("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); + for (c = 0; c < 4; c++) { + INFO("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); + } + if (is386) { + INFO("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); + INFO("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); + INFO("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); + INFO("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); + INFO("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); + INFO("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + INFO("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + INFO("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + INFO("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 { + INFO("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + INFO("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); + } + +#if 0 + INFO("Entries in readlookup : %i writelookup : %i\n", + readlnum, writelnum); +#endif + + x87_dumpregs(); + + indump = 0; +} + + +static void pfq_add(int c); +static void set_pzs(int bits); + + +static int +irq_pending(void) +{ + if ((nmi && nmi_enable && nmi_mask) || ((flags & I_FLAG) && (pic.pend & ~pic.mask) && !noint)) + return 1; + + return 0; +} + + +static void +wait(int c, int bus) +{ + cycles -= c; + if (!bus) + pfq_add(c); +} #undef readmemb -uint8_t +#undef readmemw + +/* Reads a byte from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static uint8_t readmemb(uint32_t a) { - if (a != (cs + cpu_state.pc)) memcycs += 4; + uint8_t ret; + + wait(4, 1); if (readlookup2 == NULL) - return(readmembl(a)); + ret = readmembl(a); + else { + if (readlookup2[(a) >> 12] == -1) + ret = readmembl(a); + else + ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + } - if (readlookup2[(a) >> 12] == -1) - return(readmembl(a)); - else - return(*(uint8_t *)(readlookup2[(a) >> 12] + (a))); + return ret; } -uint8_t +/* Reads a byte from the memory but does not accounts for memory transfer + cycles to subtract from the cycles to use for adding to the prefetch + queue. */ +static uint8_t readmembf(uint32_t a) { - if (readlookup2 == NULL) - return readmembl(a); + uint8_t ret; - if (readlookup2[(a)>>12]==-1) - return readmembl(a); - else - return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + a = cs + (a & 0xffff); + + if (readlookup2 == NULL) + ret = readmembl(a); + else { + if (readlookup2[(a) >> 12] == -1) + ret = readmembl(a); + else + ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + } + + return ret; } -#undef readmemw -uint16_t +/* Reads a word from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static uint16_t readmemw(uint32_t s, uint16_t a) { - if (a != (cs+cpu_state.pc)) - memcycs += (8 >> is8086); + uint16_t ret; - if (readlookup2 == NULL) - return readmemwl(s, a); + if (!is8086 || (a & 1)) { + ret = readmemb(s + a); + ret |= readmemb(s + ((a + 1) & 0xffff)) << 8; + } else { + wait(4, 1); - if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) - return readmemwl(s,a); - else - return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); + if (readlookup2 == NULL) + ret = readmemwl(s, a); + else { + if ((readlookup2[((s) + (a)) >> 12] == -1 || (s) == 0xFFFFFFFF)) + ret = readmemwl(s, a); + else + ret = *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); + } + } + + return ret; } -void +/* Writes a byte from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static void writememb(uint32_t a, uint8_t v) { - memcycs += 4; + wait(4, 1); if (writelookup2 == NULL) writemembl(a, v); - - if (writelookup2[(a)>>12]==-1) - writemembl(a,v); - else - *(uint8_t *)(writelookup2[a >> 12] + a) = v; + else { + if (writelookup2[(a) >> 12] == -1) + writemembl(a, v); + else + *(uint8_t *)(writelookup2[a >> 12] + a) = v; + } } -void +/* Writes a word from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +static void writememw(uint32_t s, uint32_t a, uint16_t v) { - memcycs += (8 >> is8086); + if (!is8086 || (a & 1)) { + writememb(s + a, v & 0xff); + writememb(s + ((a + 1) & 0xffff), v >> 8); + } else { + wait(4, 1); - if (writelookup2 == NULL) - writememwl(s, a, v); - - if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) - writememwl(s,a,v); - else - *(uint16_t *)(writelookup2[(s + a) >> 12] + s + a) = v; + if (writelookup2 == NULL) + writememwl(s, a, v); + else { + if ((writelookup2[((s) + (a)) >> 12]== -1) || ((s) == 0xFFFFFFFF)) + writememwl(s, a, v); + else + *(uint16_t *) (writelookup2[(s + a) >> 12] + s + a) = v; + } + } } -void -writememl(uint32_t s, uint32_t a, uint32_t v) +/* Fetches a byte from the prefetch queue, or from memory if the queue has + been drained. */ +static uint8_t +pfq_fetchb(void) { - if (writelookup2 == NULL) - writememll(s, a, v); + uint8_t temp, i; - if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) - writememll(s, a, v); - else - *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; -} - - -static INLINE uint8_t -FETCH(void) -{ - uint8_t temp; - - if (prefetchw==0) - { - cycles-=(4-(fetchcycles&3)); - fetchclocks+=(4-(fetchcycles&3)); - fetchcycles=4; - temp=readmembf(cs+cpu_state.pc); - prefetchpc = cpu_state.pc = cpu_state.pc + 1; - if (is8086 && (cpu_state.pc&1)) - { - prefetchqueue[0]=readmembf(cs+cpu_state.pc); - prefetchpc++; - prefetchw++; - } - } - else - { - temp=prefetchqueue[0]; - prefetchqueue[0]=prefetchqueue[1]; - prefetchqueue[1]=prefetchqueue[2]; - prefetchqueue[2]=prefetchqueue[3]; - if (is8086) { - prefetchqueue[3]=prefetchqueue[4]; - prefetchqueue[4]=prefetchqueue[5]; - } - prefetchw--; - fetchcycles-=4; - cpu_state.pc++; - } - return temp; -} - - -static INLINE void -FETCHADD(int c) -{ - int d; - if (c<0) return; - if (prefetchw>((is8086)?5:3)) return; - d=c+(fetchcycles&3); - while (d>3 && prefetchw<((is8086)?6:4)) - { - d-=4; - if (is8086 && !(prefetchpc&1)) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - if (prefetchw<(is8086)?6:4) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - } - fetchcycles+=c; - if (fetchcycles>16) fetchcycles=16; -} - - -static INLINE void -FETCHCLEAR(void) -{ - prefetchpc=cpu_state.pc; - prefetchw=0; - memcycs=cycdiff-cycles; - fetchclocks=0; -} - - -void -FETCHCOMPLETE(void) -{ - if (!(fetchcycles&3)) return; - if (prefetchw>((is8086)?5:3)) return; - if (!prefetchw) nextcyc=(4-(fetchcycles&3)); - cycles-=(4-(fetchcycles&3)); - fetchclocks+=(4-(fetchcycles&3)); - if (is8086 && !(prefetchpc&1)) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - if (prefetchw<(is8086)?6:4) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - fetchcycles+=(4-(fetchcycles&3)); -} - - -void -refreshread(void) -{ - FETCHCOMPLETE(); - - memcycs += 4; + if (pfq_pos == 0) { + cycles -= (4 - (fetchcycles & 3)); + fetchclocks += (4 - (fetchcycles & 3)); + fetchcycles = 4; + temp = readmembf(cpu_state.pc); + pfq_ip = cpu_state.pc = cpu_state.pc + 1; + if (is8086 && (cpu_state.pc & 1)) { + pfq[0] = readmembf(cpu_state.pc); + pfq_ip++; + pfq_pos++; + } + } else { + temp = pfq[0]; + for (i = 0; i < (pfq_size - 1); i++) + pfq[i] = pfq[i + 1]; + pfq_pos--; + fetchcycles -= 4; + cpu_state.pc++; + } + wait(1, 0); + return temp; } +/* Fetches a word from the prefetch queue, or from memory if the queue has + been drained. */ static uint16_t -getword(void) +pfq_fetchw(void) { - uint8_t temp=FETCH(); - return temp|(FETCH()<<8); + uint8_t temp = pfq_fetchb(); + return temp | (pfq_fetchb() << 8); } -#undef fetchea -#define fetchea() { rmdat=FETCH(); \ - cpu_reg=(rmdat>>3)&7; \ - cpu_mod=(rmdat>>6)&3; \ - cpu_rm=rmdat&7; \ - if (cpu_mod!=3) fetcheal(); } - - -/*EA calculation*/ - -/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod - From 386 programmers manual : -r8(/r) AL CL DL BL AH CH DH BH -r16(/r) AX CX DX BX SP BP SI DI -r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI -/digit (Opcode) 0 1 2 3 4 5 6 7 -REG = 000 001 010 011 100 101 110 111 -Address -disp8 denotes an 8-bit displacement following the ModR/M byte, to be -sign-extended and added to the index. disp16 denotes a 16-bit displacement -following the ModR/M byte, to be added to the index. Default segment -register is SS for the effective addresses containing a BP index, DS for -other effective addresses. -Mod R/M Values in Hexadecimal - -[BX + SI] 000 00 08 10 18 20 28 30 38 -[BX + DI] 001 01 09 11 19 21 29 31 39 -[BP + SI] 010 02 0A 12 1A 22 2A 32 3A -[BP + DI] 011 03 0B 13 1B 23 2B 33 3B -[SI] 00 100 04 0C 14 1C 24 2C 34 3C -[DI] 101 05 0D 15 1D 25 2D 35 3D -disp16 110 06 0E 16 1E 26 2E 36 3E -[BX] 111 07 0F 17 1F 27 2F 37 3F - -[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 -[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 -[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A -[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B -[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C -[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D -[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E -[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F - -[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 -[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 -[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA -[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB -[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC -[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD -[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE -[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF - -EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 -ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 -EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA -EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB -ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC -EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD -ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE -EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF - -mod = 11 - register - 10 - address + 16 bit displacement - 01 - address + 8 bit displacement - 00 - address - -reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) - 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL - 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH - - Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB - selects whether BX/BP are used at all (0=used). - - mod=00 is an exception though - 6=16 bit displacement only - 7=[BX] - - Usage varies with instructions. - - MOV AL,BL has ModR/M as C3, for example. - mod=11, reg=0, r/m=3 - MOV uses reg as dest, and r/m as src. - reg 0 is AL, reg 3 is BL - - If BP or SP are in address calc, seg is SS, else DS -*/ - -uint32_t easeg; -int rmdat; - -uint16_t zero=0; -uint16_t *mod1add[2][8]; -uint32_t *mod1seg[8]; - -int slowrm[8]; - -void makemod1table(void) +/* Adds bytes to the prefetch queue based on the instruction's cycle count. */ +static void +pfq_add(int c) { - mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; - mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; - mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; - mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; - slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; - mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; - mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; + int d; + if (c < 0) + return; + if (pfq_pos >= pfq_size) + return; + d = c + (fetchcycles & 3); + while ((d > 3) && (pfq_pos < pfq_size)) { + d -= 4; + if (is8086 && !(pfq_ip & 1)) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + if (pfq_pos < pfq_size) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + } + fetchcycles += c; + if (fetchcycles > 16) + fetchcycles = 16; } -static void fetcheal(void) -{ - if (!cpu_mod && cpu_rm==6) { cpu_state.eaaddr=getword(); easeg=ds; FETCHADD(6); } - else - { - switch (cpu_mod) - { - case 0: - cpu_state.eaaddr=0; - if (cpu_rm&4) FETCHADD(5); - else FETCHADD(7+slowrm[cpu_rm]); - break; - case 1: - cpu_state.eaaddr=(uint16_t)(int8_t)FETCH(); - if (cpu_rm&4) FETCHADD(9); - else FETCHADD(11+slowrm[cpu_rm]); - break; - case 2: - cpu_state.eaaddr=getword(); - if (cpu_rm&4) FETCHADD(9); - else FETCHADD(11+slowrm[cpu_rm]); - break; - } - cpu_state.eaaddr+=(*mod1add[0][cpu_rm])+(*mod1add[1][cpu_rm]); - easeg=*mod1seg[cpu_rm]; - cpu_state.eaaddr&=0xFFFF; - } - cpu_state.last_ea = cpu_state.eaaddr; +/* Completes a fetch (called by refreshread()). */ +static void +pfq_complete(void) +{ + if (!(fetchcycles & 3)) + return; + if (pfq_pos >= pfq_size) + return; + if (!pfq_pos) + nextcyc = (4 - (fetchcycles & 3)); + cycles -= (4 - (fetchcycles & 3)); + fetchclocks += (4 - (fetchcycles & 3)); + if (is8086 && !(pfq_ip & 1)) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + if (pfq_pos < pfq_size) { + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } + fetchcycles += (4 - (fetchcycles & 3)); } -static INLINE uint8_t geteab(void) + +/* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ +static void +pfq_clear() { - if (cpu_mod == 3) - return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; - return readmemb(easeg+cpu_state.eaaddr); + pfq_ip = cpu_state.pc; + pfq_pos = 0; + fetchclocks = 0; } -static INLINE uint16_t geteaw(void) -{ - if (cpu_mod == 3) - return cpu_state.regs[cpu_rm].w; - return readmemw(easeg,cpu_state.eaaddr); + +/* Memory refresh read - called by reads and writes on DMA channel 0. */ +void +refreshread(void) { + pfq_complete(); } -#if 0 -static INLINE uint16_t geteaw2(void) -{ - if (cpu_mod == 3) - return cpu_state.regs[cpu_rm].w; - return readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); -} -#endif -static INLINE void seteab(uint8_t val) +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) { - if (cpu_mod == 3) - { - if (cpu_rm & 4) - cpu_state.regs[cpu_rm & 3].b.h = val; - else - cpu_state.regs[cpu_rm & 3].b.l = val; - } - else - { - writememb(easeg+cpu_state.eaaddr,val); - } + mod1add[0][0] = &BX; + mod1add[0][1] = &BX; + mod1add[0][2] = &BP; + mod1add[0][3] = &BP; + mod1add[0][4] = &SI; + mod1add[0][5] = &DI; + mod1add[0][6] = &BP; + mod1add[0][7] = &BX; + mod1add[1][0] = &SI; + mod1add[1][1] = &DI; + mod1add[1][2] = &SI; + mod1add[1][3] = &DI; + mod1add[1][4] = &zero; + mod1add[1][5] = &zero; + mod1add[1][6] = &zero; + mod1add[1][7] = &zero; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; + opseg[0] = &es; + opseg[1] = &cs; + opseg[2] = &ss; + opseg[3] = &ds; + _opseg[0] = &_es; + _opseg[1] = &_cs; + _opseg[2] = &_ss; + _opseg[3] = &_ds; } -static INLINE void seteaw(uint16_t val) + +/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ +static void +do_mod_rm(void) { - if (cpu_mod == 3) - cpu_state.regs[cpu_rm].w = val; - else - { - writememw(easeg,cpu_state.eaaddr,val); - } + rmdat = pfq_fetchb(); + cpu_reg = (rmdat >> 3) & 7; + cpu_mod = (rmdat >> 6) & 3; + cpu_rm = rmdat & 7; + + if (cpu_mod == 3) + return; + + wait(3, 0); + + if (!cpu_mod && (cpu_rm == 6)) { + wait(2, 0); + cpu_state.eaaddr = pfq_fetchw(); + easeg = ds; + wait(1, 0); + } else { + switch (cpu_rm) { + case 0: + case 3: + wait(2, 0); + break; + case 1: + case 2: + wait(3, 0); + break; + } + + cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = *mod1seg[cpu_rm]; + + switch (cpu_mod) { + case 1: + wait(4, 0); + cpu_state.eaaddr += (uint16_t) (int8_t) pfq_fetchb(); + break; + case 2: + wait(4, 0); + cpu_state.eaaddr += pfq_fetchw(); + break; + } + wait(2, 0); + } + + cpu_state.eaaddr &= 0xffff; + cpu_state.last_ea = cpu_state.eaaddr; + + if (ovr_seg) + easeg = *ovr_seg; } + #undef getr8 #define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) @@ -487,3347 +537,2181 @@ static INLINE void seteaw(uint16_t val) else cpu_state.regs[r & 3].b.l = v; -/*Flags*/ -uint8_t znptable8[256]; -uint16_t znptable16[65536]; - -void makeznptable(void) +/* Reads a byte from the effective address. */ +static uint8_t +geteab(void) { - int c,d; - for (c=0;c<256;c++) - { - d=0; - if (c&1) d++; - if (c&2) d++; - if (c&4) d++; - if (c&8) d++; - if (c&16) d++; - if (c&32) d++; - if (c&64) d++; - if (c&128) d++; - if (d&1) - { - znptable8[c]=0; - } - else - { - znptable8[c]=P_FLAG; - } - if (c == 0xb1) DEBUG("znp8 b1 = %i %02X\n", d, znptable8[c]); - if (!c) znptable8[c]|=Z_FLAG; - if (c&0x80) znptable8[c]|=N_FLAG; - } - for (c=0;c<65536;c++) - { - d=0; - if (c&1) d++; - if (c&2) d++; - if (c&4) d++; - if (c&8) d++; - if (c&16) d++; - if (c&32) d++; - if (c&64) d++; - if (c&128) d++; - if (d&1) - znptable16[c]=0; - else - znptable16[c]=P_FLAG; - if (c == 0xb1) DEBUG("znp16 b1 = %i %02X\n", d, znptable16[c]); - if (c == 0x65b1) DEBUG("znp16 65b1 = %i %02X\n", d, znptable16[c]); - if (!c) znptable16[c]|=Z_FLAG; - if (c&0x8000) znptable16[c]|=N_FLAG; - } + if (cpu_mod == 3) { + return (getr8(cpu_rm)); + } + + return readmemb(easeg + cpu_state.eaaddr); } -extern uint32_t oldcs2; -extern uint32_t oldpc2; -int indump = 0; - -void dumpregs(int force) +/* Reads a word from the effective address. */ +static uint16_t +geteaw(void) { - int c,d=0,e=0; -#ifndef RELEASE_BUILD - FILE *f; -#endif - - /* Only dump when needed, and only once.. */ - if (!ram || indump || (!force && !dump_on_exit)) return; - -#ifndef RELEASE_BUILD - indump = 1; - output=0; - (void)plat_chdir(usr_path); - nopageerrors=1; - f=fopen("ram.dmp","wb"); - if (f != NULL) { - fwrite(ram,mem_size*1024,1,f); - fclose(f); - } - ERRLOG("Dumping rram.dmp\n"); - f=fopen("rram.dmp","wb"); - if (f != NULL) { - for (c=0;c<0x1000000;c++) putc(readmemb(c),f); - fclose(f); - } - ERRLOG("Dumping rram4.dmp\n"); - f=fopen("rram4.dmp","wb"); - if (f != NULL) { - for (c=0;c<0x0050000;c++) { - cpu_state.abrt = 0; - putc(readmemb386l(0,c+0x80000000),f); - } - fclose(f); - } - ERRLOG("Dumping done\n"); -#endif - if (is386) - ERRLOG("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 - ERRLOG("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); - ERRLOG("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags); - ERRLOG("%04X:%04X %04X:%04X\n",oldcs,cpu_state.oldpc, oldcs2, oldpc2); - ERRLOG("%i ins\n",ins); - if (is386) - ERRLOG("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); - else - ERRLOG("In %s mode\n",(msw&1)?"protected":"real"); - ERRLOG("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); - ERRLOG("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); - ERRLOG("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,_es.limit,_es.access, _es.limit_low, _es.limit_high); - if (is386) - { - ERRLOG("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); - ERRLOG("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); - } - ERRLOG("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); - ERRLOG("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); - ERRLOG("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); - ERRLOG("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); - ERRLOG("TR : base=%06X limit=%04X\n", tr.base, tr.limit); - if (is386) - { - ERRLOG("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); - ERRLOG("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); - } - for (c=0;c<1024*1024;c++) - { - if (readlookup2[c]!=0xFFFFFFFF) d++; - if (writelookup2[c]!=0xFFFFFFFF) e++; - } - ERRLOG("Entries in readlookup : %i writelookup : %i\n",d,e); - x87_dumpregs(); - indump = 0; + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg, cpu_state.eaaddr); } -int resets = 0; -int x86_was_reset = 0; -void resetx86(void) + +static void +read_ea(int memory_only, int bits) { - INFO("CPU: x86 reset\n"); - resets++; - ins = 0; - use32=0; - cpu_cur_status = 0; - stack32=0; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - msw=0; - if (is486) - cr0 = 1 << 30; - else - cr0 = 0; - cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; - cpu_update_waitstates(); - cr4 = 0; - eflags=0; - cgate32=0; - if(AT) - { - loadcs(0xF000); - cpu_state.pc=0xFFF0; - rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; - } - else - { - loadcs(0xFFFF); - cpu_state.pc=0; - rammask = 0xfffff; - } - idt.base = 0; - idt.limit = is386 ? 0x03FF : 0xFFFF; - flags=2; - makeznptable(); - resetreadlookup(); - makemod1table(); - resetmcr(); - FETCHCLEAR(); - x87_reset(); - cpu_set_edx(); + if (cpu_mod != 3) { + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); + return; + } + if (!memory_only) { + if (bits == 8) { + cpu_data = getr8(cpu_rm); + } else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +static void +read_ea2(int bits) +{ + if (bits == 16) + cpu_data = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xffff); + else + cpu_data = readmemb(easeg + ((cpu_state.eaaddr + 2) & 0xffff)); +} + + +/* Writes a byte to the effective address. */ +static void +seteab(uint8_t val) +{ + if (cpu_mod == 3) { + setr8(cpu_rm, val); + } else + writememb(easeg + cpu_state.eaaddr, val); +} + + +/* Writes a word to the effective address. */ +static void +seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + writememw(easeg, cpu_state.eaaddr, val); +} + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P flags. */ +static void +makeznptable(void) +{ + int c, d; + for (c = 0; c < 256; c++) { + d = 0; + if (c & 1) + d++; + if (c & 2) + d++; + if (c & 4) + d++; + if (c & 8) + d++; + if (c & 16) + d++; + if (c & 32) + d++; + if (c & 64) + d++; + if (c & 128) + d++; + if (d & 1) + znptable8[c] = 0; + else + znptable8[c] = P_FLAG; + if (c == 0xb1) + DEBUG("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) + znptable8[c] |= Z_FLAG; + if (c & 0x80) + znptable8[c] |= N_FLAG; + } + + for (c = 0; c < 65536; c++) { + d = 0; + if (c & 1) + d++; + if (c & 2) + d++; + if (c & 4) + d++; + if (c & 8) + d++; + if (c & 16) + d++; + if (c & 32) + d++; + if (c & 64) + d++; + if (c & 128) + d++; + if (d & 1) + znptable16[c] = 0; + else + znptable16[c] = P_FLAG; + if (c == 0xb1) + DEBUG("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) + DEBUG("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) + znptable16[c] |= Z_FLAG; + if (c & 0x8000) + znptable16[c] |= N_FLAG; + } +} + + +/* Common reset function. */ +static void +reset_common(int hard) +{ + if (hard) { + INFO("x86 reset\n"); + ins = 0; + } + use32 = 0; + cpu_cur_status = 0; + stack32 = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw = 0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags = 0; + cgate32 = 0; + if (AT) { + loadcs(0xF000); + cpu_state.pc = 0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } else { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + flags = 2; + trap = 0; + ovr_seg = NULL; + in_lock = halt = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + pfq_clear(); + cpu_set_edx(); EAX = 0; - ESP=0; - mmu_perm=4; - memset(inscounts, 0, sizeof(inscounts)); - x86seg_reset(); + ESP = 0; + mmu_perm = 4; + pfq_size = (is8086) ? 6 : 4; + } + + x86seg_reset(); #ifdef USE_DYNAREC - codegen_reset(); + if (hard) + codegen_reset(); #endif - x86_was_reset = 1; - port_92_clear_reset(); + x86_was_reset = 1; + port_92_clear_reset(); } -void softresetx86(void) + +/* Hard reset. */ +void +resetx86(void) { - use32=0; - stack32=0; - cpu_cur_status = 0; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - msw=0; - if (is486) - cr0 = 1 << 30; - else - cr0 = 0; - cpu_cache_int_enabled = 0; - cpu_update_waitstates(); - cr4 = 0; - eflags=0; - cgate32=0; - if(AT) - { - loadcs(0xF000); - cpu_state.pc=0xFFF0; - rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; - } - else - { - loadcs(0xFFFF); - cpu_state.pc=0; - rammask = 0xfffff; - } - flags=2; - idt.base = 0; - idt.limit = is386 ? 0x03FF : 0xFFFF; - x86seg_reset(); - x86_was_reset = 1; - port_92_clear_reset(); + reset_common(1); } -static void setznp8(uint8_t val) + +/* Soft reset. */ +void +softresetx86(void) { - flags&=~0xC4; - flags|=znptable8[val]; + reset_common(0); } -static void setznp16(uint16_t val) + +/* Pushes a word to the stack. */ +static void +push_ex(uint16_t val) { - flags&=~0xC4; - flags|=znptable16[val]; + writememw(ss, (SP & 0xFFFF), val); + cpu_state.last_ea = SP; } -static void setadd8(uint8_t a, uint8_t b) + +static void +push(uint16_t val) { - uint16_t c=(uint16_t)a+(uint16_t)b; - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadd8nc(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a+(uint16_t)b; - flags&=~0x8D4; - flags|=znptable8[c&0xFF]; - if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadc8(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a+(uint16_t)b+tempc; - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadd16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b; - flags&=~0x8D5; - flags|=znptable16[c&0xFFFF]; - if (c&0x10000) flags|=C_FLAG; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadd16nc(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b; - flags&=~0x8D4; - flags|=znptable16[c&0xFFFF]; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadc16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b+tempc; - flags&=~0x8D5; - flags|=znptable16[c&0xFFFF]; - if (c&0x10000) flags|=C_FLAG; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; + SP -= 2; + push_ex(val); } -static void setsub8(uint8_t a, uint8_t b) + +/* Pops a word from the stack. */ +static uint16_t +pop(void) { - uint16_t c=(uint16_t)a-(uint16_t)b; - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if ((a^b)&(a^c)&0x80) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsub8nc(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a-(uint16_t)b; - flags&=~0x8D4; - flags|=znptable8[c&0xFF]; - if ((a^b)&(a^c)&0x80) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsbc8(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if ((a^b)&(a^c)&0x80) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsub16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a-(uint32_t)b; - flags&=~0x8D5; - flags|=znptable16[c&0xFFFF]; - if (c&0x10000) flags|=C_FLAG; - if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsub16nc(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a-(uint32_t)b; - flags&=~0x8D4; - flags|=(znptable16[c&0xFFFF]&~4); - flags|=(znptable8[c&0xFF]&4); - if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsbc16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); - flags&=~0x8D5; - flags|=(znptable16[c&0xFFFF]&~4); - flags|=(znptable8[c&0xFF]&4); - if (c&0x10000) flags|=C_FLAG; - if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; + uint16_t tempw; + + tempw = readmemw(ss, SP); + SP += 2; + cpu_state.last_ea = SP; + return tempw; } -int current_diff = 0; -void clockhardware(void) + +static void +access(int num, int bits) { - int diff = cycdiff - cycles - current_diff; - - current_diff += diff; - - timer_end_period(cycles*xt_cpu_multi); -} - -static int takeint = 0; - - -int firstrepcycle=1; - -void rep(int fv) -{ - uint8_t temp = 0; - int c=CX; - uint8_t temp2; - uint16_t tempw,tempw2; - uint16_t ipc=cpu_state.oldpc; - int changeds=0; - uint32_t oldds = 0; - startrep: - temp=FETCH(); - - switch (temp) - { - case 0x08: - cpu_state.pc=ipc+1; - cycles-=2; - FETCHCLEAR(); - break; - case 0x26: /*ES:*/ - oldds=ds; - ds=es; - changeds=1; - cycles-=2; - goto startrep; - break; - case 0x2E: /*CS:*/ - oldds=ds; - ds=cs; - changeds=1; - cycles-=2; - goto startrep; - break; - case 0x36: /*SS:*/ - oldds=ds; - ds=ss; - changeds=1; - cycles-=2; - goto startrep; - break; - case 0x6C: /*186+ REP INSB*/ - if (is_nec) - { - if (c>0) - { - temp2=inb(DX); - writememb(ds+SI, temp2); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - } - break; - case 0x6D: /*186+ REP INSW*/ - if (is_nec) - { - if (c>0) - { - tempw2=inw(DX); - writememw(ds, SI, tempw2); - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - } - break; - case 0x6E: /*186+ REP OUTSB*/ - if (is_nec) - { - if (c>0) - { - temp2=readmemb(ds+SI); - outb(DX,temp2); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - } - break; - case 0x6F: /*186+ REP OUTSW*/ - if (is_nec) - { - if (c>0) - { - tempw2=readmemw(ds,SI); - outw(DX,tempw2); - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - } + switch (num) { + case 0: case 61: case 63: case 64: + case 67: case 69: case 71: case 72: + default: break; - case 0xA4: /*REP MOVSB*/ - while (c>0 && !IRQTEST) - { - temp2=readmemb(ds+SI); - writememb(es+DI,temp2); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - c--; - cycles-=17; - clockhardware(); - FETCHADD(17-memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xA5: /*REP MOVSW*/ - while (c>0 && !IRQTEST) - { - memcycs=0; - tempw=readmemw(ds,SI); - writememw(es,DI,tempw); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles-=17; - clockhardware(); - FETCHADD(17 - memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xA6: /*REP CMPSB*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) - { - memcycs=0; - temp=readmemb(ds+SI); - temp2=readmemb(es+DI); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - c--; - cycles -= 30; - setsub8(temp,temp2); - clockhardware(); - FETCHADD(30 - memcycs); - } - if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; - break; - case 0xA7: /*REP CMPSW*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) - { - memcycs=0; - tempw=readmemw(ds,SI); - tempw2=readmemw(es,DI); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles -= 30; - setsub16(tempw,tempw2); - clockhardware(); - FETCHADD(30 - memcycs); - } - if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; - break; - case 0xAA: /*REP STOSB*/ - while (c>0 && !IRQTEST) - { - memcycs=0; - writememb(es+DI,AL); - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles -= 10; - clockhardware(); - FETCHADD(10 - memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xAB: /*REP STOSW*/ - while (c>0 && !IRQTEST) - { - memcycs=0; - writememw(es,DI,AX); - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles -= 10; - clockhardware(); - FETCHADD(10 - memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xAC: /*REP LODSB*/ - if (c>0) - { - temp2=readmemb(ds+SI); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=4; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - case 0xAD: /*REP LODSW*/ - if (c>0) - { - tempw2=readmemw(ds,SI); - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=4; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - case 0xAE: /*REP SCASB*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - temp2=readmemb(es+DI); - setsub8(AL,temp2); - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles -= 15; - } - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - case 0xAF: /*REP SCASW*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - tempw=readmemw(es,DI); - setsub16(AX,tempw); - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles -= 15; - } - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - default: - cpu_state.pc = ipc+1; - cycles-=20; - FETCHCLEAR(); - } - CX=c; - if (changeds) ds=oldds; - if (IRQTEST) - takeint = 1; + case 1: case 6: case 8: case 9: + case 17: case 20: case 21: case 24: + case 28: case 55: case 56: + wait(1 + (cycles % 3), 0); + break; + case 2: case 15: case 22: case 23: + case 25: case 26: case 46: case 53: + wait(2 + (cycles % 3), 0); + break; + case 3: case 44: case 45: case 52: + case 54: + wait(2 + (cycles & 1), 0); + break; + case 4: + wait(5 + (cycles & 1), 0); + break; + case 5: + if (opcode == 0xcc) + wait(7 + (cycles % 3), 0); + else + wait(4 + (cycles & 1), 0); + break; + case 7: case 47: case 48: case 49: + case 50: case 51: + wait(1 + (cycles % 4), 0); + break; + case 10: case 11: case 18: case 19: + case 43: + wait(3 + (cycles % 3), 0); + break; + case 12: case 13: case 14: case 29: + case 30: case 33: + wait(4 + (cycles % 3), 0); + break; + case 16: + if (!(opcode & 1) && (cycles & 1)) + wait(1, 0); + /* Fall through. */ + case 42: + wait(3 + (cycles & 1), 0); + break; + case 27: case 32: case 37: + wait(3, 0); + break; + case 31: + wait(6 + (cycles % 3), 0); + break; + case 34: case 39: case 41: case 60: + wait(4, 0); + break; + case 35: + wait(2, 0); + break; + case 36: + wait(5 + (cycles & 1), 0); + if (cpu_mod != 3) + wait(1, 0); + break; + case 38: + wait(5 + (cycles % 3), 0); + break; + case 40: + wait(6, 0); + break; + case 57: + if (cpu_mod != 3) + wait(2, 0); + wait(4 + (cycles & 1), 0); + break; + case 58: + if (cpu_mod != 3) + wait(1, 0); + wait(4 + (cycles & 1), 0); + break; + case 59: + if (cpu_mod != 3) + wait(1, 0); + wait(5 + (cycles & 1), 0); + break; + case 62: + wait(1, 0); + break; + case 65: + wait(3 + (cycles & 1), 0); + if (cpu_mod != 3) + wait(1, 0); + break; + case 70: + wait(5, 0); + break; + } } -int inhlt=0; -uint16_t lastpc,lastcs; -int skipnextprint=0; -int instime=0; +/* Calls an interrupt. */ +static void +interrupt(uint16_t addr, int cli) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + + addr <<= 2; + old_cs = CS; + access(5, 16); + new_ip = readmemw(0, addr); + wait(1, 0); + access(6, 16); + new_cs = readmemw(0, (addr + 2) & 0xffff); + access(39, 16); + push(flags & 0x0fd7); + if (cli) + flags &= ~I_FLAG; + flags &= ~T_FLAG; + access(40, 16); + push(old_cs); + old_ip = cpu_state.pc; + loadcs(new_cs); + access(68, 16); + cpu_state.pc = new_ip; + access(41, 16); + push(old_ip); + pfq_clear(); +} +static int +rep_action(int *completed, int *repeating, int in_rep, int bits) +{ + uint16_t t; + + if (in_rep == 0) + return 0; + wait(2, 0); + t = CX; + if (irq_pending()) { + access(71, bits); + pfq_clear(); + cpu_state.pc = cpu_state.pc - 2; + t = 0; + } + if (t == 0) { + wait(1, 0); + *completed = 1; + *repeating = 0; + return 1; + } + --CX; + *completed = 0; + wait(2, 0); + if (!*repeating) + wait(2, 0); + return 0; +} + + +static uint16_t +jump(uint16_t delta) +{ + uint16_t old_ip; + access(67, 8); + wait(5, 0); + old_ip = cpu_state.pc; + cpu_state.pc = (cpu_state.pc + delta) & 0xffff; + pfq_clear(); + return old_ip; +} + + +static uint16_t +sign_extend(uint8_t data) +{ + return data + (data < 0x80 ? 0 : 0xff00); +} + + +static void +jump_short(void) +{ + jump(sign_extend((uint8_t) cpu_data)); +} + + +static uint16_t +jump_near(void) +{ + return jump(pfq_fetchw()); +} + + +/* Performs a conditional jump. */ +static void +jcc(uint8_t opcode, int cond) +{ + /* int8_t offset; */ + + wait(1, 0); + cpu_data = pfq_fetchb(); + wait(1, 0); + if ((!cond) == (opcode & 0x01)) + jump_short(); +} + + +static void +set_cf(int cond) +{ + flags = (flags & ~C_FLAG) | (cond ? C_FLAG : 0); +} + + +static void +set_if(int cond) +{ + flags = (flags & ~I_FLAG) | (cond ? I_FLAG : 0); +} + + +static void +set_df(int cond) +{ + flags = (flags & ~D_FLAG) | (cond ? D_FLAG : 0); +} + + +static void +bitwise(int bits, uint16_t data) +{ + cpu_data = data; + flags &= ~(C_FLAG | A_FLAG | V_FLAG); + set_pzs(bits); +} + + +static void +test(int bits, uint16_t dest, uint16_t src) +{ + cpu_dest = dest; + cpu_src = src; + bitwise(bits, (cpu_dest & cpu_src)); +} + + +static void +set_of(int of) +{ + flags = (flags & ~0x800) | (of ? 0x800 : 0); +} + + +static int +top_bit(uint16_t w, int bits) +{ + if (bits == 16) + return ((w & 0x8000) != 0); + else + return ((w & 0x80) != 0); +} + + +static void +set_of_add(int bits) +{ + set_of(top_bit((cpu_data ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_of_sub(int bits) +{ + set_of(top_bit((cpu_dest ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_af(int af) +{ + flags = (flags & ~0x10) | (af ? 0x10 : 0); +} + + +static void +do_af(void) +{ + set_af(((cpu_data ^ cpu_src ^ cpu_dest) & 0x10) != 0); +} + + +static void +set_apzs(int bits) +{ + set_pzs(bits); + do_af(); +} + + +static void +add(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest + cpu_src; + set_apzs(bits); + set_of_add(bits); + + /* Anything - FF with carry on is basically anything + 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (flags & C_FLAG)) + flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_data & size_mask)); +} + + +static void +sub(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest - cpu_src; + set_apzs(bits); + set_of_sub(bits); + + /* Anything - FF with carry on is basically anything - 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (flags & C_FLAG)) + flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_dest & size_mask)); +} + + +static void +alu_op(int bits) +{ + switch(cpu_alu_op) { + case 1: + bitwise(bits, (cpu_dest | cpu_src)); + break; + case 2: + if (flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 0: + add(bits); + break; + case 3: + if (flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 5: case 7: + sub(bits); + break; + case 4: + test(bits, cpu_dest, cpu_src); + break; + case 6: + bitwise(bits, (cpu_dest ^ cpu_src)); + break; + } +} + + +static void +set_sf(int bits) +{ + flags = (flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); +} + + +static void +set_pf(void) +{ + static uint8_t table[0x100] = { + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4}; + + flags = (flags & ~4) | table[cpu_data & 0xff]; +} + + +static void +mul(uint16_t a, uint16_t b) +{ + int negate = 0; + int bit_count = 8; + int carry, i; + uint16_t high_bit = 0x80; + uint16_t size_mask; + uint16_t c, r; + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd5) { + if (opcode & 1) { + bit_count = 16; + high_bit = 0x8000; + } else + wait(8, 0); + + size_mask = (1 << bit_count) - 1; + + if ((rmdat & 0x38) == 0x28) { + if (!top_bit(a, bit_count)) { + if (top_bit(b, bit_count)) { + wait(1, 0); + if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) + wait(1, 0); + b = ~b + 1; + negate = 1; + } + } else { + wait(1, 0); + a = ~a + 1; + negate = 1; + if (top_bit(b, bit_count)) { + b = ~b + 1; + negate = 0; + } else + wait(4, 0); + } + wait(10, 0); + } + wait(3, 0); + } + + c = 0; + a &= size_mask; + carry = (a & 1) != 0; + a >>= 1; + for (i = 0; i < bit_count; ++i) { + wait(7, 0); + if (carry) { + cpu_src = c; + cpu_dest = b; + add(bit_count); + c = cpu_data & size_mask; + wait(1, 0); + carry = !!(flags & C_FLAG); + } + r = (c >> 1) + (carry ? high_bit : 0); + carry = (c & 1) != 0; + c = r; + r = (a >> 1) + (carry ? high_bit : 0); + carry = (a & 1) != 0; + a = r; + } + if (negate) { + c = ~c; + a = (~a + 1) & size_mask; + if (a == 0) + ++c; + wait(9, 0); + } + cpu_data = a; + cpu_dest = c; + + set_sf(bit_count); + set_pf(); +} + + +static void +set_of_rotate(int bits) +{ + set_of(top_bit(cpu_data ^ cpu_dest, bits)); +} + + +static void +set_zf(int bits) +{ + int size_mask = (1 << bits) - 1; + + flags = (flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); +} + + +static void +set_pzs(int bits) +{ + set_pf(); + set_zf(bits); + set_sf(bits); +} + + +static void +set_co_mul(int carry) +{ + set_cf(carry); + set_of(carry); + if (!carry) + wait(1, 0); +} + + +static int +div(uint16_t l, uint16_t h) +{ + int b, bit_count = 8; + int negative = 0; + int dividend_negative = 0; + int size_mask, carry; + uint16_t r; + + if (opcode & 1) { + l = AX; + h = DX; + bit_count = 16; + } + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd4) { + if ((rmdat & 0x38) == 0x38) { + if (top_bit(h, bit_count)) { + h = ~h; + l = (~l + 1) & size_mask; + if (l == 0) + ++h; + h &= size_mask; + negative = 1; + dividend_negative = 1; + wait(4, 0); + } + if (top_bit(cpu_src, bit_count)) { + cpu_src = ~cpu_src + 1; + negative = !negative; + } else + wait(1, 0); + wait(9, 0); + } + wait(3, 0); + } + cycles -= 8; + cpu_src &= size_mask; + if (h >= cpu_src) { + if (opcode != 0xd4) + wait(1, 0); + interrupt(0, 1); + return 0; + } + if (opcode != 0xd4) + wait(1, 0); + wait(2, 0); + carry = 1; + for (b = 0; b < bit_count; ++b) { + r = (l << 1) + (carry ? 1 : 0); + carry = top_bit(l, bit_count); + l = r; + r = (h << 1) + (carry ? 1 : 0); + carry = top_bit(h, bit_count); + h = r; + wait(8, 0); + if (carry) { + carry = 0; + h -= cpu_src; + if (b == bit_count - 1) + wait(2, 0); + } else { + carry = cpu_src > h; + if (!carry) { + h -= cpu_src; + wait(1, 0); + if (b == bit_count - 1) + wait(2, 0); + } + } + } + l = ~((l << 1) + (carry ? 1 : 0)); + if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { + wait(4, 0); + if (top_bit(l, bit_count)) { + if (cpu_mod == 3) + wait(1, 0); + interrupt(0, 1); + return 0; + } + wait(7, 0); + if (negative) + l = ~l + 1; + if (dividend_negative) + h = ~h + 1; + } + if (opcode == 0xd4) { + AL = h & 0xff; + AH = l & 0xff; + } else { + AH = h & 0xff; + AL = l & 0xff; + if (opcode & 1) { + DX = h; + AX = l; + } + } + return 1; +} + + +static void +lods(int bits) +{ + if (bits == 16) + cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), SI); + else + cpu_data = readmemb((ovr_seg ? *ovr_seg : ds) + SI); + if (flags & D_FLAG) + SI -= (bits >> 3); + else + SI += (bits >> 3); +} + + +static void +stos(int bits) +{ + if (bits == 16) + writememw(es, DI, cpu_data); + else + writememb(es + DI, cpu_data); + if (flags & D_FLAG) + DI -= (bits >> 3); + else + DI += (bits >> 3); +} + + +static void +da(void) +{ + set_pzs(8); + wait(2, 0); +} + + +static void +aa(void) +{ + set_of(0); + AL &= 0x0f; + wait(6, 0); +} + + +static void +set_ca(void) +{ + set_cf(1); + set_af(1); +} + + +static void +clear_ca(void) +{ + set_cf(0); + set_af(0); +} + + +/* Executes instructions up to the specified number of cycles. */ void execx86(int cycs) { - uint8_t temp = 0,temp2; - uint16_t addr,tempw,tempw2,tempw3,tempw4; - int8_t offset; - int tempws; - uint32_t templ; - unsigned int c; - int tempi; - int trap; + uint8_t temp = 0, temp2; + uint16_t addr, tempw; + uint16_t new_cs, new_ip; + int bits, completed; + int in_rep, repeating; + int oldc; cycles += cycs; + while (cycles > 0) { - cycdiff=cycles; - timer_start_period(cycles*xt_cpu_multi); - current_diff = 0; - cycles-=nextcyc; - nextcyc=0; - fetchclocks=0; - oldcs=CS; - cpu_state.oldpc=cpu_state.pc; + timer_start_period(cycles * xt_cpu_multi); + wait(nextcyc, 0); + nextcyc = 0; + fetchclocks = 0; + cpu_state.oldpc = cpu_state.pc; + in_rep = repeating = 0; + completed = 0; opcodestart: - opcode=FETCH(); - tempc=flags&C_FLAG; - trap=flags&T_FLAG; - cpu_state.pc--; + if (halt) { + wait(2, 0); + goto on_halt; + } -#if 0 - DEBUG("%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]); -#endif + if (!repeating) { + opcode = pfq_fetchb(); + oldc = flags & C_FLAG; + trap = flags & T_FLAG; + wait(1, 0); + + /* if (!in_rep && !ovr_seg && (CS < 0xf000)) + pclog("%04X:%04X %02X\n", CS, (cpu_state.pc - 1) & 0xFFFF, opcode); */ + } - cpu_state.pc++; - inhlt=0; switch (opcode) { - case 0x00: /*ADD 8,reg*/ - fetchea(); - temp=geteab(); - setadd8(temp,getr8(cpu_reg)); - temp+=getr8(cpu_reg); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); + case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ + access(29, 16); + push(_opseg[(opcode >> 3) & 0x03]->seg); break; - - case 0x01: /*ADD 16,reg*/ - fetchea(); - tempw=geteaw(); - setadd16(tempw, cpu_state.regs[cpu_reg].w); - tempw += cpu_state.regs[cpu_reg].w; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x02: /*ADD cpu_reg,8*/ - fetchea(); - temp=geteab(); - setadd8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)+temp); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x03: /*ADD cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setadd16(cpu_state.regs[cpu_reg].w,tempw); - cpu_state.regs[cpu_reg].w+=tempw; - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x04: /*ADD AL,#8*/ - temp=FETCH(); - setadd8(AL,temp); - AL+=temp; - cycles-=4; - break; - - case 0x05: /*ADD AX,#16*/ - tempw=getword(); - setadd16(AX,tempw); - AX+=tempw; - cycles-=4; - break; - - case 0x06: /*PUSH ES*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),ES); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - - case 0x07: /*POP ES*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_es); - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - break; - - case 0x08: /*OR 8,reg*/ - fetchea(); - temp=geteab(); - temp|=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x09: /*OR 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw|=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x0A: /*OR cpu_reg,8*/ - fetchea(); - temp=geteab(); - temp|=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x0B: /*OR reg,16*/ - fetchea(); - tempw=geteaw(); - tempw|=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cpu_state.regs[cpu_reg].w=tempw; - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x0C: /*OR AL,#8*/ - AL|=FETCH(); - setznp8(AL); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x0D: /*OR AX,#16*/ - AX|=getword(); - setznp16(AX); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x0E: /*PUSH CS*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),CS); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - - case 0x0F: /*0F handler for NEC V20 soon */ - if (! is_nec) { /*POP CS - 8088/8086 only*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_cs); - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - } - break; - - case 0x10: /*ADC 8,reg*/ - fetchea(); - temp=geteab(); - temp2=getr8(cpu_reg); - setadc8(temp,temp2); - temp+=temp2+tempc; - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x11: /*ADC 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setadc16(tempw,tempw2); - tempw+=tempw2+tempc; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x12: /*ADC cpu_reg,8*/ - fetchea(); - temp=geteab(); - setadc8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)+temp+tempc); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x13: /*ADC cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setadc16(cpu_state.regs[cpu_reg].w,tempw); - cpu_state.regs[cpu_reg].w+=tempw+tempc; - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x14: /*ADC AL,#8*/ - tempw=FETCH(); - setadc8(AL,tempw & 0xff); - AL+=tempw+tempc; - cycles-=4; - break; - - case 0x15: /*ADC AX,#16*/ - tempw=getword(); - setadc16(AX,tempw); - AX+=tempw+tempc; - cycles-=4; - break; - - case 0x16: /*PUSH SS*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),SS); - SP-=2; - cycles-=14; - cpu_state.last_ea = SP; - break; - - case 0x17: /*POP SS*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_ss); - SP+=2; - cpu_state.last_ea = SP; - noint=1; - cycles-=12; - break; - - case 0x18: /*SBB 8,reg*/ - fetchea(); - temp=geteab(); - temp2=getr8(cpu_reg); - setsbc8(temp,temp2); - temp-=(temp2+tempc); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x19: /*SBB 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setsbc16(tempw,tempw2); - tempw-=(tempw2+tempc); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x1A: /*SBB cpu_reg,8*/ - fetchea(); - temp=geteab(); - setsbc8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)-(temp+tempc)); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x1B: /*SBB cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setsbc16(tempw2,tempw); - tempw2-=(tempw+tempc); - cpu_state.regs[cpu_reg].w=tempw2; - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x1C: /*SBB AL,#8*/ - temp=FETCH(); - setsbc8(AL,temp); - AL-=(temp+tempc); - cycles-=4; - break; - - case 0x1D: /*SBB AX,#16*/ - tempw=getword(); - setsbc16(AX,tempw); - AX-=(tempw+tempc); - cycles-=4; - break; - - case 0x1E: /*PUSH DS*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),DS); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - - case 0x1F: /*POP DS*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_ds); - if (cpu_state.ssegs) oldds=ds; - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - break; - - case 0x20: /*AND 8,reg*/ - fetchea(); - temp=geteab(); - temp&=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x21: /*AND 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw&=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x22: /*AND cpu_reg,8*/ - fetchea(); - temp=geteab(); - temp&=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x23: /*AND cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - tempw&=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cpu_state.regs[cpu_reg].w=tempw; - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x24: /*AND AL,#8*/ - AL&=FETCH(); - setznp8(AL); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x25: /*AND AX,#16*/ - AX&=getword(); - setznp16(AX); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x26: /*ES:*/ - oldss=ss; - oldds=ds; - ds=ss=es; - cpu_state.ssegs=2; - cycles-=4; - goto opcodestart; - - case 0x27: /*DAA*/ - if ((flags&A_FLAG) || ((AL&0xF)>9)) { - tempi=((uint16_t)AL)+6; - AL+=6; - flags|=A_FLAG; - if (tempi&0x100) flags|=C_FLAG; - } - if ((flags&C_FLAG) || (AL>0x9F)) { - AL+=0x60; - flags|=C_FLAG; - } - setznp8(AL); - cycles-=4; - break; - - case 0x28: /*SUB 8,reg*/ - fetchea(); - temp=geteab(); - setsub8(temp,getr8(cpu_reg)); - temp-=getr8(cpu_reg); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x29: /*SUB 16,reg*/ - fetchea(); - tempw=geteaw(); - setsub16(tempw,cpu_state.regs[cpu_reg].w); - tempw-=cpu_state.regs[cpu_reg].w; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x2A: /*SUB cpu_reg,8*/ - fetchea(); - temp=geteab(); - setsub8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)-temp); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x2B: /*SUB cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setsub16(cpu_state.regs[cpu_reg].w,tempw); - cpu_state.regs[cpu_reg].w-=tempw; - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x2C: /*SUB AL,#8*/ - temp=FETCH(); - setsub8(AL,temp); - AL-=temp; - cycles-=4; - break; - - case 0x2D: /*SUB AX,#16*/ - tempw=getword(); - setsub16(AX,tempw); - AX-=tempw; - cycles-=4; - break; - - case 0x2E: /*CS:*/ - oldss=ss; - oldds=ds; - ds=ss=cs; - cpu_state.ssegs=2; - cycles-=4; - goto opcodestart; - - case 0x2F: /*DAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) { - tempi=((uint16_t)AL)-6; - AL-=6; - flags|=A_FLAG; - if (tempi&0x100) flags|=C_FLAG; - } - if ((flags&C_FLAG)||(AL>0x9F)) { - AL-=0x60; - flags|=C_FLAG; - } - setznp8(AL); - cycles-=4; - break; - - case 0x30: /*XOR 8,reg*/ - fetchea(); - temp=geteab(); - temp^=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x31: /*XOR 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw^=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x32: /*XOR cpu_reg,8*/ - fetchea(); - temp=geteab(); - temp^=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x33: /*XOR cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - tempw^=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cpu_state.regs[cpu_reg].w=tempw; - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x34: /*XOR AL,#8*/ - AL^=FETCH(); - setznp8(AL); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x35: /*XOR AX,#16*/ - AX^=getword(); - setznp16(AX); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x36: /*SS:*/ - oldss=ss; - oldds=ds; - ds=ss=ss; - cpu_state.ssegs=2; - cycles-=4; - goto opcodestart; - - case 0x37: /*AAA*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) { - AL+=6; - AH++; - flags|=(A_FLAG|C_FLAG); + case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ + access(22, 16); + if (opcode == 0x0F) { + loadcs(pop()); + pfq_clear(); } else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles-=8; + loadseg(pop(), _opseg[(opcode >> 3) & 0x03]); + wait(1, 0); + noint = 1; break; - case 0x38: /*CMP 8,reg*/ - fetchea(); - temp=geteab(); - setsub8(temp,getr8(cpu_reg)); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x39: /*CMP 16,reg*/ - fetchea(); - tempw=geteaw(); - setsub16(tempw,cpu_state.regs[cpu_reg].w); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x3A: /*CMP cpu_reg,8*/ - fetchea(); - temp=geteab(); - setsub8(getr8(cpu_reg),temp); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x3B: /*CMP cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setsub16(cpu_state.regs[cpu_reg].w,tempw); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x3C: /*CMP AL,#8*/ - temp=FETCH(); - setsub8(AL,temp); - cycles-=4; - break; - - case 0x3D: /*CMP AX,#16*/ - tempw=getword(); - setsub16(AX,tempw); - cycles-=4; - break; - - case 0x3E: /*DS:*/ - oldss=ss; - oldds=ds; - ds=ss=ds; - cpu_state.ssegs=2; - cycles-=4; + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + wait(1, 0); + ovr_seg = opseg[(opcode >> 3) & 0x03]; goto opcodestart; + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x38: case 0x39: case 0x3a: case 0x3b: + /* alu rm, r / r, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(46, bits); + if (opcode & 1) + tempw = geteaw(); + else + tempw = geteab(); + cpu_alu_op = (opcode >> 3) & 7; + if ((opcode & 2) == 0) { + cpu_dest = tempw; + cpu_src = (opcode & 1) ? cpu_state.regs[cpu_reg].w : getr8(cpu_reg); + } else { + cpu_dest = (opcode & 1) ? cpu_state.regs[cpu_reg].w : getr8(cpu_reg); + cpu_src = tempw; + } + if (cpu_mod != 3) + wait(2, 0); + wait(1, 0); + alu_op(bits); + if (cpu_alu_op != 7) { + if ((opcode & 2) == 0) { + access(10, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + if (cpu_mod == 3) + wait(1, 0); + } else { + if (opcode & 1) + cpu_state.regs[cpu_reg].w = cpu_data; + else + setr8(cpu_reg, cpu_data); + wait(1, 0); + } + } else + wait(1, 0); + break; + + case 0x04: case 0x05: case 0x0c: case 0x0d: + case 0x14: case 0x15: case 0x1c: case 0x1d: + case 0x24: case 0x25: case 0x2c: case 0x2d: + case 0x34: case 0x35: case 0x3c: case 0x3d: + /* alu A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + if (opcode & 1) { + cpu_data = pfq_fetchw(); + cpu_dest = AX; + } else { + cpu_data = pfq_fetchb(); + cpu_dest = AL; + } + cpu_src = cpu_data; + cpu_alu_op = (opcode >> 3) & 7; + alu_op(bits); + if (cpu_alu_op != 7) { + if (opcode & 1) + AX = cpu_data; + else + AL = cpu_data & 0xff; + } + wait(1, 0); + break; + + case 0x27: /*DAA*/ + wait(1, 0); + if ((flags & A_FLAG) || (AL & 0x0f) > 9) { + cpu_data = AL + 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((flags & C_FLAG) || AL > 0x9f) { + AL += 0x60; + set_cf(1); + } + da(); + break; + case 0x2F: /*DAS*/ + wait(1, 0); + temp = AL; + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_data = AL - 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((flags & C_FLAG) || temp > 0x9f) { + AL -= 0x60; + set_cf(1); + } + da(); + break; + case 0x37: /*AAA*/ + wait(1, 0); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL += 6; + ++AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; case 0x3F: /*AAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) { - AL-=6; - AH--; - flags|=(A_FLAG|C_FLAG); - } else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles-=8; + wait(1, 0); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL -= 6; + --AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); break; - case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: - setadd16nc(cpu_state.regs[opcode&7].w,1); - cpu_state.regs[opcode&7].w++; - cycles-=3; - break; - - case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: - setsub16nc(cpu_state.regs[opcode&7].w,1); - cpu_state.regs[opcode&7].w--; - cycles-=3; + /* INCDEC rw */ + wait(1, 0); + cpu_dest = cpu_state.regs[opcode & 7].w; + cpu_src = 1; + bits = 16; + if ((opcode & 8) == 0) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(16); + cpu_state.regs[opcode & 7].w = cpu_data; break; - case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ case 0x54: case 0x55: case 0x56: case 0x57: - if (cpu_state.ssegs) ss=oldss; - SP-=2; - cpu_state.last_ea = SP; - writememw(ss,SP,cpu_state.regs[opcode&7].w); - cycles-=15; + access(30, 16); + if (opcode == 0x54) { + SP -= 2; + push_ex(cpu_state.regs[opcode & 0x07].w); + } else + push(cpu_state.regs[opcode & 0x07].w); break; - - case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ case 0x5C: case 0x5D: case 0x5E: case 0x5F: - if (cpu_state.ssegs) ss=oldss; - SP+=2; - cpu_state.last_ea = SP; - cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); - cycles-=12; + access(23, 16); + cpu_state.regs[opcode & 0x07].w = pop(); + wait(1, 0); break; - case 0x60: - if (is_nec) { /*186+ PUSHA*/ - writememw(ss, ((SP - 2) & 0xFFFF), AX); - writememw(ss, ((SP - 4) & 0xFFFF), CX); - writememw(ss, ((SP - 6) & 0xFFFF), DX); - writememw(ss, ((SP - 8) & 0xFFFF), BX); - writememw(ss, ((SP - 10) & 0xFFFF), SP); - writememw(ss, ((SP - 12) & 0xFFFF), BP); - writememw(ss, ((SP - 14) & 0xFFFF), SI); - writememw(ss, ((SP - 16) & 0xFFFF), DI); - cycles-=18; - break; - } else { /*JO alias*/ - offset=(int8_t)FETCH(); - if (flags&V_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - } + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + jcc(opcode, flags & V_FLAG); break; - - case 0x61: - if (is_nec) { /*186+ POPA*/ - DI = readmemw(ss, ((SP) & 0xFFFF)); - SI = readmemw(ss, ((SP + 2) & 0xFFFF)); - BP = readmemw(ss, ((SP + 4) & 0xFFFF)); - BX = readmemw(ss, ((SP + 8) & 0xFFFF)); - DX = readmemw(ss, ((SP + 10) & 0xFFFF)); - CX = readmemw(ss, ((SP + 12) & 0xFFFF)); - AX = readmemw(ss, ((SP + 14) & 0xFFFF)); - SP += 16; - cycles-=24; - break; - } else { /*JNO alias*/ - offset=(int8_t)FETCH(); - if (!(flags&V_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - } + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + jcc(opcode, flags & C_FLAG); break; - - case 0x62: - if (is_nec) { /*186+ BOUND*/ - int16_t low, high; - - low = geteaw(); - high = readmemw(easeg,cpu_state.eaaddr); - - if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) - { - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0x14); - loadcs(readmemw(0,0x14+2)); - FETCHCLEAR(); - return; - } - cycles-=10; - break; - } else { /*JB alias*/ - offset=(int8_t)FETCH(); - if (flags&C_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - } + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + jcc(opcode, flags & Z_FLAG); break; - - case 0x70: /*JO*/ - offset=(int8_t)FETCH(); - if (flags&V_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + jcc(opcode, flags & (C_FLAG | Z_FLAG)); break; - - case 0x71: /*JNO*/ - offset=(int8_t)FETCH(); - if (!(flags&V_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + jcc(opcode, flags & N_FLAG); break; - - case 0x72: /*JB*/ - offset=(int8_t)FETCH(); - if (flags&C_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x63: /*JNB alias*/ - case 0x73: /*JNB*/ - offset=(int8_t)FETCH(); - if (!(flags&C_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x64: /*JE alias*/ - case 0x74: /*JE*/ - offset=(int8_t)FETCH(); - if (flags&Z_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x65: /*JNE alias*/ - case 0x75: /*JNE*/ - offset=(int8_t)FETCH(); - cycles-=4; - if (!(flags&Z_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - break; - - case 0x66: /*JBE alias*/ - case 0x76: /*JBE*/ - offset=(int8_t)FETCH(); - if (flags&(C_FLAG|Z_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x67: /*JNBE alias*/ - case 0x77: /*JNBE*/ - offset=(int8_t)FETCH(); - if (!(flags&(C_FLAG|Z_FLAG))) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x68: - if (is_nec) { /*186+ PUSH imm*/ - tempw = getword(); - cpu_state.pc = tempw; - cycles-=2; - FETCHCLEAR(); - return; - } else { /*JS alias*/ - offset=(int8_t)FETCH(); - if (flags&N_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - } - break; - - case 0x78: /*JS*/ - offset=(int8_t)FETCH(); - if (flags&N_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x69: - if (is_nec) { /*186+ IMUL*/ - tempw = geteaw(); - tempw2 = getword(); - - templ = ((int)tempw) * ((int)tempw2); - if ((templ >> 15) != 0 && (templ >> 15) != -1) - flags |= C_FLAG | V_FLAG; - else - flags &= ~(C_FLAG | V_FLAG); - cpu_state.regs[cpu_reg].w = templ & 0xffff; - cycles-=((cpu_mod==3)?14:17); - FETCHCLEAR(); - } else { /*JNS alias*/ - offset=(int8_t)FETCH(); - if (!(flags&N_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - } - break; - - case 0x79: /*JNS*/ - offset=(int8_t)FETCH(); - if (!(flags&N_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x6A: - if (is_nec) { /*186+ PUSH imm8*/ - temp = (int8_t)FETCH(); - cpu_state.pc = temp; - cycles-=2; - FETCHCLEAR(); - return; - } else { /*JP alias*/ - offset=(int8_t)FETCH(); - if (flags&P_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - } - break; - - case 0x7A: /*JP*/ - offset=(int8_t)FETCH(); - if (flags&P_FLAG) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x6B: - if (is_nec) { /*186+ IMUL byte*/ - tempw = geteaw(); - tempw2 = (int8_t)FETCH(); - if (tempw2 & 0x80) tempw2 |= 0xff00; - - templ = ((int)tempw) * ((int)tempw2); - if ((templ >> 15) != 0 && (templ >> 15) != -1) - flags |= C_FLAG | V_FLAG; - else - flags &= ~(C_FLAG | V_FLAG); - cpu_state.regs[cpu_reg].w = templ & 0xffff; - cycles-=((cpu_mod==3)?14:17); - FETCHCLEAR(); - } else { /*JNP alias*/ - offset=(int8_t)FETCH(); - if (!(flags&P_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - } - break; - + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + case 0x6B: /*JNP alias*/ case 0x7B: /*JNP*/ - offset=(int8_t)FETCH(); - if (!(flags&P_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; + jcc(opcode, flags & P_FLAG); + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + temp = (flags & N_FLAG) ? 1 : 0; + temp2 = (flags & V_FLAG) ? 1 : 0; + jcc(opcode, temp ^ temp2); + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + temp = (flags & N_FLAG) ? 1 : 0; + temp2 = (flags & V_FLAG) ? 1 : 0; + jcc(opcode, (flags & Z_FLAG) || (temp != temp2)); break; - case 0x6C: /*JL alias*/ - case 0x7C: /*JL*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (temp!=temp2) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); + case 0x80: case 0x81: case 0x82: case 0x83: + /* alu rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(47, bits); + if (opcode & 1) + cpu_data = geteaw(); + else + cpu_data = geteab(); + cpu_dest = cpu_data; + if (cpu_mod != 3) + wait(3, 0); + if (opcode == 0x81) { + if (cpu_mod == 3) + wait(1, 0); + cpu_src = pfq_fetchw(); + } else { + if (cpu_mod == 3) + wait(1, 0); + if (opcode == 0x83) + cpu_src = sign_extend(pfq_fetchb()); + else + cpu_src = pfq_fetchb() | 0xff00; } - cycles-=4; - break; - - case 0x6D: /*JNL alias*/ - case 0x7D: /*JNL*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (temp==temp2) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x6E: /*JLE alias*/ - case 0x7E: /*JLE*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if ((flags&Z_FLAG) || (temp!=temp2)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x6F: /*JNLE alias*/ - case 0x7F: /*JNLE*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (!((flags&Z_FLAG) || (temp!=temp2))) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=4; - break; - - case 0x80: case 0x82: - fetchea(); - temp=geteab(); - temp2=FETCH(); - switch (rmdat&0x38) { - case 0x00: /*ADD b,#8*/ - setadd8(temp,temp2); - seteab(temp+temp2); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x08: /*OR b,#8*/ - temp|=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x10: /*ADC b,#8*/ - setadc8(temp,temp2); - seteab(temp+temp2+tempc); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x18: /*SBB b,#8*/ - setsbc8(temp,temp2); - seteab(temp-(temp2+tempc)); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x20: /*AND b,#8*/ - temp&=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x28: /*SUB b,#8*/ - setsub8(temp,temp2); - seteab(temp-temp2); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x30: /*XOR b,#8*/ - temp^=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x38: /*CMP b,#8*/ - setsub8(temp,temp2); - cycles-=((cpu_mod==3)?4:14); - break; + wait(1, 0); + cpu_alu_op = (rmdat & 0x38) >> 3; + alu_op(bits); + if (cpu_alu_op != 7) { + access(11, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + } else { + if (cpu_mod != 3) + wait(1, 0); } break; - case 0x81: - fetchea(); - tempw=geteaw(); - tempw2=getword(); - switch (rmdat&0x38) { - case 0x00: /*ADD w,#16*/ - setadd16(tempw,tempw2); - tempw+=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x08: /*OR w,#16*/ - tempw|=tempw2; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x10: /*ADC w,#16*/ - setadc16(tempw,tempw2); - tempw+=tempw2+tempc; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x20: /*AND w,#16*/ - tempw&=tempw2; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x18: /*SBB w,#16*/ - setsbc16(tempw,tempw2); - seteaw(tempw-(tempw2+tempc)); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x28: /*SUB w,#16*/ - setsub16(tempw,tempw2); - tempw-=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x30: /*XOR w,#16*/ - tempw^=tempw2; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x38: /*CMP w,#16*/ - setsub16(tempw,tempw2); - cycles-=((cpu_mod==3)?4:14); - break; + case 0x84: case 0x85: + /* TEST rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(48, bits); + if (opcode & 1) { + cpu_data = geteaw(); + test(bits, cpu_data, cpu_state.regs[cpu_reg].w); + } else { + cpu_data = geteab(); + test(bits, cpu_data, getr8(cpu_reg)); } + if (cpu_mod == 3) + wait(2, 0); + wait(2, 0); break; - - case 0x83: - fetchea(); - tempw=geteaw(); - tempw2=FETCH(); - if (tempw2&0x80) tempw2|=0xFF00; - switch (rmdat&0x38) { - case 0x00: /*ADD w,#8*/ - setadd16(tempw,tempw2); - tempw+=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x08: /*OR w,#8*/ - tempw|=tempw2; - setznp16(tempw); - seteaw(tempw); - flags&=~(C_FLAG|A_FLAG|V_FLAG); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x10: /*ADC w,#8*/ - setadc16(tempw,tempw2); - tempw+=tempw2+tempc; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x18: /*SBB w,#8*/ - setsbc16(tempw,tempw2); - tempw-=(tempw2+tempc); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x20: /*AND w,#8*/ - tempw&=tempw2; - setznp16(tempw); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - flags&=~(C_FLAG|A_FLAG|V_FLAG); - break; - - case 0x28: /*SUB w,#8*/ - setsub16(tempw,tempw2); - tempw-=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - - case 0x30: /*XOR w,#8*/ - tempw^=tempw2; - setznp16(tempw); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - flags&=~(C_FLAG|A_FLAG|V_FLAG); - break; - - case 0x38: /*CMP w,#8*/ - setsub16(tempw,tempw2); - cycles-=((cpu_mod==3)?4:14); - break; + case 0x86: case 0x87: + /* XCHG rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(49, bits); + if (opcode & 1) { + cpu_data = geteaw(); + cpu_src = cpu_state.regs[cpu_reg].w; + cpu_state.regs[cpu_reg].w = cpu_data; + } else { + cpu_data = geteab(); + cpu_src = getr8(cpu_reg); + setr8(cpu_reg, cpu_data); } + wait(3, 0); + access(12, bits); + if (opcode & 1) + seteaw(cpu_src); + else + seteab(cpu_src); break; - case 0x84: /*TEST b,reg*/ - fetchea(); - temp=geteab(); - temp2=getr8(cpu_reg); - setznp8(temp&temp2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?3:13); + case 0x88: case 0x89: + /* MOV rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + access(13, bits); + if (opcode & 1) + seteaw(cpu_state.regs[cpu_reg].w); + else + seteab(getr8(cpu_reg)); + break; + case 0x8A: case 0x8B: + /* MOV reg, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(50, bits); + if (opcode & 1) + cpu_state.regs[cpu_reg].w = geteaw(); + else + setr8(cpu_reg, geteab()); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); break; - case 0x85: /*TEST w,reg*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setznp16(tempw&tempw2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?3:13); - break; - - case 0x86: /*XCHG b,reg*/ - fetchea(); - temp=geteab(); - seteab(getr8(cpu_reg)); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?4:25); - break; - - case 0x87: /*XCHG w,reg*/ - fetchea(); - tempw=geteaw(); - seteaw(cpu_state.regs[cpu_reg].w); - cpu_state.regs[cpu_reg].w=tempw; - cycles-=((cpu_mod==3)?4:25); - break; - - case 0x88: /*MOV b,reg*/ - fetchea(); - seteab(getr8(cpu_reg)); - cycles-=((cpu_mod==3)?2:13); - break; - - case 0x89: /*MOV w,reg*/ - fetchea(); - seteaw(cpu_state.regs[cpu_reg].w); - cycles-=((cpu_mod==3)?2:13); - break; - - case 0x8A: /*MOV cpu_reg,b*/ - fetchea(); - temp=geteab(); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?2:12); - break; - - case 0x8B: /*MOV cpu_reg,w*/ - fetchea(); - tempw=geteaw(); - cpu_state.regs[cpu_reg].w=tempw; - cycles-=((cpu_mod==3)?2:12); - break; - - case 0x8C: /*MOV w,sreg*/ - fetchea(); - switch (rmdat&0x38) { - case 0x00: /*ES*/ + case 0x8C: /*MOV w,sreg*/ + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(14, 16); + switch (rmdat & 0x38) { + case 0x00: /*ES*/ seteaw(ES); break; - - case 0x08: /*CS*/ + case 0x08: /*CS*/ seteaw(CS); break; - - case 0x18: /*DS*/ - if (cpu_state.ssegs) ds=oldds; + case 0x18: /*DS*/ seteaw(DS); break; - - case 0x10: /*SS*/ - if (cpu_state.ssegs) ss=oldss; + case 0x10: /*SS*/ seteaw(SS); break; } - cycles-=((cpu_mod==3)?2:13); break; - case 0x8D: /*LEA*/ - fetchea(); - cpu_state.regs[cpu_reg].w=(cpu_mod == 3)?cpu_state.last_ea:cpu_state.eaaddr; - cycles-=2; + case 0x8D: /*LEA*/ + do_mod_rm(); + cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); break; - case 0x8E: /*MOV sreg,w*/ - fetchea(); - switch (rmdat&0x38) { - case 0x00: /*ES*/ - tempw=geteaw(); - loadseg(tempw,&_es); + case 0x8E: /*MOV sreg,w*/ + do_mod_rm(); + access(51, 16); + tempw = geteaw(); + switch (rmdat & 0x38) { + case 0x00: /*ES*/ + loadseg(tempw, &_es); break; - - case 0x08: /*CS - 8088/8086 only*/ - tempw=geteaw(); - loadseg(tempw,&_cs); + case 0x08: /*CS - 8088/8086 only*/ + loadcs(tempw); + pfq_clear(); break; - - case 0x18: /*DS*/ - tempw=geteaw(); - loadseg(tempw,&_ds); - if (cpu_state.ssegs) oldds=ds; + case 0x18: /*DS*/ + loadseg(tempw, &_ds); break; - - case 0x10: /*SS*/ - tempw=geteaw(); - loadseg(tempw,&_ss); - if (cpu_state.ssegs) oldss=ss; + case 0x10: /*SS*/ + loadseg(tempw, &_ss); break; } - cycles-=((cpu_mod==3)?2:12); - skipnextprint=1; - noint=1; + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + noint = 1; break; - case 0x8F: /*POPW*/ - fetchea(); - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - SP+=2; - cpu_state.last_ea = SP; - seteaw(tempw); - cycles-=25; + case 0x8F: /*POPW*/ + do_mod_rm(); + wait(1, 0); + cpu_src = cpu_state.eaaddr; + access(24, 16); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pop(); + cpu_state.eaaddr = cpu_src; + wait(2, 0); + access(15, 16); + seteaw(cpu_data); break; - case 0x90: /*NOP*/ - cycles-=3; - break; - - case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - tempw=AX; - AX=cpu_state.regs[opcode&7].w; - cpu_state.regs[opcode&7].w=tempw; - cycles-=3; + /* XCHG AX, rw */ + wait(1, 0); + cpu_data = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = AX; + AX = cpu_data; + wait(1, 0); break; - case 0x98: /*CBW*/ - AH=(AL&0x80)?0xFF:0; - cycles-=2; + case 0x98: /*CBW*/ + wait(1, 0); + AX = sign_extend(AL); break; - - case 0x99: /*CWD*/ - DX=(AX&0x8000)?0xFFFF:0; - cycles-=5; - break; - - case 0x9A: /*CALL FAR*/ - tempw=getword(); - tempw2=getword(); - tempw3=CS; - tempw4=cpu_state.pc; - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=tempw; - loadcs(tempw2); - writememw(ss,(SP-2)&0xFFFF,tempw3); - writememw(ss,(SP-4)&0xFFFF,tempw4); - SP-=4; - cpu_state.last_ea = SP; - cycles-=36; - FETCHCLEAR(); - break; - - case 0x9B: /*WAIT*/ - cycles-=4; - break; - - case 0x9C: /*PUSHF*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags|0xF000); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - - case 0x9D: /*POPF*/ - if (cpu_state.ssegs) ss=oldss; - flags=readmemw(ss,SP)&0xFFF; - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - break; - - case 0x9E: /*SAHF*/ - flags=(flags&0xFF00)|AH; - cycles-=4; - break; - - case 0x9F: /*LAHF*/ - AH=flags&0xFF; - cycles-=4; - break; - - case 0xA0: /*MOV AL,(w)*/ - addr=getword(); - AL=readmemb(ds+addr); - cycles-=14; - break; - - case 0xA1: /*MOV AX,(w)*/ - addr=getword(); - AX=readmemw(ds,addr); - cycles-=14; - break; - - case 0xA2: /*MOV (w),AL*/ - addr=getword(); - writememb(ds+addr,AL); - cycles-=14; - break; - - case 0xA3: /*MOV (w),AX*/ - addr=getword(); - writememw(ds,addr,AX); - cycles-=14; - break; - - case 0xA4: /*MOVSB*/ - temp=readmemb(ds+SI); - writememb(es+DI,temp); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - cycles-=18; - break; - - case 0xA5: /*MOVSW*/ - tempw=readmemw(ds,SI); - writememw(es,DI,tempw); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - cycles-=18; - break; - - case 0xA6: /*CMPSB*/ - temp =readmemb(ds+SI); - temp2=readmemb(es+DI); - setsub8(temp,temp2); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - cycles-=30; - break; - - case 0xA7: /*CMPSW*/ - tempw =readmemw(ds,SI); - tempw2=readmemw(es,DI); - setsub16(tempw,tempw2); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - cycles-=30; - break; - - case 0xA8: /*TEST AL,#8*/ - temp=FETCH(); - setznp8(AL&temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=5; - break; - - case 0xA9: /*TEST AX,#16*/ - tempw=getword(); - setznp16(AX&tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=5; - break; - - case 0xAA: /*STOSB*/ - writememb(es+DI,AL); - if (flags&D_FLAG) DI--; - else DI++; - cycles-=11; - break; - - case 0xAB: /*STOSW*/ - writememw(es,DI,AX); - if (flags&D_FLAG) DI-=2; - else DI+=2; - cycles-=11; - break; - - case 0xAC: /*LODSB*/ - AL=readmemb(ds+SI); - if (flags&D_FLAG) SI--; - else SI++; - cycles-=16; - break; - - case 0xAD: /*LODSW*/ - AX=readmemw(ds,SI); - if (flags&D_FLAG) SI-=2; - else SI+=2; - cycles-=16; - break; - - case 0xAE: /*SCASB*/ - temp=readmemb(es+DI); - setsub8(AL,temp); - if (flags&D_FLAG) DI--; - else DI++; - cycles-=19; - break; - - case 0xAF: /*SCASW*/ - tempw=readmemw(es,DI); - setsub16(AX,tempw); - if (flags&D_FLAG) DI-=2; - else DI+=2; - cycles-=19; - break; - - case 0xB0: /*MOV AL,#8*/ - AL=FETCH(); - cycles-=4; - break; - - case 0xB1: /*MOV CL,#8*/ - CL=FETCH(); - cycles-=4; - break; - - case 0xB2: /*MOV DL,#8*/ - DL=FETCH(); - cycles-=4; - break; - - case 0xB3: /*MOV BL,#8*/ - BL=FETCH(); - cycles-=4; - break; - - case 0xB4: /*MOV AH,#8*/ - AH=FETCH(); - cycles-=4; - break; - - case 0xB5: /*MOV CH,#8*/ - CH=FETCH(); - cycles-=4; - break; - - case 0xB6: /*MOV DH,#8*/ - DH=FETCH(); - cycles-=4; - break; - - case 0xB7: /*MOV BH,#8*/ - BH=FETCH(); - cycles-=4; - break; - - case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ - case 0xBC: case 0xBD: case 0xBE: case 0xBF: - cpu_state.regs[opcode&7].w=getword(); - cycles-=4; - break; - - case 0xC0: /*RET alias*/ - case 0xC2: /*RET*/ - tempw=getword(); - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - SP+=2+tempw; - cycles-=24; - FETCHCLEAR(); - break; - - case 0xC1: /*RET alias*/ - case 0xC3: /*RET*/ - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - SP+=2; - cycles-=20; - FETCHCLEAR(); - break; - - case 0xC4: /*LES*/ - fetchea(); - cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); - tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); - loadseg(tempw,&_es); - cycles-=24; - break; - - case 0xC5: /*LDS*/ - fetchea(); - cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); - tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); - loadseg(tempw,&_ds); - if (cpu_state.ssegs) oldds=ds; - cycles-=24; - break; - - case 0xC6: /*MOV b,#8*/ - fetchea(); - temp=FETCH(); - seteab(temp); - cycles-=((cpu_mod==3)?4:14); - break; - - case 0xC7: /*MOV w,#16*/ - fetchea(); - tempw=getword(); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:14); - break; - - case 0xC8: /*186+ ENTER*/ - if (is_nec) { - uint16_t offsetw; - int count; - - offsetw = getword(); - - tempw=readmemw(ss,SP); - tempw2=readmemw(ss,(SP-2)&0xFFFF); - tempw3=CS; - tempw4=cpu_state.pc; - - if (cpu_state.ssegs) ss=oldss; - - count=geteaw(); - - if (count > 0) { - while (--count) { - cpu_state.pc=tempw; - loadcs(tempw2); - cycles-=4; - } - writememw(ss,(SP-2)&0xFFFF,tempw3); - writememw(ss,((SP-4)&0xFFFF),tempw4); - cycles-=5; - } - cpu_state.last_ea = SP; - SP-=offsetw; - cycles-=10; - FETCHCLEAR(); - } else { /*RETF alias*/ - tempw=getword(); - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - SP+=4; - SP+=tempw; - cycles-=33; - FETCHCLEAR(); + case 0x99: /*CWD*/ + wait(4, 0); + if (!top_bit(AX, 16)) + DX = 0; + else { + wait(1, 0); + DX = 0xffff; } break; - - case 0xC9: - if (is_nec) { /*186+ LEAVE*/ - if (cpu_state.ssegs) ss=oldss; - cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); - cpu_state.last_ea = SP; - cycles-=4; - } else { /*RETF alias*/ - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - SP+=4; - cycles-=34; - FETCHCLEAR(); - } + case 0x9A: /*CALL FAR*/ + wait(1, 0); + new_ip = pfq_fetchw(); + wait(1, 0); + new_cs = pfq_fetchw(); + access(31, 16); + push(CS); + access(60, 16); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + cpu_state.pc = new_ip; + access(32, 16); + push(cpu_state.oldpc); + pfq_clear(); break; - - case 0xCA: /*RETF*/ - tempw=getword(); - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - SP+=4; - SP+=tempw; - cycles-=33; - FETCHCLEAR(); - break; - - case 0xCB: /*RETF*/ - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - SP+=4; - cycles-=34; - FETCHCLEAR(); - break; - - case 0xCC: /*INT 3*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags|0xF000); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); - SP-=6; - addr=3<<2; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - FETCHCLEAR(); - cycles-=72; - break; - - case 0xCD: /*INT*/ - lastpc=cpu_state.pc; - lastcs=CS; - temp=FETCH(); - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags|0xF000); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); - flags&=~T_FLAG; - SP-=6; - addr=temp<<2; - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - FETCHCLEAR(); - cycles-=71; - break; - - case 0xCF: /*IRET*/ - if (cpu_state.ssegs) ss=oldss; - tempw=CS; - tempw2=cpu_state.pc; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,((SP+2)&0xFFFF))); - flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; - SP+=6; - cycles-=44; - FETCHCLEAR(); - nmi_enable = 1; - break; - - case 0xD0: - fetchea(); - temp=geteab(); - switch (rmdat&0x38) { - case 0x00: /*ROL b,1*/ - if (temp&0x80) - flags|=C_FLAG; - else - flags&=~C_FLAG; - temp<<=1; - if (flags&C_FLAG) temp|=1; - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) - flags|=V_FLAG; - else - flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x08: /*ROR b,1*/ - if (temp&1) - flags|=C_FLAG; - else - flags&=~C_FLAG; - temp>>=1; - if (flags&C_FLAG) temp|=0x80; - seteab(temp); - if ((temp^(temp>>1))&0x40) - flags|=V_FLAG; - else - flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x10: /*RCL b,1*/ - temp2=flags&C_FLAG; - if (temp&0x80) - flags|=C_FLAG; - else - flags&=~C_FLAG; - temp<<=1; - if (temp2) temp|=1; - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) - flags|=V_FLAG; - else - flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x18: /*RCR b,1*/ - temp2=flags&C_FLAG; - if (temp&1) - flags|=C_FLAG; - else - flags&=~C_FLAG; - temp>>=1; - if (temp2) temp|=0x80; - seteab(temp); - if ((temp^(temp>>1))&0x40) - flags|=V_FLAG; - else - flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x20: case 0x30: /*SHL b,1*/ - if (temp&0x80) - flags|=C_FLAG; - else - flags&=~C_FLAG; - if ((temp^(temp<<1))&0x80) - flags|=V_FLAG; - else - flags&=~V_FLAG; - temp<<=1; - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; - - case 0x28: /*SHR b,1*/ - if (temp&1) - flags|=C_FLAG; - else - flags&=~C_FLAG; - if (temp&0x80) - flags|=V_FLAG; - else - flags&=~V_FLAG; - temp>>=1; - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; - - case 0x38: /*SAR b,1*/ - if (temp&1) - flags|=C_FLAG; - else - flags&=~C_FLAG; - temp>>=1; - if (temp&0x40) temp|=0x80; - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - flags&=~V_FLAG; - break; - } - break; - - case 0xD1: - fetchea(); - tempw=geteaw(); - switch (rmdat&0x38) { - case 0x00: /*ROL w,1*/ - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw<<=1; - if (flags&C_FLAG) tempw|=1; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x08: /*ROR w,1*/ - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=1; - if (flags&C_FLAG) tempw|=0x8000; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x10: /*RCL w,1*/ - temp2=flags&C_FLAG; - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw<<=1; - if (temp2) tempw|=1; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x18: /*RCR w,1*/ - temp2=flags&C_FLAG; - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=1; - if (temp2) tempw|=0x8000; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?2:23); - break; - - case 0x20: case 0x30: /*SHL w,1*/ - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; - else flags&=~V_FLAG; - tempw<<=1; - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; - - case 0x28: /*SHR w,1*/ - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - if (tempw&0x8000) flags|=V_FLAG; - else flags&=~V_FLAG; - tempw>>=1; - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; - - case 0x38: /*SAR w,1*/ - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=1; - if (tempw&0x4000) tempw|=0x8000; - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - flags&=~V_FLAG; - break; - } - break; - - case 0xD2: - fetchea(); - temp=geteab(); - c=CL; - if (!c) break; - switch (rmdat&0x38) { - case 0x00: /*ROL b,CL*/ - temp2=(temp&0x80)?1:0; - if (!c) { - cycles-=((cpu_mod==3)?8:28); - break; - } - while (c>0) { - temp2=(temp&0x80)?1:0; - temp=(temp<<1)|temp2; - c--; - cycles-=4; - } - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x08: /*ROR b,CL*/ - temp2=temp&1; - if (!c) { - cycles-=((cpu_mod==3)?8:28); - break; - } - while (c>0) { - temp2=temp&1; - temp>>=1; - if (temp2) temp|=0x80; - c--; - cycles-=4; - } - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x10: /*RCL b,CL*/ - while (c>0) { - templ=flags&C_FLAG; - temp2=temp&0x80; - temp<<=1; - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - if (templ) temp|=1; - c--; - cycles-=4; - } - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x18: /*RCR b,CL*/ - while (c>0) { - templ=flags&C_FLAG; - temp2=temp&1; - temp>>=1; - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - if (templ) temp|=0x80; - c--; - cycles-=4; - } - seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x20: case 0x30: /*SHL b,CL*/ - if (c > 8) { - temp = 0; - flags &= ~C_FLAG; - } else { - if ((temp<<(c-1))&0x80) flags|=C_FLAG; - else flags&=~C_FLAG; - temp<<=c; - } - seteab(temp); - setznp8(temp); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - - case 0x28: /*SHR b,CL*/ - if (c > 8) { - temp = 0; - flags &= ~C_FLAG; - } else { - if ((temp>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - temp>>=c; - } - seteab(temp); - setznp8(temp); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - - case 0x38: /*SAR b,CL*/ - if ((temp>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - while (c>0) { - temp>>=1; - if (temp&0x40) temp|=0x80; - c--; - cycles-=4; - } - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - } - break; - - case 0xD3: - fetchea(); - tempw=geteaw(); - c=CL; - if (!c) break; - switch (rmdat&0x38) { - case 0x00: /*ROL w,CL*/ - while (c>0) { - temp=(tempw&0x8000)?1:0; - tempw=(tempw<<1)|temp; - c--; - cycles-=4; - } - if (temp) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x08: /*ROR w,CL*/ - tempw2=(tempw&1)?0x8000:0; - if (!c) { - cycles-=((cpu_mod==3)?8:28); - break; - } - while (c>0) { - tempw2=(tempw&1)?0x8000:0; - tempw=(tempw>>1)|tempw2; - c--; - cycles-=4; - } - if (tempw2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x10: /*RCL w,CL*/ - while (c>0) { - templ=flags&C_FLAG; - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw=(tempw<<1)|templ; - c--; - cycles-=4; - } - if (temp) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x18: /*RCR w,CL*/ - templ=flags&C_FLAG; - tempw2=(templ&1)?0x8000:0; - if (!c) { - cycles-=((cpu_mod==3)?8:28); - break; - } - while (c>0) { - templ=flags&C_FLAG; - tempw2=(templ&1)?0x8000:0; - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw=(tempw>>1)|tempw2; - c--; - cycles-=4; - } - if (tempw2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - - case 0x20: case 0x30: /*SHL w,CL*/ - if (c>16) { - tempw=0; - flags&=~C_FLAG; - } else { - if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw<<=c; - } - seteaw(tempw); - setznp16(tempw); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - - case 0x28: /*SHR w,CL*/ - if (c > 16) { - tempw = 0; - flags &= ~C_FLAG; - } else { - if ((tempw>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=c; - } - seteaw(tempw); - setznp16(tempw); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - - case 0x38: /*SAR w,CL*/ - tempw2=tempw&0x8000; - if ((tempw>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - while (c>0) { - tempw=(tempw>>1)|tempw2; - c--; - cycles-=4; - } - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - } - break; - - case 0xD4: /*AAM*/ - tempws=FETCH(); - AH=AL/tempws; - AL%=tempws; - setznp16(AX); - cycles-=83; - break; - - case 0xD5: /*AAD*/ - tempws=FETCH(); - AL=(AH*tempws)+AL; - AH=0; - setznp16(AX); - cycles-=60; - break; - - case 0xD6: /*SETALC*/ - AL = (flags & C_FLAG) ? 0xff : 0; + case 0x9B: /*WAIT*/ cycles -= 4; break; - - case 0xD7: /*XLAT*/ - addr=BX+AL; - cpu_state.last_ea = addr; - AL=readmemb(ds+addr); - cycles-=11; + case 0x9C: /*PUSHF*/ + access(33, 16); + push((flags & 0x0fd7) | 0xf000); + break; + case 0x9D: /*POPF*/ + access(25, 16); + flags = pop() | 2; + wait(1, 0); + break; + case 0x9E: /*SAHF*/ + wait(1, 0); + flags = (flags & 0xff02) | AH; + wait(2, 0); + break; + case 0x9F: /*LAHF*/ + wait(1, 0); + AH = flags & 0xd7; break; - case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ - case 0xDC: case 0xDE: case 0xDF: case 0xD8: - fetchea(); - geteab(); + case 0xA0: case 0xA1: + /* MOV A, [iw] */ + bits = 8 << (opcode & 1); + wait(1, 0); + addr = pfq_fetchw(); + access(1, bits); + if (opcode & 1) + AX = readmemw((ovr_seg ? *ovr_seg : ds), addr); + else + AL = readmemb((ovr_seg ? *ovr_seg : ds) + addr); + wait(1, 0); + break; + case 0xA2: case 0xA3: + /* MOV [iw], A */ + bits = 8 << (opcode & 1); + wait(1, 0); + addr = pfq_fetchw(); + access(7, bits); + if (opcode & 1) + writememw((ovr_seg ? *ovr_seg : ds), addr, AX); + else + writememb((ovr_seg ? *ovr_seg : ds) + addr, AL); break; - case 0xE0: /*LOOPNE*/ - offset=(int8_t)FETCH(); - CX--; - if (CX && !(flags&Z_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); + case 0xA4: case 0xA5: /* MOVS */ + case 0xAC: case 0xAD: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1 /*2*/, 0); + if ((opcode & 8) == 0 && in_rep != 0) + wait(1, 0); } - cycles-=6; - break; - - case 0xE1: /*LOOPE*/ - offset=(int8_t)FETCH(); - CX--; - if (CX && (flags&Z_FLAG)) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); + if (rep_action(&completed, &repeating, in_rep, bits)) { + wait(1, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; } - cycles-=6; - break; - - case 0xE2: /*LOOP*/ - offset=(int8_t)FETCH(); - CX--; - if (CX) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=5; - break; - - case 0xE3: /*JCXZ*/ - offset=(int8_t)FETCH(); - if (!CX) { - cpu_state.pc+=offset; - cycles-=12; - FETCHCLEAR(); - } - cycles-=6; - break; - - case 0xE4: /*IN AL*/ - temp=FETCH(); - AL=inb(temp); - cycles-=14; - break; - - case 0xE5: /*IN AX*/ - temp=FETCH(); - AL=inb(temp); - AH=inb(temp+1); - cycles-=14; - break; - - case 0xE6: /*OUT AL*/ - temp=FETCH(); - outb(temp,AL); - cycles-=14; - break; - - case 0xE7: /*OUT AX*/ - temp=FETCH(); - outb(temp,AL); - outb(temp+1,AH); - cycles-=14; - break; - - case 0xE8: /*CALL rel 16*/ - tempw=getword(); - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); - SP-=2; - cpu_state.last_ea = SP; - cpu_state.pc+=tempw; - cycles-=23; - FETCHCLEAR(); - break; - - case 0xE9: /*JMP rel 16*/ - tempw = getword(); - cpu_state.pc += tempw; - cycles-=15; - FETCHCLEAR(); - break; - - case 0xEA: /*JMP far*/ - addr=getword(); - tempw=getword(); - cpu_state.pc=addr; - loadcs(tempw); - cycles-=15; - FETCHCLEAR(); - break; - - case 0xEB: /*JMP rel*/ - offset=(int8_t)FETCH(); - cpu_state.pc+=offset; - cycles-=15; - FETCHCLEAR(); - break; - - case 0xEC: /*IN AL,DX*/ - AL=inb(DX); - cycles-=12; - break; - case 0xED: /*IN AX,DX*/ - AL=inb(DX); - AH=inb(DX+1); - cycles-=12; - break; - - case 0xEE: /*OUT DX,AL*/ - outb(DX,AL); - cycles-=12; - break; - case 0xEF: /*OUT DX,AX*/ - outb(DX,AL); - outb(DX+1,AH); - cycles-=12; - break; - - case 0xF0: /*LOCK*/ - case 0xF1: /*LOCK alias*/ - cycles-=4; - break; - - case 0xF2: /*REPNE*/ - rep(0); - break; - - case 0xF3: /*REPE*/ - rep(1); - break; - - case 0xF4: /*HLT*/ - inhlt=1; - cpu_state.pc--; - FETCHCLEAR(); - cycles-=2; - break; - - case 0xF5: /*CMC*/ - flags^=C_FLAG; - cycles-=2; - break; - - case 0xF6: - fetchea(); - temp=geteab(); - switch (rmdat&0x38) { - case 0x00: /*TEST b,#8*/ - case 0x08: - temp2=FETCH(); - temp&=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?5:11); - break; - - case 0x10: /*NOT b*/ - temp=~temp; - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x18: /*NEG b*/ - setsub8(0,temp); - temp=0-temp; - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x20: /*MUL AL,b*/ - setznp8(AL); - AX=AL*temp; - if (AX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - if (AH) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles-=70; - break; - - case 0x28: /*IMUL AL,b*/ - setznp8(AL); - tempws=(int)((int8_t)AL)*(int)((int8_t)temp); - AX=tempws&0xFFFF; - if (AX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - if (AH) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles-=80; - break; - - case 0x30: /*DIV AL,b*/ - tempw=AX; - if (temp) { - tempw2=tempw%temp; - AH=tempw2 & 0xff; - tempw/=temp; - AL=tempw&0xFF; - } else { - ERRLOG("CPU: DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=80; - break; - - case 0x38: /*IDIV AL,b*/ - tempws=(int)AX; - if (temp) { - tempw2=tempws%(int)((int8_t)temp); - AH=tempw2&0xFF; - tempws/=(int)((int8_t)temp); - AL=tempws&0xFF; - } else { - ERRLOG("CPU: IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=101; - break; - } - break; - - case 0xF7: - fetchea(); - tempw=geteaw(); - switch (rmdat&0x38) { - case 0x00: /*TEST w*/ - case 0x08: - tempw2=getword(); - setznp16(tempw&tempw2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?5:11); - break; - - case 0x10: /*NOT w*/ - seteaw(~tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x18: /*NEG w*/ - setsub16(0,tempw); - tempw=0-tempw; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - - case 0x20: /*MUL AX,w*/ - setznp16(AX); - templ=AX*tempw; - AX=templ&0xFFFF; - DX=templ>>16; - if (AX|DX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - if (DX) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles-=118; - break; - - case 0x28: /*IMUL AX,w*/ - setznp16(AX); - tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); - if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - AX=tempws&0xFFFF; - tempws=(uint16_t)(tempws>>16); - DX=tempws&0xFFFF; - if (AX|DX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - cycles-=128; - break; - - case 0x30: /*DIV AX,w*/ - templ=(DX<<16)|AX; - if (tempw) { - tempw2=templ%tempw; - DX=tempw2; - templ/=tempw; - AX=templ&0xFFFF; - } else { - ERRLOG("CPU: DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=144; - break; - - case 0x38: /*IDIV AX,w*/ - tempws=(int)((DX<<16)|AX); - if (tempw) { - tempw2=tempws%(int)((int16_t)tempw); - DX=tempw2; - tempws/=(int)((int16_t)tempw); - AX=tempws&0xFFFF; - } else { - ERRLOG("CPU: IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=165; - break; - } - break; - - case 0xF8: /*CLC*/ - flags&=~C_FLAG; - cycles-=2; - break; - - case 0xF9: /*STC*/ - flags|=C_FLAG; - cycles-=2; - break; - - case 0xFA: /*CLI*/ - flags&=~I_FLAG; - cycles-=3; - break; - - case 0xFB: /*STI*/ - flags|=I_FLAG; - cycles-=2; - break; - - case 0xFC: /*CLD*/ - flags&=~D_FLAG; - cycles-=2; - break; - - case 0xFD: /*STD*/ - flags|=D_FLAG; - cycles-=2; - break; - - case 0xFE: /*INC/DEC b*/ - fetchea(); - temp=geteab(); - flags&=~V_FLAG; - if (rmdat&0x38) { - setsub8nc(temp,1); - temp2=temp-1; - if ((temp&0x80) && !(temp2&0x80)) - flags|=V_FLAG; + if (in_rep != 0 && (opcode & 8) != 0) + wait(1, 0); + access(20, bits); + lods(bits); + if ((opcode & 8) == 0) { + access(27, bits); + stos(bits); } else { - setadd8nc(temp,1); - temp2=temp+1; - if ((temp2&0x80) && !(temp&0x80)) - flags|=V_FLAG; + if (opcode & 1) + AX = cpu_data; + else + AL = cpu_data; + if (in_rep != 0) + wait(2, 0); } - seteab(temp2); - cycles-=((cpu_mod==3)?3:23); + if (in_rep == 0) { + wait(3, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + repeating = 1; + timer_end_period(cycles * xt_cpu_multi); + goto opcodestart; + + case 0xA6: case 0xA7: /* CMPS */ + case 0xAE: case 0xAF: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) + wait(1, 0); + if (rep_action(&completed, &repeating, in_rep, bits)) { + wait(2, 0); + break; + } + if (in_rep != 0) + wait(1, 0); + if (opcode & 1) + cpu_dest = AX; + else + cpu_dest = AL; + if ((opcode & 8) == 0) { + access(21, bits); + lods(bits); + wait(1, 0); + cpu_dest = cpu_data; + } + access(2, bits); + if (opcode & 1) + cpu_data = readmemw(es, DI); + else + cpu_data = readmemb(es + DI); + if (flags & D_FLAG) + DI -= (bits >> 3); + else + DI += (bits >> 3); + cpu_src = cpu_data; + sub(bits); + wait(2, 0); + if (in_rep == 0) { + wait(3, 0); + break; + } + if ((!!(flags & Z_FLAG)) == (in_rep == 1)) { + wait(4, 0); + break; + } + repeating = 1; + timer_end_period(cycles * xt_cpu_multi); + goto opcodestart; + + case 0xA8: case 0xA9: + /* TEST A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + if (opcode & 1) { + cpu_data = pfq_fetchw(); + test(bits, AX, cpu_data); + } else { + cpu_data = pfq_fetchb(); + test(bits, AL, cpu_data); + } + wait(1, 0); break; - case 0xFF: - fetchea(); - switch (rmdat&0x38) { - case 0x00: /*INC w*/ - tempw=geteaw(); - setadd16nc(tempw,1); - seteaw(tempw+1); - cycles-=((cpu_mod==3)?3:23); - break; + case 0xAA: case 0xAB: /* STOS */ + bits = 8 << (opcode & 1); + if (!repeating) { + if (opcode & 1) + wait(1, 0); + if (in_rep != 0) + wait(1, 0); + } + if (rep_action(&completed, &repeating, in_rep, bits)) { + wait(1, 0); + break; + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait(3, 0); + break; + } + repeating = 1; + timer_end_period(cycles * xt_cpu_multi); + goto opcodestart; - case 0x08: /*DEC w*/ - tempw=geteaw(); - setsub16nc(tempw,1); - seteaw(tempw-1); - cycles-=((cpu_mod==3)?3:23); - break; + case 0xB0: case 0xB1: case 0xB2: case 0xB3: /*MOV cpu_reg,#8*/ + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + wait(1, 0); + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + wait(1, 0); + break; - case 0x10: /*CALL*/ - tempw=geteaw(); - if (cpu_state.ssegs) ss=oldss; - writememw(ss,(SP-2)&0xFFFF,cpu_state.pc); - SP-=2; - cpu_state.last_ea = SP; - cpu_state.pc=tempw; - cycles-=((cpu_mod==3)?20:29); - FETCHCLEAR(); - break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + wait(1, 0); + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + wait(1, 0); + break; - case 0x18: /*CALL far*/ - tempw=readmemw(easeg,cpu_state.eaaddr); - tempw2=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); - tempw3=CS; - tempw4=cpu_state.pc; - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=tempw; - loadcs(tempw2); - writememw(ss,(SP-2)&0xFFFF,tempw3); - writememw(ss,((SP-4)&0xFFFF),tempw4); - SP-=4; - cpu_state.last_ea = SP; - cycles-=53; - FETCHCLEAR(); - break; + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + /* RET */ + bits = 8 + (opcode & 0x08); + if ((opcode & 9) != 1) + wait(1, 0); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); + wait(1, 0); + } + if ((opcode & 9) == 9) + wait(1, 0); + access(26, bits); + new_ip = pop(); + wait(2, 0); + if ((opcode & 8) == 0) + new_cs = CS; + else { + access(42, bits); + new_cs = pop(); + if (opcode & 1) + wait(1, 0); + } + if (!(opcode & 1)) { + SP += cpu_src; + wait(1, 0); + } + loadcs(new_cs); + access(72, bits); + cpu_state.pc = new_ip; + pfq_clear(); + break; - case 0x20: /*JMP*/ - cpu_state.pc=geteaw(); - cycles-=((cpu_mod==3)?11:18); - FETCHCLEAR(); - break; + case 0xC4: case 0xC5: + /* LsS rw, rmd */ + do_mod_rm(); + bits = 16; + access(52, bits); + cpu_state.regs[cpu_reg].w = readmemw(easeg, cpu_state.eaaddr); + tempw = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xFFFF); + loadseg(tempw, (opcode & 0x01) ? &_ds : &_es); + wait(1, 0); + noint = 1; + break; - case 0x28: /*JMP far*/ - cpu_state.pc=readmemw(easeg,cpu_state.eaaddr); - loadcs(readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF)); - cycles-=24; - FETCHCLEAR(); - break; + case 0xC6: case 0xC7: + /* MOV rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + if (opcode & 1) + cpu_data = pfq_fetchw(); + else + cpu_data = pfq_fetchb(); + if (cpu_mod == 3) + wait(1, 0); + access(16, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + break; - case 0x30: /*PUSH w*/ - case 0x38: /*PUSH w alias, reported by reenigne*/ - tempw=geteaw(); - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),tempw); - SP-=2; - cpu_state.last_ea = SP; - cycles-=((cpu_mod==3)?15:24); + case 0xCC: /*INT 3*/ + interrupt(3, 1); + break; + case 0xCD: /*INT*/ + wait(1, 0); + interrupt(pfq_fetchb(), 1); + break; + case 0xCE: /*INTO*/ + wait(3, 0); + if (flags & V_FLAG) { + wait(2, 0); + interrupt(4, 1); + } + break; + + case 0xCF: /*IRET*/ + access(43, 8); + new_ip = pop(); + wait(3, 0); + access(44, 8); + new_cs = pop(); + loadcs(new_cs); + access(62, 8); + cpu_state.pc = new_ip; + access(45, 8); + flags = pop() | 2; + wait(5, 0); + noint = 1; + nmi_enable = 1; + pfq_clear(); + break; + + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(53, bits); + if (opcode & 1) + cpu_data = geteaw(); + else + cpu_data = geteab(); + if ((opcode & 2) == 0) { + cpu_src = 1; + wait((cpu_mod != 3) ? 4 : 0, 0); + } else { + cpu_src = CL; + wait((cpu_mod != 3) ? 9 : 6, 0); + } + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = flags & C_FLAG; + switch (rmdat & 0x38) { + case 0x00: /* ROL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + cpu_data |= ((flags & C_FLAG) ? 1 : 0); + set_of_rotate(bits); + break; + case 0x08: /* ROR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (flags & C_FLAG) + cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); + set_of_rotate(bits); + break; + case 0x10: /* RCL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); + set_of_rotate(bits); + break; + case 0x18: /* RCR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (oldc) + cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); + set_cf((cpu_dest & 1) != 0); + set_of_rotate(bits); + break; + case 0x20: /* SHL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + set_of_rotate(bits); + set_pzs(bits); + break; + case 0x28: /* SHR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + case 0x30: /* SETMO - undocumented? */ + bitwise(bits, 0xffff); + set_cf(0); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x38: /* SAR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (!(opcode & 1)) + cpu_data |= (cpu_dest & 0x80); + else + cpu_data |= (cpu_dest & 0x8000); + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + } + if ((opcode & 2) != 0) + wait(4, 0); + --cpu_src; + } + access(17, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + break; + + case 0xD4: /*AAM*/ + wait(1, 0); + cpu_src = pfq_fetchb(); + if (div(AL, 0)) + set_pzs(16); + break; + case 0xD5: /*AAD*/ + wait(1, 0); + mul(pfq_fetchb(), AH); + AL += cpu_data; + AH = 0x00; + set_pzs(16); + break; + case 0xD6: /*SALC*/ + wait(1, 0); + AL = (flags & C_FLAG) ? 0xff : 0x00; + wait(1, 0); + break; + case 0xD7: /*XLATB*/ + addr = BX + AL; + cpu_state.last_ea = addr; + access(4, 8); + AL = readmemb((ovr_seg ? *ovr_seg : ds) + addr); + wait(1, 0); + break; + + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDD: case 0xDC: case 0xDE: case 0xDF: + /* esc i, r, rm */ + do_mod_rm(); + access(54, 16); + geteaw(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0xE0: case 0xE1: case 0xE2: case 0xE3: + /* LOOP */ + wait(3, 0); + cpu_data = pfq_fetchb(); + if (opcode != 0xe2) + wait(1, 0); + if (opcode != 0xe3) { + --CX; + oldc = (CX != 0); + switch (opcode) { + case 0xE0: + if (flags & Z_FLAG) + oldc = 0; + break; + case 0xE1: + if (!(flags & Z_FLAG)) + oldc = 0; + break; + } + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + break; + + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) + wait(1, 0); + if ((opcode & 8) == 0) + cpu_data = pfq_fetchb(); + else + cpu_data = DX; + if ((opcode & 2) == 0) { + access(3, bits); + if ((opcode & 1) && is8086) { + AX = inw(cpu_data); + wait(4, 1); /* I/O access and wait state. */ + } else { + AL = inb(cpu_data); + if (opcode & 1) + AH = inb(temp + 1); + wait(bits >> 1, 1); /* I/O access. */ + } + wait(1, 0); + } else { + if ((opcode & 8) == 0) + access(8, bits); + else + access(9, bits); + if ((opcode & 1) && is8086) { + outw(cpu_data, AX); + wait(4, 1); + } else { + outb(cpu_data, AL); + if (opcode & 1) + outb(cpu_data + 1, AH); + wait(bits >> 1, 1); /* I/O access. */ + } + } + break; + + case 0xE8: /*CALL rel 16*/ + wait(1, 0); + cpu_state.oldpc = jump_near(); + access(34, 8); + push(cpu_state.oldpc); + pfq_clear(); + break; + case 0xE9: /*JMP rel 16*/ + wait(1, 0); + jump_near(); + break; + case 0xEA: /*JMP far*/ + wait(1, 0); + addr = pfq_fetchw(); + wait(1, 0); + tempw = pfq_fetchw(); + loadcs(tempw); + access(70, 8); + cpu_state.pc = addr; + pfq_clear(); + break; + case 0xEB: /*JMP rel*/ + wait(1, 0); + cpu_data = (int8_t) pfq_fetchb(); + jump_short(); + wait(1, 0); + pfq_clear(); + break; + + case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait(1, 0); + goto opcodestart; + + case 0xF2: /*REPNE*/ + case 0xF3: /*REPE*/ + wait(1, 0); + in_rep = (opcode == 0xf2 ? 1 : 2); + repeating = 0; + completed = 0; + goto opcodestart; + + case 0xF4: /*HLT*/ + halt = 1; + pfq_clear(); + wait(2, 0); + break; + case 0xF5: /*CMC*/ + wait(1, 0); + flags ^= C_FLAG; + break; + + case 0xF6: case 0xF7: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(55, bits); + if (opcode & 1) + cpu_data = geteaw(); + else + cpu_data = geteab(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: + /* TEST */ + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + if (opcode & 1) + cpu_src = pfq_fetchw(); + else + cpu_src = pfq_fetchb(); + wait(1, 0); + test(bits, cpu_data, cpu_src); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x10: /* NOT */ + case 0x18: /* NEG */ + wait(2, 0); + if ((rmdat & 0x38) == 0x10) + cpu_data = ~cpu_data; + else { + cpu_src = cpu_data; + cpu_dest = 0; + sub(bits); + } + access(18, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + break; + case 0x20: /* MUL */ + case 0x28: /* IMUL */ + wait(1, 0); + if (opcode & 1) { + mul(AX, cpu_data); + AX = cpu_data; + DX = cpu_dest; + cpu_data |= DX; + set_co_mul((DX != ((AX & 0x8000) == 0) || ((rmdat & 0x38) == 0x20) ? 0 : 0xffff)); + } else { + mul(AL, cpu_data); + AL = (uint8_t) cpu_data; + AH = (uint8_t) cpu_dest; + set_co_mul(AH != (((AL & 0x80) == 0) || ((rmdat & 0x38) == 0x20) ? 0 : 0xff)); + } + set_zf(bits); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x30: /* DIV */ + case 0x38: /* IDIV */ + if (cpu_mod != 3) + wait(1, 0); + cpu_src = cpu_data; + if (div(AL, AH)) + wait(1, 0); + break; + } + break; + + case 0xF8: case 0xF9: + /* CLCSTC */ + wait(1, 0); + set_cf(opcode & 1); + break; + case 0xFA: case 0xFB: + /* CLISTI */ + wait(1, 0); + set_if(opcode & 1); + break; + case 0xFC: case 0xFD: + /* CLDSTD */ + wait(1, 0); + set_df(opcode & 1); + break; + + case 0xFE: case 0xFF: + /* misc */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(56, bits); + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + cpu_dest = cpu_data; + cpu_src = 1; + if ((rmdat & 0x38) == 0x00) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(bits); + wait(2, 0); + access(19, bits); + if (opcode & 1) + seteaw(cpu_data); + else + seteab(cpu_data); + break; + case 0x10: /* CALL rm */ + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } + access(63, bits); + wait(5, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(1, 0); /* Wait. */ + cpu_state.oldpc = cpu_state.pc; + cpu_state.pc = cpu_data; + wait(2, 0); + access(35, bits); + push(cpu_state.oldpc); + pfq_clear(); + break; + case 0x18: /* CALL rmd */ + new_ip = cpu_data; + access(58, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + access(36, bits); + push(CS); + access(64, bits); + wait(4, 0); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + cpu_state.pc = new_ip; + access(37, bits); + push(cpu_state.oldpc); + pfq_clear(); + break; + case 0x20: /* JMP rm */ + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } + access(65, bits); + cpu_state.pc = cpu_data; + pfq_clear(); + break; + case 0x28: /* JMP rmd */ + new_ip = cpu_data; + access(59, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + loadcs(new_cs); + access(66, bits); + cpu_state.pc = new_ip; + pfq_clear(); + break; + case 0x30: /* PUSH rm */ + case 0x38: + if (cpu_mod != 3) + wait(1, 0); + access(38, bits); + if ((cpu_mod == 3) && (cpu_rm == 4)) + push(cpu_data - 2); + else + push(cpu_data); break; } break; default: - FETCH(); - cycles-=8; + ERRLOG("CPU: illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait(8, 0); break; } - cpu_state.pc&=0xFFFF; - if (cpu_state.ssegs) { - ds=oldds; - ss=oldss; - cpu_state.ssegs=0; - } - - FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); - if ((cycdiff-cycles) * Miran Grca, * Fred N. van Kempen, * + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,9 +50,12 @@ CPU cpus_8088[] = { {"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/9.54", CPU_8088, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, +#ifdef _DEBUG + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, +#endif {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} }; diff --git a/src/cpu/x86.h b/src/cpu/x86.h index f3aca86..254c577 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -62,7 +62,6 @@ extern int skipnextprint; extern int inhlt; extern uint8_t opcode; -extern int noint; extern uint16_t lastcs,lastpc; extern int timetolive,keyboardtimer; @@ -103,8 +102,6 @@ extern uint16_t *mod1add[2][8]; extern uint32_t *mod1seg[8]; -#define IRQTEST ((flags&I_FLAG) && (pic.pend&~pic.mask) && !noint) - extern int cgate32; diff --git a/src/devices/ports/parallel.c b/src/devices/ports/parallel.c index 9e4ac5c..4edbe0f 100644 --- a/src/devices/ports/parallel.c +++ b/src/devices/ports/parallel.c @@ -8,13 +8,13 @@ * * Implementation of the "LPT" style parallel ports. * - * Version: @(#)parallel.c 1.0.14 2018/11/11 + * Version: @(#)parallel.c 1.0.15 2019/01/03 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. * @@ -103,13 +103,16 @@ parallel_write(uint16_t port, uint8_t val, void *priv) DBGLOG(2, "PARALLEL: write(%04X, %02X)\n", port, val); switch (port & 3) { - case 0: + case 0: /* data */ if (dev->dev_ts != NULL) dev->dev_ts->write_data(val, dev->dev_ps); dev->dat = val; break; - case 2: + case 1: /* status */ + break; + + case 2: /* control */ if (dev->dev_ts != NULL) dev->dev_ts->write_ctrl(val, dev->dev_ps); dev->ctrl = val; @@ -126,18 +129,25 @@ parallel_read(uint16_t port, void *priv) uint8_t ret = 0xff; switch (port & 3) { - case 0: - ret = dev->dat; + case 0: /* data */ + if (dev->dev_ts != NULL) + ret = dev->dev_ts->read_data(dev->dev_ps); + else + ret = dev->dat; break; - case 1: + case 1: /* status */ if (dev->dev_ts != NULL) ret = dev->dev_ts->read_status(dev->dev_ps); - else ret = 0x00; + else + ret = 0x00; break; - case 2: - ret = dev->ctrl; + case 2: /* control */ + if (dev->dev_ts != NULL) + ret = dev->dev_ts->read_ctrl(dev->dev_ps); + else + ret = dev->ctrl; break; } @@ -202,7 +212,7 @@ parallel_close(void *priv) const device_t parallel_1_device = { - "LPT1:", + "LPT1", 0, 0, parallel_init, parallel_close, NULL, @@ -212,7 +222,7 @@ const device_t parallel_1_device = { const device_t parallel_2_device = { - "LPT2:", + "LPT2", 0, 1, parallel_init, parallel_close, NULL, @@ -222,7 +232,7 @@ const device_t parallel_2_device = { const device_t parallel_3_device = { - "LPT3:", + "LPT3", 0, 2, parallel_init, parallel_close, NULL, diff --git a/src/devices/ports/parallel_dev.c b/src/devices/ports/parallel_dev.c index a31e1b5..d074af8 100644 --- a/src/devices/ports/parallel_dev.c +++ b/src/devices/ports/parallel_dev.c @@ -8,11 +8,11 @@ * * Implementation of the parallel-port-attached devices. * - * Version: @(#)parallel_dev.c 1.0.9 2018/10/06 + * Version: @(#)parallel_dev.c 1.0.10 2019/01/03 * * Author: Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. + * Copyright 2018,2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the diff --git a/src/devices/ports/parallel_dev.h b/src/devices/ports/parallel_dev.h index cfceb29..2d60560 100644 --- a/src/devices/ports/parallel_dev.h +++ b/src/devices/ports/parallel_dev.h @@ -8,11 +8,11 @@ * * Definitions for the parallel port-attached devices. * - * Version: @(#)parallel_dev.h 1.0.4 2018/09/03 + * Version: @(#)parallel_dev.h 1.0.5 2019/01/03 * * Author: Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. + * Copyright 2018,2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -55,6 +55,8 @@ typedef struct _lpt_device_ { void (*close)(void *priv); void (*write_data)(uint8_t val, void *priv); void (*write_ctrl)(uint8_t val, void *priv); + uint8_t (*read_data)(void *priv); + uint8_t (*read_ctrl)(void *priv); uint8_t (*read_status)(void *priv); } lpt_device_t; diff --git a/src/devices/printer/printer.h b/src/devices/printer/printer.h index 4586ceb..4a6b650 100644 --- a/src/devices/printer/printer.h +++ b/src/devices/printer/printer.h @@ -8,7 +8,7 @@ * * Definitions for the printers module. * - * Version: @(#)printer.h 1.0.3 2018/09/03 + * Version: @(#)printer.h 1.0.4 2018/11/24 * * Author: Fred N. van Kempen, * @@ -48,6 +48,9 @@ # define PRINTER_H +#define PRT_TIMEOUT 500000LL + + #define FONT_FILE_DOTMATRIX L"dotmatrix.ttf" #define FONT_FILE_ROMAN L"roman.ttf" @@ -66,7 +69,7 @@ extern const lpt_device_t lpt_prt_escp_device; #endif -extern const uint16_t *select_codepage(uint16_t num); +extern void select_codepage(uint16_t code, uint16_t *bufp); #endif /*PRINTER_H*/ diff --git a/src/devices/printer/prt_cpmap.c b/src/devices/printer/prt_cpmap.c index ef6fe02..f8bc952 100644 --- a/src/devices/printer/prt_cpmap.c +++ b/src/devices/printer/prt_cpmap.c @@ -8,7 +8,7 @@ * * Various ASCII to Unicode maps, for the various codepages. * - * Version: @(#)prt_cpmap.c 1.0.3 2018/10/20 + * Version: @(#)prt_cpmap.c 1.0.4 2018/11/24 * * Authors: Michael Drüing, * Fred N. van Kempen, @@ -58,7 +58,10 @@ #include "printer.h" -static const uint16_t cp437Map[256] = { +typedef uint16_t cpmap_t[256]; + + +static const cpmap_t cp437Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -93,7 +96,7 @@ static const uint16_t cp437Map[256] = { 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp737Map[256] = { +static const cpmap_t cp737Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -128,7 +131,7 @@ static const uint16_t cp737Map[256] = { 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp775Map[256] = { +static const cpmap_t cp775Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -163,7 +166,7 @@ static const uint16_t cp775Map[256] = { 0x00b0,0x2219,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp850Map[256] = { +static const cpmap_t cp850Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -198,7 +201,7 @@ static const uint16_t cp850Map[256] = { 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp852Map[256] = { +static const cpmap_t cp852Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -233,7 +236,7 @@ static const uint16_t cp852Map[256] = { 0x00b0,0x00a8,0x02d9,0x0171,0x0158,0x0159,0x25a0,0x00a0 }; -static const uint16_t cp855Map[256] = { +static const cpmap_t cp855Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -268,7 +271,7 @@ static const uint16_t cp855Map[256] = { 0x042d,0x0449,0x0429,0x0447,0x0427,0x00a7,0x25a0,0x00a0 }; -static const uint16_t cp857Map[256] = { +static const cpmap_t cp857Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -303,7 +306,7 @@ static const uint16_t cp857Map[256] = { 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp860Map[256] = { +static const cpmap_t cp860Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -338,7 +341,7 @@ static const uint16_t cp860Map[256] = { 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp861Map[256] = { +static const cpmap_t cp861Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -373,7 +376,7 @@ static const uint16_t cp861Map[256] = { 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp862Map[256] = { +static const cpmap_t cp862Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -408,7 +411,7 @@ static const uint16_t cp862Map[256] = { 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp863Map[256] = { +static const cpmap_t cp863Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -443,7 +446,7 @@ static const uint16_t cp863Map[256] = { 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp864Map[256] = { +static const cpmap_t cp864Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -478,7 +481,7 @@ static const uint16_t cp864Map[256] = { 0xfed5,0xfef5,0xfef6,0xfedd,0xfed9,0xfef1,0x25a0,0x00a0 }; -static const uint16_t cp865Map[256] = { +static const cpmap_t cp865Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -513,7 +516,7 @@ static const uint16_t cp865Map[256] = { 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; -static const uint16_t cp866Map[256] = { +static const cpmap_t cp866Map = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, @@ -551,39 +554,46 @@ static const uint16_t cp866Map[256] = { static const struct { uint16_t code; - const uint16_t *map; + const cpmap_t *map; } maps[] = { - { 437, cp437Map }, - { 737, cp737Map }, - { 775, cp775Map }, - { 850, cp850Map }, - { 852, cp852Map }, - { 855, cp855Map }, - { 857, cp857Map }, - { 860, cp860Map }, - { 861, cp861Map }, - { 862, cp862Map }, - { 863, cp863Map }, - { 864, cp864Map }, - { 865, cp865Map }, - { 866, cp866Map }, + { 437, &cp437Map }, + { 737, &cp737Map }, + { 775, &cp775Map }, + { 850, &cp850Map }, + { 852, &cp852Map }, + { 855, &cp855Map }, + { 857, &cp857Map }, + { 860, &cp860Map }, + { 861, &cp861Map }, + { 862, &cp862Map }, + { 863, &cp863Map }, + { 864, &cp864Map }, + { 865, &cp865Map }, + { 866, &cp866Map }, { 0, NULL } }; /* Select a ASCII->Unicode mapping by CP number */ -const uint16_t * -select_codepage(uint16_t code) +void +select_codepage(uint16_t code, uint16_t *bufp) { + const cpmap_t *map; int i; - for (i = 0; maps[i].code != 0; i++) - if (maps[i].code == code) return(maps[i].map); + map = maps[0].map; - if (code == 0) - return(maps[0].map); + for (i = 0; maps[i].code != 0; i++) { + if (maps[i].code == code) { + map = maps[i].map; + break; + } + } - ERRLOG("CPMAP: unsupported code page %i, using CP437...\n", code); + if (code == 0) { + INFO("CPMAP: unsupported code page %i, using CP437...\n", code); + } - return(maps[0].map); + /* Copy the actual map data. */ + memcpy(bufp, map, sizeof(cpmap_t)); } diff --git a/src/devices/printer/prt_escp.c b/src/devices/printer/prt_escp.c index 6a3ac10..5521463 100644 --- a/src/devices/printer/prt_escp.c +++ b/src/devices/printer/prt_escp.c @@ -8,15 +8,15 @@ * * Implementation of the Generic ESC/P Dot-Matrix printer. * - * Version: @(#)prt_escp.c 1.0.5 2018/11/11 + * Version: @(#)prt_escp.c 1.0.6 2019/01/11 * * Authors: Michael Drüing, * Fred N. van Kempen, * * Based on code by Frederic Weymann (originally for DosBox.) * + * Copyright 2018,2019 Fred N. van Kempen. * Copyright 2018 Michael Drüing. - * Copyright 2018 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -64,13 +64,24 @@ #include "../../rom.h" #include "../../plat.h" #include "../../ui/ui.h" -#include "../../png.h" #include "../ports/parallel_dev.h" +#include "../video/video.h" +#include "../../png.h" #include "printer.h" +#define USE_COLOR yes + /* Color values. */ -#define COLOR_BLACK (7 << 5) +#define SET_COLOR(x) (x << 5) +#define COLOR_WHITE 0 /* white 000 */ +#define COLOR_MAGENTA 1 /* magenta* 001 */ +#define COLOR_CYAN 2 /* cyan* 010 */ +#define COLOR_VIOLET 3 /* "violet" 011 */ +#define COLOR_YELLOW 4 /* yellow* 100 */ +#define COLOR_RED 5 /* red 101 */ +#define COLOR_GREEN 6 /* green 110 */ +#define COLOR_BLACK 7 /* black 111 */ /* Default page values (for now.) */ #define PAGE_WIDTH 8.5 /* standard U.S. Letter */ @@ -179,8 +190,8 @@ static const dllimp_t ft_imports[] = { /* Some helper macros. */ #define PARAM16(x) (dev->esc_parms[x+1] * 256 + dev->esc_parms[x]) -#define PIXX (floor(dev->curr_x * dev->dpi + 0.5)) -#define PIXY (floor(dev->curr_y * dev->dpi + 0.5)) +#define PIXX ((unsigned)floor(dev->curr_x * dev->dpi + 0.5)) +#define PIXY ((unsigned)floor(dev->curr_y * dev->dpi + 0.5)) typedef struct { @@ -198,7 +209,7 @@ typedef struct { typedef struct { const char *name; - /* page data (TODO: make configurable) */ + /* Page data (TODO: make configurable.) */ double page_width, /* all in inches */ page_height, left_margin, @@ -212,18 +223,18 @@ typedef struct { uint8_t color; char pad; - /* font data */ + /* Font data. */ double actual_cpi; /* actual cpi as with current font */ double linespacing; /* in inch */ double hmi; /* hor. motion index (inch); overrides CPI */ - /* tabstops */ + /* Tab stops. */ double horizontal_tabs[32]; double vertical_tabs[16]; - int16_t num_horizontal_tabs; - int16_t num_vertical_tabs; + uint8_t num_horizontal_tabs; + uint8_t num_vertical_tabs; - /* bit graphics data */ + /* Bit Graphics data. */ uint16_t bg_h_density; /* in dpi */ uint16_t bg_v_density; /* in dpi */ int8_t bg_adjacent; /* print adjacent pixels (ignored) */ @@ -232,58 +243,61 @@ typedef struct { uint8_t bg_column[6]; /* #bytes of the current and last col */ uint8_t bg_bytes_read; /* #bytes read so far for current col */ - /* handshake data */ - uint8_t ctrl; - uint8_t data; - int8_t ack; - int8_t select; - int8_t busy; - int8_t int_pending; - int8_t error; - int8_t autofeed; + /* Port timeout. */ + int64_t timeout; - /* ESC command data */ + /* ESC command data. */ int8_t esc_seen; /* set to 1 if an ESC char was seen */ int8_t fss_seen; /* set to 1 if an FS char was seen */ uint16_t esc_pending; /* in which ESC command are we */ uint8_t esc_parms_req; uint8_t esc_parms_curr; - uint8_t esc_parms[10]; /* 10 should be enough for everybody */ + uint8_t esc_parms[20]; /* 20 should be enough for everybody */ - /* internal page data */ + /* Internal page data. */ wchar_t fontpath[1024]; wchar_t pagepath[1024]; psurface_t *page; double curr_x, curr_y; /* print head position (inch) */ uint16_t current_font; FT_Face fontface; - int8_t lq_typeface; - int8_t font_style; - int8_t print_quality; + uint8_t lq_typeface; + uint8_t print_quality; uint8_t font_score; + uint16_t font_style; double extra_intra_space; /* extra spacing between chars (inch) */ - /* other internal data */ - uint16_t char_tables[4]; /* the character tables for ESC t */ - uint16_t curr_char_table; /* the active char table index */ + /* Other internal data. */ uint16_t curr_cpmap[256]; /* current ASCII->Unicode map table */ + uint16_t char_tables[4]; /* the character tables for ESC t */ + uint8_t curr_char_table; /* the active char table index */ - int8_t multipoint_mode; /* multipoint mode, ESC X */ - double multipoint_size; /* size of font, in points */ - double multipoint_cpi; /* chars per inch in multipoint mode */ + int8_t msb; /* MSB mode, -1 = off */ + int8_t print_upper_control; /* ESC 6, ESC 7 */ + int8_t print_everything_count; /* for ESC ( ^ */ uint8_t density_k; /* density modes for ESC K/L/Y/Z */ uint8_t density_l; uint8_t density_y; uint8_t density_z; - int8_t print_upper_control; /* ESC 6, ESC 7 */ - int8_t print_everything_count; /* for ESC ( ^ */ + int8_t multipoint_mode; /* multipoint mode, ESC X */ + double multipoint_size; /* size of font, in points */ + double multipoint_cpi; /* chars per inch in multipoint mode */ double defined_unit; /* internal unit for some ESC/P * commands. -1 = use default */ + PALETTE palcol; - int8_t msb; /* MSB mode, -1 = off */ + /* Port data */ + int8_t ack, + select, + busy, + int_pending, + error, + autofeed; + uint8_t ctrl, + data; } escp_t; @@ -294,9 +308,12 @@ static const uint16_t codepages[15] = { }; -/* "patches" to the codepage for the international charsets - * these bytes patch the following 12 positions of the char table, in order: +/* + * "patches" to the codepage for the international charsets. + * + * These bytes patch the following 12 positions of the char table, in order: * 0x23 0x24 0x40 0x5b 0x5c 0x5d 0x5e 0x60 0x7b 0x7c 0x7d 0x7e + * * TODO: Implement the missing international charsets */ static const uint16_t intCharSets[15][12] = { @@ -351,13 +368,8 @@ static const uint16_t intCharSets[15][12] = { static void init_codepage(escp_t *dev, uint16_t num) { - const uint16_t *cp; - /* Get the codepage map for this number. */ - cp = select_codepage(num); - - /* Copy the map over since it might get modified later. */ - memcpy(dev->curr_cpmap, cp, 256 * sizeof(uint16_t)); + select_codepage(num, dev->curr_cpmap); } @@ -541,7 +553,12 @@ dump_page(escp_t *dev) /* Try PNG first. */ plat_tempfile(temp, NULL, L".png"); wcscat(path, temp); +# ifdef USE_COLOR + if (! png_write_pal(path, dev->page->pixels, dev->page->w, dev->page->h, + dev->page->pitch, dev->palcol)) { +# else if (! png_write_gray(path, 1, dev->page->pixels, dev->page->w, dev->page->h)) { +# endif wcscpy(path, dev->pagepath); #endif plat_tempfile(temp, NULL, L".pgm"); @@ -565,50 +582,70 @@ new_page(escp_t *dev, int8_t save, int8_t reset_x) /* Clear page. */ dev->curr_y = dev->top_margin; dev->page->dirty = 0; - memset(dev->page->pixels, 0x00, dev->page->h * dev->page->pitch); + memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); + +#if 0 + /* Make the page's file name. */ + plat_tempfile(dev->page_fn, NULL, L".png"); +#endif } static void -reset_printer(escp_t *dev) +printer_reset(escp_t *dev) { - int16_t i; + int i; /* TODO: these should be configurable. */ - dev->color = COLOR_BLACK; - dev->page_width = PAGE_WIDTH; - dev->page_height = PAGE_HEIGHT; - dev->left_margin = PAGE_LMARGIN; - dev->right_margin = PAGE_RMARGIN; - dev->top_margin = PAGE_TMARGIN; - dev->bottom_margin = PAGE_BMARGIN; - dev->dpi = PAGE_DPI; - dev->cpi = PAGE_CPI; - dev->lpi = PAGE_LPI; + dev->color = SET_COLOR(COLOR_BLACK); - dev->hmi = -1.0; + dev->right_margin = dev->page_width = PAGE_WIDTH; + dev->bottom_margin = dev->page_height = PAGE_HEIGHT; + dev->top_margin = dev->left_margin = 0.0; + dev->lpi = PAGE_LPI; + dev->cpi = PAGE_CPI; + dev->dpi = PAGE_DPI; + + dev->autofeed = 0; + dev->esc_seen = dev->esc_pending = dev->fss_seen = 0; + dev->esc_parms_req = dev->esc_parms_curr = 0; + + dev->hmi = -1; dev->curr_x = dev->curr_y = 0.0; dev->linespacing = 1.0 / dev->lpi; - dev->char_tables[0] = 0; /* italics */ - dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ dev->curr_char_table = 1; + dev->char_tables[0] = 0; /* italics */ + dev->char_tables[1] = /* all other tables use CP437 */ + dev->char_tables[2] = + dev->char_tables[3] = 437; init_codepage(dev, dev->char_tables[dev->curr_char_table]); - dev->num_horizontal_tabs = 32; for (i = 0; i < 32; i++) - dev->horizontal_tabs[i] = i * 8.0 / dev->cpi; - dev->num_vertical_tabs = -1; + dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); + dev->num_horizontal_tabs = i; + dev->num_vertical_tabs = 255; /* -1 */ dev->current_font = FONT_COURIER; dev->lq_typeface = TYPEFACE_COURIER; + dev->print_quality = QUALITY_DRAFT; dev->fontface = 0; + dev->font_style = 0; + dev->font_score = 0; dev->multipoint_mode = 0; dev->multipoint_size = 0.0; dev->multipoint_cpi = 0.0; - dev->font_style = 0; - dev->font_score = 0; - dev->print_quality = QUALITY_DRAFT; + + dev->msb = 255; + dev->defined_unit = -1.0; + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->print_everything_count = 0; + + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; dev->bg_h_density = dev->bg_v_density = 0; dev->bg_adjacent = 0; @@ -621,20 +658,13 @@ reset_printer(escp_t *dev) dev->esc_parms_req = dev->esc_parms_curr = 0; memset(dev->esc_parms, 0x00, sizeof(dev->esc_parms)); - dev->msb = -1; - dev->print_everything_count = 0; - dev->print_upper_control = 0; - if (dev->page != NULL) - dev->page->dirty = 0; - dev->extra_intra_space = 0.0; - dev->defined_unit = -1.0; - dev->density_k = 0; - dev->density_l = 1; - dev->density_y = 2; - dev->density_z = 3; - update_font(dev); + if (dev->page != NULL) { + new_page(dev, 0, 1); + dev->page->dirty = 0; + } + INFO("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", dev->page_width, dev->page_height, (int)dev->dpi, (int)dev->cpi, (int)dev->lpi); @@ -644,6 +674,8 @@ reset_printer(escp_t *dev) static void setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) { + DEBUG("ESC/P: density=%d\n", density); + switch (density) { case 0: dev->bg_h_density = 60; @@ -745,6 +777,7 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) default: ERRLOG("ESC/P: Unsupported bit image density %d.\n", density); + break; } dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; @@ -754,12 +787,14 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) /* This is the actual ESC/P interpreter. */ static int -process_char(escp_t *dev, uint8_t ch) +process_data(escp_t *dev, uint8_t ch) { double new_x, new_y; double move_to; double unit_size; uint16_t rel_move; + double reverse; + double new_top, new_bottom; int16_t i; /* Determine number of additional command params that are expected. */ @@ -771,117 +806,133 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_parms_curr = 0; switch (dev->esc_pending) { - case 0x02: // Undocumented - case 0x0a: // Reverse line feed - case 0x0c: // Return to top of current page - case 0x0e: // Select dbl-width printing (1 line) (ESC SO) - case 0x0f: // Select condensed printing (ESC SI) - case 0x23: // Cancel MSB control (ESC #) - case 0x30: // Select 1/8-inch line spacing (ESC 0) - case 0x32: // Select 1/6-inch line spacing (ESC 2) - case 0x34: // Select italic font (ESC 4) - case 0x35: // Cancel italic font (ESC 5) - case 0x36: // Enable printing of upper ctrl codes (ESC 6) - case 0x37: // Enable upper control codes (ESC 7) - case 0x3c: // Unidirectional mode (one line) (ESC <) - case 0x3d: // Set MSB to 0 (ESC =) - case 0x3e: // Set MSB to 1 (ESC >) - case 0x40: // Initialize printer (ESC @) - case 0x45: // Select bold font (ESC E) - case 0x46: // Cancel bold font (ESC F) - case 0x47: // Select double-strike printing (ESC G) - case 0x48: // Cancel double-strike printing (ESC H) - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - case 0x54: // Cancel superscript/subscript printing (ESC T) - case 0x5e: // Enable printing of all character codes on next character - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - case 0x73: // Select low-speed mode (ESC s) - case 0x834: // Select italic font (FS 4) (= ESC 4) - case 0x835: // Cancel italic font (FS 5) (= ESC 5) - case 0x846: // Select forward feed mode (FS F) - case 0x852: // Select reverse feed mode (FS R) + case 0x02: /* undocumented */ + case 0x0a: /* reverse line feed */ + case 0x0c: /* return to top of current page */ + case 0x0e: /* slct dbl-width printing (1 line) (ESC SO) */ + case 0x0f: /* slct condensed printing (ESC SI) */ + case 0x23: /* cancel MSB control (ESC #) */ + case 0x30: /* slct 1/8-in line spacing (ESC 0) */ + case 0x31: /* slct 7/60-in line spacing */ + case 0x32: /* slct 1/6-in line spacing (ESC 2) */ + case 0x34: /* slct italic font (ESC 4) */ + case 0x35: /* cancel italic font (ESC 5) */ + case 0x36: /* ena printing of upper ctrl codes (ESC 6) */ + case 0x37: /* ena upper control codes (ESC 7) */ + case 0x38: /* dis paper-out detector */ + case 0x39: /* ena paper-out detector */ + case 0x3c: /* unidirectional mode (one line) (ESC <) */ + case 0x3d: /* set MSB to 0 (ESC =) */ + case 0x3e: /* set MSB to 1 (ESC >) */ + case 0x40: /* initialize printer (ESC @) */ + case 0x45: /* slct bold font (ESC E) */ + case 0x46: /* cancel bold font (ESC F) */ + case 0x47: /* slct double-strike printing (ESC G) */ + case 0x48: /* cancel double-strike printing (ESC H) */ + case 0x4d: /* slct 10.5-point, 12-cpi (ESC M) */ + case 0x4f: /* cancel bottom margin */ + case 0x50: /* slct 10.5-point, 10-cpi (ESC P) */ + case 0x54: /* cancel super/subscript printing (ESC T) */ + case 0x5e: /* ena printing of all char codes on next char */ + case 0x67: /* slct 10.5-point, 15-cpi (ESC g) */ + case 0x0834: /* slct italic font (FS 4) (= ESC 4) */ + case 0x0835: /* cancel italic font (FS 5) (= ESC 5) */ + case 0x0846: /* slct forward feed mode (FS F) */ + case 0x0852: /* slct reverse feed mode (FS R) */ dev->esc_parms_req = 0; break; - case 0x19: // Control paper loading/ejecting (ESC EM) - case 0x20: // Set intercharacter space (ESC SP) - case 0x21: // Master select (ESC !) - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x2d: // Turn underline on/off (ESC -) - case 0x2f: // Select vertical tab channel (ESC /) - case 0x33: // Set n/180-inch line spacing (ESC 3) - case 0x41: // Set n/60-inch line spacing - case 0x43: // Set page length in lines (ESC C) - case 0x4a: // Advance print position vertically (ESC J n) - case 0x4e: // Set bottom margin (ESC N) - case 0x51: // Set right margin (ESC Q) - case 0x52: // Select an intl character set (ESC R) - case 0x53: // Select super/subscript printing (ESC S) - case 0x55: // Turn unidirectional mode on/off (ESC U) - case 0x57: // Turn double-width printing on/off (ESC W) - case 0x61: // Select justification (ESC a) - case 0x6b: // Select typeface (ESC k) - case 0x6c: // Set left margin (ESC 1) - case 0x70: // Turn proportional mode on/off (ESC p) - case 0x72: // Select printing color (ESC r) - case 0x74: // Select character table (ESC t) - case 0x77: // Turn double-height printing on/off (ESC w) - case 0x78: // Select LQ or draft (ESC x) - case 0x7e: // Select/Deselect slash zero (ESC ~) - case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) - case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) - case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) - case 0x843: // Select LQ type style (FS C) (= ESC k) - case 0x845: // Select character width (FS E) - case 0x849: // Select character table (FS I) (= ESC t) - case 0x853: // Select High Speed/Density Elite pitch (FS S) - case 0x856: // Turn dbl-height printing on/off (FS V)(= ESC w) + case 0x19: /* control paper loading/ejecting (ESC EM) */ + case 0x20: /* set intercharacter space (ESC SP) */ + case 0x21: /* master select (ESC !) */ + case 0x2b: /* set n/360-in line spacing (ESC +) */ + case 0x2d: /* turn underline on/off (ESC -) */ + case 0x2f: /* slct vertical tab channel (ESC /) */ + case 0x33: /* set n/180-in line spacing (ESC 3) */ + case 0x41: /* set n/60-in line spacing */ + case 0x43: /* set page length in lines (ESC C) */ + case 0x49: /* slct character type and print pitch */ + case 0x4a: /* advance print pos vertically (ESC J n) */ + case 0x4e: /* set bottom margin (ESC N) */ + case 0x51: /* set right margin (ESC Q) */ + case 0x52: /* slct an intl character set (ESC R) */ + case 0x53: /* slct super/subscript printing (ESC S) */ + case 0x55: /* turn unidirectional mode on/off (ESC U) */ + case 0x57: /* turn double-width printing on/off (ESC W) */ + case 0x61: /* slct justification (ESC a) */ + case 0x66: /* abs hor tab in columns [conflict] */ + case 0x68: /* slct double or quadruple size */ + case 0x69: /* immediate print */ + case 0x6a: /* reverse paper feed */ + case 0x6b: /* slct typeface (ESC k) */ + case 0x6c: /* set left margin (ESC 1) */ + case 0x70: /* turn proportional mode on/off (ESC p) */ + case 0x72: /* slct printing color (ESC r) */ + case 0x73: /* select low-speed mode (ESC s) */ + case 0x74: /* slct character table (ESC t) */ + case 0x77: /* turn dbl-height printing on/off (ESC w) */ + case 0x78: /* slct LQ or draft (ESC x) */ + case 0x7e: /* slct/Deselect slash zero (ESC ~) */ + case 0x0832: /* slct 1/6-in line spacing (FS 2) (= ESC 2) */ + case 0x0833: /* set n/360-in line spacing (FS 3) (= ESC +) */ + case 0x0841: /* set n/60-in line spacing (FS A) (= ESC A) */ + case 0x0843: /* slct LQ type style (FS C) (= ESC k) */ + case 0x0845: /* slct character width (FS E) */ + case 0x0849: /* slct character table (FS I) (= ESC t) */ + case 0x0853: /* slct HighSpeed/HighDensity elite pitch (FS S) */ + case 0x0856: /* turn dbl-height printing on/off (FS V) (= ESC w) */ dev->esc_parms_req = 1; break; - case 0x24: // Set abs horizontal print position (ESC $) - case 0x3f: // Reassign bit-image mode (ESC ?) - case 0x4b: // Select 60-dpi graphics (ESC K) - case 0x4c: // Select 120-dpi graphics (ESC L) - case 0x59: // Select 120-dpi, dbl-speed graphics (ESC Y) - case 0x5a: // Select 240-dpi graphics (ESC Z) - case 0x5c: // Set rel horizontal print position (ESC \) - case 0x63: // Set horizontal motion index (HMI) (ESC c) - case 0x65: // Set vertical tab stops every n lines (ESC e) - case 0x85a: // Print 24-bit hex-density graphics (FS Z) + case 0x24: /* set abs horizontal print position (ESC $) */ + case 0x3f: /* reassign bit-image mode (ESC ?) */ + case 0x4b: /* slct 60-dpi graphics (ESC K) */ + case 0x4c: /* slct 120-dpi graphics (ESC L) */ + case 0x59: /* slct 120-dpi, dbl-speed graphics (ESC Y) */ + case 0x5a: /* slct 240-dpi graphics (ESC Z) */ + case 0x5c: /* set rel horizontal print position (ESC \) */ + case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + case 0x65: /* set vertical tab stops every n lines (ESC e) */ + case 0x085a: /* print 24-bit hex-density graphics (FS Z) */ dev->esc_parms_req = 2; break; - case 0x2a: // Select bit image (ESC *) - case 0x58: // Select font by pitch and point (ESC X) + case 0x2a: /* slct bit image (ESC *) */ + case 0x58: /* slct font by pitch and point (ESC X) */ dev->esc_parms_req = 3; break; - case 0x5b: // Select character height, width, line spacing + case 0x5b: /* slct char height, width, line spacing */ dev->esc_parms_req = 7; break; - case 0x42: // Set vertical tabs (ESC B) - case 0x62: // Set vertical tabs in VFU channels (ESC b) + case 0x42: /* set vertical tabs (ESC B) */ + case 0x62: /* set vertical tabs in VFU channels (ESC b) */ dev->num_vertical_tabs = 0; return 1; - case 0x44: // Set horizontal tabs (ESC D) + case 0x44: /* set horizontal tabs (ESC D) */ dev->num_horizontal_tabs = 0; return 1; - case 0x25: // Select user-defined set (ESC %) - case 0x26: // Define user-defined characters (ESC &) - case 0x3a: // Copy ROM to RAM (ESC :) - ERRLOG("ESC/P: User-defined characters not supported.\n"); + case 0x25: /* slct user-defined set (ESC %) */ + case 0x26: /* define user-defined characters (ESC &) */ + case 0x3a: /* copy ROM to RAM (ESC :) */ + ERRLOG("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", + dev->esc_pending >= 0x20 ? dev->esc_pending + : '?', + dev->esc_pending); return 1; - case 0x28: // Two bytes sequence + case 0x28: /* two bytes sequence */ /* return and wait for second ESC byte */ return 1; + case 0x2e: + fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); + /*NOTREACHED*/ + return 1; + default: ERRLOG("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", dev->esc_pending >= 0x20 ? dev->esc_pending @@ -901,36 +952,38 @@ process_char(escp_t *dev, uint8_t ch) if (dev->esc_pending == 0x28) { dev->esc_pending = 0x0200 + ch; + DEBUG("ESC/P: two-byte command pending=%03x, font path=%ls\n", + dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { - case 0x0242: // Bar code setup and print (ESC (B) - case 0x025e: // Print data as characters (ESC (^) + case 0x0242: /* Bar code setup and print (ESC (B) */ + case 0x025e: /* Print data as characters (ESC (^) */ dev->esc_parms_req = 2; break; - case 0x0255: // Set unit (ESC (U) + case 0x0255: /* Set unit (ESC (U) */ dev->esc_parms_req = 3; break; - case 0x0243: // Set page length in defined unit (ESC (C) - case 0x0256: // Set abs vertical print position (ESC (V) - case 0x0276: // Set rel vertical print position (ESC (v) + case 0x0243: /* Set page length in defined unit (ESC (C) */ + case 0x0256: /* Set abs vertical print position (ESC (V) */ + case 0x0276: /* Set rel vertical print position (ESC (v) */ dev->esc_parms_req = 4; break; - case 0x0228: // Assign character table (ESC (t) - case 0x022d: // Select line/score (ESC (-) + case 0x0228: /* Assign character table (ESC (t) */ + case 0x022d: /* Select line/score (ESC (-) */ dev->esc_parms_req = 5; break; - case 0x0263: // Set page format (ESC (c) + case 0x0263: /* Set page format (ESC (c) */ dev->esc_parms_req = 6; break; default: - // ESC ( commands are always followed by a "number of parameters" word parameter - ERRLOG("ESC/P: Skipping unsupported extended command ESC ( %c (0x%02x).\n", - dev->esc_pending >= 0x20 ? dev->esc_pending : '?', - dev->esc_pending); + /* + * ESC ( commands are always followed by a + * "number of parameters" word parameter.. + */ dev->esc_parms_req = 2; /* Dummy value, to be checked later. */ @@ -958,9 +1011,8 @@ process_char(escp_t *dev, uint8_t ch) (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double)ch * dev->linespacing)) { dev->esc_pending = 0; } else { - if (dev->num_vertical_tabs < 16) { + if (dev->num_vertical_tabs < 16) dev->vertical_tabs[dev->num_vertical_tabs++] = (double)ch * dev->linespacing; - } } } @@ -971,9 +1023,8 @@ process_char(escp_t *dev, uint8_t ch) (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double)ch * (1.0 / dev->cpi))) { dev->esc_pending = 0; } else { - if (dev->num_horizontal_tabs < 32) { + if (dev->num_horizontal_tabs < 32) dev->horizontal_tabs[dev->num_horizontal_tabs++] = (double)ch * (1.0 / dev->cpi); - } } } @@ -1002,7 +1053,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 0x000f: /* select condensed printing (ESC SI) */ - if (! dev->multipoint_mode) { + if (! dev->multipoint_mode && (dev->cpi != 15.0)) { dev->hmi = -1; dev->font_style |= STYLE_CONDENSED; update_font(dev); @@ -1028,8 +1079,8 @@ process_char(escp_t *dev, uint8_t ch) case 0x0021: /* master select (ESC !) */ dev->cpi = dev->esc_parms[0] & 0x01 ? 12.0 : 10.0; - /* Reset first seven bits. */ - dev->font_style &= ~0x7f; + /* Reset lower seven bits. */ + dev->font_style &= 0xff80; if (dev->esc_parms[0] & 0x02) dev->font_style |= STYLE_PROP; if (dev->esc_parms[0] & 0x04) @@ -1053,7 +1104,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 0x0023: /* cancel MSB control (ESC #) */ - dev->msb = -1; + dev->msb = 255; break; case 0x0024: /* set abs horizontal print position (ESC $) */ @@ -1097,6 +1148,10 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing = 1.0 / 8.0; break; + case 0x0031: /* select 7/60-inch line spacing (ESC 1) */ + dev->linespacing = 7.0 / 60.0; + break; + case 0x0032: /* select 1/6-inch line spacing (ESC 2) */ dev->linespacing = 1.0 / 6.0; break; @@ -1147,24 +1202,25 @@ process_char(escp_t *dev, uint8_t ch) break; case 0x0040: /* initialize printer (ESC @) */ - reset_printer(dev); + printer_reset(dev); break; - case 0x0041: /* set n/60-inch line spacing */ + case 0x0041: /* set n/60-inch line spacing (ESC A) */ + case 0x0841: /* FS A */ dev->linespacing = (double)dev->esc_parms[0] / 60.0; break; case 0x0043: /* set page length in lines (ESC C) */ - if (dev->esc_parms[0]) { - dev->page_height = dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; - } else { /* == 0 => Set page length in inches */ + if (dev->esc_parms[0] == 0) { + /* == 0 => Set page length in inches */ dev->esc_parms_req = 1; dev->esc_parms_curr = 0; /* Dummy value, for later checking. */ dev->esc_pending = 0x0100; return 1; - } + } else + dev->page_height = dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; break; case 0x0045: /* select bold font (ESC E) */ @@ -1187,9 +1243,8 @@ process_char(escp_t *dev, uint8_t ch) case 0x004a: /* advance print pos vertically (ESC J n) */ dev->curr_y += (double)dev->esc_parms[0] / 180.0; - if (dev->curr_y > dev->bottom_margin) { + if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); - } break; case 0x004b: /* select 60-dpi graphics (ESC K) */ @@ -1259,7 +1314,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 0x0054: /* cancel super/subscript printing (ESC T) */ - dev->font_style &= ~(STYLE_SUPERSCRIPT | STYLE_SUBSCRIPT); + dev->font_style &= 0xffff - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; update_font(dev); break; @@ -1286,12 +1341,11 @@ process_char(escp_t *dev, uint8_t ch) dev->multipoint_cpi= dev->cpi; if (dev->esc_parms[0] > 0) { /* set CPI */ - if (dev->esc_parms[0] == 1) { + if (dev->esc_parms[0] == 1) /* Proportional spacing. */ dev->font_style |= STYLE_PROP; - } else if (dev->esc_parms[0] >= 5) { + else if (dev->esc_parms[0] >= 5) dev->multipoint_cpi = 360.0 / (double)dev->esc_parms[0]; - } } if (dev->multipoint_size == 0.0) @@ -1339,10 +1393,23 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; + case 0x0846: /* select forward feed mode (FS F) - set reverse not implemented yet */ + if (dev->linespacing < 0) + dev->linespacing *= -1; + break; + + case 0x006a: /* reverse paper feed (ESC j) */ + reverse = (double)PARAM16(0) / (double)216.0; + reverse = dev->curr_y - reverse; + if (reverse < dev->left_margin) + dev->curr_y = dev->left_margin; + else + dev->curr_y = reverse; + break; + case 0x006b: /* select typeface (ESC k) */ - if (dev->esc_parms[0] <= 11 || dev->esc_parms[0] == 30 || dev->esc_parms[0] == 31) { + if (dev->esc_parms[0] <= 11 || dev->esc_parms[0] == 30 || dev->esc_parms[0] == 31) dev->lq_typeface = dev->esc_parms[0]; - } update_font(dev); break; @@ -1366,9 +1433,9 @@ process_char(escp_t *dev, uint8_t ch) case 0x0072: /* select printing color (ESC r) */ if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) - dev->color = COLOR_BLACK; + dev->color = SET_COLOR(COLOR_BLACK); else - dev->color = dev->esc_parms[0] << 5; + dev->color = SET_COLOR(dev->esc_parms[0]); break; case 0x0073: /* select low-speed mode (ESC s) */ @@ -1377,11 +1444,10 @@ process_char(escp_t *dev, uint8_t ch) case 0x0074: /* select character table (ESC t) */ case 0x0849: /* select character table (FS I) */ - if (dev->esc_parms[0] < 4) { + if (dev->esc_parms[0] < 4) dev->curr_char_table = dev->esc_parms[0]; - } else if ((dev->esc_parms[0] >= '0') && (dev->esc_parms[0] <= '3')) { + else if ((dev->esc_parms[0] >= '0') && (dev->esc_parms[0] <= '3')) dev->curr_char_table = dev->esc_parms[0] - '0'; - } init_codepage(dev, dev->char_tables[dev->curr_char_table]); update_font(dev); break; @@ -1397,11 +1463,16 @@ process_char(escp_t *dev, uint8_t ch) break; case 0x0078: /* select LQ or draft (ESC x) */ - if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') { dev->print_quality = QUALITY_DRAFT; - if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') - dev->print_quality = QUALITY_LQ; - update_font(dev); + dev->font_style |= STYLE_CONDENSED; + } + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->print_quality = QUALITY_LQ; + dev->font_style &= ~STYLE_CONDENSED; + } + dev->hmi = -1; + update_font(dev); break; /* Our special command markers. */ @@ -1421,9 +1492,8 @@ process_char(escp_t *dev, uint8_t ch) case 0x0274: if (dev->esc_parms[2] < 4 && dev->esc_parms[3] < 16) { dev->char_tables[dev->esc_parms[2]] = codepages[dev->esc_parms[3]]; - if (dev->esc_parms[2] == dev->curr_char_table) { + if (dev->esc_parms[2] == dev->curr_char_table) init_codepage(dev, dev->char_tables[dev->curr_char_table]); - } } break; @@ -1477,8 +1547,16 @@ process_char(escp_t *dev, uint8_t ch) case 0x0263: /* set page format (ESC (c) */ if (dev->defined_unit > 0.0) { - dev->top_margin = (double)PARAM16(2) * dev->defined_unit; - dev->bottom_margin = (double)PARAM16(4) * dev->defined_unit; + new_top = (double)PARAM16(2) * dev->defined_unit; + new_bottom = (double)PARAM16(4) * dev->defined_unit; + if (new_top >= new_bottom) + break; + if (new_top < dev->page_height) + dev->top_margin = new_top; + if (new_bottom < dev->page_height) + dev->bottom_margin = new_bottom; + if (dev->top_margin > dev->curr_y) + dev->curr_y = dev->top_margin; } break; @@ -1488,11 +1566,10 @@ process_char(escp_t *dev, uint8_t ch) unit_size = 360.0; new_y = dev->curr_y + (double)((int16_t)PARAM16(2)) * unit_size; if (new_y > dev->top_margin) { - if (new_y > dev->bottom_margin) { + if (new_y > dev->bottom_margin) new_page(dev, 1, 0); - } else { + else dev->curr_y = new_y; - } } break; @@ -1527,15 +1604,14 @@ process_char(escp_t *dev, uint8_t ch) /* Find tab right to current pos. */ move_to = -1.0; for (i = 0; i < dev->num_horizontal_tabs; i++) { - if (dev->horizontal_tabs[i] > dev->curr_x) { + if (dev->horizontal_tabs[i] > dev->curr_x) move_to = dev->horizontal_tabs[i]; - break; - } } /* Nothing found or out of page bounds => Ignore. */ if (move_to > 0.0 && move_to < dev->right_margin) dev->curr_x = move_to; + return 1; case 0x0b: /* Tab vertically (VT) */ @@ -1552,10 +1628,8 @@ process_char(escp_t *dev, uint8_t ch) /* Find tab below current pos. */ move_to = -1; for (i = 0; i < dev->num_vertical_tabs; i++) { - if (dev->vertical_tabs[i] > dev->curr_y) { + if (dev->vertical_tabs[i] > dev->curr_y) move_to = dev->vertical_tabs[i]; - break; - } } /* Nothing found => Act like FF. */ @@ -1573,7 +1647,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x0c: /* Form feed (FF) */ if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { - dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + dev->font_style &= 0xffff - STYLE_DOUBLEWIDTHONELINE; update_font(dev); } new_page(dev, 1, 1); @@ -1587,15 +1661,15 @@ process_char(escp_t *dev, uint8_t ch) case 0x0a: /* Line feed */ if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { - dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + dev->font_style &= 0xffff - STYLE_DOUBLEWIDTHONELINE; update_font(dev); } + //FIXME: not sure an LF also resets printhead- check! --FvK dev->curr_x = dev->left_margin; dev->curr_y += dev->linespacing; - if (dev->curr_y > dev->bottom_margin) { + if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); - } return 1; case 0x0e: /* select Real64-width printing (one line) (SO) */ @@ -1616,7 +1690,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x11: /* select printer (DC1) */ /* Ignore. */ - return 1; + return 0; case 0x12: /* cancel condensed printing (DC2) */ dev->hmi = -1; @@ -1626,7 +1700,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x13: /* deselect printer (DC3) */ /* Ignore. */ - return 1; + return 0; case 0x14: /* cancel double-width printing (one line) (DC4) */ dev->hmi = -1; @@ -1662,22 +1736,22 @@ process_char(escp_t *dev, uint8_t ch) * hard to do. */ static void -blit_glyph(escp_t *dev, uint16_t destx, uint16_t desty, int8_t add) +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) { FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; + unsigned x, y; uint8_t src, *dst; - uint16_t x, y; - /* Make sure we have FreeType loaded. */ + /* check if freetype is available */ if (ft_lib == NULL) return; for (y = 0; y < bitmap->rows; y++) { for (x = 0; x < bitmap->width; x++) { - src = *(bitmap->buffer + y * bitmap->pitch + x); + src = *(bitmap->buffer + x + y * bitmap->pitch); - /* Ignore background, and respect page size. */ - if (src && (destx + x < dev->page->w) && (desty + y < dev->page->h)) { - dst = (uint8_t *)dev->page->pixels + x + destx + (y + desty) * dev->page->pitch; + /* ignore background, and respect page size */ + if (src > 0 && (destx + x < (unsigned)dev->page->w) && (desty + y < (unsigned)dev->page->h)) { + dst = (uint8_t *)dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; src >>= 3; if (add) { @@ -1687,8 +1761,8 @@ blit_glyph(escp_t *dev, uint16_t destx, uint16_t desty, int8_t add) *dst += src; *dst |= dev->color; } - } else - *dst = src|dev->color; + } else + *dst = src | dev->color; } } } @@ -1697,21 +1771,21 @@ blit_glyph(escp_t *dev, uint16_t destx, uint16_t desty, int8_t add) /* Draw anti-aliased line. */ static void -draw_hline(escp_t *dev, uint16_t from_x, uint16_t to_x, uint16_t y, int8_t broken) +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) { - uint16_t breakmod = dev->dpi / 15; - uint16_t gapstart = (breakmod * 4) / 5; - uint16_t x; + unsigned breakmod = dev->dpi / 15; + unsigned gapstart = (breakmod * 4) / 5; + unsigned x; for (x = from_x; x <= to_x; x++) { /* Skip parts if broken line or going over the border. */ if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { if (y > 0 && (y - 1) < dev->page->h) - *((uint8_t*)dev->page->pixels + x + (y - 1)*dev->page->pitch) = 120; + *((uint8_t*)dev->page->pixels + x + (y - 1) * (unsigned)dev->page->pitch) = 240; if (y < dev->page->h) - *((uint8_t*)dev->page->pixels + x + y * dev->page->pitch) = !broken ? 255 : 120; + *((uint8_t*)dev->page->pixels + x + y * (unsigned)dev->page->pitch) = !broken ? 255 : 240; if (y + 1 < dev->page->h) - *((uint8_t*)dev->page->pixels + x + (y + 1)*dev->page->pitch) = 120; + *((uint8_t*)dev->page->pixels + x + (y + 1) * (unsigned)dev->page->pitch) = 240; } } } @@ -1722,7 +1796,7 @@ print_bit_graph(escp_t *dev, uint8_t ch) { uint8_t pixel_w; /* width of the "pixel" */ uint8_t pixel_h; /* height of the "pixel" */ - uint8_t i, j, xx, yy; + unsigned i, j, xx, yy; double old_y; dev->bg_column[dev->bg_bytes_read++] = ch; @@ -1734,12 +1808,13 @@ print_bit_graph(escp_t *dev, uint8_t ch) old_y = dev->curr_y; + pixel_w = 1; + pixel_h = 1; + if (dev->bg_adjacent) { + /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; - } else { - pixel_w = 1; - pixel_h = 1; } for (i = 0; i < dev->bg_bytes_per_column; i++) { @@ -1750,14 +1825,13 @@ print_bit_graph(escp_t *dev, uint8_t ch) /* draw a "pixel" */ for (xx = 0; xx < pixel_w; xx++) { for (yy = 0; yy < pixel_h; yy++) { - if (((PIXX + xx) < dev->page->w) && ((PIXY + yy) < dev->page->h)) { - ((uint8_t *)(dev->page->pixels))[(int)((PIXY + yy) * dev->page->pitch + (PIXX + xx))] |= (dev->color | 0x1f); - } + if (((PIXX + xx) < (unsigned)dev->page->w) && ((PIXY + yy) < (unsigned)dev->page->h)) + *((uint8_t *)dev->page->pixels + (PIXX + xx) + (PIXY + yy)*dev->page->pitch) |= (dev->color | 0x1f); } } } - dev->curr_y += 1.0 / dev->bg_v_density; + dev->curr_y += 1.0 / (double)dev->bg_v_density; } } @@ -1767,28 +1841,32 @@ print_bit_graph(escp_t *dev, uint8_t ch) /* Restore Y-position. */ dev->curr_y = old_y; + dev->bg_bytes_read = 0; + /* Advance print head. */ dev->curr_x += 1.0 / dev->bg_h_density; } static void -handle_char(escp_t *dev) +escp_handle(escp_t *dev, uint8_t ch) { FT_UInt char_index; uint16_t pen_x, pen_y; - uint8_t ch = dev->data; uint16_t line_start, line_y; double x_advance; + /* OK, we have seen the character. */ + dev->ack = 1; + if (dev->page == NULL) return; /* MSB mode */ if (dev->msb != 255) { - if (dev->msb == 0) - ch &= 0x7f; - else if (dev->msb == 1) - ch |= 0x80; + if (dev->msb == 0) + ch &= 0x7f; + else if (dev->msb == 1) + ch |= 0x80; } /* Are we still printing bitmap graphics? */ @@ -1799,9 +1877,10 @@ handle_char(escp_t *dev) /* Are we still in "print everything" (aka. ESC ( ^) mode? */ if (dev->print_everything_count > 0) { + DEBUG("ESC/P: print everything count=%i\n", dev->print_everything_count); /* do not process command char, just continue */ --dev->print_everything_count; - } else if (process_char(dev, ch)) { + } else if (process_data(dev, ch)) { /* command was processed */ return; } @@ -1809,6 +1888,9 @@ handle_char(escp_t *dev) /* We cannot print if we have no font loaded. */ if (dev->fontface == 0) return; + if (ch == 0x01) + ch = 0x20; + /* OK, so we need to print the character now. */ if (ft_lib != NULL) { char_index = ft_Get_Char_Index(dev->fontface, dev->curr_cpmap[ch]); @@ -1818,7 +1900,7 @@ handle_char(escp_t *dev) pen_x = (uint16_t)PIXX + dev->fontface->glyph->bitmap_left; pen_y = (uint16_t)PIXY - dev->fontface->glyph->bitmap_top + (uint16_t)(dev->fontface->size->metrics.ascender / 64); - + if (dev->font_style & STYLE_SUBSCRIPT) pen_y += dev->fontface->glyph->bitmap.rows / 2; @@ -1828,14 +1910,20 @@ handle_char(escp_t *dev) /* Draw the rendered glyph. */ blit_glyph(dev, pen_x, pen_y, 0); + blit_glyph(dev, pen_x + 1, pen_y, 1); /* doublestrike -> draw glyph a second time, 1px below */ - if (dev->font_style & STYLE_DOUBLESTRIKE) + if (dev->font_style & STYLE_DOUBLESTRIKE) { blit_glyph(dev, pen_x, pen_y + 1, 1); + blit_glyph(dev, pen_x + 1, pen_y + 1, 1); + } /* bold -> draw glyph a second time, 1px to the right */ - if (dev->font_style & STYLE_BOLD) + if (dev->font_style & STYLE_BOLD) { blit_glyph(dev, pen_x + 1, pen_y, 1); + blit_glyph(dev, pen_x + 2, pen_y, 1); + blit_glyph(dev, pen_x + 3, pen_y, 1); + } line_start = (uint16_t)PIXX; @@ -1857,9 +1945,9 @@ handle_char(escp_t *dev) line_y = (uint16_t)PIXY; if (dev->font_style & STYLE_UNDERLINE) - line_y = pen_y + 5 + dev->fontface->glyph->bitmap.rows; + line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.9)); if (dev->font_style & STYLE_STRIKETHROUGH) - line_y = (uint16_t)(PIXY + dev->fontface->size->metrics.ascender / 128.0); + line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.45)); if (dev->font_style & STYLE_OVERSCORE) line_y = (uint16_t)PIXY - ((dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) ? 5 : 0); @@ -1881,95 +1969,47 @@ handle_char(escp_t *dev) static void -write_data(uint8_t val, void *priv) +printer_timeout(void *priv) { escp_t *dev = (escp_t *)priv; - DBGLOG(1, "ESC/P: data(%02x)\n", val); + if (dev->page->dirty) + new_page(dev, 1, 1); - if (dev == NULL) return; - - dev->data = val; + dev->timeout = 0LL; } -static void -write_ctrl(uint8_t val, void *priv) +static void +fill_palette(uint8_t rmax, uint8_t gmax, uint8_t bmax, uint8_t id, escp_t *dev) { - escp_t *dev = (escp_t *)priv; + float r, g, b; + uint8_t mask; + int i; - DEBUG("ESC/P: ctrl(%02x)\n", val); + mask = id <<= 5; + r = (float)rmax / (float)30.9; + g = (float)gmax / (float)30.9; + b = (float)bmax / (float)30.9; - if (dev == NULL) return; - - /* set autofeed value */ - dev->autofeed = val & 0x02 ? 1 : 0; - - if (val & 0x08) { /* SELECT */ - /* select printer */ - dev->select = 1; + for (i = 0; i < 32; i++) { + dev->palcol[i + mask].r = 255 - (uint8_t)floor(r * (float)i); + dev->palcol[i + mask].g = 255 - (uint8_t)floor(g * (float)i); + dev->palcol[i + mask].b = 255 - (uint8_t)floor(b * (float)i); } - - if ((val & 0x04) && !(dev->ctrl & 0x04)) { - /* reset printer */ - dev->select = 0; - - reset_printer(dev); - } - - if (!(val & 0x01) && (dev->ctrl & 0x01)) { /* STROBE */ - /* Process incoming character. */ - handle_char(dev); - - /* ACK it, will be read on next READ STATUS. */ - dev->ack = 1; - } - - /* Save new value. */ - dev->ctrl = val; } - - -static uint8_t -read_status(void *priv) -{ - escp_t *dev = (escp_t *)priv; - uint8_t ret = 0xdf; - - if (dev == NULL) return(ret); - -#if 0 - ret = 0x1f; - if (! dev->busy) - ret |= 0x80; - - if (! dev->ack) - ret |= 0x40; -#else - ret = (dev->ack ? 0x00 : 0x40) | - (dev->select ? 0x10 : 0x00) | - (dev->busy ? 0x00 : 0x80) | - (dev->int_pending ? 0x00 : 0x04) | - (dev->error ? 0x00 : 0x08); -#endif - - /* Clear ACK after reading status. */ - dev->ack = 0; - - DEBUG("ESC/P: status(%02x)\n", ret); - - return(ret); -} - - + + +/* API: initialize the printer device. */ static void * escp_init(const lpt_device_t *info) { wchar_t temp[512]; const char *fn = PATH_FREETYPE_DLL; escp_t *dev; + int i; - INFO("ESC/P: LPT printer '%s' initializing\n", info->name); + INFO("ESC/P: printer '%s' initializing\n", info->name); /* Dynamically load FreeType. */ if (ft_handle == NULL) { @@ -2000,7 +2040,6 @@ escp_init(const lpt_device_t *info) dev = (escp_t *)mem_alloc(sizeof(escp_t)); memset(dev, 0x00, sizeof(escp_t)); dev->name = info->name; - dev->ctrl = 0x04; /* Create a full pathname for the font files. */ wcscpy(dev->fontpath, rom_path(PRINTER_PATH)); @@ -2014,8 +2053,23 @@ escp_init(const lpt_device_t *info) plat_dir_create(dev->pagepath); plat_append_slash(dev->pagepath); + /* Initialize color palette. */ + for (i = 0; i < 32; i++) { + dev->palcol[i].r = 255; + dev->palcol[i].g = 255; + dev->palcol[i].b = 255; + } + fill_palette( 0, 0, 0, COLOR_WHITE, dev); + fill_palette( 0, 255, 0, COLOR_MAGENTA, dev); + fill_palette(255, 0, 0, COLOR_CYAN, dev); + fill_palette(255, 255, 0, COLOR_VIOLET, dev); + fill_palette( 0, 0, 255, COLOR_YELLOW, dev); + fill_palette( 0, 255, 255, COLOR_RED, dev); + fill_palette(255, 0, 255, COLOR_GREEN, dev); + fill_palette(255, 255, 255, COLOR_BLACK, dev); + /* Initialize parameters. */ - reset_printer(dev); + printer_reset(dev); /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *)mem_alloc(sizeof(psurface_t)); @@ -2025,12 +2079,18 @@ escp_init(const lpt_device_t *info) dev->page->pixels = (uint8_t *)mem_alloc(dev->page->pitch * dev->page->h); memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); - DEBUG("ESC/P: created a virtual page of dimensions %d x %d pixels.\n", - dev->page->w, dev->page->h); + /* Create a timer to detect port timeouts. */ + timer_add(printer_timeout, &dev->timeout, &dev->timeout, dev); + + dev->ctrl = 0x04; + + DEBUG("ESC/P: created virtual page of %ix%i pixels\n", + dev->page->w, dev->page->h); return(dev); } +/* API: close (release) the printer device. */ static void escp_close(void *priv) { @@ -2045,6 +2105,7 @@ escp_close(void *priv) if (dev->page->pixels != NULL) free(dev->page->pixels); + free(dev->page); } @@ -2052,12 +2113,124 @@ escp_close(void *priv) } +/************************************************************************ + * *** THIS BLOCK WILL BE MOVED TO THE 'PARPRNT' MODULE !! *** * + ************************************************************************/ +static void +parprnt_reset(escp_t *dev) +{ + dev->timeout = 0LL; + dev->ack = 0; + + printer_reset(dev); +} + + +static void +parprnt_write_data(uint8_t val, void *priv) +{ + escp_t *dev = (escp_t *)priv; + + DBGLOG(1, "PARPRNT: data(%02x)\n", val); + + if (dev != NULL) + dev->data = val; +} + + +static void +parprnt_write_ctrl(uint8_t val, void *priv) +{ + escp_t *dev = (escp_t *)priv; + + DEBUG("PARPRNT: ctrl(%02x)\n", val); + + if (dev == NULL) return; + + if (val & 0x08) { /* SELECT */ + /* select printer */ + dev->select = 1; + } + + if ((val & 0x04) && !(dev->ctrl & 0x04)) { + /* reset printer */ + dev->select = 0; + + parprnt_reset(dev); + } + + /* set autofeed value */ + dev->autofeed = val & 0x02 ? 1 : 0; + + /* + * Data is strobed to the parallel printer + * on the falling edge of the strobe bit. + */ + if (!(val & 0x01) && (dev->ctrl & 0x01)) { + /* Process incoming character. */ + escp_handle(dev, dev->data); + + dev->timeout = 500000LL * TIMER_USEC; + } + + /* Save new value. */ + dev->ctrl = val; +} + + +static uint8_t +parprnt_read_data(void *priv) +{ + escp_t *dev = (escp_t *)priv; + uint8_t ret = 0xff; + + if (dev != NULL) + ret = dev->data; + + return(ret); +} + + +static uint8_t +parprnt_read_ctrl(void *priv) +{ + escp_t *dev = (escp_t *)priv; + uint8_t ret = 0xe0; + + if (dev != NULL) + ret |= (dev->autofeed ? 0x02 : 0x00 | (dev->ctrl & 0xfd)); + + return(ret); +} + + +static uint8_t +parprnt_read_status(void *priv) +{ + escp_t *dev = (escp_t *)priv; + uint8_t ret = 0x1f; + + if (dev != NULL) { +#if 0 + if (! dev->busy) +#endif + ret |= 0x80; + + if (! dev->ack) + ret |= 0x40; + } + + DEBUG("PARPRNT: status(%02x)\n", ret); + + return(ret); +} + + const lpt_device_t lpt_prt_escp_device = { "EPSON ESC/P compatible printer", 0, - escp_init, - escp_close, - write_data, - write_ctrl, - read_status + escp_init, escp_close, + parprnt_write_data, parprnt_write_ctrl, + parprnt_read_data, parprnt_read_ctrl, + parprnt_read_status }; diff --git a/src/devices/printer/prt_text.c b/src/devices/printer/prt_text.c index 14dc518..808c29c 100644 --- a/src/devices/printer/prt_text.c +++ b/src/devices/printer/prt_text.c @@ -15,11 +15,11 @@ * printer mechanics. This would lead to a page being 66 lines * of 80 characters each. * - * Version: @(#)prt_text.c 1.0.4 2018/11/11 + * Version: @(#)prt_text.c 1.0.6 2019/01/13 * * Author: Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. + * Copyright 2018,2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -63,13 +63,13 @@ #include "printer.h" -#define FULL_PAGE 1 /* set if no top/bot margins */ +#define FULL_PAGE 1 /* set if no top/bot margins */ /* Default page values (for now.) */ -#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ +#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ #define PAGE_HEIGHT 11 -#define PAGE_LMARGIN 0.25 /* 0.25" left and right */ +#define PAGE_LMARGIN 0.25 /* 0.25" left and right */ #define PAGE_RMARGIN 0.25 #if FULL_PAGE # define PAGE_TMARGIN 0 @@ -78,18 +78,18 @@ # define PAGE_TMARGIN 0.25 # define PAGE_BMARGIN 0.25 #endif -#define PAGE_CPI 10.0 /* standard 10 cpi */ -#define PAGE_LPI 6.0 /* standard 6 lpi */ +#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_LPI 6.0 /* standard 6 lpi */ typedef struct { - int8_t dirty; /* has the page been printed on? */ + int8_t dirty; /* has the page been printed on? */ char pad; - uint8_t w; /* size info */ + uint8_t w; /* size info */ uint8_t h; - char *chars; /* character data */ + char *chars; /* character data */ } psurface_t; @@ -99,35 +99,35 @@ typedef struct { /* Output file name. */ wchar_t filename[1024]; - /* page data (TODO: make configurable) */ - double page_width, /* all in inches */ + /* Page data (TODO: make configurable.) */ + double page_width, /* all in inches */ page_height, left_margin, top_margin, right_margin, bot_margin; + double cpi, /* chars per inch */ + lpi; /* lines per inch */ - /* internal page data */ + /* Internal page data. */ psurface_t *page; uint8_t max_chars, max_lines; uint8_t curr_x, /* print head position (chars) */ curr_y; - /* font data */ - double cpi, /* defined chars per inch */ - lpi; /* defined lines per inch */ + /* Printer timeout. */ + int64_t timeout; - /* handshake data */ - uint8_t ctrl; - uint8_t data; - - int8_t ack; - int8_t select; - int8_t busy; - int8_t int_pending; - int8_t error; - int8_t autofeed; + /* Port Interface data */ + int8_t ack, + select, + busy, + int_pending, + error, + autofeed; + uint8_t ctrl, + data; } prnt_t; @@ -192,8 +192,9 @@ new_page(prnt_t *dev) } +/* API: reset the printer device. */ static void -reset_printer(prnt_t *dev) +prnt_reset(prnt_t *dev) { /* TODO: these three should be configurable */ dev->page_width = PAGE_WIDTH; @@ -224,7 +225,7 @@ reset_printer(prnt_t *dev) static int -process_char(prnt_t *dev, uint8_t ch) +process_data(prnt_t *dev, uint8_t ch) { uint8_t i; @@ -310,19 +311,21 @@ process_char(prnt_t *dev, uint8_t ch) } +/* API: process incoming data. */ static void -handle_char(prnt_t *dev) +prnt_handle(prnt_t *dev, uint8_t ch) { - uint8_t ch = dev->data; + /* Character has been seen. */ + dev->ack = 1; if (dev->page == NULL) return; - if (process_char(dev, ch) == 1) { - /* Command was processed. */ + if (process_data(dev, ch) == 1) { + /* A printer command was processed. */ return; } - /* Store character in the page buffer. */ + /* No command; store printable character in the page buffer. */ dev->page->chars[(dev->curr_y * dev->page->w) + dev->curr_x] = ch; dev->page->dirty = 1; @@ -335,73 +338,20 @@ handle_char(prnt_t *dev) } +/* API: the interface port timed out. */ static void -write_data(uint8_t val, void *priv) +prnt_timeout(void *priv) { prnt_t *dev = (prnt_t *)priv; - if (dev == NULL) return; + if (dev->page->dirty) + new_page(dev); - dev->data = val; + dev->timeout = 0LL; } + - -static void -write_ctrl(uint8_t val, void *priv) -{ - prnt_t *dev = (prnt_t *)priv; - - if (dev == NULL) return; - - /* set autofeed value */ - dev->autofeed = val & 0x02 ? 1 : 0; - - if (val & 0x08) { /* SELECT */ - /* select printer */ - dev->select = 1; - } - - if ((val & 0x04) && !(dev->ctrl & 0x04)) { - /* reset printer */ - dev->select = 0; - - reset_printer(dev); - } - - if (!(val & 0x01) && (dev->ctrl & 0x01)) { /* STROBE */ - /* Process incoming character. */ - handle_char(dev); - - /* ACK it, will be read on next READ STATUS. */ - dev->ack = 1; - } - - /* Save new value. */ - dev->ctrl = val; -} - - -static uint8_t -read_status(void *priv) -{ - prnt_t *dev = (prnt_t *)priv; - uint8_t ret = 0xff; - - if (dev == NULL) return(ret); - - ret = (dev->ack ? 0x00 : 0x40) | - (dev->select ? 0x10 : 0x00) | - (dev->busy ? 0x00 : 0x80) | - (dev->int_pending ? 0x00 : 0x04) | - (dev->error ? 0x00 : 0x08); - - /* Clear ACK after reading status. */ - dev->ack = 0; - - return(ret); -} - - +/* API: create and initialize the printer device. */ static void * prnt_init(const lpt_device_t *info) { @@ -411,12 +361,14 @@ prnt_init(const lpt_device_t *info) dev = (prnt_t *)mem_alloc(sizeof(prnt_t)); memset(dev, 0x00, sizeof(prnt_t)); dev->name = info->name; - dev->ctrl = 0x04; - INFO("PRNT: LPT printer '%s' initializing\n", dev->name); + INFO("PRNT: printer '%s' initializing\n", dev->name); /* Initialize parameters. */ - reset_printer(dev); + prnt_reset(dev); + + /* Create a timer to catch port timeouts. */ + timer_add(prnt_timeout, &dev->timeout, &dev->timeout, dev); /* Create a page buffer. */ dev->page = (psurface_t *)mem_alloc(sizeof(psurface_t)); @@ -425,12 +377,15 @@ prnt_init(const lpt_device_t *info) dev->page->chars = (char *)mem_alloc(dev->page->w * dev->page->h); memset(dev->page->chars, 0x00, dev->page->w * dev->page->h); + dev->ctrl = 0x04; + DEBUG("PRNT: created a virtual %ix%i page.\n", dev->page->w, dev->page->h); return(dev); } +/* API: close and release the printer device. */ static void prnt_close(void *priv) { @@ -452,12 +407,135 @@ prnt_close(void *priv) } +/* Reset a parallel printer device. */ +static void +parprnt_reset(prnt_t *dev) +{ + /* Reset the port interface. */ + dev->timeout = 0LL; + dev->ack = 0; + + /* Reset the printer. */ + prnt_reset(dev); +} + + +static void +parprnt_write_data(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + DBGLOG(1, "PARPRNT: data(%02x)\n", val); + + if (dev != NULL) + dev->data = val; +} + + +static void +parprnt_write_ctrl(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + DEBUG("PARPRNT: ctrl(%02x)\n", val); + + if (dev == NULL) return; + + if (val & 0x08) { /* SELECT */ + /* select printer */ + dev->select = 1; + } + + if ((val & 0x04) && !(dev->ctrl & 0x04)) { + /* reset printer */ + dev->select = 0; + + parprnt_reset(dev); + } + + /* set autofeed value */ + dev->autofeed = val & 0x02 ? 1 : 0; + + /* + * Data is strobed to the parallel printer + * on the falling edge of the strobe bit. + */ + if (!(val & 0x01) && (dev->ctrl & 0x01)) { + /* Process incoming character. */ + prnt_handle(dev, dev->data); + + /* ACK it, will be read on next READ STATUS. */ + dev->ack = 1; + + dev->timeout = 500000LL * TIMER_USEC; + } + + /* Save new value. */ + dev->ctrl = val; +} + + +static uint8_t +parprnt_read_data(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + uint8_t ret = 0xff; + + if (dev != NULL) + ret = dev->data; + + DBGLOG(1, "PARPRNT: data=%02x\n", ret); + + return(ret); +} + + +static uint8_t +parprnt_read_ctrl(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + uint8_t ret = 0xe0; + + if (dev != NULL) + ret |= (dev->autofeed ? 0x02 : 0x00 | (dev->ctrl & 0xfd)); + + DEBUG("PARPRNT: ctrl=%02x\n", ret); + + return(ret); +} + + +static uint8_t +parprnt_read_status(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + uint8_t ret = 0x1f; + + if (dev != NULL) { + ret = (dev->select ? 0x10 : 0x00) | + (dev->int_pending ? 0x00 : 0x04) | + (dev->error ? 0x00 : 0x08); + +#if 0 + if (! dev->busy) +#endif + ret |= 0x80; + + if (! dev->ack) + ret |= 0x40; + } + + DEBUG("PARPRNT: status=%02x\n", ret); + + return(ret); +} + + const lpt_device_t lpt_prt_text_device = { "Generic TEXT printer", 0, - prnt_init, - prnt_close, - write_data, - write_ctrl, - read_status + prnt_init, prnt_close, + parprnt_write_data, parprnt_write_ctrl, + parprnt_read_data, parprnt_read_ctrl, + parprnt_read_status }; diff --git a/src/devices/sound/snd_gus.c b/src/devices/sound/snd_gus.c index 4813e02..cc99f78 100644 --- a/src/devices/sound/snd_gus.c +++ b/src/devices/sound/snd_gus.c @@ -8,7 +8,7 @@ * * Implementation of the Gravis UltraSound sound device. * - * Version: @(#)snd_gus.c 1.0.9 2019/01/13 + * Version: @(#)snd_gus.c 1.0.10 2019/01/13 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -240,7 +240,9 @@ static void gus_write(uint16_t addr, uint8_t val, void *priv) { gus_t *dev = (gus_t *)priv; +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) uint16_t ioport; +#endif int c, d, old; if (dev->latch_enable && addr != 0x24b) diff --git a/src/devices/sound/snd_pas16.c b/src/devices/sound/snd_pas16.c index f3c6f73..e6e5a77 100644 --- a/src/devices/sound/snd_pas16.c +++ b/src/devices/sound/snd_pas16.c @@ -79,13 +79,13 @@ * FF88 - board model * 3 = PAS16 * - * Version: @(#)snd_pas16.c 1.0.8 2018/10/16 + * Version: @(#)snd_pas16.c 1.0.9 2019/02/08 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017,2019 Fred N. van Kempen. * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. * @@ -430,12 +430,18 @@ static void pas16_out(uint16_t port, uint8_t val, void *p) } if (cpu_state.pc == 0x80048CF3) { +#if 0 if (output) +#endif fatal("here\n"); +#if 0 output = 3; +#endif } -/* if (CS == 0x1FF4 && pc == 0x0431) - output = 3;*/ +#if 0 + if (CS == 0x1FF4 && pc == 0x0431) + output = 3; +#endif } static void pas16_pit_out(uint16_t port, uint8_t val, void *p) diff --git a/src/devices/video/vid_cga.c b/src/devices/video/vid_cga.c index ac0b2e4..08e224e 100644 --- a/src/devices/video/vid_cga.c +++ b/src/devices/video/vid_cga.c @@ -8,7 +8,7 @@ * * Emulation of the old and new IBM CGA graphics cards. * - * Version: @(#)vid_cga.c 1.0.7 2019/01/13 + * Version: @(#)vid_cga.c 1.0.8 2019/02/09 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -429,10 +429,20 @@ cga_poll(void *priv) dev->cgadispon = 1; if (! dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - if ((dev->crtc[10] & 0x60) == 0x20) - dev->cursoron = 0; - else - dev->cursoron = dev->cgablink & 8; + + switch (dev->crtc[10] & 0x60) { + case 0x20: + dev->cursoron = 0; + break; + + case 0x60: + dev->cursoron = dev->cgablink & 0x10; + break; + + default: + dev->cursoron = dev->cgablink & 8; + break; + } } if (dev->vc == dev->crtc[7]) { diff --git a/src/devices/video/vid_voodoo.c b/src/devices/video/vid_voodoo.c index 0cd0851..4e02f57 100644 --- a/src/devices/video/vid_voodoo.c +++ b/src/devices/video/vid_voodoo.c @@ -8,7 +8,7 @@ * * Emulation of the 3DFX Voodoo Graphics controller. * - * Version: @(#)vid_voodoo.c 1.0.13 2018/11/13 + * Version: @(#)vid_voodoo.c 1.0.14 2019/01/16 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1675,13 +1675,13 @@ static void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) for (d = 0; d < 4; d++) { - int addr_start = voodoo->texture_cache[tmu][c].addr_start[d]; - int addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + uint32_t addr_start = voodoo->texture_cache[tmu][c].addr_start[d]; + uint32_t addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; if (addr_end != 0) { - int addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff; - int addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff; + uint32_t addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff; + uint32_t addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff; if (addr_end_masked < addr_start_masked) addr_end_masked = voodoo->texture_mask+1; @@ -3626,7 +3626,7 @@ static void render_thread(void *param, int odd_even) thread_set_event(voodoo->render_not_full_event[odd_even]); end_time = plat_timer_read(); - voodoo->render_time[odd_even] += end_time - start_time; + voodoo->render_time[odd_even] += (int) (end_time - start_time); } voodoo->render_voodoo_busy[odd_even] = 0; @@ -5973,7 +5973,7 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) addr &= 0xffffff; - cycles -= voodoo->read_time; + cycles -= (int)voodoo->read_time; if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ { @@ -6030,7 +6030,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) voodoo->rd_count++; addr &= 0xffffff; - cycles -= voodoo->read_time; + cycles -= (int)voodoo->read_time; if (addr & 0x800000) /*Texture*/ { @@ -6235,9 +6235,9 @@ static void voodoo_writew(uint32_t addr, uint16_t val, void *p) addr &= 0xffffff; if (addr == voodoo->last_write_addr+4) - cycles -= voodoo->burst_time; + cycles -= (int)voodoo->burst_time; else - cycles -= voodoo->write_time; + cycles -= (int)voodoo->write_time; voodoo->last_write_addr = addr; if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ @@ -6249,7 +6249,7 @@ static void voodoo_pixelclock_update(voodoo_t *voodoo) int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2; int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2; int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07); - float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + float t = (float) (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); double clock_const; int line_length; @@ -6277,9 +6277,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) addr &= 0xffffff; if (addr == voodoo->last_write_addr+4) - cycles -= voodoo->burst_time; + cycles -= (int)voodoo->burst_time; else - cycles -= voodoo->write_time; + cycles -= (int)voodoo->write_time; voodoo->last_write_addr = addr; if (addr & 0x800000) /*Texture*/ @@ -7018,9 +7018,9 @@ static void voodoo_generate_filter_v1(voodoo_t *voodoo) float thiscol, thiscolg, thiscolb, lined; float fcr, fcg, fcb; - fcr = FILTCAP * 5; - fcg = FILTCAPG * 6; - fcb = FILTCAPB * 5; + fcr = (float) (FILTCAP * 5); + fcg = (float) (FILTCAPG * 6); + fcb = (float) (FILTCAPB * 5); for (g=0;g FILTCAP) - difference = FILTCAP; - if (difference < -FILTCAP) - difference = -FILTCAP; + if (difference > (float)FILTCAP) + difference = (float)FILTCAP; + if (difference < (float)-FILTCAP) + difference = (float)-FILTCAP; - if (diffg > FILTCAPG) - diffg = FILTCAPG; - if (diffg < -FILTCAPG) - diffg = -FILTCAPG; + if (diffg > (float)FILTCAPG) + diffg = (float)FILTCAPG; + if (diffg < (float)-FILTCAPG) + diffg = (float)-FILTCAPG; - if (diffb > FILTCAPB) - diffb = FILTCAPB; - if (diffb < -FILTCAPB) - diffb = -FILTCAPB; + if (diffb > (float)FILTCAPB) + diffb = (float)FILTCAPB; + if (diffb < (float)-FILTCAPB) + diffb = (float)-FILTCAPB; // hack - to make it not bleed onto black //if (g == 0){ @@ -7053,11 +7053,11 @@ static void voodoo_generate_filter_v1(voodoo_t *voodoo) //} if ((difference < fcr) || (-difference > -fcr)) - thiscol = g + (difference / 2); + thiscol = (float) (g + (difference / 2)); if ((diffg < fcg) || (-diffg > -fcg)) - thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ + thiscolg = (float) (g + (diffg / 2)); /* need these divides so we can actually undither! */ if ((diffb < fcb) || (-diffb > -fcb)) - thiscolb = g + (diffb / 2); + thiscolb = (float) (g + (diffb / 2)); if (thiscol < 0) thiscol = 0; @@ -7074,21 +7074,21 @@ static void voodoo_generate_filter_v1(voodoo_t *voodoo) if (thiscolb > FILTDIV-1) thiscolb = FILTDIV-1; - voodoo->thefilter[g][h] = thiscol; - voodoo->thefilterg[g][h] = thiscolg; - voodoo->thefilterb[g][h] = thiscolb; + voodoo->thefilter[g][h] = (uint8_t)thiscol; + voodoo->thefilterg[g][h] = (uint8_t)thiscolg; + voodoo->thefilterb[g][h] = (uint8_t)thiscolb; } - lined = g + 4; + lined = (float) (g + 4); if (lined > 255) - lined = 255; - voodoo->purpleline[g][0] = lined; - voodoo->purpleline[g][2] = lined; + lined = (float)255; + voodoo->purpleline[g][0] = (uint16_t)lined; + voodoo->purpleline[g][2] = (uint16_t)lined; - lined = g + 0; + lined = (float) (g + 0); if (lined > 255) - lined = 255; - voodoo->purpleline[g][1] = lined; + lined = (float)255; + voodoo->purpleline[g][1] = (uint16_t)lined; } } @@ -7102,13 +7102,13 @@ static void voodoo_generate_filter_v2(voodoo_t *voodoo) // pre-clamping - fcr = FILTCAP; - fcg = FILTCAPG; - fcb = FILTCAPB; + fcr = (float)FILTCAP; + fcg = (float)FILTCAPG; + fcb = (float)FILTCAPB; - if (fcr > 32) fcr = 32; - if (fcg > 32) fcg = 32; - if (fcb > 32) fcb = 32; + if (fcr > 32) fcr = (float)32; + if (fcg > 32) fcg = (float)32; + if (fcb > 32) fcb = (float)32; for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into { @@ -7123,7 +7123,7 @@ static void voodoo_generate_filter_v2(voodoo_t *voodoo) if (avgdiff < 0) avgdiff *= -1; if (difference < 0) difference *= -1; - thiscol = thiscolg = thiscolb = g; + thiscol = thiscolg = thiscolb = (float)g; // try lighten if (h > g) @@ -7140,11 +7140,11 @@ static void voodoo_generate_filter_v2(voodoo_t *voodoo) thiscolb = g + clb; if (thiscol>g+FILTCAP) - thiscol=g+FILTCAP; + thiscol=(float) (g+FILTCAP); if (thiscolg>g+FILTCAPG) - thiscolg=g+FILTCAPG; + thiscolg=(float) (g+FILTCAPG); if (thiscolb>g+FILTCAPB) - thiscolb=g+FILTCAPB; + thiscolb=(float) (g+FILTCAPB); if (thiscol>g+avgdiff) @@ -7157,37 +7157,37 @@ static void voodoo_generate_filter_v2(voodoo_t *voodoo) } if (difference > FILTCAP) - thiscol = g; + thiscol = (float)g; if (difference > FILTCAPG) - thiscolg = g; + thiscolg = (float)g; if (difference > FILTCAPB) - thiscolb = g; + thiscolb = (float)g; // clamp - if (thiscol < 0) thiscol = 0; - if (thiscolg < 0) thiscolg = 0; - if (thiscolb < 0) thiscolb = 0; + if (thiscol < 0) thiscol = (float)0; + if (thiscolg < 0) thiscolg = (float)0; + if (thiscolb < 0) thiscolb = (float)0; - if (thiscol > 255) thiscol = 255; - if (thiscolg > 255) thiscolg = 255; - if (thiscolb > 255) thiscolb = 255; + if (thiscol > 255) thiscol = (float)255; + if (thiscolg > 255) thiscolg = (float)255; + if (thiscolb > 255) thiscolb = (float)255; // add to the table - voodoo->thefilter[g][h] = (thiscol); - voodoo->thefilterg[g][h] = (thiscolg); - voodoo->thefilterb[g][h] = (thiscolb); + voodoo->thefilter[g][h] = (uint8_t)thiscol; + voodoo->thefilterg[g][h] = (uint8_t)thiscolg; + voodoo->thefilterb[g][h] = (uint8_t)thiscolb; // debug the ones that don't give us much of a difference //if (difference < FILTCAP) //DEBUG("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); } - lined = g + 3; + lined = (float) (g + 3); if (lined > 255) - lined = 255; - voodoo->purpleline[g][0] = lined; - voodoo->purpleline[g][1] = 0; - voodoo->purpleline[g][2] = lined; + lined = (float)255; + voodoo->purpleline[g][0] = (uint16_t)lined; + voodoo->purpleline[g][1] = (uint16_t)0; + voodoo->purpleline[g][2] = (uint16_t)lined; } } @@ -7256,9 +7256,9 @@ static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uin { for (x=0; xpurpleline[fil[x*3]][0]; - fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; - fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; + fil[x*3] = (uint8_t)voodoo->purpleline[fil[x*3]][0]; + fil[x*3+1] = (uint8_t)voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = (uint8_t)voodoo->purpleline[fil[x*3+2]][2]; } } diff --git a/src/machines/m_zenith.c b/src/machines/m_zenith.c index b481d3b..2f673d4 100644 --- a/src/machines/m_zenith.c +++ b/src/machines/m_zenith.c @@ -6,16 +6,16 @@ * * This file is part of the VARCem Project. * - * Implementation of the Zenith SuperSport. + * Implementation of the Zenith SupersPORT. * - * Version: @(#)m_zenith.c 1.0.1 2019/01/13 + * Version: @(#)m_zenith.c 1.0.2 2019/01/13 * * Authors: Fred N. van Kempen, * Original patch for PCem by 'Tux' * Sarah Walker, * * Copyright 2019 Fred N. van Kempen. - * Copyright 2019 Sarah Walker. + * Copyright 2018,2019 Sarah Walker. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -91,16 +91,20 @@ scratchpad_init(const device_t *info) dev = (zenith_t *)mem_alloc(sizeof(zenith_t)); memset(dev, 0x00, sizeof(zenith_t)); - - dev->scratchpad_ram = mem_alloc(0x4000); - + + /* Disable ROM area at F0000, need it for Scratchpad RAM. */ mem_map_disable(&bios_mapping[4]); mem_map_disable(&bios_mapping[5]); - mem_map_add(&dev->scratchpad_mapping, 0xf0000, 0x4000, + /* Allocate and initialize the Scratchpad RAM area. */ + dev->scratchpad_ram = mem_alloc(16384); + memset(dev->scratchpad_ram, 0x00, 16384); + + /* Create and enable a mapping for this memory. */ + mem_map_add(&dev->scratchpad_mapping, 0xf0000, 16384, scratchpad_read,NULL,NULL, scratchpad_write,NULL,NULL, dev->scratchpad_ram, MEM_MAPPING_EXTERNAL, dev); - + return dev; } @@ -121,9 +125,7 @@ static const device_t scratchpad_device = { "Zenith scratchpad RAM", 0, 0, scratchpad_init, scratchpad_close, NULL, - NULL, - NULL, - NULL, + NULL, NULL, NULL, NULL, NULL }; diff --git a/src/pc.c b/src/pc.c index e750eb4..c49f82a 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,13 +8,13 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.62 2018/11/22 + * Version: @(#)pc.c 1.0.63 2019/01/27 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. * @@ -215,8 +215,13 @@ pclog_ex(const char *fmt, va_list ap) /* If a logpath was set, override the default. */ if (log_path[0] != L'\0') { fp = plat_fopen(log_path, L"w"); - if (fp != NULL) + if (fp != NULL) { + /* Set the new logging handle. */ logfp = fp; + + /* Clear the path so we do not try this again. */ + memset(log_path, 0x00, sizeof(log_path)); + } } vsprintf(temp, fmt, ap); diff --git a/src/png.c b/src/png.c index 85e08d5..778982d 100644 --- a/src/png.c +++ b/src/png.c @@ -8,11 +8,11 @@ * * Provide centralized access to the PNG image handler. * - * Version: @(#)png.c 1.0.4 2018/10/07 + * Version: @(#)png.c 1.0.5 2019/01/11 * * Author: Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. + * Copyright 2018,2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -97,6 +97,16 @@ static void (*PNG_set_IHDR)(png_const_structrp png_ptr, int color_type, int interlace_method, int compression_method, int filter_method); +static void (*PNG_set_PLTE)(png_structrp png_ptr, + png_inforp info_ptr, + png_const_colorp palette, + int num_palette); +static void (*PNG_set_rows)(png_const_structrp png_ptr, + png_inforp info_ptr, + png_bytepp row_pointers); +static void (*PNG_write_png)(png_structrp png_ptr, + png_inforp info_ptr, + int transforms, png_voidp params); static png_size_t (*PNG_get_rowbytes)(png_const_structrp png_ptr, png_const_inforp info_ptr); static void (*PNG_write_info)(png_structrp png_ptr, @@ -110,25 +120,47 @@ static void (*PNG_write_rows)(png_structrp png_ptr, static void (*PNG_write_end)(png_structrp png_ptr, png_inforp info_ptr); +static void (*PNG_set_compression_level)(png_structrp png_ptr, + int level); +static void (*PNG_set_compression_mem_level)(png_structrp png_ptr, + int mem_level); +static void (*PNG_set_compression_strategy)(png_structrp png_ptr, + int strategy); +static void (*PNG_set_compression_window_bits)(png_structrp png_ptr, + int window_bits); +static void (*PNG_set_compression_method)(png_structrp png_ptr, + int method); +static void (*PNG_set_compression_buffer_size)(png_structrp png_ptr, + png_size_t size); + static const dllimp_t png_imports[] = { - { "png_create_write_struct", &PNG_create_write_struct }, - { "png_destroy_write_struct", &PNG_destroy_write_struct }, - { "png_create_info_struct", &PNG_create_info_struct }, + { "png_create_write_struct", &PNG_create_write_struct }, + { "png_destroy_write_struct", &PNG_destroy_write_struct }, + { "png_create_info_struct", &PNG_create_info_struct }, # if USE_CUSTOM_IO - { "png_set_write_fn", &PNG_set_write_fn }, - { "png_get_io_ptr", &PNG_get_io_ptr }, + { "png_set_write_fn", &PNG_set_write_fn }, + { "png_get_io_ptr", &PNG_get_io_ptr }, # else - { "png_init_io", &PNG_init_io }, + { "png_init_io", &PNG_init_io }, # endif - { "png_set_IHDR", &PNG_set_IHDR }, - { "png_get_rowbytes", &PNG_get_rowbytes }, - { "png_write_info", &PNG_write_info }, - { "png_write_row", &PNG_write_row }, - { "png_write_rows", &PNG_write_rows }, - { "png_write_image", &PNG_write_image }, - { "png_write_end", &PNG_write_end }, - { NULL, NULL } + { "png_set_IHDR", &PNG_set_IHDR }, + { "png_set_PLTE", &PNG_set_PLTE }, + { "png_get_rowbytes", &PNG_get_rowbytes }, + { "png_set_rows", &PNG_set_rows }, + { "png_write_png", &PNG_write_png }, + { "png_write_info", &PNG_write_info }, + { "png_write_row", &PNG_write_row }, + { "png_write_rows", &PNG_write_rows }, + { "png_write_image", &PNG_write_image }, + { "png_write_end", &PNG_write_end }, + { "png_set_compression_level", &PNG_set_compression_level }, + { "png_set_compression_mem_level", &PNG_set_compression_mem_level }, + { "png_set_compression_strategy", &PNG_set_compression_strategy }, + { "png_set_compression_window_bits", &PNG_set_compression_window_bits}, + { "png_set_compression_method", &PNG_set_compression_method }, + { "png_set_compression_buffer_size", &PNG_set_compression_buffer_size}, + { NULL, NULL } }; #endif @@ -170,7 +202,7 @@ flush_handler(png_struct *png_ptr) #endif -/* Prepare the PNG library for use, load DLL if needed. */ +/* Prepare for use, load DLL if needed. */ int png_load(void) { @@ -201,7 +233,7 @@ png_load(void) } -/* PNG library no longer needed, unload DLL if needed. */ +/* No longer needed, unload DLL if needed. */ void png_unload(void) { @@ -214,7 +246,7 @@ png_unload(void) } -/* Write the given image as an 8-bit GrayScale PNG image file. */ +/* Write the given image as an 8-bit GrayScale file. */ int png_write_gray(const wchar_t *fn, int inv, uint8_t *pix, int16_t w, int16_t h) { @@ -278,6 +310,14 @@ error: #else PNGFUNC(init_io)(png, fp); #endif + PNGFUNC(set_compression_level)(png, 9); + + /* Set other "zlib" parameters. */ + PNGFUNC(set_compression_mem_level)(png, 8); + PNGFUNC(set_compression_strategy)(png, PNG_Z_DEFAULT_STRATEGY); + PNGFUNC(set_compression_window_bits)(png, 15); + PNGFUNC(set_compression_method)(png, 8); + PNGFUNC(set_compression_buffer_size)(png, 8192); PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, @@ -316,7 +356,7 @@ error: } -/* Write the given BITMAP-format image as an 8-bit RGBA PNG image file. */ +/* Write the given BITMAP-format image as an 8-bit RGBA file. */ int png_write_rgb(const wchar_t *fn, uint8_t *pix, int16_t w, int16_t h) { @@ -370,6 +410,14 @@ error: #else PNGFUNC(init_io)(png, fp); #endif + PNGFUNC(set_compression_level)(png, 9); + + /* Set other "zlib" parameters. */ + PNGFUNC(set_compression_mem_level)(png, 8); + PNGFUNC(set_compression_strategy)(png, PNG_Z_DEFAULT_STRATEGY); + PNGFUNC(set_compression_window_bits)(png, 15); + PNGFUNC(set_compression_method)(png, 8); + PNGFUNC(set_compression_buffer_size)(png, 8192); PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, @@ -429,3 +477,102 @@ error: return(1); } + + +/* Write the given BITMAP-format image as an 8-bit color palette file. */ +int +png_write_pal(const wchar_t *fn, uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE pal) +{ + png_color palette[256]; + png_structp png = NULL; + png_infop info = NULL; + png_bytepp rows; + FILE *fp; + int i; + + /* Load the DLL if needed, give up if that fails. */ + if (! png_load()) return(0); + + /* Create the image file. */ + fp = plat_fopen(fn, L"wb"); + if (fp == NULL) { + ERRLOG("PNG: File %ls could not be opened for writing!\n", fn); +error: + if (png != NULL) + PNGFUNC(destroy_write_struct)(&png, &info); + if (fp != NULL) + (void)fclose(fp); + return(0); + } + + /* Initialize PNG stuff. */ + png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL, + error_handler, warning_handler); + if (png == NULL) { + ERRLOG("PNG: create_write_struct failed!\n"); + goto error; + } + + info = PNGFUNC(create_info_struct)(png); + if (info == NULL) { + ERRLOG("PNG: create_info_struct failed!\n"); + goto error; + } + +#if USE_CUSTOM_IO + /* + * We use our own I/O routines, because it seems that some of + * the PNG DLL's out there are compiled in Debug mode, which + * causes the 'FILE' definition to be different. This in turn + * results in pretty bad crashes when trying to write.. + * + * Using custom I/O routines, we avoid this issue. + */ + PNGFUNC(set_write_fn)(png, (void *)fp, write_handler, flush_handler); +#else + PNGFUNC(init_io)(png, fp); +#endif + PNGFUNC(set_compression_level)(png, 9); + + /* Set other "zlib" parameters. */ + PNGFUNC(set_compression_mem_level)(png, 8); + PNGFUNC(set_compression_strategy)(png, PNG_Z_DEFAULT_STRATEGY); + PNGFUNC(set_compression_window_bits)(png, 15); + PNGFUNC(set_compression_method)(png, 8); + PNGFUNC(set_compression_buffer_size)(png, 8192); + + PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + PNGFUNC(write_info)(png, info); + + /* Create the palette. */ + for (i = 0; i < 256; i++) { + palette[i].red = pal[i].r; + palette[i].green = pal[i].g; + palette[i].blue = pal[i].b; + } + PNGFUNC(set_PLTE)(png, info, palette, i); + + /* Create a buffer for scanlines of pixels. */ + rows = (png_bytep *)mem_alloc(sizeof(png_bytep) * h); + for (i = 0; i < h; i++) { + /* Create a buffer for this scanline. */ + rows[i] = (pix + (i * pitch)); + } + PNGFUNC(set_rows)(png, info, rows); + + /* Write image to the file. */ + PNGFUNC(write_png)(png, info, 0, NULL); + + /* No longer need the row buffers. */ + free(rows); + + PNGFUNC(destroy_write_struct)(&png, &info); + + /* Clean up. */ + (void)fclose(fp); + + return(1); +} diff --git a/src/png.h b/src/png.h index 20cd5c8..f8df57f 100644 --- a/src/png.h +++ b/src/png.h @@ -8,11 +8,11 @@ * * Definitions for the centralized PNG image handler. * - * Version: @(#)png.h 1.0.1 2018/09/01 + * Version: @(#)png.h 1.0.2 2019/01/11 * * Author: Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. + * Copyright 2018,2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -58,8 +58,14 @@ extern void png_unload(void); extern int png_write_gray(const wchar_t *path, int invert, uint8_t *pix, int16_t w, int16_t h); -extern int png_write_rgb(const wchar_t *fn, - uint8_t *pix, int16_t w, int16_t h); +extern int png_write_rgb(const wchar_t *fn, uint8_t *pix, + int16_t w, int16_t h); + +#ifdef EMU_VIDEO_H +extern int png_write_pal(const wchar_t *fn, uint8_t *pix, + int16_t w, int16_t h, + uint16_t pitch, PALETTE pal); +#endif #ifdef __cplusplus } diff --git a/src/win/VARCem.rc b/src/win/VARCem.rc index 0fa7fdd..c287175 100644 --- a/src/win/VARCem.rc +++ b/src/win/VARCem.rc @@ -51,7 +51,14 @@ #include "resource.h" +#define RTL 0 + + +#if RTL +LANGUAGE LANG_HEBREW, 0x01 +#else LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#endif #include "../ui/lang/VARCem.str" @@ -220,7 +227,11 @@ VS_VERSION_INFO VERSIONINFO BEGIN BLOCK "StringFileInfo" BEGIN +#if RTL + BLOCK "040dfde9" +#else BLOCK "0409fde9" +#endif BEGIN VALUE "CompanyName", "IRC #VARCem on FreeNode" VALUE "FileDescription", "Virtual ARchaeological Computer EMulator" @@ -237,6 +248,10 @@ VS_VERSION_INFO VERSIONINFO END BLOCK "VarFileInfo" BEGIN +#if RTL + VALUE "Translation", 0x040d, 65001 +#else VALUE "Translation", 0x0409, 65001 +#endif END END diff --git a/src/win/win.c b/src/win/win.c index 5b8ca93..8f6a986 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -216,6 +216,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) /* First, set our (default) language. */ lang = (int)GetUserDefaultUILanguage(); +INFO("WIN: uilang = %04x\n", lang); /* * Set the initial active language for this application. @@ -230,6 +231,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) lang = 0x0409; (void)ui_lang_set(lang); } +INFO("WIN: initial lang = %04x\n", lang); #ifdef USE_CRASHDUMP /* Enable crash dump services. */ @@ -257,6 +259,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) lang = emu_lang_id; (void)ui_lang_set(lang); } +INFO("WIN: lang = %04x / %04x\n", language, lang); #ifdef USE_HOST_CDROM cdrom_host_init(); diff --git a/src/win/win_settings_periph.h b/src/win/win_settings_periph.h index 44b2b04..cb698f0 100644 --- a/src/win/win_settings_periph.h +++ b/src/win/win_settings_periph.h @@ -8,12 +8,12 @@ * * Implementation of the Settings dialog. * - * Version: @(#)win_settings_periph.h 1.0.16 2018/10/24 + * Version: @(#)win_settings_periph.h 1.0.17 2019/01/15 * * Authors: Fred N. van Kempen, * Miran Grca, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2016-2018 Miran Grca. * * This program is free software; you can redistribute it and/or modify @@ -109,7 +109,6 @@ recalc_hdc_list(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_HDC); SendMessage(h, CB_RESETCONTENT, 0, 0); -INFO("LIST: active=%d (%s)\n", temp_hdc_type, hdc_get_name(temp_hdc_type)); c = d = 0; for (;;) { stransi = hdc_get_internal_name(c); @@ -145,7 +144,6 @@ INFO("LIST: active=%d (%s)\n", temp_hdc_type, hdc_get_name(temp_hdc_type)); hdc_to_list[c] = d; list_to_hdc[d] = c; -INFO("[%d]=%d\n", c, hdc_to_list[c], d, list_to_hdc[d]); c++; d++; } diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 0ec4626..e4731fd 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -717,7 +717,12 @@ ui_init(int nCmdShow) * always keep in mind when changing the window size. */ swprintf(title, sizeof_w(title), L"%s %s", EMU_NAME, emu_version); - hwndMain = CreateWindow( + hwndMain = CreateWindowEx( +#if 0 + WS_EX_LAYOUTRTL | WS_EX_RIGHT, +#else + 0, +#endif CLASS_NAME, /* class name */ title, /* Title Text */ flags, /* style flags */