Subversion Repositories Kolibri OS

Rev

Rev 8523 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. // 8086tiny: a tiny, highly functional, highly portable PC emulator/VM
  2. // Copyright 2013-14, Adrian Cable (adrian.cable@gmail.com) - http://www.megalith.co.uk/8086tiny
  3. //
  4. // Revision 1.25
  5. //
  6. // This work is licensed under the MIT License. See included LICENSE.TXT.
  7.  
  8. #include <time.h>
  9. //#include <sys/timeb.h>
  10.  
  11. struct timeb
  12. {
  13.     time_t              time;           /* Seconds since the epoch      */
  14.     unsigned short      millitm;
  15.     short               timezone;
  16.     short               dstflag;
  17. };
  18.  
  19. static int ftime(struct timeb* tp)
  20. {
  21.         unsigned counter = 0;
  22.         __asm__ volatile("int $0x40" : "=a"(counter) : "a"(26), "b"(9));
  23.         tp->millitm = (counter % 100) * 10;
  24.         return 0;
  25. }
  26.  
  27.  
  28. #include <memory.h>
  29.  
  30. #ifndef _WIN32
  31. #include <unistd.h>
  32. #include <fcntl.h>
  33. #endif
  34.  
  35. #ifndef NO_GRAPHICS
  36. #include <SDL/SDL.h>
  37. #endif
  38.  
  39. // Emulator system constants
  40. #define IO_PORT_COUNT 0x10000
  41. #define RAM_SIZE 0x10FFF0
  42. #define REGS_BASE 0xF0000
  43. #define VIDEO_RAM_SIZE 0x10000
  44.  
  45. // Graphics/timer/keyboard update delays (explained later)
  46. #ifndef GRAPHICS_UPDATE_DELAY
  47. #define GRAPHICS_UPDATE_DELAY 36000 //1000 times
  48. #endif
  49. #define KEYBOARD_TIMER_UPDATE_DELAY 2000 //1000 times
  50.  
  51. // 16-bit register decodes
  52. #define REG_AX 0
  53. #define REG_CX 1
  54. #define REG_DX 2
  55. #define REG_BX 3
  56. #define REG_SP 4
  57. #define REG_BP 5
  58. #define REG_SI 6
  59. #define REG_DI 7
  60.  
  61. #define REG_ES 8
  62. #define REG_CS 9
  63. #define REG_SS 10
  64. #define REG_DS 11
  65.  
  66. #define REG_ZERO 12
  67. #define REG_SCRATCH 13
  68.  
  69. // 8-bit register decodes
  70. #define REG_AL 0
  71. #define REG_AH 1
  72. #define REG_CL 2
  73. #define REG_CH 3
  74. #define REG_DL 4
  75. #define REG_DH 5
  76. #define REG_BL 6
  77. #define REG_BH 7
  78.  
  79. // FLAGS register decodes
  80. #define FLAG_CF 40
  81. #define FLAG_PF 41
  82. #define FLAG_AF 42
  83. #define FLAG_ZF 43
  84. #define FLAG_SF 44
  85. #define FLAG_TF 45
  86. #define FLAG_IF 46
  87. #define FLAG_DF 47
  88. #define FLAG_OF 48
  89.  
  90. // Lookup tables in the BIOS binary
  91. #define TABLE_XLAT_OPCODE 8
  92. #define TABLE_XLAT_SUBFUNCTION 9
  93. #define TABLE_STD_FLAGS 10
  94. #define TABLE_PARITY_FLAG 11
  95. #define TABLE_BASE_INST_SIZE 12
  96. #define TABLE_I_W_SIZE 13
  97. #define TABLE_I_MOD_SIZE 14
  98. #define TABLE_COND_JUMP_DECODE_A 15
  99. #define TABLE_COND_JUMP_DECODE_B 16
  100. #define TABLE_COND_JUMP_DECODE_C 17
  101. #define TABLE_COND_JUMP_DECODE_D 18
  102. #define TABLE_FLAGS_BITFIELDS 19
  103.  
  104. // Bitfields for TABLE_STD_FLAGS values
  105. #define FLAGS_UPDATE_SZP 1
  106. #define FLAGS_UPDATE_AO_ARITH 2
  107. #define FLAGS_UPDATE_OC_LOGIC 4
  108.  
  109. // Helper macros
  110.  
  111. // Decode mod, r_m and reg fields in instruction
  112. #define DECODE_RM_REG scratch2_uint = 4 * !i_mod, \
  113.                                           op_to_addr = rm_addr = i_mod < 3 ? SEGREG(seg_override_en ? seg_override : bios_table_lookup[scratch2_uint + 3][i_rm], bios_table_lookup[scratch2_uint][i_rm], regs16[bios_table_lookup[scratch2_uint + 1][i_rm]] + bios_table_lookup[scratch2_uint + 2][i_rm] * i_data1+) : GET_REG_ADDR(i_rm), \
  114.                                           op_from_addr = GET_REG_ADDR(i_reg), \
  115.                                           i_d && (scratch_uint = op_from_addr, op_from_addr = rm_addr, op_to_addr = scratch_uint)
  116.  
  117. // Return memory-mapped register location (offset into mem array) for register #reg_id
  118. #define GET_REG_ADDR(reg_id) (REGS_BASE + (i_w ? 2 * reg_id : 2 * reg_id + reg_id / 4 & 7))
  119.  
  120. // Returns number of top bit in operand (i.e. 8 for 8-bit operands, 16 for 16-bit operands)
  121. #define TOP_BIT 8*(i_w + 1)
  122.  
  123. // Opcode execution unit helpers
  124. #define OPCODE ;break; case
  125. #define OPCODE_CHAIN ; case
  126.  
  127. // [I]MUL/[I]DIV/DAA/DAS/ADC/SBB helpers
  128. #define MUL_MACRO(op_data_type,out_regs) (set_opcode(0x10), \
  129.                                                                                   out_regs[i_w + 1] = (op_result = CAST(op_data_type)mem[rm_addr] * (op_data_type)*out_regs) >> 16, \
  130.                                                                                   regs16[REG_AX] = op_result, \
  131.                                                                                   set_OF(set_CF(op_result - (op_data_type)op_result)))
  132. #define DIV_MACRO(out_data_type,in_data_type,out_regs) (scratch_int = CAST(out_data_type)mem[rm_addr]) && !(scratch2_uint = (in_data_type)(scratch_uint = (out_regs[i_w+1] << 16) + regs16[REG_AX]) / scratch_int, scratch2_uint - (out_data_type)scratch2_uint) ? out_regs[i_w+1] = scratch_uint - scratch_int * (*out_regs = scratch2_uint) : pc_interrupt(0)
  133. #define DAA_DAS(op1,op2,mask,min) set_AF((((scratch2_uint = regs8[REG_AL]) & 0x0F) > 9) || regs8[FLAG_AF]) && (op_result = regs8[REG_AL] op1 6, set_CF(regs8[FLAG_CF] || (regs8[REG_AL] op2 scratch2_uint))), \
  134.                                                                   set_CF((((mask & 1 ? scratch2_uint : regs8[REG_AL]) & mask) > min) || regs8[FLAG_CF]) && (op_result = regs8[REG_AL] op1 0x60)
  135. #define ADC_SBB_MACRO(a) OP(a##= regs8[FLAG_CF] +), \
  136.                                                  set_CF(regs8[FLAG_CF] && (op_result == op_dest) || (a op_result < a(int)op_dest)), \
  137.                                                  set_AF_OF_arith()
  138.  
  139. // Execute arithmetic/logic operations in emulator memory/registers
  140. #define R_M_OP(dest,op,src) (i_w ? op_dest = CAST(unsigned short)dest, op_result = CAST(unsigned short)dest op (op_source = CAST(unsigned short)src) \
  141.                                                                  : (op_dest = dest, op_result = dest op (op_source = CAST(unsigned char)src)))
  142. #define MEM_OP(dest,op,src) R_M_OP(mem[dest],op,mem[src])
  143. #define OP(op) MEM_OP(op_to_addr,op,op_from_addr)
  144.  
  145. // Increment or decrement a register #reg_id (usually SI or DI), depending on direction flag and operand size (given by i_w)
  146. #define INDEX_INC(reg_id) (regs16[reg_id] -= (2 * regs8[FLAG_DF] - 1)*(i_w + 1))
  147.  
  148. // Helpers for stack operations
  149. #define R_M_PUSH(a) (i_w = 1, R_M_OP(mem[SEGREG(REG_SS, REG_SP, --)], =, a))
  150. #define R_M_POP(a) (i_w = 1, regs16[REG_SP] += 2, R_M_OP(a, =, mem[SEGREG(REG_SS, REG_SP, -2+)]))
  151.  
  152. // Convert segment:offset to linear address in emulator memory space
  153. #define SEGREG(reg_seg,reg_ofs,op) 16 * regs16[reg_seg] + (unsigned short)(op regs16[reg_ofs])
  154.  
  155. // Returns sign bit of an 8-bit or 16-bit operand
  156. #define SIGN_OF(a) (1 & (i_w ? CAST(short)a : a) >> (TOP_BIT - 1))
  157.  
  158. // Reinterpretation cast
  159. #define CAST(a) *(a*)&
  160.  
  161. // Keyboard driver for console. This may need changing for UNIX/non-UNIX platforms
  162. #ifdef _WIN32
  163. #define KEYBOARD_DRIVER kbhit() && (mem[0x4A6] = getch(), pc_interrupt(7))
  164. #else
  165. //#define KEYBOARD_DRIVER read(0, mem + 0x4A6, 1) && (int8_asap = (mem[0x4A6] == 0x1B), pc_interrupt(7))
  166.  
  167. #define KEYBOARD_DRIVER kbhit() && (mem[0x4A6] = getch(), pc_interrupt(7))
  168. #endif
  169.  
  170. // Keyboard driver for SDL
  171. #ifdef NO_GRAPHICS
  172. #define SDL_KEYBOARD_DRIVER KEYBOARD_DRIVER
  173. #else
  174. #define SDL_KEYBOARD_DRIVER sdl_screen ? SDL_PollEvent(&sdl_event) && (sdl_event.type == SDL_KEYDOWN || sdl_event.type == SDL_KEYUP) && (scratch_uint = sdl_event.key.keysym.unicode, scratch2_uint = sdl_event.key.keysym.mod, CAST(short)mem[0x4A6] = 0x400 + 0x800*!!(scratch2_uint & KMOD_ALT) + 0x1000*!!(scratch2_uint & KMOD_SHIFT) + 0x2000*!!(scratch2_uint & KMOD_CTRL) + 0x4000*(sdl_event.type == SDL_KEYUP) + ((!scratch_uint || scratch_uint > 0x7F) ? sdl_event.key.keysym.sym : scratch_uint), pc_interrupt(7)) : (KEYBOARD_DRIVER)
  175. #endif
  176.  
  177. // Global variable definitions
  178. unsigned char mem[RAM_SIZE], io_ports[IO_PORT_COUNT], *opcode_stream, *regs8, i_rm, i_w, i_reg, i_mod, i_mod_size, i_d, i_reg4bit, raw_opcode_id, xlat_opcode_id, extra, rep_mode, seg_override_en, rep_override_en, trap_flag, int8_asap, scratch_uchar, io_hi_lo, *vid_mem_base, spkr_en, bios_table_lookup[20][256];
  179. unsigned short *regs16, reg_ip, seg_override, file_index, wave_counter;
  180. unsigned int op_source, op_dest, rm_addr, op_to_addr, op_from_addr, i_data0, i_data1, i_data2, scratch_uint, scratch2_uint, inst_counter, set_flags_type, GRAPHICS_X, GRAPHICS_Y, pixel_colors[16], vmem_ctr;
  181. int op_result, disk[3], scratch_int;
  182. time_t clock_buf;
  183. struct timeb ms_clock;
  184.  
  185. #ifndef NO_GRAPHICS
  186. SDL_AudioSpec sdl_audio = {44100, AUDIO_U8, 1, 0, 128};
  187. SDL_AudioSpec sdl_audio_obt = {44100, AUDIO_U8, 1, 0, 128};
  188. SDL_Surface *sdl_screen;
  189. SDL_Event sdl_event;
  190. unsigned short vid_addr_lookup[VIDEO_RAM_SIZE], cga_colors[4] = {0 /* Black */, 0x1F1F /* Cyan */, 0xE3E3 /* Magenta */, 0xFFFF /* White */};
  191. #endif
  192.  
  193. // Helper functions
  194.  
  195. // Set carry flag
  196. char set_CF(int new_CF)
  197. {
  198.         return regs8[FLAG_CF] = !!new_CF;
  199. }
  200.  
  201. // Set auxiliary flag
  202. char set_AF(int new_AF)
  203. {
  204.         return regs8[FLAG_AF] = !!new_AF;
  205. }
  206.  
  207. // Set overflow flag
  208. char set_OF(int new_OF)
  209. {
  210.         return regs8[FLAG_OF] = !!new_OF;
  211. }
  212.  
  213. // Set auxiliary and overflow flag after arithmetic operations
  214. char set_AF_OF_arith()
  215. {
  216.         set_AF((op_source ^= op_dest ^ op_result) & 0x10);
  217.         if (op_result == op_dest)
  218.                 return set_OF(0);
  219.         else
  220.                 return set_OF(1 & (regs8[FLAG_CF] ^ op_source >> (TOP_BIT - 1)));
  221. }
  222.  
  223. // Assemble and return emulated CPU FLAGS register in scratch_uint
  224. void make_flags()
  225. {
  226.         scratch_uint = 0xF002; // 8086 has reserved and unused flags set to 1
  227.         for (int i = 9; i--;)
  228.                 scratch_uint += regs8[FLAG_CF + i] << bios_table_lookup[TABLE_FLAGS_BITFIELDS][i];
  229. }
  230.  
  231. // Set emulated CPU FLAGS register from regs8[FLAG_xx] values
  232. void set_flags(int new_flags)
  233. {
  234.         for (int i = 9; i--;)
  235.                 regs8[FLAG_CF + i] = !!(1 << bios_table_lookup[TABLE_FLAGS_BITFIELDS][i] & new_flags);
  236. }
  237.  
  238. // Convert raw opcode to translated opcode index. This condenses a large number of different encodings of similar
  239. // instructions into a much smaller number of distinct functions, which we then execute
  240. void set_opcode(unsigned char opcode)
  241. {
  242.         xlat_opcode_id = bios_table_lookup[TABLE_XLAT_OPCODE][raw_opcode_id = opcode];
  243.         extra = bios_table_lookup[TABLE_XLAT_SUBFUNCTION][opcode];
  244.         i_mod_size = bios_table_lookup[TABLE_I_MOD_SIZE][opcode];
  245.         set_flags_type = bios_table_lookup[TABLE_STD_FLAGS][opcode];
  246. }
  247.  
  248. // Execute INT #interrupt_num on the emulated machine
  249. char pc_interrupt(unsigned char interrupt_num)
  250. {
  251.         set_opcode(0xCD); // Decode like INT
  252.  
  253.         make_flags();
  254.         R_M_PUSH(scratch_uint);
  255.         R_M_PUSH(regs16[REG_CS]);
  256.         R_M_PUSH(reg_ip);
  257.         MEM_OP(REGS_BASE + 2 * REG_CS, =, 4 * interrupt_num + 2);
  258.         R_M_OP(reg_ip, =, mem[4 * interrupt_num]);
  259.  
  260.         return regs8[FLAG_TF] = regs8[FLAG_IF] = 0;
  261. }
  262.  
  263. // AAA and AAS instructions - which_operation is +1 for AAA, and -1 for AAS
  264. int AAA_AAS(char which_operation)
  265. {
  266.         return (regs16[REG_AX] += 262 * which_operation*set_AF(set_CF(((regs8[REG_AL] & 0x0F) > 9) || regs8[FLAG_AF])), regs8[REG_AL] &= 0x0F);
  267. }
  268.  
  269. #ifndef NO_GRAPHICS
  270. void audio_callback(void *data, unsigned char *stream, int len)
  271. {
  272.         for (int i = 0; i < len; i++)
  273.                 stream[i] = (spkr_en == 3) && CAST(unsigned short)mem[0x4AA] ? -((54 * wave_counter++ / CAST(unsigned short)mem[0x4AA]) & 1) : sdl_audio.silence;
  274.  
  275.         spkr_en = io_ports[0x61] & 3;
  276. }
  277. #endif
  278.  
  279. #define printf con_printf
  280. #define gets con_gets
  281. #undef main
  282. #include "console.c"
  283.  
  284. // Emulator entry point
  285. int main(int argc, char **argv)
  286. {
  287.     CONSOLE_INIT("8086");
  288.    
  289.     //freopen("OUT", "w" ,stdout);
  290. #ifndef NO_GRAPHICS
  291.         // Initialise SDL
  292.         SDL_Init(SDL_INIT_AUDIO);
  293.         sdl_audio.callback = audio_callback;
  294. #ifdef _WIN32
  295.         sdl_audio.samples = 512;
  296. #endif
  297.         SDL_OpenAudio(&sdl_audio, &sdl_audio_obt);
  298. #endif
  299.  
  300.         // regs16 and reg8 point to F000:0, the start of memory-mapped registers. CS is initialised to F000
  301.         regs16 = (unsigned short *)(regs8 = mem + REGS_BASE);
  302.         regs16[REG_CS] = 0xF000;
  303.  
  304.         // Trap flag off
  305.         regs8[FLAG_TF] = 0;
  306.  
  307.         // Set DL equal to the boot device: 0 for the FD, or 0x80 for the HD. Normally, boot from the FD.
  308.         // But, if the HD image file is prefixed with @, then boot from the HD
  309.         regs8[REG_DL] = ((argc > 3) && (*argv[3] == '@')) ? argv[3]++, 0x80 : 0;
  310.  
  311.         // Open BIOS (file id disk[2]), floppy disk image (disk[1]), and hard disk image (disk[0]) if specified
  312.         for (file_index = 3; file_index;)
  313.                 disk[--file_index] = *++argv ? open(*argv, 32898) : 0;
  314.  
  315.         // Set CX:AX equal to the hard disk image size, if present
  316.         CAST(unsigned)regs16[REG_AX] = *disk ? lseek(*disk, 0, 2) >> 9 : 0;
  317.  
  318.         // Load BIOS image into F000:0100, and set IP to 0100
  319.         read(disk[2], regs8 + (reg_ip = 0x100), 0xFF00);
  320.  
  321.         // Load instruction decoding helper table
  322.         for (int i = 0; i < 20; i++)
  323.                 for (int j = 0; j < 256; j++)
  324.                         bios_table_lookup[i][j] = regs8[regs16[0x81 + i] + j];
  325.  
  326.         // Instruction execution loop. Terminates if CS:IP = 0:0
  327.         for (; opcode_stream = mem + 16 * regs16[REG_CS] + reg_ip, opcode_stream != mem;)
  328.         {
  329.                 // Set up variables to prepare for decoding an opcode
  330.                 set_opcode(*opcode_stream);
  331.  
  332.                 // Extract i_w and i_d fields from instruction
  333.                 i_w = (i_reg4bit = raw_opcode_id & 7) & 1;
  334.                 i_d = i_reg4bit / 2 & 1;
  335.  
  336.                 // Extract instruction data fields
  337.                 i_data0 = CAST(short)opcode_stream[1];
  338.                 i_data1 = CAST(short)opcode_stream[2];
  339.                 i_data2 = CAST(short)opcode_stream[3];
  340.  
  341.                 // seg_override_en and rep_override_en contain number of instructions to hold segment override and REP prefix respectively
  342.                 if (seg_override_en)
  343.                         seg_override_en--;
  344.                 if (rep_override_en)
  345.                         rep_override_en--;
  346.  
  347.                 // i_mod_size > 0 indicates that opcode uses i_mod/i_rm/i_reg, so decode them
  348.                 if (i_mod_size)
  349.                 {
  350.                         i_mod = (i_data0 & 0xFF) >> 6;
  351.                         i_rm = i_data0 & 7;
  352.                         i_reg = i_data0 / 8 & 7;
  353.  
  354.                         if ((!i_mod && i_rm == 6) || (i_mod == 2))
  355.                                 i_data2 = CAST(short)opcode_stream[4];
  356.                         else if (i_mod != 1)
  357.                                 i_data2 = i_data1;
  358.                         else // If i_mod is 1, operand is (usually) 8 bits rather than 16 bits
  359.                                 i_data1 = (char)i_data1;
  360.  
  361.                         DECODE_RM_REG;
  362.                 }
  363.  
  364.                 // Instruction execution unit
  365.                 switch (xlat_opcode_id)
  366.                 {
  367.                         OPCODE_CHAIN 0: // Conditional jump (JAE, JNAE, etc.)
  368.                                 // i_w is the invert flag, e.g. i_w == 1 means JNAE, whereas i_w == 0 means JAE
  369.                                 scratch_uchar = raw_opcode_id / 2 & 7;
  370.                                 reg_ip += (char)i_data0 * (i_w ^ (regs8[bios_table_lookup[TABLE_COND_JUMP_DECODE_A][scratch_uchar]] || regs8[bios_table_lookup[TABLE_COND_JUMP_DECODE_B][scratch_uchar]] || regs8[bios_table_lookup[TABLE_COND_JUMP_DECODE_C][scratch_uchar]] ^ regs8[bios_table_lookup[TABLE_COND_JUMP_DECODE_D][scratch_uchar]]))
  371.                         OPCODE 1: // MOV reg, imm
  372.                                 i_w = !!(raw_opcode_id & 8);
  373.                                 R_M_OP(mem[GET_REG_ADDR(i_reg4bit)], =, i_data0)
  374.                         OPCODE 3: // PUSH regs16
  375.                                 R_M_PUSH(regs16[i_reg4bit])
  376.                         OPCODE 4: // POP regs16
  377.                                 R_M_POP(regs16[i_reg4bit])
  378.                         OPCODE 2: // INC|DEC regs16
  379.                                 i_w = 1;
  380.                                 i_d = 0;
  381.                                 i_reg = i_reg4bit;
  382.                                 DECODE_RM_REG;
  383.                                 i_reg = extra
  384.                         OPCODE_CHAIN 5: // INC|DEC|JMP|CALL|PUSH
  385.                                 if (i_reg < 2) // INC|DEC
  386.                                         MEM_OP(op_from_addr, += 1 - 2 * i_reg +, REGS_BASE + 2 * REG_ZERO),
  387.                                         op_source = 1,
  388.                                         set_AF_OF_arith(),
  389.                                         set_OF(op_dest + 1 - i_reg == 1 << (TOP_BIT - 1)),
  390.                                         (xlat_opcode_id == 5) && (set_opcode(0x10), 0); // Decode like ADC
  391.                                 else if (i_reg != 6) // JMP|CALL
  392.                                         i_reg - 3 || R_M_PUSH(regs16[REG_CS]), // CALL (far)
  393.                                         i_reg & 2 && R_M_PUSH(reg_ip + 2 + i_mod*(i_mod != 3) + 2*(!i_mod && i_rm == 6)), // CALL (near or far)
  394.                                         i_reg & 1 && (regs16[REG_CS] = CAST(short)mem[op_from_addr + 2]), // JMP|CALL (far)
  395.                                         R_M_OP(reg_ip, =, mem[op_from_addr]),
  396.                                         set_opcode(0x9A); // Decode like CALL
  397.                                 else // PUSH
  398.                                         R_M_PUSH(mem[rm_addr])
  399.                         OPCODE 6: // TEST r/m, imm16 / NOT|NEG|MUL|IMUL|DIV|IDIV reg
  400.                                 op_to_addr = op_from_addr;
  401.  
  402.                                 switch (i_reg)
  403.                                 {
  404.                                         OPCODE_CHAIN 0: // TEST
  405.                                                 set_opcode(0x20); // Decode like AND
  406.                                                 reg_ip += i_w + 1;
  407.                                                 R_M_OP(mem[op_to_addr], &, i_data2)
  408.                                         OPCODE 2: // NOT
  409.                                                 OP(=~)
  410.                                         OPCODE 3: // NEG
  411.                                                 OP(=-);
  412.                                                 op_dest = 0;
  413.                                                 set_opcode(0x28); // Decode like SUB
  414.                                                 set_CF(op_result > op_dest)
  415.                                         OPCODE 4: // MUL
  416.                                                 i_w ? MUL_MACRO(unsigned short, regs16) : MUL_MACRO(unsigned char, regs8)
  417.                                         OPCODE 5: // IMUL
  418.                                                 i_w ? MUL_MACRO(short, regs16) : MUL_MACRO(char, regs8)
  419.                                         OPCODE 6: // DIV
  420.                                                 i_w ? DIV_MACRO(unsigned short, unsigned, regs16) : DIV_MACRO(unsigned char, unsigned short, regs8)
  421.                                         OPCODE 7: // IDIV
  422.                                                 i_w ? DIV_MACRO(short, int, regs16) : DIV_MACRO(char, short, regs8);
  423.                                 }
  424.                         OPCODE 7: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP AL/AX, immed
  425.                                 rm_addr = REGS_BASE;
  426.                                 i_data2 = i_data0;
  427.                                 i_mod = 3;
  428.                                 i_reg = extra;
  429.                                 reg_ip--;
  430.                         OPCODE_CHAIN 8: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP reg, immed
  431.                                 op_to_addr = rm_addr;
  432.                                 regs16[REG_SCRATCH] = (i_d |= !i_w) ? (char)i_data2 : i_data2;
  433.                                 op_from_addr = REGS_BASE + 2 * REG_SCRATCH;
  434.                                 reg_ip += !i_d + 1;
  435.                                 set_opcode(0x08 * (extra = i_reg));
  436.                         OPCODE_CHAIN 9: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP|MOV reg, r/m
  437.                                 switch (extra)
  438.                                 {
  439.                                         OPCODE_CHAIN 0: // ADD
  440.                                                 OP(+=),
  441.                                                 set_CF(op_result < op_dest)
  442.                                         OPCODE 1: // OR
  443.                                                 OP(|=)
  444.                                         OPCODE 2: // ADC
  445.                                                 ADC_SBB_MACRO(+)
  446.                                         OPCODE 3: // SBB
  447.                                                 ADC_SBB_MACRO(-)
  448.                                         OPCODE 4: // AND
  449.                                                 OP(&=)
  450.                                         OPCODE 5: // SUB
  451.                                                 OP(-=),
  452.                                                 set_CF(op_result > op_dest)
  453.                                         OPCODE 6: // XOR
  454.                                                 OP(^=)
  455.                                         OPCODE 7: // CMP
  456.                                                 OP(-),
  457.                                                 set_CF(op_result > op_dest)
  458.                                         OPCODE 8: // MOV
  459.                                                 OP(=);
  460.                                 }
  461.                         OPCODE 10: // MOV sreg, r/m | POP r/m | LEA reg, r/m
  462.                                 if (!i_w) // MOV
  463.                                         i_w = 1,
  464.                                         i_reg += 8,
  465.                                         DECODE_RM_REG,
  466.                                         OP(=);
  467.                                 else if (!i_d) // LEA
  468.                                         seg_override_en = 1,
  469.                                         seg_override = REG_ZERO,
  470.                                         DECODE_RM_REG,
  471.                                         R_M_OP(mem[op_from_addr], =, rm_addr);
  472.                                 else // POP
  473.                                         R_M_POP(mem[rm_addr])
  474.                         OPCODE 11: // MOV AL/AX, [loc]
  475.                                 i_mod = i_reg = 0;
  476.                                 i_rm = 6;
  477.                                 i_data1 = i_data0;
  478.                                 DECODE_RM_REG;
  479.                                 MEM_OP(op_from_addr, =, op_to_addr)
  480.                         OPCODE 12: // ROL|ROR|RCL|RCR|SHL|SHR|???|SAR reg/mem, 1/CL/imm (80186)
  481.                                 scratch2_uint = SIGN_OF(mem[rm_addr]),
  482.                                 scratch_uint = extra ? // xxx reg/mem, imm
  483.                                         ++reg_ip,
  484.                                         (char)i_data1
  485.                                 : // xxx reg/mem, CL
  486.                                         i_d
  487.                                                 ? 31 & regs8[REG_CL]
  488.                                 : // xxx reg/mem, 1
  489.                                         1;
  490.                                 if (scratch_uint)
  491.                                 {
  492.                                         if (i_reg < 4) // Rotate operations
  493.                                                 scratch_uint %= i_reg / 2 + TOP_BIT,
  494.                                                 R_M_OP(scratch2_uint, =, mem[rm_addr]);
  495.                                         if (i_reg & 1) // Rotate/shift right operations
  496.                                                 R_M_OP(mem[rm_addr], >>=, scratch_uint);
  497.                                         else // Rotate/shift left operations
  498.                                                 R_M_OP(mem[rm_addr], <<=, scratch_uint);
  499.                                         if (i_reg > 3) // Shift operations
  500.                                                 set_opcode(0x10); // Decode like ADC
  501.                                         if (i_reg > 4) // SHR or SAR
  502.                                                 set_CF(op_dest >> (scratch_uint - 1) & 1);
  503.                                 }
  504.  
  505.                                 switch (i_reg)
  506.                                 {
  507.                                         OPCODE_CHAIN 0: // ROL
  508.                                                 R_M_OP(mem[rm_addr], += , scratch2_uint >> (TOP_BIT - scratch_uint));
  509.                                                 set_OF(SIGN_OF(op_result) ^ set_CF(op_result & 1))
  510.                                         OPCODE 1: // ROR
  511.                                                 scratch2_uint &= (1 << scratch_uint) - 1,
  512.                                                 R_M_OP(mem[rm_addr], += , scratch2_uint << (TOP_BIT - scratch_uint));
  513.                                                 set_OF(SIGN_OF(op_result * 2) ^ set_CF(SIGN_OF(op_result)))
  514.                                         OPCODE 2: // RCL
  515.                                                 R_M_OP(mem[rm_addr], += (regs8[FLAG_CF] << (scratch_uint - 1)) + , scratch2_uint >> (1 + TOP_BIT - scratch_uint));
  516.                                                 set_OF(SIGN_OF(op_result) ^ set_CF(scratch2_uint & 1 << (TOP_BIT - scratch_uint)))
  517.                                         OPCODE 3: // RCR
  518.                                                 R_M_OP(mem[rm_addr], += (regs8[FLAG_CF] << (TOP_BIT - scratch_uint)) + , scratch2_uint << (1 + TOP_BIT - scratch_uint));
  519.                                                 set_CF(scratch2_uint & 1 << (scratch_uint - 1));
  520.                                                 set_OF(SIGN_OF(op_result) ^ SIGN_OF(op_result * 2))
  521.                                         OPCODE 4: // SHL
  522.                                                 set_OF(SIGN_OF(op_result) ^ set_CF(SIGN_OF(op_dest << (scratch_uint - 1))))
  523.                                         OPCODE 5: // SHR
  524.                                                 set_OF(SIGN_OF(op_dest))
  525.                                         OPCODE 7: // SAR
  526.                                                 scratch_uint < TOP_BIT || set_CF(scratch2_uint);
  527.                                                 set_OF(0);
  528.                                                 R_M_OP(mem[rm_addr], +=, scratch2_uint *= ~(((1 << TOP_BIT) - 1) >> scratch_uint));
  529.                                 }
  530.                         OPCODE 13: // LOOPxx|JCZX
  531.                                 scratch_uint = !!--regs16[REG_CX];
  532.  
  533.                                 switch(i_reg4bit)
  534.                                 {
  535.                                         OPCODE_CHAIN 0: // LOOPNZ
  536.                                                 scratch_uint &= !regs8[FLAG_ZF]
  537.                                         OPCODE 1: // LOOPZ
  538.                                                 scratch_uint &= regs8[FLAG_ZF]
  539.                                         OPCODE 3: // JCXXZ
  540.                                                 scratch_uint = !++regs16[REG_CX];
  541.                                 }
  542.                                 reg_ip += scratch_uint*(char)i_data0
  543.                         OPCODE 14: // JMP | CALL short/near
  544.                                 reg_ip += 3 - i_d;
  545.                                 if (!i_w)
  546.                                 {
  547.                                         if (i_d) // JMP far
  548.                                                 reg_ip = 0,
  549.                                                 regs16[REG_CS] = i_data2;
  550.                                         else // CALL
  551.                                                 R_M_PUSH(reg_ip);
  552.                                 }
  553.                                 reg_ip += i_d && i_w ? (char)i_data0 : i_data0
  554.                         OPCODE 15: // TEST reg, r/m
  555.                                 MEM_OP(op_from_addr, &, op_to_addr)
  556.                         OPCODE 16: // XCHG AX, regs16
  557.                                 i_w = 1;
  558.                                 op_to_addr = REGS_BASE;
  559.                                 op_from_addr = GET_REG_ADDR(i_reg4bit);
  560.                         OPCODE_CHAIN 24: // NOP|XCHG reg, r/m
  561.                                 if (op_to_addr != op_from_addr)
  562.                                         OP(^=),
  563.                                         MEM_OP(op_from_addr, ^=, op_to_addr),
  564.                                         OP(^=)
  565.                         OPCODE 17: // MOVSx (extra=0)|STOSx (extra=1)|LODSx (extra=2)
  566.                                 scratch2_uint = seg_override_en ? seg_override : REG_DS;
  567.  
  568.                                 for (scratch_uint = rep_override_en ? regs16[REG_CX] : 1; scratch_uint; scratch_uint--)
  569.                                 {
  570.                                         MEM_OP(extra < 2 ? SEGREG(REG_ES, REG_DI,) : REGS_BASE, =, extra & 1 ? REGS_BASE : SEGREG(scratch2_uint, REG_SI,)),
  571.                                         extra & 1 || INDEX_INC(REG_SI),
  572.                                         extra & 2 || INDEX_INC(REG_DI);
  573.                                 }
  574.  
  575.                                 if (rep_override_en)
  576.                                         regs16[REG_CX] = 0
  577.                         OPCODE 18: // CMPSx (extra=0)|SCASx (extra=1)
  578.                                 scratch2_uint = seg_override_en ? seg_override : REG_DS;
  579.  
  580.                                 if ((scratch_uint = rep_override_en ? regs16[REG_CX] : 1))
  581.                                 {
  582.                                         for (; scratch_uint; rep_override_en || scratch_uint--)
  583.                                         {
  584.                                                 MEM_OP(extra ? REGS_BASE : SEGREG(scratch2_uint, REG_SI,), -, SEGREG(REG_ES, REG_DI,)),
  585.                                                 extra || INDEX_INC(REG_SI),
  586.                                                 INDEX_INC(REG_DI), rep_override_en && !(--regs16[REG_CX] && (!op_result == rep_mode)) && (scratch_uint = 0);
  587.                                         }
  588.  
  589.                                         set_flags_type = FLAGS_UPDATE_SZP | FLAGS_UPDATE_AO_ARITH; // Funge to set SZP/AO flags
  590.                                         set_CF(op_result > op_dest);
  591.                                 }
  592.                         OPCODE 19: // RET|RETF|IRET
  593.                                 i_d = i_w;
  594.                                 R_M_POP(reg_ip);
  595.                                 if (extra) // IRET|RETF|RETF imm16
  596.                                         R_M_POP(regs16[REG_CS]);
  597.                                 if (extra & 2) // IRET
  598.                                         set_flags(R_M_POP(scratch_uint));
  599.                                 else if (!i_d) // RET|RETF imm16
  600.                                         regs16[REG_SP] += i_data0
  601.                         OPCODE 20: // MOV r/m, immed
  602.                                 R_M_OP(mem[op_from_addr], =, i_data2)
  603.                         OPCODE 21: // IN AL/AX, DX/imm8
  604.                                 io_ports[0x20] = 0; // PIC EOI
  605.                                 io_ports[0x42] = --io_ports[0x40]; // PIT channel 0/2 read placeholder
  606.                                 io_ports[0x3DA] ^= 9; // CGA refresh
  607.                                 scratch_uint = extra ? regs16[REG_DX] : (unsigned char)i_data0;
  608.                                 scratch_uint == 0x60 && (io_ports[0x64] = 0); // Scancode read flag
  609.                                 scratch_uint == 0x3D5 && (io_ports[0x3D4] >> 1 == 7) && (io_ports[0x3D5] = ((mem[0x49E]*80 + mem[0x49D] + CAST(short)mem[0x4AD]) & (io_ports[0x3D4] & 1 ? 0xFF : 0xFF00)) >> (io_ports[0x3D4] & 1 ? 0 : 8)); // CRT cursor position
  610.                                 R_M_OP(regs8[REG_AL], =, io_ports[scratch_uint]);
  611.                         OPCODE 22: // OUT DX/imm8, AL/AX
  612.                                 scratch_uint = extra ? regs16[REG_DX] : (unsigned char)i_data0;
  613.                                 R_M_OP(io_ports[scratch_uint], =, regs8[REG_AL]);
  614.                                 scratch_uint == 0x61 && (io_hi_lo = 0, spkr_en |= regs8[REG_AL] & 3); // Speaker control
  615.                                 (scratch_uint == 0x40 || scratch_uint == 0x42) && (io_ports[0x43] & 6) && (mem[0x469 + scratch_uint - (io_hi_lo ^= 1)] = regs8[REG_AL]); // PIT rate programming
  616. #ifndef NO_GRAPHICS
  617.                                 scratch_uint == 0x43 && (io_hi_lo = 0, regs8[REG_AL] >> 6 == 2) && (SDL_PauseAudio((regs8[REG_AL] & 0xF7) != 0xB6), 0); // Speaker enable
  618. #endif
  619.                                 scratch_uint == 0x3D5 && (io_ports[0x3D4] >> 1 == 6) && (mem[0x4AD + !(io_ports[0x3D4] & 1)] = regs8[REG_AL]); // CRT video RAM start offset
  620.                                 scratch_uint == 0x3D5 && (io_ports[0x3D4] >> 1 == 7) && (scratch2_uint = ((mem[0x49E]*80 + mem[0x49D] + CAST(short)mem[0x4AD]) & (io_ports[0x3D4] & 1 ? 0xFF00 : 0xFF)) + (regs8[REG_AL] << (io_ports[0x3D4] & 1 ? 0 : 8)) - CAST(short)mem[0x4AD], mem[0x49D] = scratch2_uint % 80, mem[0x49E] = scratch2_uint / 80); // CRT cursor position
  621.                                 scratch_uint == 0x3B5 && io_ports[0x3B4] == 1 && (GRAPHICS_X = regs8[REG_AL] * 16); // Hercules resolution reprogramming. Defaults are set in the BIOS
  622.                                 scratch_uint == 0x3B5 && io_ports[0x3B4] == 6 && (GRAPHICS_Y = regs8[REG_AL] * 4);
  623.                         OPCODE 23: // REPxx
  624.                                 rep_override_en = 2;
  625.                                 rep_mode = i_w;
  626.                                 seg_override_en && seg_override_en++
  627.                         OPCODE 25: // PUSH reg
  628.                                 R_M_PUSH(regs16[extra])
  629.                         OPCODE 26: // POP reg
  630.                                 R_M_POP(regs16[extra])
  631.                         OPCODE 27: // xS: segment overrides
  632.                                 seg_override_en = 2;
  633.                                 seg_override = extra;
  634.                                 rep_override_en && rep_override_en++
  635.                         OPCODE 28: // DAA/DAS
  636.                                 i_w = 0;
  637.                                 extra ? DAA_DAS(-=, >=, 0xFF, 0x99) : DAA_DAS(+=, <, 0xF0, 0x90) // extra = 0 for DAA, 1 for DAS
  638.                         OPCODE 29: // AAA/AAS
  639.                                 op_result = AAA_AAS(extra - 1)
  640.                         OPCODE 30: // CBW
  641.                                 regs8[REG_AH] = -SIGN_OF(regs8[REG_AL])
  642.                         OPCODE 31: // CWD
  643.                                 regs16[REG_DX] = -SIGN_OF(regs16[REG_AX])
  644.                         OPCODE 32: // CALL FAR imm16:imm16
  645.                                 R_M_PUSH(regs16[REG_CS]);
  646.                                 R_M_PUSH(reg_ip + 5);
  647.                                 regs16[REG_CS] = i_data2;
  648.                                 reg_ip = i_data0
  649.                         OPCODE 33: // PUSHF
  650.                                 make_flags();
  651.                                 R_M_PUSH(scratch_uint)
  652.                         OPCODE 34: // POPF
  653.                                 set_flags(R_M_POP(scratch_uint))
  654.                         OPCODE 35: // SAHF
  655.                                 make_flags();
  656.                                 set_flags((scratch_uint & 0xFF00) + regs8[REG_AH])
  657.                         OPCODE 36: // LAHF
  658.                                 make_flags(),
  659.                                 regs8[REG_AH] = scratch_uint
  660.                         OPCODE 37: // LES|LDS reg, r/m
  661.                                 i_w = i_d = 1;
  662.                                 DECODE_RM_REG;
  663.                                 OP(=);
  664.                                 MEM_OP(REGS_BASE + extra, =, rm_addr + 2)
  665.                         OPCODE 38: // INT 3
  666.                                 ++reg_ip;
  667.                                 pc_interrupt(3)
  668.                         OPCODE 39: // INT imm8
  669.                                 reg_ip += 2;
  670.                                 pc_interrupt(i_data0)
  671.                         OPCODE 40: // INTO
  672.                                 ++reg_ip;
  673.                                 regs8[FLAG_OF] && pc_interrupt(4)
  674.                         OPCODE 41: // AAM
  675.                                 if (i_data0 &= 0xFF)
  676.                                         regs8[REG_AH] = regs8[REG_AL] / i_data0,
  677.                                         op_result = regs8[REG_AL] %= i_data0;
  678.                                 else // Divide by zero
  679.                                         pc_interrupt(0)
  680.                         OPCODE 42: // AAD
  681.                                 i_w = 0;
  682.                                 regs16[REG_AX] = op_result = 0xFF & regs8[REG_AL] + i_data0 * regs8[REG_AH]
  683.                         OPCODE 43: // SALC
  684.                                 regs8[REG_AL] = -regs8[FLAG_CF]
  685.                         OPCODE 44: // XLAT
  686.                                 regs8[REG_AL] = mem[SEGREG(seg_override_en ? seg_override : REG_DS, REG_BX, regs8[REG_AL] +)]
  687.                         OPCODE 45: // CMC
  688.                                 regs8[FLAG_CF] ^= 1
  689.                         OPCODE 46: // CLC|STC|CLI|STI|CLD|STD
  690.                                 regs8[extra / 2] = extra & 1
  691.                         OPCODE 47: // TEST AL/AX, immed
  692.                                 R_M_OP(regs8[REG_AL], &, i_data0)
  693.                         OPCODE 48: // Emulator-specific 0F xx opcodes
  694.                                 switch ((char)i_data0)
  695.                                 {
  696.                                         OPCODE_CHAIN 0: // PUTCHAR_AL
  697.                                                 write(1, regs8, 1);
  698.                         printf("%c", regs8[0]);
  699.                                         OPCODE 1: // GET_RTC
  700.                                                 time(&clock_buf);
  701.                                                 ftime(&ms_clock);
  702.                                                 memcpy(mem + SEGREG(REG_ES, REG_BX,), localtime(&clock_buf), sizeof(struct tm));
  703.                                                 CAST(short)mem[SEGREG(REG_ES, REG_BX, 36+)] = ms_clock.millitm;
  704.                                         OPCODE 2: // DISK_READ
  705.                                         OPCODE_CHAIN 3: // DISK_WRITE
  706.                                                 regs8[REG_AL] = ~lseek(disk[regs8[REG_DL]], CAST(unsigned)regs16[REG_BP] << 9, 0)
  707.                                                         ? ((char)i_data0 == 3 ? (int(*)())write : (int(*)())read)(disk[regs8[REG_DL]], mem + SEGREG(REG_ES, REG_BX,), regs16[REG_AX])
  708.                                                         : 0;
  709.                                 }
  710.                 }
  711.  
  712.                 // Increment instruction pointer by computed instruction length. Tables in the BIOS binary
  713.                 // help us here.
  714.                 reg_ip += (i_mod*(i_mod != 3) + 2*(!i_mod && i_rm == 6))*i_mod_size + bios_table_lookup[TABLE_BASE_INST_SIZE][raw_opcode_id] + bios_table_lookup[TABLE_I_W_SIZE][raw_opcode_id]*(i_w + 1);
  715.  
  716.                 // If instruction needs to update SF, ZF and PF, set them as appropriate
  717.                 if (set_flags_type & FLAGS_UPDATE_SZP)
  718.                 {
  719.                         regs8[FLAG_SF] = SIGN_OF(op_result);
  720.                         regs8[FLAG_ZF] = !op_result;
  721.                         regs8[FLAG_PF] = bios_table_lookup[TABLE_PARITY_FLAG][(unsigned char)op_result];
  722.  
  723.                         // If instruction is an arithmetic or logic operation, also set AF/OF/CF as appropriate.
  724.                         if (set_flags_type & FLAGS_UPDATE_AO_ARITH)
  725.                                 set_AF_OF_arith();
  726.                         if (set_flags_type & FLAGS_UPDATE_OC_LOGIC)
  727.                                 set_CF(0), set_OF(0);
  728.                 }
  729.  
  730.                 // Poll timer/keyboard every KEYBOARD_TIMER_UPDATE_DELAY instructions
  731.                 if (!(++inst_counter % KEYBOARD_TIMER_UPDATE_DELAY))
  732.                         int8_asap = 1;
  733.  
  734. #ifndef NO_GRAPHICS
  735.                 // Update the video graphics display every GRAPHICS_UPDATE_DELAY instructions
  736.                 if (!(inst_counter % GRAPHICS_UPDATE_DELAY))
  737.                 {
  738.                         // Video card in graphics mode?
  739.                         if (io_ports[0x3B8] & 2)
  740.                         {
  741.                                 // If we don't already have an SDL window open, set it up and compute color and video memory translation tables
  742.                                 if (!sdl_screen)
  743.                                 {
  744.                                         for (int i = 0; i < 16; i++)
  745.                                                 pixel_colors[i] = mem[0x4AC] ? // CGA?
  746.                                                         cga_colors[(i & 12) >> 2] + (cga_colors[i & 3] << 16) // CGA -> RGB332
  747.                                                         : 0xFF*(((i & 1) << 24) + ((i & 2) << 15) + ((i & 4) << 6) + ((i & 8) >> 3)); // Hercules -> RGB332
  748.  
  749.                                         for (int i = 0; i < GRAPHICS_X * GRAPHICS_Y / 4; i++)
  750.                                                 vid_addr_lookup[i] = i / GRAPHICS_X * (GRAPHICS_X / 8) + (i / 2) % (GRAPHICS_X / 8) + 0x2000*(mem[0x4AC] ? (2 * i / GRAPHICS_X) % 2 : (4 * i / GRAPHICS_X) % 4);
  751.  
  752.                                         SDL_Init(SDL_INIT_VIDEO);
  753.                                         sdl_screen = SDL_SetVideoMode(GRAPHICS_X, GRAPHICS_Y, 8, 0);
  754.                                         SDL_EnableUNICODE(1);
  755.                                         SDL_EnableKeyRepeat(500, 30);
  756.                                 }
  757.  
  758.                                 // Refresh SDL display from emulated graphics card video RAM
  759.                                 vid_mem_base = mem + 0xB0000 + 0x8000*(mem[0x4AC] ? 1 : io_ports[0x3B8] >> 7); // B800:0 for CGA/Hercules bank 2, B000:0 for Hercules bank 1
  760.                                 for (int i = 0; i < GRAPHICS_X * GRAPHICS_Y / 4; i++)
  761.                                         ((unsigned *)sdl_screen->pixels)[i] = pixel_colors[15 & (vid_mem_base[vid_addr_lookup[i]] >> 4*!(i & 1))];
  762.  
  763.                                 SDL_Flip(sdl_screen);
  764.                         }
  765.                         else if (sdl_screen) // Application has gone back to text mode, so close the SDL window
  766.                         {
  767.                                 SDL_QuitSubSystem(SDL_INIT_VIDEO);
  768.                                 sdl_screen = 0;
  769.                         }
  770.                         SDL_PumpEvents();
  771.                 }
  772. #endif
  773.  
  774.                 // Application has set trap flag, so fire INT 1
  775.                 if (trap_flag)
  776.                         pc_interrupt(1);
  777.  
  778.                 trap_flag = regs8[FLAG_TF];
  779.  
  780.                 // If a timer tick is pending, interrupts are enabled, and no overrides/REP are active,
  781.                 // then process the tick and check for new keystrokes
  782.                 if (int8_asap && !seg_override_en && !rep_override_en && regs8[FLAG_IF] && !regs8[FLAG_TF])
  783.                         pc_interrupt(0xA), int8_asap = 0, SDL_KEYBOARD_DRIVER;
  784.         }
  785.  
  786. #ifndef NO_GRAPHICS
  787.         SDL_Quit();
  788. #endif
  789.         return 0;
  790. }
  791.