Big squash

e72eac2fc A few more sse instructions
bdf83e0f0 temp rebase to resolve conflicts
58aa08353 replace all usage of modrm_byte with the set/get fns
7f1dbadf4 move registers to wasm memory
9a0432708 remove stdio inclusion
60f49f735 partial branch port of read_e8
747c51979 partial port of do_div32
8700c3042 remove wasm file from repo
c69bc5c91 revert div32 to js
ead0195b9 move last_op1 to wasm
16e9a2801 move last_op2 to wasm
4b5e749c8 move last_op_size to wasm
3a02ec98c move last_add_result, last_result, flags_changed to wasm
882b5476b implement add in C
8a8b15e11 move flags to wasm
4667917a9 implement getcf in C
1199537a1 implement adc in C
a8a2f81ba implement sub in C
697cb4070 implement sbb in C
1e4e08079 implement inc in C
35259ddc3 implement dec in C
82498a632 implement neg in C
47fe549af copy opsize and reg constants
39c0f07aa implement mul8 in C
443aef4b2 implement imul8 in C
afd2ec864 refactor memory accessing from C
f937617bc implement mul16 in C
af430b023 rewrite reg_* macros
6639f23a7 implement imul16 in C
6c490e88d add wasm build to makefile
ea698b8bc refactor modrm_byte access
71899e821 split cpu.c into individual files
00dc878be capitalize flag constants
e1ccf9477 remove unused buffer view
f0175e480 refactor JS to wasm replacement
f52c5f3a6 add assert.h
ccf73539e implement imul_reg16 in C
8ae41facd implement do_mul32 in C and port mul32_result to wasm memory
77d3875eb implement do_imul32 in C
af1cdc85d implement mul32 in C
820f514e3 implement imul32 in C
e165f02e0 implement imul_reg32 in C
fdee993e9 implement xadd8 in C
4e5d6f1c2 implement xadd16 in C
1c903565f implement xadd32 in C
1be111a93 implement getaf in C
4c2bc9f43 implement bcd_daa in C
3852cee61 implement bcd_das in C
ed68e2777 implement bcd_aad in C
b56c17640 implement bcd_aaa in C
5650e48c6 implement bcd_aas in C
99aeb5682 implement and in C
39d2308aa implement or in C
c76e59a0b implement xor in C
b14b87b95 async wasm instantiation
7f11605bc implement rol8 in C
161c662cf implement rol16 in C
37bf420f6 implement rol32 in C
921f06821 implement rcl8 in C
2f1bf0c2d implement rcl16 in C
ad1d56ebe implement rcl32 in C
ebcded69e implement ror8 in C
9bc225ff0 implement ror16 in C
403125717 implement ror32 in C
2a21a0896 implement rcr8 in C
80bf2667e implement rcr16 in C
f8fe46c47 implement rcr32 in C
95493a272 split error_code flag in call_interrupt_vector
a6f19110e export throw_cpu_exception to C
dd5d8ce0d export call_interrupt_vector to C
537c08f65 implement raise_exception_with_code to C
8347e787e port instruction_pointer to wasm memory (offset 556)
0e62a7046 port previous_ip to wasm memory (offset 560)
c09089e40 implement trigger_gp in C
a4f0fed1b implement raise_exception in C
0b41949f4 implement trigger_de in C
fc2a568a6 implement div8 in C
acc6bbb54 implement idiv8 in C
5a3db2d09 implement div16 in C
d77f0d151 Move wasm replacements to a dedicated function
135b19af0 port idtr_size and idtr_offset to wasm (offset 564, 568)
5f0ad7257 port gdtr_size to wasm (offset 572)
dc17f7b7a port gdtr_offset to wasm (offset 576)
07876e86f port cr to wasm (offsets 580-608)
50b0213c2 port cpl to wasm (offset 612)
5cea3efcc port page_size_extensions to wasm (offset 616)
89d6fd6e8 port last_virt_eip to wasm (offset 620)
68f4111fd port eip_phys to wasm (offset 624)
73b146319 port last_virt_esp to wasm (offset 628)
dbf920ff7 port esp_phys to wasm (offset 632)
c05177c5a port sysenter_cs to wasm (offset 636)
63dd72194 port sysenter_esp to wasm (offset 640)
59d8aa686 port sysenter_eip to wasm (offset 644)
c5e02dd8b port prefixes to wasm (offset 648)
259ca5d72 port tsc_offset to wasm (offset 652)
62ecc8825 port phys_addr to wasm (offset 656)
188ea275e port phys_addr_high to wasm (offset 660)
f458cb2bb port timestamp_counter to wasm (offset 664)
890449fa3 port sreg to wasm (offsets 668-682)
ebe65e6f3 port dreg to wasm (offsets 684-716)
df6553220 port fw_value to wasm (offset 720)
0cd3b78ea port segment isnull, offsets and limits to wasm (offset 724-796)
4fb0ecebc Turn off verbose logging
b55bc2cae fix unzip command in readme
f5b897bc3 fix docs links to api.md
ba03a7b4e Remove outdated test
930483ac4 Add elf parser
6597973c8 Shift addresses correctly
189903a7d Add comment to lss #ud
0a46ec4a9 Fix iret #gp error code (Windows XP)
28986b7ee Lower TIME_PER_FRAME
4ce987d71 Add acpi PM timer
43c31ea99 Handle access to debug registers when cr4.DE is set
283305215 Add run_hardware_timers
c617846f2 A few more assertions for IO ports
32e7444f4 Make Closure Compiler happy
a661c408c Buffer get written blocks
9306fd080 Add debug panel (#108)
795ff1a50 More complete APIC and IOAPIC implementation (#86)
4a4253956 Makefile: Refactor using addprefix
ac1009331 More VGA logging
18ee4ecde Only check irqs when irr changed
cdbc55e03 Add multiboot image loading, currently only supporting kvm-unit-test (#95, #129)
3ee9a1c85 Disable advanced optimisations for libv86. Fixes tests
12df5c76d Import kvm-unit-test into this repo
249f9ba37 Add kvm-unit-test (#129)
99b824f49 Mention than FreeBSD works
91fe8a3a1 ATA flush cache
0af630d99 PCI: Fix command/status
30fc01491 Rename function
569d1f3d6 APIC version write
df376842c Split movsx/movzx into 16/32 bit versions
dda21c5e2 CR3 ignored bits
b1f039211 Implement #NP (kvm-unit-test)
57dd8358f Minor (style and logging)
17fd08e29 Less incomplete task switch implementation
797fd5bd8 cpuid level 5
24e66a43f Missing parameter
a679829f0 PIC logging
e68ea4573 Don't create new arrays in reset(), set to 0 instead
550e55186 Update readme regarding Arch Linux
3b565e54e Use local kolibriOS image on https. Temporary workaround for #141
1a0f804d6 Fix restoring state
b397f1934 Leave ACPI disabled, fixes #151
83db7e871 add note about range header in SimpleHTTPServer
a20794873 update linux 9p image mount hook doc
88e65312e Improve fprem instruction implementation to update FPU status word's condition codes
9844ef433 Remove comments from fprem instruction
a429bbe73 Disable Oberon tests
ba3092060 Add kvm-unit-test to travis CI (#129)
6a8813567 Travis fix
46da581de Travis fix (gcc-multilib)
c78dcb105 Travis fix (switch to Trusty)
dbc2ab704 Reduce memory for kvm-unit-test
2c6bd1889 Fix multiboot images smaller than 8192 bytes
f5dead1f5 expand Archlinux doc with scripted install example
a34cd08d9 fix raw RangeHTTPServer link to wget
35f9923fb change state to initial state in archlinux doc
2aed2636f extend archlinux doc with networking example
2aa8f3722 First entry in LDT is valid (#145)
7492c8d3c Basic 16-bit tss implementation. Fixes #127. Fixes #145. Fixes windows 3.0
098d84a02 Minor
b9c93f8c6 Proper CD IDE DMA implementation, fixes #147, fixes #107
9b9123d6e Improved file loading in nodejs, simplify tests
40ee13f9b Add dummy screen
a58bd7419 Fix test: Check if disk image is missing
c8a7fd8dc Reenable Oberon tests
bd63f49ad Minor: Semicolons
d10f0b7ff Implement elcr in legacy pic
aed5b441a Change virtio irq to 10, old one collides with ps2 mouse
b93519c8a PS2 minor changes
25e64afa6 Update build command
5377f9457 Add maximum debug to emscripten build
dac6ce6a4 Reduce logging
f44f3b467 Convert argument for call from C
e1808f222 Raise when C assertion fails
bb6d38e6e Add cpu imports, in order to be called from C
f3f909d5d Port constants
7bab32657 Port protected_mode, is_32 and stack_size_32
ee02cdd86 Port the main instruction table
fe15a6cc0 fixes for prop mangling and closure type checks
11935fcc0 remove redundant pointer timestamp_counter
a7021eb20 port read_imm8 to wasm
f7a432691 strip useless brackets
90c7435f8 Reduce logging
047f0f405 Port a few small functions
df293f8d4 Port get_seg*
37774b0d1 Remove useless comparison
47f7a89b9 Port instructions with 0F prefix
8a822bae4 Remove useless brackets again (lost in rebase) and use correct quote style
2f6e90023 port read_imm{8s,16,32s}
8f5ce2dbf remove redundant declaration
5785195ce port read_write_e8 and write_e8
5fa1a15af Make instruction functions static
4a2336d12 Port jmp_rel16, jmpcc8, jmpcc16, jmpcc32
8633cfad9 Port set_e*
f024aec98 Port read_imm* aliases
d39cb4d7b Port read_g*
fa838388d Port read_e*
2f1c41d93 Port write_g*
43157269f Port logging and assertions
ac2c937d5 Port read_write_e{16,32} and write_e{16,32}
eeb7340c2 Port safe_read*
54d89b3d1 Port safe_write*
c5557a227 Port diverged, branch_taken, branch_taken
e3bb35939 Fix loading in node
00f6b2638 Remove useless `| 0` and `>> 0`. Use unsigned comparison
70fa762e3 Optimise read_imm8
4487917fd Port a20_enabled to wasm
a8f16cb20 Fix a20_enabled booleans for closure compiler
95145ec53 Move mul32 result so offsets are reserved in order (and mention length)
a3264e132 Move global pointer reservations to its own header file and make sure all .c files include all headers
78c779cbd Port FPU's stack_empty to wasm (offset 816)
4f25fc4b7 Port FPU's safe_tag_word function to wasm
8589a1c21 Port emms instruction to wasm
feb5079c7 port memory_size to wasm (offset 812)
262559291 port in_mapped_range to C
8a72ad56c Port a20_enabled to wasm
ce393e211 [wip] port read8
e936b49d1 port read8 to wasm
80cf98a3a port read16 to wasm
3a423372b port read_aligned16 to wasm
4725e1bac port read32s to wasm
60815b748 port write8 to wasm
5d64b295b port write16 to wasm
5fc83a791 port write32 to wasm
7148b6804 port push{16,32} to wasm
697222408 port pusha{16,32} to wasm
6adb5be15 Port paging, tlb_info, tlb_info_global and tlb_data
c8ab560af Port translate_address_*
8bb3e4285 Port get_eflags and getzf
c7a70a79b Port getsf
0d35dd621 Port getof
e4d3ec252 Port getpf
9aacf2cfe Port test_* (branch conditions)
9cb64f970 Add v86-debug.wasm build target
37012099d Call mmap_* functions statically
8fb9da298 Add missing voids
0bcbe7ef4 Silence warning
6fb9db2fd Simplify translate_address_read and translate_address_write
28b66ca6b Optimized versions of resolve_modrm32 and resolve_sib
cf4aea666 Silence warning
b4915a2d2 Port adjust_stack_reg, get_stack_pointer and pop32s
7ddc14948 Optimised memory reads and writes
This commit is contained in:
Fabian 2017-07-05 18:59:48 -05:00
parent 5ef8c3e614
commit aebcff84ed
33 changed files with 10494 additions and 1297 deletions

3
.gitignore vendored
View file

@ -9,8 +9,9 @@ closure-compiler/
images/
*.bak
*.orig
*.wasm
*.o
*.bin
*.img
*.fixture
*.fuse_hidden*
*.fuse_hidden*

View file

@ -5,6 +5,7 @@ NASM_TEST_DIR=./tests/nasm
all: build/v86_all.js
browser: build/v86_all.js
wasm: build/v86.wasm
# Used for nodejs builds and in order to profile code.
# `debug` gives identifiers a readable name, make sure it doesn't have any side effects.
@ -123,11 +124,42 @@ build/libv86.js: $(CLOSURE) src/*.js lib/*.js src/browser/*.js
ls -lh build/libv86.js
build/v86.wasm: src/native/*.c src/native/*.h
mkdir -p build
-ls -lh build/v86.wasm
# --llvm-opts 3
# -Wno-extra-semi
# EMCC_WASM_BACKEND=1
emcc src/native/all.c \
-Wall -Wpedantic -Wextra \
-DDEBUG=false \
-DNDEBUG \
-Wno-bitwise-op-parentheses -Wno-gnu-binary-literal \
-fcolor-diagnostics \
-fwrapv \
--llvm-opts 3 \
-O3 \
-g4 \
-s WASM=1 -s SIDE_MODULE=1 -o build/v86.wasm
ls -lh build/v86.wasm
build/v86-debug.wasm: src/native/*.c src/native/*.h
emcc src/native/all.c \
-Wall -Wpedantic -Wextra \
-Wno-bitwise-op-parentheses -Wno-gnu-binary-literal \
-fcolor-diagnostics \
-fwrapv \
-Os \
-g4 \
-s WASM=1 -s SIDE_MODULE=1 -o build/v86-debug.wasm
ls -lh build/v86-debug.wasm
clean:
-rm build/libv86.js
-rm build/v86_all.js
-rm build/libv86.js.map
-rm build/v86_all.js.map
-rm build/v86.wasm
$(MAKE) -C $(NASM_TEST_DIR) clean
run:

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,42 @@ var ASYNC_SAFE = false;
v86util.AsyncFileBuffer = AsyncFileBuffer;
v86util.SyncFileBuffer = SyncFileBuffer;
v86util.load_wasm = function load_wasm(filename, imports, cb) {
if (!imports) {
imports = {};
}
const STATIC_MEMORY_BASE = 64 * 1024 * 1024; // XXX
v86util.load_file(filename, { done: function(buffer)
{
WebAssembly.compile(buffer)
.then(module => {
if (!imports['env']) {
imports['env'] = {};
}
imports['env']['___assert_fail'] = (a, b, c, d) => {
console.error('Assertion Failed', a, b, c, d);
dbg_assert(false);
};
imports['env']['memoryBase'] = STATIC_MEMORY_BASE;
imports['env']['tableBase'] = 0;
imports['env']['memory'] = new WebAssembly.Memory({ ['initial']: 4096, });
imports['env']['table'] = new WebAssembly.Table({ ['initial']: 18, ['element']: 'anyfunc' });
return WebAssembly.instantiate(module, imports).then(instance => ({ instance, module }));
})
.then(({ instance, module }) => {
cb({
mem: imports['env']['memory'],
funcs: instance['exports'],
instance,
imports,
filename,
});
});
}
});
};
/**
* @param {string} filename
* @param {Object} options

View file

@ -92,7 +92,190 @@ function V86Starter(options)
var bus = Bus.create();
var adapter_bus = this.bus = bus[0];
this.emulator_bus = bus[1];
var emulator = this.v86 = new v86(this.emulator_bus);
var emulator;
var cpu;
var mem;
var wasm_shared_funcs = {
"_throw_cpu_exception": () => { throw MAGIC_CPU_EXCEPTION; },
"_hlt_op": function() { return cpu.hlt_op(); },
"abort": function() { dbg_assert(false); },
"_dbg_assert": function() { return cpu.dbg_assert.apply(cpu, arguments); },
"_dbg_log": function() { return cpu.dbg_log.apply(cpu, arguments); },
"_todo": function() { return cpu.todo.apply(cpu, arguments); },
"_undefined_instruction": function() { return cpu.undefined_instruction.apply(cpu, arguments); },
"_unimplemented_sse": function() { return cpu.unimplemented_sse_wasm(); },
"_microtick": function() { return v86.microtick(); },
"_get_rand_int": function() { return v86util.get_rand_int(); },
"_has_rand_int": function() { return v86util.has_rand_int(); },
"_printf": function(offset) { dbg_log_wasm(mem, offset, [].slice.call(arguments, 1)); },
"_call_interrupt_vector": function(interrupt_nr, is_software_int, has_error_code, error_code) {
cpu.call_interrupt_vector(interrupt_nr, is_software_int, !!has_error_code, error_code);
},
"_far_jump": function(eip, selector, is_call) { return cpu.far_jump(eip, selector, !!is_call); },
"_far_return": function(eip, selector, stack_adjust) { return cpu.far_return(eip, selector, stack_adjust); },
"_switch_seg": function(reg, selector) { cpu.switch_seg(reg, selector); },
"_iret16": function() { return cpu.iret16(); },
"_iret32": function() { return cpu.iret32(); },
"_io_port_read8": function(addr) { return cpu.io.port_read8(addr); },
"_io_port_read16": function(addr) { return cpu.io.port_read16(addr); },
"_io_port_read32": function(addr) { return cpu.io.port_read32(addr); },
"_io_port_write8": function(addr, value) { cpu.io.port_write8(addr, value); },
"_io_port_write16": function(addr, value) { cpu.io.port_write16(addr, value); },
"_io_port_write32": function(addr, value) { cpu.io.port_write32(addr, value); },
"_mmap_read8": function(addr) { return cpu.mmap_read8(addr); },
"_mmap_read16": function(addr) { return cpu.mmap_read16(addr); },
"_mmap_read32": function(addr) { return cpu.mmap_read32(addr); },
"_mmap_write8": function(addr, value) { return cpu.mmap_write8(addr, value); },
"_mmap_write16": function(addr, value) { return cpu.mmap_write16(addr, value); },
"_mmap_write32": function(addr, value) { return cpu.mmap_write32(addr, value); },
"_fpu_op_D8_reg": function() { return cpu.fpu.op_D8_reg.apply(cpu.fpu, arguments); },
"_fpu_op_D9_reg": function() { return cpu.fpu.op_D9_reg.apply(cpu.fpu, arguments); },
"_fpu_op_DA_reg": function() { return cpu.fpu.op_DA_reg.apply(cpu.fpu, arguments); },
"_fpu_op_DB_reg": function() { return cpu.fpu.op_DB_reg.apply(cpu.fpu, arguments); },
"_fpu_op_DC_reg": function() { return cpu.fpu.op_DC_reg.apply(cpu.fpu, arguments); },
"_fpu_op_DD_reg": function() { return cpu.fpu.op_DD_reg.apply(cpu.fpu, arguments); },
"_fpu_op_DE_reg": function() { return cpu.fpu.op_DE_reg.apply(cpu.fpu, arguments); },
"_fpu_op_DF_reg": function() { return cpu.fpu.op_DF_reg.apply(cpu.fpu, arguments); },
"_fpu_op_D8_mem": function() { return cpu.fpu.op_D8_mem.apply(cpu.fpu, arguments); },
"_fpu_op_D9_mem": function() { return cpu.fpu.op_D9_mem.apply(cpu.fpu, arguments); },
"_fpu_op_DA_mem": function() { return cpu.fpu.op_DA_mem.apply(cpu.fpu, arguments); },
"_fpu_op_DB_mem": function() { return cpu.fpu.op_DB_mem.apply(cpu.fpu, arguments); },
"_fpu_op_DC_mem": function() { return cpu.fpu.op_DC_mem.apply(cpu.fpu, arguments); },
"_fpu_op_DD_mem": function() { return cpu.fpu.op_DD_mem.apply(cpu.fpu, arguments); },
"_fpu_op_DE_mem": function() { return cpu.fpu.op_DE_mem.apply(cpu.fpu, arguments); },
"_fpu_op_DF_mem": function() { return cpu.fpu.op_DF_mem.apply(cpu.fpu, arguments); },
"_fwait": function() { return cpu.fpu.fwait(); },
"_do_page_translation": function() { return cpu.do_page_translation.apply(cpu, arguments); },
"_read_reg_e16": function() { return cpu.read_reg_e16.apply(cpu, arguments); },
"_read_reg_e32s": function() { return cpu.read_reg_e32s.apply(cpu, arguments); },
"_write_reg_e16": function() { return cpu.write_reg_e16.apply(cpu, arguments); },
"_write_reg_e32": function() { return cpu.write_reg_e32.apply(cpu, arguments); },
"_read_moffs": function() { return cpu.read_moffs.apply(cpu, arguments); },
"_popa16": function() { return cpu.popa16.apply(cpu, arguments); },
"_popa32": function() { return cpu.popa32.apply(cpu, arguments); },
"_arpl": function() { return cpu.arpl.apply(cpu, arguments); },
"_trigger_ud": function() { return cpu.trigger_ud.apply(cpu, arguments); },
"_trigger_nm": function() { return cpu.trigger_nm.apply(cpu, arguments); },
"_pop16": function() { return cpu.pop16.apply(cpu, arguments); },
"_virt_boundary_read16": function() { return cpu.virt_boundary_read16.apply(cpu, arguments); },
"_virt_boundary_read32s": function() { return cpu.virt_boundary_read32s.apply(cpu, arguments); },
"_virt_boundary_write16": function() { return cpu.virt_boundary_write16.apply(cpu, arguments); },
"_virt_boundary_write32": function() { return cpu.virt_boundary_write32.apply(cpu, arguments); },
"_set_stack_reg": function() { return cpu.set_stack_reg.apply(cpu, arguments); },
"_getiopl": function() { return cpu.getiopl.apply(cpu, arguments); },
"_vm86_mode": function() { return cpu.vm86_mode.apply(cpu, arguments); },
"_shl8": function() { return cpu.shl8.apply(cpu, arguments); },
"_shr8": function() { return cpu.shr8.apply(cpu, arguments); },
"_sar8": function() { return cpu.sar8.apply(cpu, arguments); },
"_shl16": function() { return cpu.shl16.apply(cpu, arguments); },
"_shr16": function() { return cpu.shr16.apply(cpu, arguments); },
"_sar16": function() { return cpu.sar16.apply(cpu, arguments); },
"_shl32": function() { return cpu.shl32.apply(cpu, arguments); },
"_shr32": function() { return cpu.shr32.apply(cpu, arguments); },
"_sar32": function() { return cpu.sar32.apply(cpu, arguments); },
"_shrd16": function() { return cpu.shrd16.apply(cpu, arguments); },
"_shrd32": function() { return cpu.shrd32.apply(cpu, arguments); },
"_shld16": function() { return cpu.shld16.apply(cpu, arguments); },
"_shld32": function() { return cpu.shld32.apply(cpu, arguments); },
"_bt_reg": function() { return cpu.bt_reg.apply(cpu, arguments); },
"_bt_mem": function() { return cpu.bt_mem.apply(cpu, arguments); },
"_btr_reg": function() { return cpu.btr_reg.apply(cpu, arguments); },
"_btr_mem": function() { return cpu.btr_mem.apply(cpu, arguments); },
"_btc_reg": function() { return cpu.btc_reg.apply(cpu, arguments); },
"_btc_mem": function() { return cpu.btc_mem.apply(cpu, arguments); },
"_bts_reg": function() { return cpu.bts_reg.apply(cpu, arguments); },
"_bts_mem": function() { return cpu.bts_mem.apply(cpu, arguments); },
"_bsf16": function() { return cpu.bsf16.apply(cpu, arguments); },
"_bsf32": function() { return cpu.bsf32.apply(cpu, arguments); },
"_bsr16": function() { return cpu.bsr16.apply(cpu, arguments); },
"_bsr32": function() { return cpu.bsr32.apply(cpu, arguments); },
"_popcnt": function() { return cpu.popcnt.apply(cpu, arguments); },
"_bswap": function() { return cpu.bswap.apply(cpu, arguments); },
"_setcc": function() { return cpu.setcc.apply(cpu, arguments); },
"_cmovcc16": function() { return cpu.cmovcc16.apply(cpu, arguments); },
"_cmovcc32": function() { return cpu.cmovcc32.apply(cpu, arguments); },
"_lar": function() { return cpu.lar.apply(cpu, arguments); },
"_lsl": function() { return cpu.lsl.apply(cpu, arguments); },
"_verw": function() { return cpu.verw.apply(cpu, arguments); },
"_verr": function() { return cpu.verr.apply(cpu, arguments); },
"_full_clear_tlb": function() { return cpu.full_clear_tlb.apply(cpu, arguments); },
"_invlpg": function() { return cpu.invlpg.apply(cpu, arguments); },
"_writable_or_pagefault": function() { return cpu.writable_or_pagefault.apply(cpu, arguments); },
"_cpl_changed": function() { return cpu.cpl_changed.apply(cpu, arguments); },
"_set_cr0": function() { return cpu.set_cr0.apply(cpu, arguments); },
"_update_cs_size": function() { return cpu.update_cs_size.apply(cpu, arguments); },
"_clear_tlb": function() { return cpu.clear_tlb.apply(cpu, arguments); },
"_cpuid": function() { return cpu.cpuid.apply(cpu, arguments); },
"_load_ldt": function() { return cpu.load_ldt.apply(cpu, arguments); },
"_load_tr": function() { return cpu.load_tr.apply(cpu, arguments); },
"_idiv16": function() { return cpu.idiv16.apply(cpu, arguments); },
"_div32": function() { return cpu.div32.apply(cpu, arguments); },
"_idiv32": function() { return cpu.idiv32.apply(cpu, arguments); },
"_insb": function() { return cpu.insb.apply(cpu, arguments); },
"_insw": function() { return cpu.insw.apply(cpu, arguments); },
"_insd": function() { return cpu.insd.apply(cpu, arguments); },
"_outsb": function() { return cpu.outsb.apply(cpu, arguments); },
"_outsw": function() { return cpu.outsw.apply(cpu, arguments); },
"_outsd": function() { return cpu.outsd.apply(cpu, arguments); },
"_movsb": function() { return cpu.movsb.apply(cpu, arguments); },
"_movsw": function() { return cpu.movsw.apply(cpu, arguments); },
"_movsd": function() { return cpu.movsd.apply(cpu, arguments); },
"_cmpsb": function() { return cpu.cmpsb.apply(cpu, arguments); },
"_cmpsw": function() { return cpu.cmpsw.apply(cpu, arguments); },
"_cmpsd": function() { return cpu.cmpsd.apply(cpu, arguments); },
"_stosb": function() { return cpu.stosb.apply(cpu, arguments); },
"_stosw": function() { return cpu.stosw.apply(cpu, arguments); },
"_stosd": function() { return cpu.stosd.apply(cpu, arguments); },
"_lodsb": function() { return cpu.lodsb.apply(cpu, arguments); },
"_lodsw": function() { return cpu.lodsw.apply(cpu, arguments); },
"_lodsd": function() { return cpu.lodsd.apply(cpu, arguments); },
"_scasb": function() { return cpu.scasb.apply(cpu, arguments); },
"_scasw": function() { return cpu.scasw.apply(cpu, arguments); },
"_scasd": function() { return cpu.scasd.apply(cpu, arguments); },
"_lss16": function() { return cpu.lss16.apply(cpu, arguments); },
"_lss32": function() { return cpu.lss32.apply(cpu, arguments); },
"_enter16": function() { return cpu.enter16.apply(cpu, arguments); },
"_enter32": function() { return cpu.enter32.apply(cpu, arguments); },
"_update_eflags": function() { return cpu.update_eflags.apply(cpu, arguments); },
"_handle_irqs": function() { return cpu.handle_irqs.apply(cpu, arguments); },
"_get_real_eip": function() { return cpu.get_real_eip.apply(cpu, arguments); },
"_xchg8": function() { return cpu.xchg8.apply(cpu, arguments); },
"_xchg16": function() { return cpu.xchg16.apply(cpu, arguments); },
"_xchg16r": function() { return cpu.xchg16r.apply(cpu, arguments); },
"_xchg32": function() { return cpu.xchg32.apply(cpu, arguments); },
"_xchg32r": function() { return cpu.xchg32r.apply(cpu, arguments); },
"_loop": function() { return cpu.loop.apply(cpu, arguments); },
"_loope": function() { return cpu.loope.apply(cpu, arguments); },
"_loopne": function() { return cpu.loopne.apply(cpu, arguments); },
"_bcd_aam": function() { return cpu.bcd_aam.apply(cpu, arguments); },
"_task_switch_test": function() { return cpu.task_switch_test.apply(cpu, arguments); },
"_jcxz": function() { return cpu.jcxz.apply(cpu, arguments); },
"_test_privileges_for_io": function() { return cpu.test_privileges_for_io.apply(cpu, arguments); },
"_fxsave": function() { return cpu.fxsave.apply(cpu, arguments); },
"_fxrstor": function() { return cpu.fxrstor.apply(cpu, arguments); },
};
let wasm_file = DEBUG ? "v86-debug.wasm" : "v86.wasm";
v86util.load_wasm("build/" + wasm_file, { 'env': wasm_shared_funcs }, wm => {
emulator = this.v86 = new v86(this.emulator_bus, wm);
cpu = emulator.cpu;
mem = wm.mem.buffer;
this.bus.register("emulator-stopped", function()
{
@ -423,6 +606,8 @@ function V86Starter(options)
}.bind(this), 0);
}.bind(this), 0);
}
});
}
/**
@ -627,7 +812,7 @@ V86Starter.prototype.get_instruction_counter = function()
{
if(this.v86)
{
return this.v86.cpu.timestamp_counter;
return this.v86.cpu.timestamp_counter[0];
}
else
{

View file

@ -26,7 +26,7 @@ var LOG_PAGE_FAULTS = false;
var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC &
~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK;
~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA;
/** @const */

1062
src/cpu.js

File diff suppressed because it is too large Load diff

View file

@ -130,7 +130,7 @@ CPU.prototype.debug_init = function()
cpu.running = false;
var a = parseInt(prompt("input hex", ""), 16);
if(a) while(cpu.instruction_pointer != a) step();
if(a) while(cpu.instruction_pointer[0] != a) step();
}
// http://ref.x86asm.net/x86reference.xml
@ -215,15 +215,17 @@ CPU.prototype.debug_init = function()
function get_state(where)
{
var vm = (cpu.flags & flag_vm) ? 1 : 0;
var mode = cpu.protected_mode ? vm ? "vm86" : "prot" : "real";
if(!DEBUG) return;
var mode = cpu.protected_mode[0] ? "prot" : "real";
var vm = (cpu.flags[0] & flag_vm) ? 1 : 0;
var flags = cpu.get_eflags();
var iopl = cpu.getiopl();
var cpl = cpu.cpl;
var cpl = cpu.cpl[0];
var cs_eip = h(cpu.sreg[reg_cs], 4) + ":" + h(cpu.get_real_eip() >>> 0, 8);
var ss_esp = h(cpu.sreg[reg_ss], 4) + ":" + h(cpu.get_stack_reg() >>> 0, 8);
var op_size = cpu.is_32 ? "32" : "16";
var if_ = (cpu.flags & flag_interrupt) ? 1 : 0;
var op_size = cpu.is_32[0] ? "32" : "16";
var if_ = (cpu.flags[0] & flag_interrupt) ? 1 : 0;
var flag_names = {
[flag_carry]: "c",
@ -253,12 +255,12 @@ CPU.prototype.debug_init = function()
}
}
return ("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging) +
return ("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging[0]) +
" iopl=" + iopl + " cpl=" + cpl + " if=" + if_ + " cs:eip=" + cs_eip +
" cs_off=" + h(cpu.get_seg(reg_cs) >>> 0, 8) +
" flgs=" + h(cpu.get_eflags() >>> 0, 6) + " (" + flag_string + ")" +
" ss:esp=" + ss_esp +
" ssize=" + (+cpu.stack_size_32) +
" ssize=" + (+cpu.stack_size_32[0]) +
(where ? " in " + where : ""));
}
@ -357,8 +359,8 @@ CPU.prototype.debug_init = function()
{
if(!DEBUG) return;
dbg_log("gdt: (len = " + h(cpu.gdtr_size) + ")");
dump_table(cpu.translate_address_system_read(cpu.gdtr_offset), cpu.gdtr_size);
dbg_log("gdt: (len = " + h(cpu.gdtr_size[0]) + ")");
dump_table(cpu.translate_address_system_read(cpu.gdtr_offset[0]), cpu.gdtr_size[0]);
dbg_log("\nldt: (len = " + h(cpu.segment_limits[reg_ldtr]) + ")");
dump_table(cpu.translate_address_system_read(cpu.segment_offsets[reg_ldtr]), cpu.segment_limits[reg_ldtr]);
@ -439,9 +441,9 @@ CPU.prototype.debug_init = function()
{
if(!DEBUG) return;
for(var i = 0; i < cpu.idtr_size; i += 8)
for(var i = 0; i < cpu.idtr_size[0]; i += 8)
{
var addr = cpu.translate_address_system_read(cpu.idtr_offset + i),
var addr = cpu.translate_address_system_read(cpu.idtr_offset[0] + i),
base = cpu.read16(addr) | cpu.read16(addr + 6) << 16,
selector = cpu.read16(addr + 2),
type = cpu.read8(addr + 5),
@ -583,7 +585,7 @@ CPU.prototype.debug_init = function()
if(start === undefined)
{
start = 0;
count = cpu.memory_size;
count = cpu.memory_size[0];
}
else if(count === undefined)
{
@ -630,7 +632,7 @@ CPU.prototype.debug_init = function()
var width = 0x80,
height = 0x10,
block_size = cpu.memory_size / width / height | 0,
block_size = cpu.memory_size[0] / width / height | 0,
row;
for(var i = 0; i < height; i++)

View file

@ -14,3 +14,4 @@ var exports = {};
var define = {};
var module = {};
var WebAssembly = { Memory() {}, Table() {}, instantiate() {}, compile() {} };

View file

@ -76,7 +76,8 @@ function FPU(cpu)
// bitmap of which stack registers are empty
this.stack_empty = 0xff;
this.stack_empty = new Int32Array(cpu.wm.mem.buffer, 816, 1);
this.stack_empty[0] = 0xff;
this.stack_ptr = 0;
this.control_word = 0x37F;
@ -96,14 +97,20 @@ function FPU(cpu)
Math.log(2) / Math.LN10, Math.LN2, 0
]);
this.wasm_patch();
}
FPU.prototype.wasm_patch = function()
{
this.set_tag_word = this.cpu.wm.funcs["_safe_tag_word"];
};
FPU.prototype.get_state = function()
{
var state = [];
state[0] = this.st;
state[1] = this.stack_empty;
state[1] = this.stack_empty[0];
state[2] = this.stack_ptr;
state[3] = this.control_word;
state[4] = this.fpu_dp_selector;
@ -119,7 +126,7 @@ FPU.prototype.get_state = function()
FPU.prototype.set_state = function(state)
{
this.st.set(state[0]);
this.stack_empty = state[1];
this.stack_empty[0] = state[1];
this.stack_ptr = state[2];
this.control_word = state[3];
this.fpu_dp_selector = state[4];
@ -182,23 +189,23 @@ FPU.prototype.fcomi = function(y)
{
var x = this.st[this.stack_ptr];
this.cpu.flags_changed &= ~(1 | flag_parity | flag_zero);
this.cpu.flags &= ~(1 | flag_parity | flag_zero);
this.cpu.flags_changed[0] &= ~(1 | flag_parity | flag_zero);
this.cpu.flags[0] &= ~(1 | flag_parity | flag_zero);
if(x > y)
{
}
else if(y > x)
{
this.cpu.flags |= 1;
this.cpu.flags[0] |= 1;
}
else if(x === y)
{
this.cpu.flags |= flag_zero;
this.cpu.flags[0] |= flag_zero;
}
else
{
this.cpu.flags |= 1 | flag_parity | flag_zero;
this.cpu.flags[0] |= 1 | flag_parity | flag_zero;
}
}
@ -233,7 +240,7 @@ FPU.prototype.fxam = function(x)
this.status_word &= ~FPU_RESULT_FLAGS;
this.status_word |= this.sign(0) << 9;
if(this.stack_empty >> this.stack_ptr & 1)
if(this.stack_empty[0] >> this.stack_ptr & 1)
{
this.status_word |= FPU_C3 | FPU_C0;
}
@ -265,7 +272,7 @@ FPU.prototype.finit = function()
this.fpu_dp = 0;
this.fpu_opcode = 0;
this.stack_empty = 0xFF;
this.stack_empty[0] = 0xFF;
this.stack_ptr = 0;
}
@ -289,7 +296,7 @@ FPU.prototype.load_tag_word = function()
{
value = this.st[i];
if(this.stack_empty >> i & 1)
if(this.stack_empty[0] >> i & 1)
{
tag_word |= 3 << (i << 1);
}
@ -303,18 +310,18 @@ FPU.prototype.load_tag_word = function()
}
}
//dbg_log("load tw=" + h(tag_word) + " se=" + h(this.stack_empty) + " sp=" + this.stack_ptr, LOG_FPU);
//dbg_log("load tw=" + h(tag_word) + " se=" + h(this.stack_empty[0]) + " sp=" + this.stack_ptr, LOG_FPU);
return tag_word;
}
FPU.prototype.set_tag_word = function(tag_word)
{
this.stack_empty = 0;
this.stack_empty[0] = 0;
for(var i = 0; i < 8; i++)
{
this.stack_empty |= (tag_word >> i) & (tag_word >> i + 1) & 1 << i;
this.stack_empty[0] |= (tag_word >> i) & (tag_word >> i + 1) & 1 << i;
}
//dbg_log("set_tag_word tw=" + h(tag_word) + " se=" + h(this.stack_empty), LOG_FPU);
@ -447,10 +454,10 @@ FPU.prototype.push = function(x)
{
this.stack_ptr = this.stack_ptr - 1 & 7;
if(this.stack_empty >> this.stack_ptr & 1)
if(this.stack_empty[0] >> this.stack_ptr & 1)
{
this.status_word &= ~FPU_C1;
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
this.st[this.stack_ptr] = x;
}
else
@ -463,7 +470,7 @@ FPU.prototype.push = function(x)
FPU.prototype.pop = function()
{
this.stack_empty |= 1 << this.stack_ptr;
this.stack_empty[0] |= 1 << this.stack_ptr;
this.stack_ptr = this.stack_ptr + 1 & 7;
}
@ -473,7 +480,7 @@ FPU.prototype.get_sti = function(i)
i = i + this.stack_ptr & 7;
if(this.stack_empty >> i & 1)
if(this.stack_empty[0] >> i & 1)
{
this.status_word &= ~FPU_C1;
this.stack_fault();
@ -487,7 +494,7 @@ FPU.prototype.get_sti = function(i)
FPU.prototype.get_st0 = function()
{
if(this.stack_empty >> this.stack_ptr & 1)
if(this.stack_empty[0] >> this.stack_ptr & 1)
{
this.status_word &= ~FPU_C1;
this.stack_fault();
@ -646,12 +653,12 @@ FPU.prototype.dbg_log_fpu_op = function(op, imm8)
if(imm8 >= 0xC0)
{
dbg_log(h(op, 2) + " " + h(imm8, 2) + "/" + (imm8 >> 3 & 7) + "/" + (imm8 & 7) +
" @" + h(this.cpu.instruction_pointer >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty, 2), LOG_FPU);
" @" + h(this.cpu.instruction_pointer[0] >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty[0], 2), LOG_FPU);
}
else
{
dbg_log(h(op, 2) + " /" + (imm8 >> 3 & 7) +
" @" + h(this.cpu.instruction_pointer >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty, 2), LOG_FPU);
" @" + h(this.cpu.instruction_pointer[0] >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty[0], 2), LOG_FPU);
}
}
@ -987,7 +994,7 @@ FPU.prototype.op_DA_reg = function(imm8)
if(this.cpu.test_b())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 1:
@ -995,7 +1002,7 @@ FPU.prototype.op_DA_reg = function(imm8)
if(this.cpu.test_z())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 2:
@ -1003,7 +1010,7 @@ FPU.prototype.op_DA_reg = function(imm8)
if(this.cpu.test_be())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 3:
@ -1011,7 +1018,7 @@ FPU.prototype.op_DA_reg = function(imm8)
if(this.cpu.test_p())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 5:
@ -1096,7 +1103,7 @@ FPU.prototype.op_DB_reg = function(imm8)
if(!this.cpu.test_b())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 1:
@ -1104,7 +1111,7 @@ FPU.prototype.op_DB_reg = function(imm8)
if(!this.cpu.test_z())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 2:
@ -1112,7 +1119,7 @@ FPU.prototype.op_DB_reg = function(imm8)
if(!this.cpu.test_be())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 3:
@ -1120,7 +1127,7 @@ FPU.prototype.op_DB_reg = function(imm8)
if(!this.cpu.test_p())
{
this.st[this.stack_ptr] = this.get_sti(low);
this.stack_empty &= ~(1 << this.stack_ptr);
this.stack_empty[0] &= ~(1 << this.stack_ptr);
}
break;
case 4:
@ -1329,7 +1336,7 @@ FPU.prototype.op_DD_reg = function(imm8)
{
case 0:
// ffree
this.stack_empty |= 1 << (this.stack_ptr + low & 7);
this.stack_empty[0] |= 1 << (this.stack_ptr + low & 7);
break;
case 2:
// fst

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,7 @@ function IO(cpu)
this.ports[i] = this.create_empty_entry();
}
var memory_size = cpu.memory_size;
var memory_size = cpu.memory_size[0];
for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++)
{
@ -253,7 +253,7 @@ IO.prototype.in_mmap_range = function(start, count)
var end = start + count;
if(end >= this.cpu.memory_size)
if(end >= this.cpu.memory_size[0])
{
return true;
}

View file

@ -120,7 +120,7 @@ function IOAPIC(cpu)
dbg_assert(false);
}
});
}
};
IOAPIC.prototype.remote_eoi = function(vector)
{

View file

@ -87,6 +87,27 @@ var dbg_log = (function()
return dbg_log_;
})();
function dbg_log_wasm(memory, offset, args)
{
if(!(LOG_LEVEL & LOG_CPU))
{
return;
}
let s = new Uint8Array(memory, offset);
let length = s.indexOf(0);
if(length !== -1)
{
s = new Uint8Array(memory, offset, length);
}
let format_string = "[CPU ] " + String.fromCharCode.apply(String, s);
let format_args = [format_string];
format_args.push.apply(format_args, args);
console.log.apply(console, format_args);
}
/**
* @param {number=} level
*/

View file

@ -1,7 +1,10 @@
"use strict";
/** @constructor */
function v86(bus)
/**
* @constructor
* @param {Object=} wm
*/
function v86(bus, wm)
{
/** @type {boolean} */
this.running = false;
@ -10,7 +13,7 @@ function v86(bus)
this.stopped = false;
/** @type {CPU} */
this.cpu = new CPU(bus);
this.cpu = new CPU(bus, wm);
this.bus = bus;
bus.register("cpu-init", this.init, this);

View file

@ -81,7 +81,7 @@ CPU.prototype.mmap_write32 = function(addr, value)
CPU.prototype.in_mapped_range = function(addr)
{
return (addr | 0) >= 0xA0000 && (addr | 0) < 0xC0000 || (addr >>> 0) >= (this.memory_size >>> 0);
return (addr | 0) >= 0xA0000 && (addr | 0) < 0xC0000 || (addr >>> 0) >= (this.memory_size[0] >>> 0);
};
/**
@ -90,7 +90,7 @@ CPU.prototype.in_mapped_range = function(addr)
CPU.prototype.read8 = function(addr)
{
this.debug_read(addr, 1);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK;
if(this.in_mapped_range(addr))
{
@ -108,7 +108,7 @@ CPU.prototype.read8 = function(addr)
CPU.prototype.read16 = function(addr)
{
this.debug_read(addr, 2);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK;
if(this.in_mapped_range(addr))
{
@ -127,7 +127,7 @@ CPU.prototype.read_aligned16 = function(addr)
{
dbg_assert(addr >= 0 && addr < 0x80000000);
this.debug_read(addr << 1, 2);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK16;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK16;
if(this.in_mapped_range(addr << 1))
{
@ -145,7 +145,7 @@ CPU.prototype.read_aligned16 = function(addr)
CPU.prototype.read32s = function(addr)
{
this.debug_read(addr, 4);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK;
if(this.in_mapped_range(addr))
{
@ -165,7 +165,7 @@ CPU.prototype.read_aligned32 = function(addr)
{
dbg_assert(addr >= 0 && addr < 0x40000000);
this.debug_read(addr << 2, 4);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK32;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK32;
if(this.in_mapped_range(addr << 2))
{
@ -184,7 +184,7 @@ CPU.prototype.read_aligned32 = function(addr)
CPU.prototype.write8 = function(addr, value)
{
this.debug_write(addr, 1, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK;
if(this.in_mapped_range(addr))
{
@ -203,7 +203,7 @@ CPU.prototype.write8 = function(addr, value)
CPU.prototype.write16 = function(addr, value)
{
this.debug_write(addr, 2, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK;
if(this.in_mapped_range(addr))
{
@ -224,7 +224,7 @@ CPU.prototype.write_aligned16 = function(addr, value)
{
dbg_assert(addr >= 0 && addr < 0x80000000);
this.debug_write(addr << 1, 2, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK16;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK16;
if(this.in_mapped_range(addr << 1))
{
@ -243,7 +243,7 @@ CPU.prototype.write_aligned16 = function(addr, value)
CPU.prototype.write32 = function(addr, value)
{
this.debug_write(addr, 4, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK;
if(this.in_mapped_range(addr))
{
@ -262,7 +262,7 @@ CPU.prototype.write_aligned32 = function(addr, value)
{
dbg_assert(addr >= 0 && addr < 0x40000000);
this.debug_write(addr << 2, 4, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK32;
if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK32;
if(this.in_mapped_range(addr << 2))
{

View file

@ -20,7 +20,7 @@ CPU.prototype.jmpcc8 = function(condition)
var imm8 = this.read_op8s();
if(condition)
{
this.instruction_pointer = this.instruction_pointer + imm8 | 0;
this.instruction_pointer[0] = this.instruction_pointer[0] + imm8 | 0;
this.branch_taken();
}
else
@ -35,9 +35,9 @@ CPU.prototype.jmp_rel16 = function(rel16)
// limit ip to 16 bit
// ugly
this.instruction_pointer -= current_cs;
this.instruction_pointer = (this.instruction_pointer + rel16) & 0xFFFF;
this.instruction_pointer = this.instruction_pointer + current_cs | 0;
this.instruction_pointer[0] -= current_cs;
this.instruction_pointer[0] = (this.instruction_pointer[0] + rel16) & 0xFFFF;
this.instruction_pointer[0] = this.instruction_pointer[0] + current_cs | 0;
};
CPU.prototype.jmpcc16 = function(condition)
@ -54,7 +54,6 @@ CPU.prototype.jmpcc16 = function(condition)
}
}
CPU.prototype.jmpcc32 = function(condition)
{
var imm32s = this.read_op32s();
@ -63,7 +62,7 @@ CPU.prototype.jmpcc32 = function(condition)
// don't change to `this.instruction_pointer += this.read_op32s()`,
// since read_op32s modifies instruction_pointer
this.instruction_pointer = this.instruction_pointer + imm32s | 0;
this.instruction_pointer[0] = this.instruction_pointer[0] + imm32s | 0;
this.branch_taken();
}
else
@ -99,7 +98,7 @@ CPU.prototype.loopne = function(imm8s)
{
if(this.decr_ecx_asize() && !this.getzf())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0;
this.branch_taken();
}
else
@ -112,7 +111,7 @@ CPU.prototype.loope = function(imm8s)
{
if(this.decr_ecx_asize() && this.getzf())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0;
this.branch_taken();
}
else
@ -125,7 +124,7 @@ CPU.prototype.loop = function(imm8s)
{
if(this.decr_ecx_asize())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0;
this.branch_taken();
}
else
@ -138,7 +137,7 @@ CPU.prototype.jcxz = function(imm8s)
{
if(this.get_reg_asize(reg_ecx) === 0)
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0;
this.branch_taken();
}
else
@ -149,83 +148,82 @@ CPU.prototype.jcxz = function(imm8s)
/**
* @return {number}
* @const
*/
CPU.prototype.getcf = function()
{
if(this.flags_changed & 1)
if(this.flags_changed[0] & 1)
{
return (this.last_op1 ^ (this.last_op1 ^ this.last_op2) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1;
return (this.last_op1[0] ^ (this.last_op1[0] ^ this.last_op2[0]) & (this.last_op2[0] ^ this.last_add_result[0])) >>> this.last_op_size[0] & 1;
}
else
{
return this.flags & 1;
return this.flags[0] & 1;
}
};
/** @return {number} */
CPU.prototype.getpf = function()
{
if(this.flags_changed & flag_parity)
if(this.flags_changed[0] & flag_parity)
{
// inverted lookup table
return 0x9669 << 2 >> ((this.last_result ^ this.last_result >> 4) & 0xF) & flag_parity;
return 0x9669 << 2 >> ((this.last_result[0] ^ this.last_result[0] >> 4) & 0xF) & flag_parity;
}
else
{
return this.flags & flag_parity;
return this.flags[0] & flag_parity;
}
};
/** @return {number} */
CPU.prototype.getaf = function()
{
if(this.flags_changed & flag_adjust)
if(this.flags_changed[0] & flag_adjust)
{
return (this.last_op1 ^ this.last_op2 ^ this.last_add_result) & flag_adjust;
return (this.last_op1[0] ^ this.last_op2[0] ^ this.last_add_result[0]) & flag_adjust;
}
else
{
return this.flags & flag_adjust;
return this.flags[0] & flag_adjust;
}
};
/** @return {number} */
CPU.prototype.getzf = function()
{
if(this.flags_changed & flag_zero)
if(this.flags_changed[0] & flag_zero)
{
return (~this.last_result & this.last_result - 1) >>> this.last_op_size & 1;
return (~this.last_result[0] & this.last_result[0] - 1) >>> this.last_op_size[0] & 1;
}
else
{
return this.flags & flag_zero;
return this.flags[0] & flag_zero;
}
};
/** @return {number} */
CPU.prototype.getsf = function()
{
if(this.flags_changed & flag_sign)
if(this.flags_changed[0] & flag_sign)
{
return this.last_result >>> this.last_op_size & 1;
return this.last_result[0] >>> this.last_op_size[0] & 1;
}
else
{
return this.flags & flag_sign;
return this.flags[0] & flag_sign;
}
};
/** @return {number} */
CPU.prototype.getof = function()
{
if(this.flags_changed & flag_overflow)
if(this.flags_changed[0] & flag_overflow)
{
return ((this.last_op1 ^ this.last_add_result) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1;
return ((this.last_op1[0] ^ this.last_add_result[0]) & (this.last_op2[0] ^ this.last_add_result[0])) >>> this.last_op_size[0] & 1;
}
else
{
return this.flags & flag_overflow;
return this.flags[0] & flag_overflow;
}
};
@ -402,44 +400,44 @@ CPU.prototype.xchg32r = function(operand)
CPU.prototype.lss16 = function(seg)
{
if(this.modrm_byte >= 0xC0)
if(this.modrm_byte[0] >= 0xC0)
{
// 0xc4c4 #ud (EMULATOR_BOP) is used by reactos and windows to exit vm86 mode
this.trigger_ud();
}
var addr = this.modrm_resolve(this.modrm_byte);
var addr = this.modrm_resolve(this.modrm_byte[0]);
var new_reg = this.safe_read16(addr),
new_seg = this.safe_read16(addr + 2 | 0);
this.switch_seg(seg, new_seg);
this.reg16[this.modrm_byte >> 2 & 14] = new_reg;
this.reg16[this.modrm_byte[0] >> 2 & 14] = new_reg;
}
CPU.prototype.lss32 = function(seg)
{
if(this.modrm_byte >= 0xC0)
if(this.modrm_byte[0] >= 0xC0)
{
this.trigger_ud();
}
var addr = this.modrm_resolve(this.modrm_byte);
var addr = this.modrm_resolve(this.modrm_byte[0]);
var new_reg = this.safe_read32s(addr),
new_seg = this.safe_read16(addr + 4 | 0);
this.switch_seg(seg, new_seg);
this.reg32s[this.modrm_byte >> 3 & 7] = new_reg;
this.reg32s[this.modrm_byte[0] >> 3 & 7] = new_reg;
}
CPU.prototype.enter16 = function(size, nesting_level)
{
nesting_level &= 31;
if(nesting_level) dbg_log("enter16 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU);
if(nesting_level) dbg_log("enter16 stack=" + (this.stack_size_32[0] ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU);
this.push16(this.reg16[reg_bp]);
var frame_temp = this.reg16[reg_sp];
@ -461,7 +459,7 @@ CPU.prototype.enter32 = function(size, nesting_level)
{
nesting_level &= 31;
if(nesting_level) dbg_log("enter32 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU);
if(nesting_level) dbg_log("enter32 stack=" + (this.stack_size_32[0] ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU);
this.push32(this.reg32s[reg_ebp]);
var frame_temp = this.reg32s[reg_esp];
@ -492,7 +490,7 @@ CPU.prototype.fxsave = function(addr)
this.safe_write16(addr + 0 | 0, this.fpu.control_word);
this.safe_write16(addr + 2 | 0, this.fpu.load_status_word());
this.safe_write8( addr + 4 | 0, ~this.fpu.stack_empty & 0xFF);
this.safe_write8( addr + 4 | 0, ~this.fpu.stack_empty[0] & 0xFF);
this.safe_write16(addr + 6 | 0, this.fpu.fpu_opcode);
this.safe_write32(addr + 8 | 0, this.fpu.fpu_ip);
this.safe_write16(addr + 12 | 0, this.fpu.fpu_ip_selector);
@ -534,7 +532,7 @@ CPU.prototype.fxrstor = function(addr)
this.fpu.control_word = this.safe_read16(addr + 0 | 0);
this.fpu.set_status_word(this.safe_read16(addr + 2 | 0));
this.fpu.stack_empty = ~this.safe_read8(addr + 4 | 0) & 0xFF;
this.fpu.stack_empty[0] = ~this.safe_read8(addr + 4 | 0) & 0xFF;
this.fpu.fpu_opcode = this.safe_read16(addr + 6 | 0);
this.fpu.fpu_ip = this.safe_read32s(addr + 8 | 0);
this.fpu.fpu_ip = this.safe_read16(addr + 12 | 0);

19
src/native/all.c Normal file
View file

@ -0,0 +1,19 @@
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
extern void call_interrupt_vector(int32_t interrupt_nr, bool is_software_int, bool has_error_code, int32_t error_code);
extern void throw_cpu_exception(void);
#include "const.h"
#include "global_pointers.h"
#include "log.c"
#include "cpu.c"
#include "memory.c"
#include "modrm.c"
#include "misc_instr.c"
#include "arith.c"
#include "fpu.c"
#include "instructions.c"
#include "instructions_0f.c"

825
src/native/arith.c Normal file
View file

@ -0,0 +1,825 @@
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "const.h"
#include "global_pointers.h"
int32_t add(int32_t dest_operand, int32_t source_operand, int32_t op_size)
{
*last_op1 = dest_operand;
*last_op2 = source_operand;
int32_t res = dest_operand + source_operand;
*last_add_result = *last_result = res;
*last_op_size = op_size;
*flags_changed = FLAGS_ALL;
return res;
}
int32_t adc(int32_t dest_operand, int32_t source_operand, int32_t op_size)
{
int32_t cf = getcf();
*last_op1 = dest_operand;
*last_op2 = source_operand;
int32_t res = dest_operand + source_operand + cf;
*last_add_result = *last_result = res;
*last_op_size = op_size;
*flags_changed = FLAGS_ALL;
return res;
}
int32_t sub(int32_t dest_operand, int32_t source_operand, int32_t op_size)
{
*last_add_result = dest_operand;
*last_op2 = source_operand;
int32_t res = dest_operand - source_operand;
*last_op1 = *last_result = res;
*last_op_size = op_size;
*flags_changed = FLAGS_ALL;
return res;
}
int32_t sbb(int32_t dest_operand, int32_t source_operand, int32_t op_size)
{
int32_t cf = getcf();
*last_add_result = dest_operand;
*last_op2 = source_operand;
int32_t res = dest_operand - source_operand - cf;
*last_op1 = *last_result = res;
*last_op_size = op_size;
*flags_changed = FLAGS_ALL;
return res;
}
int32_t add8(int32_t x, int32_t y) { return add(x, y, OPSIZE_8); }
int32_t add16(int32_t x, int32_t y) { return add(x, y, OPSIZE_16); }
int32_t add32(int32_t x, int32_t y) { return add(x, y, OPSIZE_32); }
int32_t sub8(int32_t x, int32_t y) { return sub(x, y, OPSIZE_8); }
int32_t sub16(int32_t x, int32_t y) { return sub(x, y, OPSIZE_16); }
int32_t sub32(int32_t x, int32_t y) { return sub(x, y, OPSIZE_32); }
int32_t adc8(int32_t x, int32_t y) { return adc(x, y, OPSIZE_8); }
int32_t adc16(int32_t x, int32_t y) { return adc(x, y, OPSIZE_16); }
int32_t adc32(int32_t x, int32_t y) { return adc(x, y, OPSIZE_32); }
int32_t sbb8(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_8); }
int32_t sbb16(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_16); }
int32_t sbb32(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_32); }
void cmp8(int32_t x, int32_t y) { sub(x, y, OPSIZE_8); }
void cmp16(int32_t x, int32_t y) { sub(x, y, OPSIZE_16); }
void cmp32(int32_t x, int32_t y) { sub(x, y, OPSIZE_32); }
int32_t inc(int32_t dest_operand, int32_t op_size)
{
*flags = (*flags & ~1) | getcf();
*last_op1 = dest_operand;
*last_op2 = 1;
int32_t res = dest_operand + 1;
*last_add_result = *last_result = res;
*last_op_size = op_size;
*flags_changed = FLAGS_ALL & ~1;
return res;
}
int32_t dec(int32_t dest_operand, int32_t op_size)
{
*flags = (*flags & ~1) | getcf();
*last_add_result = dest_operand;
*last_op2 = 1;
int32_t res = dest_operand - 1;
*last_op1 = *last_result = res;
*last_op_size = op_size;
*flags_changed = FLAGS_ALL & ~1;
return res;
}
int32_t inc8(int32_t x) { return inc(x, OPSIZE_8); }
int32_t inc16(int32_t x) { return inc(x, OPSIZE_16); }
int32_t inc32(int32_t x) { return inc(x, OPSIZE_32); }
int32_t dec8(int32_t x) { return dec(x, OPSIZE_8); }
int32_t dec16(int32_t x) { return dec(x, OPSIZE_16); }
int32_t dec32(int32_t x) { return dec(x, OPSIZE_32); }
int32_t neg(int32_t dest_operand, int32_t op_size)
{
int32_t res = -dest_operand;
*last_op1 = *last_result = res;
*flags_changed = FLAGS_ALL;
*last_add_result = 0;
*last_op2 = dest_operand;
*last_op_size = op_size;
return res;
}
int32_t neg8(int32_t x) { return neg(x, OPSIZE_8); }
int32_t neg16(int32_t x) { return neg(x, OPSIZE_16); }
int32_t neg32(int32_t x) { return neg(x, OPSIZE_32); }
void mul8(int32_t source_operand)
{
int32_t result = source_operand * reg8[AL];
reg16[AX] = result;
*last_result = result & 0xFF;
*last_op_size = OPSIZE_8;
if(result < 0x100)
{
*flags = *flags & ~1 & ~FLAG_OVERFLOW;
}
else
{
*flags = *flags | 1 | FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
}
void imul8(int32_t source_operand)
{
int32_t result = source_operand * reg8s[AL];
reg16[AX] = result;
*last_result = result & 0xFF;
*last_op_size = OPSIZE_8;
if(result > 0x7F || result < -0x80)
{
*flags = *flags | 1 | FLAG_OVERFLOW;
}
else
{
*flags = *flags & ~1 & ~FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
}
void mul16(uint32_t source_operand)
{
uint32_t result = source_operand * reg16[AX];
uint32_t high_result = result >> 16;
reg16[AX] = result;
reg16[DX] = high_result;
*last_result = result & 0xFFFF;
*last_op_size = OPSIZE_16;
if(high_result == 0)
{
*flags &= ~1 & ~FLAG_OVERFLOW;
}
else
{
*flags |= *flags | 1 | FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
}
void imul16(int32_t source_operand)
{
int32_t result = source_operand * reg16s[AX];
reg16[AX] = result;
reg16[DX] = result >> 16;
*last_result = result & 0xFFFF;
*last_op_size = OPSIZE_16;
if(result > 0x7FFF || result < -0x8000)
{
*flags |= 1 | FLAG_OVERFLOW;
}
else
{
*flags &= ~1 & ~FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
}
int32_t imul_reg16(int32_t operand1, int32_t operand2)
{
assert(operand1 < 0x8000 && operand1 >= -0x8000);
assert(operand2 < 0x8000 && operand2 >= -0x8000);
int32_t result = operand1 * operand2;
*last_result = result & 0xFFFF;
*last_op_size = OPSIZE_16;
if(result > 0x7FFF || result < -0x8000)
{
*flags |= 1 | FLAG_OVERFLOW;
}
else
{
*flags &= ~1 & ~FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
return result;
}
void do_mul32(uint32_t a, uint32_t b)
{
uint32_t a00 = a & 0xFFFF;
uint32_t a16 = a >> 16;
uint32_t b00 = b & 0xFFFF;
int32_t b16 = b >> 16;
uint32_t low_result = a00 * b00;
uint32_t mid = (low_result >> 16) + (a16 * b00);
uint32_t high_result = mid >> 16;
mid = (mid & 0xFFFF) + (a00 * b16);
mul32_result[0] = (mid << 16) | low_result & 0xFFFF;
mul32_result[1] = ((mid >> 16) + (a16 * b16)) + high_result;
}
void do_imul32(int32_t a, int32_t b)
{
bool is_neg = false;
if(a < 0) {
is_neg = true;
a = -a;
}
if(b < 0) {
is_neg = !is_neg;
b = -b;
}
do_mul32(a, b);
if(is_neg) {
mul32_result[0] = -mul32_result[0];
mul32_result[1] = ~mul32_result[1] + !mul32_result[0];
}
}
void mul32(int32_t source_operand)
{
int32_t dest_operand = reg32s[EAX];
do_mul32(dest_operand, source_operand);
reg32s[EAX] = mul32_result[0];
reg32s[EDX] = mul32_result[1];
*last_result = mul32_result[0];
*last_op_size = OPSIZE_32;
if(mul32_result[1] == 0)
{
*flags &= ~1 & ~FLAG_OVERFLOW;
}
else
{
*flags |= 1 | FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
}
void imul32(int32_t source_operand)
{
//XXX: this assert fails since the limits here are out of bounds for int32
//but the assert is present in the original JS source :|
//assert(source_operand < 0x80000000 && source_operand >= -0x80000000);
int32_t dest_operand = reg32s[EAX];
do_imul32(dest_operand, source_operand);
reg32s[EAX] = mul32_result[0];
reg32s[EDX] = mul32_result[1];
*last_result = mul32_result[0];
*last_op_size = OPSIZE_32;
if(mul32_result[1] == (mul32_result[0] >> 31))
{
*flags &= ~1 & ~FLAG_OVERFLOW;
}
else
{
*flags |= 1 | FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
}
int32_t imul_reg32(int32_t operand1, int32_t operand2)
{
//XXX: assert limits OOB for int32
//dbg_assert(operand1 < 0x80000000 && operand1 >= -0x80000000);
//dbg_assert(operand2 < 0x80000000 && operand2 >= -0x80000000);
do_imul32(operand1, operand2);
*last_result = mul32_result[0];
*last_op_size = OPSIZE_32;
if(mul32_result[1] == (mul32_result[0] >> 31))
{
*flags &= ~1 & ~FLAG_OVERFLOW;
}
else
{
*flags |= 1 | FLAG_OVERFLOW;
}
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW;
return mul32_result[0];
}
int32_t xadd8(int32_t source_operand, int32_t reg)
{
int32_t tmp = reg8[reg];
reg8[reg] = source_operand;
return add(source_operand, tmp, OPSIZE_8);
}
int32_t xadd16(int32_t source_operand, int32_t reg)
{
int32_t tmp = reg16[reg];
reg16[reg] = source_operand;
return add(source_operand, tmp, OPSIZE_16);
}
int32_t xadd32(int32_t source_operand, int32_t reg)
{
int32_t tmp = reg32s[reg];
reg32s[reg] = source_operand;
return add(source_operand, tmp, OPSIZE_32);
}
void bcd_daa()
{
int32_t old_al = reg8[AL];
int32_t old_cf = getcf();
int32_t old_af = getaf();
*flags &= ~1 & ~FLAG_ADJUST;
if((old_al & 0xF) > 9 || old_af)
{
reg8[AL] += 6;
*flags |= FLAG_ADJUST;
}
if(old_al > 0x99 || old_cf)
{
reg8[AL] += 0x60;
*flags |= 1;
}
*last_result = reg8[AL];
*last_op_size = OPSIZE_8;
*last_op1 = *last_op2 = 0;
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW;
}
void bcd_das()
{
int32_t old_al = reg8[AL];
int32_t old_cf = getcf();
*flags &= ~1;
if((old_al & 0xF) > 9 || getaf())
{
reg8[AL] -= 6;
*flags |= FLAG_ADJUST;
*flags = *flags & ~1 | old_cf | (old_al < 6);
}
else
{
*flags &= ~FLAG_ADJUST;
}
if(old_al > 0x99 || old_cf)
{
reg8[AL] -= 0x60;
*flags |= 1;
}
*last_result = reg8[AL];
*last_op_size = OPSIZE_8;
*last_op1 = *last_op2 = 0;
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW;
}
void bcd_aad(int32_t imm8)
{
int32_t result = reg8[AL] + reg8[AH] * imm8;
*last_result = result & 0xFF;
reg16[AX] = *last_result;
*last_op_size = OPSIZE_8;
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW;
*flags &= ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW;
if(result > 0xFFFF)
{
*flags |= 1;
}
}
void bcd_aaa()
{
if((reg8[AL] & 0xF) > 9 || getaf())
{
reg16[AX] += 6;
reg8[AH] += 1;
*flags |= FLAG_ADJUST | 1;
}
else
{
*flags &= ~FLAG_ADJUST & ~1;
}
reg8[AL] &= 0xF;
*flags_changed &= ~FLAG_ADJUST & ~1;
}
void bcd_aas()
{
if((reg8[AL] & 0xF) > 9 || getaf())
{
reg16[AX] -= 6;
reg8[AH] -= 1;
*flags |= FLAG_ADJUST | 1;
}
else
{
*flags &= ~FLAG_ADJUST & ~1;
}
reg8[AL] &= 0xF;
*flags_changed &= ~FLAG_ADJUST & ~1;
}
int32_t and(int32_t dest_operand, int32_t source_operand, int32_t op_size)
{
*last_result = dest_operand & source_operand;
*last_op_size = op_size;
*flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST;
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST;
return *last_result;
}
int32_t or(int32_t dest_operand, int32_t source_operand, int32_t op_size)
{
*last_result = dest_operand | source_operand;
*last_op_size = op_size;
*flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST;
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST;
return *last_result;
}
int32_t xor(int32_t dest_operand, int32_t source_operand, int32_t op_size)
{
*last_result = dest_operand ^ source_operand;
*last_op_size = op_size;
*flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST;
*flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST;
return *last_result;
}
int32_t and8(int32_t x, int32_t y) { return and(x, y, OPSIZE_8); }
int32_t and16(int32_t x, int32_t y) { return and(x, y, OPSIZE_16); }
int32_t and32(int32_t x, int32_t y) { return and(x, y, OPSIZE_32); }
void test8(int32_t x, int32_t y) { and(x, y, OPSIZE_8); }
void test16(int32_t x, int32_t y) { and(x, y, OPSIZE_16); }
void test32(int32_t x, int32_t y) { and(x, y, OPSIZE_32); }
int32_t or8(int32_t x, int32_t y) { return or(x, y, OPSIZE_8); }
int32_t or16(int32_t x, int32_t y) { return or(x, y, OPSIZE_16); }
int32_t or32(int32_t x, int32_t y) { return or(x, y, OPSIZE_32); }
int32_t xor8(int32_t x, int32_t y) { return xor(x, y, OPSIZE_8); }
int32_t xor16(int32_t x, int32_t y) { return xor(x, y, OPSIZE_16); }
int32_t xor32(int32_t x, int32_t y) { return xor(x, y, OPSIZE_32); }
int32_t rol8(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
count &= 7;
int32_t result = dest_operand << count | dest_operand >> (8 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result & 1)
| (result << 11 ^ result << 4) & FLAG_OVERFLOW;
return result;
}
int32_t rol16(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
count &= 15;
int32_t result = dest_operand << count | dest_operand >> (16 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result & 1)
| (result << 11 ^ result >> 4) & FLAG_OVERFLOW;
return result;
}
int32_t rol32(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
int32_t result = dest_operand << count | ((uint32_t) dest_operand) >> (32 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result & 1)
| (result << 11 ^ result >> 20) & FLAG_OVERFLOW;
return result;
}
int32_t rcl8(int32_t dest_operand, int32_t count)
{
count %= 9;
if(!count)
{
return dest_operand;
}
int32_t result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (9 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result >> 8 & 1)
| (result << 3 ^ result << 4) & FLAG_OVERFLOW;
return result;
}
int32_t rcl16(int32_t dest_operand, int32_t count)
{
count %= 17;
if(!count)
{
return dest_operand;
}
int32_t result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (17 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result >> 16 & 1)
| (result >> 5 ^ result >> 4) & FLAG_OVERFLOW;
return result;
}
int32_t rcl32(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
int32_t result = dest_operand << count | getcf() << (count - 1);
if(count > 1)
{
result |= ((uint32_t) dest_operand) >> (33 - count);
}
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW) | (((uint32_t) dest_operand) >> (32 - count) & 1);
*flags |= (*flags << 11 ^ result >> 20) & FLAG_OVERFLOW;
return result;
}
int32_t ror8(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
count &= 7;
int32_t result = dest_operand >> count | dest_operand << (8 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result >> 7 & 1)
| (result << 4 ^ result << 5) & FLAG_OVERFLOW;
return result;
}
int32_t ror16(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
count &= 15;
int32_t result = dest_operand >> count | dest_operand << (16 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result >> 15 & 1)
| (result >> 4 ^ result >> 3) & FLAG_OVERFLOW;
return result;
}
int32_t ror32(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
int32_t result = ((uint32_t) dest_operand) >> count | dest_operand << (32 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result >> 31 & 1)
| (result >> 20 ^ result >> 19) & FLAG_OVERFLOW;
return result;
}
int32_t rcr8(int32_t dest_operand, int32_t count)
{
count %= 9;
if(!count)
{
return dest_operand;
}
int32_t result = dest_operand >> count | getcf() << (8 - count) | dest_operand << (9 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result >> 8 & 1)
| (result << 4 ^ result << 5) & FLAG_OVERFLOW;
return result;
}
int32_t rcr16(int32_t dest_operand, int32_t count)
{
count %= 17;
if(!count)
{
return dest_operand;
}
int32_t result = dest_operand >> count | getcf() << (16 - count) | dest_operand << (17 - count);
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (result >> 16 & 1)
| (result >> 4 ^ result >> 3) & FLAG_OVERFLOW;
return result;
}
int32_t rcr32(int32_t dest_operand, int32_t count)
{
if(!count)
{
return dest_operand;
}
int32_t result = ((uint32_t) dest_operand) >> count | getcf() << (32 - count);
if(count > 1)
{
result |= dest_operand << (33 - count);
}
*flags_changed &= ~1 & ~FLAG_OVERFLOW;
*flags = (*flags & ~1 & ~FLAG_OVERFLOW)
| (dest_operand >> (count - 1) & 1)
| (result >> 20 ^ result >> 19) & FLAG_OVERFLOW;
return result;
}
void div8(uint32_t source_operand)
{
if(source_operand == 0)
{
trigger_de();
return;
}
uint16_t target_operand = reg16[AX];
uint16_t result = target_operand / source_operand;
if(result >= 0x100)
{
trigger_de();
}
else
{
reg8[AL] = result;
reg8[AH] = target_operand % source_operand;
}
}
void idiv8(int32_t source_operand)
{
if(source_operand == 0)
{
trigger_de();
return;
}
int32_t target_operand = reg16s[AX];
int32_t result = target_operand / source_operand;
if(result >= 0x80 || result <= -0x81)
{
trigger_de();
}
else
{
reg8[AL] = result;
reg8[AH] = target_operand % source_operand;
}
}
void div16(uint32_t source_operand)
{
if(source_operand == 0)
{
trigger_de();
return;
}
uint32_t target_operand = reg16[AX] | reg16[DX] << 16;
uint32_t result = target_operand / source_operand;
if(result >= 0x10000)
{
trigger_de();
}
else
{
reg16[AX] = result;
reg16[DX] = target_operand % source_operand;
}
}

159
src/native/const.h Normal file
View file

@ -0,0 +1,159 @@
#ifndef DEBUG
#define DEBUG true
#endif
#define FLAG_CARRY 1
#define FLAG_PARITY 4
#define FLAG_ADJUST 16
#define FLAG_ZERO 64
#define FLAG_SIGN 128
#define FLAG_TRAP 256
#define FLAG_INTERRUPT 512
#define FLAG_DIRECTION 1024
#define FLAG_OVERFLOW 2048
#define FLAG_IOPL (1 << 12 | 1 << 13)
#define FLAG_NT (1 << 14)
#define FLAG_RF (1 << 16)
#define FLAG_VM (1 << 17)
#define FLAG_AC (1 << 18)
#define FLAG_VIF (1 << 19)
#define FLAG_VIP (1 << 20)
#define FLAG_ID (1 << 21)
#define FLAGS_DEFAULT (1 << 1)
#define FLAGS_MASK ( \
FLAG_CARRY | FLAG_PARITY | FLAG_ADJUST | FLAG_ZERO | FLAG_SIGN | FLAG_TRAP | FLAG_INTERRUPT | \
FLAG_DIRECTION | FLAG_OVERFLOW | FLAG_IOPL | FLAG_NT | FLAG_RF | FLAG_VM | FLAG_AC | \
FLAG_VIF | FLAG_VIP | FLAG_ID)
#define FLAGS_ALL (FLAG_CARRY | FLAG_PARITY | FLAG_ADJUST | FLAG_ZERO | FLAG_SIGN | FLAG_OVERFLOW)
#define OPSIZE_8 7
#define OPSIZE_16 15
#define OPSIZE_32 31
#define EAX 0
#define ECX 1
#define EDX 2
#define EBX 3
#define ESP 4
#define EBP 5
#define ESI 6
#define EDI 7
#define AX 0
#define CX 2
#define DX 4
#define BX 6
#define SP 8
#define BP 10
#define SI 12
#define DI 14
#define AL 0
#define CL 4
#define DL 8
#define BL 12
#define AH 1
#define CH 5
#define DH 9
#define BH 13
#define ES 0
#define CS 1
#define SS 2
#define DS 3
#define FS 4
#define GS 5
#define TR 6
#define LDTR 7
#define TLB_SYSTEM_READ 1
#define TLB_SYSTEM_WRITE 2
#define TLB_USER_READ 4
#define TLB_USER_WRITE 8
#define PSE_ENABLED 128
#define MMAP_BLOCK_BITS 17
#define MMAP_BLOCK_SIZE = (1 << MMAP_BLOCK_BITS)
#define CR0_PE 1
#define CR0_MP (1 << 1)
#define CR0_EM (1 << 2)
#define CR0_TS (1 << 3)
#define CR0_ET (1 << 4)
#define CR0_WP (1 << 16)
#define CR0_NW (1 << 29)
#define CR0_CD (1 << 30)
#define CR0_PG (1 << 31)
#define CR4_VME (1)
#define CR4_PVI (1 << 1)
#define CR4_TSD (1 << 2)
#define CR4_PSE (1 << 4)
#define CR4_DE (1 << 3)
#define CR4_PAE (1 << 5)
#define CR4_PGE (1 << 7)
#define IA32_SYSENTER_CS 0x174
#define IA32_SYSENTER_ESP 0x175
#define IA32_SYSENTER_EIP 0x176
#define IA32_TIME_STAMP_COUNTER 0x10
#define IA32_PLATFORM_ID 0x17
#define IA32_APIC_BASE_MSR 0x1B
#define IA32_BIOS_SIGN_ID 0x8B
#define IA32_MISC_ENABLE 0x1A0
#define IA32_RTIT_CTL 0x570
#define MSR_SMI_COUNT 0x34
#define IA32_MCG_CAP 0x179
#define IA32_KERNEL_GS_BASE 0xC0000101
#define MSR_PKG_C2_RESIDENCY 0x60D
#define IA32_APIC_BASE_BSP (1 << 8)
#define IA32_APIC_BASE_EXTD (1 << 10)
#define IA32_APIC_BASE_EN (1 << 11)
// Note: Duplicated in apic.js
#define APIC_ADDRESS ((int32_t)0xFEE00000)
// Segment prefixes must not collide with reg_*s variables
// _ZERO is a special zero offset segment
#define SEG_PREFIX_NONE (-1)
#define SEG_PREFIX_ZERO 7
#define PREFIX_MASK_REP 0b11000
#define PREFIX_REPZ 0b01000
#define PREFIX_REPNZ 0b10000
#define PREFIX_MASK_SEGMENT 0b111
#define PREFIX_MASK_OPSIZE 0b100000
#define PREFIX_MASK_ADDRSIZE 0b1000000
/**
* How many cycles the CPU does at a time before running hardware timers
*/
#define LOOP_COUNTER 11001
#define TSC_RATE (8 * 1024)
#define LOG_CPU 0x000002
#define CPU_LOG_VERBOSE false
#define ENABLE_ACPI false
#define A20_MASK (~(1 << 20))
#define A20_MASK16 (~(1 << (20 - 1)))
#define A20_MASK32 (~(1 << (20 - 2)))
#define USE_A20 false
#define MXCSR_MASK (0xFFFF & ~(1 << 6))

572
src/native/cpu.c Normal file
View file

@ -0,0 +1,572 @@
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "const.h"
#include "global_pointers.h"
int32_t read_e8_partial_branch() {
return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1];
}
int32_t translate_address_read(int32_t);
int32_t translate_address_write(int32_t);
int32_t read8(uint32_t);
int32_t read16(uint32_t);
int32_t read32s(uint32_t);
int32_t virt_boundary_read16(int32_t, int32_t);
int32_t virt_boundary_read32s(int32_t, int32_t);
void write8(uint32_t, uint8_t);
void write16(uint32_t, uint16_t);
void write32(uint32_t, int32_t);
void virt_boundary_write16(int32_t, int32_t, int32_t);
void virt_boundary_write32(int32_t, int32_t, int32_t);
void trigger_gp(int32_t);
int32_t safe_read8(int32_t);
int32_t safe_read16(int32_t);
int32_t safe_read32s(int32_t);
void safe_write8(int32_t, int32_t);
void safe_write16(int32_t, int32_t);
void safe_write32(int32_t, int32_t);
void fxsave(int32_t);
void fxrstor(int32_t);
int32_t do_page_translation(int32_t, bool, bool);
void diverged() {}
void branch_taken() {}
void branch_not_taken() {}
int32_t getcf(void);
int32_t getpf(void);
int32_t getaf(void);
int32_t getzf(void);
int32_t getsf(void);
int32_t getof(void);
int32_t get_eflags()
{
return (*flags & ~FLAGS_ALL) | !!getcf() | !!getpf() << 2 | !!getaf() << 4 |
!!getzf() << 6 | !!getsf() << 7 | !!getof() << 11;
}
int32_t translate_address_read(int32_t address)
{
if(!*paging) return address;
int32_t base = (uint32_t)address >> 12;
if(tlb_info[base] & (*cpl == 3 ? TLB_USER_READ : TLB_SYSTEM_READ))
{
return tlb_data[base] ^ address;
}
else
{
return do_page_translation(address, 0, *cpl == 3) | address & 0xFFF;
}
}
int32_t translate_address_write(int32_t address)
{
if(!*paging) return address;
int32_t base = (uint32_t)address >> 12;
if(tlb_info[base] & (*cpl == 3 ? TLB_USER_WRITE : TLB_SYSTEM_WRITE))
{
return tlb_data[base] ^ address;
}
else
{
return do_page_translation(address, 1, *cpl == 3) | address & 0xFFF;
}
}
int32_t read_imm8()
{
int32_t eip = *instruction_pointer;
if((eip & ~0xFFF) ^ *last_virt_eip)
{
*eip_phys = translate_address_read(eip) ^ eip;
*last_virt_eip = eip & ~0xFFF;
}
int32_t data8 = read8(*eip_phys ^ eip);
*instruction_pointer = eip + 1;
return data8;
}
int32_t read_imm8s()
{
return read_imm8() << 24 >> 24;
}
int32_t read_imm16()
{
// Two checks in one comparison:
// 1. Did the high 20 bits of eip change
// or 2. Are the low 12 bits of eip 0xFFF (and this read crosses a page boundary)
if((uint32_t)(*instruction_pointer ^ *last_virt_eip) > 0xFFE)
{
return read_imm8() | read_imm8() << 8;
}
int32_t data16 = read16(*eip_phys ^ *instruction_pointer);
*instruction_pointer = *instruction_pointer + 2;
return data16;
}
int32_t read_imm32s()
{
// Analogue to the above comment
if((uint32_t)(*instruction_pointer ^ *last_virt_eip) > 0xFFC)
{
return read_imm16() | read_imm16() << 16;
}
int32_t data32 = read32s(*eip_phys ^ *instruction_pointer);
*instruction_pointer = *instruction_pointer + 4;
return data32;
}
int32_t read_op0F() { return read_imm8(); }
int32_t read_sib() { return read_imm8(); }
int32_t read_op8() { return read_imm8(); }
int32_t read_op8s() { return read_imm8s(); }
int32_t read_op16() { return read_imm16(); }
int32_t read_op32s() { return read_imm32s(); }
int32_t read_disp8() { return read_imm8(); }
int32_t read_disp8s() { return read_imm8s(); }
int32_t read_disp16() { return read_imm16(); }
int32_t read_disp32s() { return read_imm32s(); }
bool is_osize_32()
{
return *is_32 != ((*prefixes & PREFIX_MASK_OPSIZE) == PREFIX_MASK_OPSIZE);
}
bool is_asize_32()
{
return *is_32 != ((*prefixes & PREFIX_MASK_ADDRSIZE) == PREFIX_MASK_ADDRSIZE);
}
void read_modrm_byte()
{
*modrm_byte = read_imm8();
}
int32_t get_seg(int32_t segment)
{
assert(segment >= 0 && segment < 8);
// TODO: Remove protected_mode check
if(*protected_mode)
{
if(segment_is_null[segment])
{
assert(segment != CS && segment != SS);
trigger_gp(0);
}
}
return segment_offsets[segment];
}
int32_t get_seg_prefix(int32_t default_segment)
{
int32_t prefix = *prefixes & PREFIX_MASK_SEGMENT;
if(prefix)
{
if(prefix == SEG_PREFIX_ZERO)
{
return 0; // TODO: Remove this special case
}
else
{
return get_seg(prefix - 1);
}
}
else
{
return get_seg(default_segment);
}
}
int32_t get_seg_prefix_ds(int32_t offset) { return get_seg_prefix(DS) + offset; }
int32_t get_seg_prefix_ss(int32_t offset) { return get_seg_prefix(SS) + offset; }
int32_t get_seg_prefix_cs(int32_t offset) { return get_seg_prefix(CS) + offset; }
static void run_instruction(int32_t);
static int32_t resolve_modrm16(int32_t);
static int32_t resolve_modrm32(int32_t);
static int32_t modrm_resolve(int32_t modrm_byte)
{
if(is_asize_32())
{
return resolve_modrm32(modrm_byte);
}
else
{
return resolve_modrm16(modrm_byte);
}
}
void set_e8(int32_t value)
{
int32_t modrm_byte_ = *modrm_byte;
if(modrm_byte_ < 0xC0) {
int32_t addr = modrm_resolve(modrm_byte_);
safe_write8(addr, value);
} else {
reg8[modrm_byte_ << 2 & 0xC | modrm_byte_ >> 2 & 1] = value;
}
}
void set_e16(int32_t value)
{
int32_t modrm_byte_ = *modrm_byte;
if(modrm_byte_ < 0xC0) {
int32_t addr = modrm_resolve(modrm_byte_);
safe_write16(addr, value);
} else {
reg16[modrm_byte_ << 1 & 14] = value;
}
}
void set_e32(int32_t value)
{
int32_t modrm_byte_ = *modrm_byte;
if(modrm_byte_ < 0xC0) {
int32_t addr = modrm_resolve(modrm_byte_);
safe_write32(addr, value);
} else {
reg32s[modrm_byte_ & 7] = value;
}
}
int32_t read_g8()
{
return reg8[*modrm_byte >> 1 & 0xC | *modrm_byte >> 5 & 1];
}
int32_t read_g16()
{
return reg16[*modrm_byte >> 2 & 14];
}
int32_t read_g16s()
{
return reg16s[*modrm_byte >> 2 & 14];
}
int32_t read_g32s()
{
return reg32s[*modrm_byte >> 3 & 7];
}
void write_g8(int32_t value)
{
reg8[*modrm_byte >> 1 & 0xC | *modrm_byte >> 5 & 1] = value;
}
void write_g16(int32_t value)
{
reg16[*modrm_byte >> 2 & 14] = value;
}
void write_g32(int32_t value)
{
reg32s[*modrm_byte >> 3 & 7] = value;
}
int32_t read_e8()
{
if(*modrm_byte < 0xC0)
{
return safe_read8(modrm_resolve(*modrm_byte));
}
else
{
return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1];
}
}
int32_t read_e8s()
{
return read_e8() << 24 >> 24;
}
int32_t read_e16()
{
if(*modrm_byte < 0xC0)
{
return safe_read16(modrm_resolve(*modrm_byte));
}
else
{
return reg16[*modrm_byte << 1 & 14];
}
}
int32_t read_e16s()
{
return read_e16() << 16 >> 16;
}
int32_t read_e32s()
{
if(*modrm_byte < 0xC0)
{
return safe_read32s(modrm_resolve(*modrm_byte));
}
else
{
return reg32s[*modrm_byte & 7];
}
}
void cycle_internal()
{
previous_ip[0] = instruction_pointer[0];
(*timestamp_counter)++;
int32_t opcode = read_imm8();
run_instruction(opcode);
}
static void run_prefix_instruction()
{
run_instruction(read_imm8());
}
void clear_prefixes()
{
*prefixes = 0;
}
void segment_prefix_op(int32_t seg)
{
assert(seg <= 5);
*prefixes |= seg + 1;
run_prefix_instruction();
*prefixes = 0;
}
void do_many_cycles_unsafe()
{
for(int32_t k = 0; k < LOOP_COUNTER; k++)
{
cycle_internal();
}
}
void raise_exception(int32_t interrupt_nr)
{
call_interrupt_vector(interrupt_nr, false, false, 0);
throw_cpu_exception();
}
void raise_exception_with_code(int32_t interrupt_nr, int32_t error_code)
{
call_interrupt_vector(interrupt_nr, false, true, error_code);
throw_cpu_exception();
}
void trigger_de()
{
*instruction_pointer = *previous_ip;
raise_exception(0);
}
void trigger_gp(int32_t code)
{
*instruction_pointer = *previous_ip;
raise_exception_with_code(13, code);
}
int32_t safe_read8(int32_t addr)
{
return read8(translate_address_read(addr));
}
int32_t safe_read16(int32_t addr)
{
if((addr & 0xFFF) == 0xFFF)
{
return safe_read8(addr) | safe_read8(addr + 1) << 8;
}
else
{
return read16(translate_address_read(addr));
}
}
int32_t safe_read32s(int32_t addr)
{
if((addr & 0xFFF) >= 0xFFD)
{
return safe_read16(addr) | safe_read16(addr + 2) << 16;
}
else
{
return read32s(translate_address_read(addr));
}
}
void safe_write8(int32_t addr, int32_t value)
{
write8(translate_address_write(addr), value);
}
void safe_write16(int32_t addr, int32_t value)
{
int32_t phys_low = translate_address_write(addr);
if((addr & 0xFFF) == 0xFFF)
{
virt_boundary_write16(phys_low, translate_address_write(addr + 1), value);
}
else
{
write16(phys_low, value);
}
}
void safe_write32(int32_t addr, int32_t value)
{
int32_t phys_low = translate_address_write(addr);
if((addr & 0xFFF) >= 0xFFD)
{
virt_boundary_write32(phys_low, translate_address_write(addr + 3 & ~3) | (addr + 3) & 3, value);
}
else
{
write32(phys_low, value);
}
}
int32_t read_write_e8()
{
if(*modrm_byte < 0xC0)
{
int32_t virt_addr = modrm_resolve(*modrm_byte);
*phys_addr = translate_address_write(virt_addr);
return read8(*phys_addr);
}
else
{
return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1];
}
}
void write_e8(int32_t value)
{
if(*modrm_byte < 0xC0)
{
write8(*phys_addr, value);
}
else
{
reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1] = value;
}
}
int32_t read_write_e16()
{
if(*modrm_byte < 0xC0)
{
int32_t virt_addr = modrm_resolve(*modrm_byte);
*phys_addr = translate_address_write(virt_addr);
if((virt_addr & 0xFFF) == 0xFFF)
{
*phys_addr_high = translate_address_write(virt_addr + 1);
dbg_assert(*phys_addr_high);
return virt_boundary_read16(*phys_addr, *phys_addr_high);
}
else
{
*phys_addr_high = 0;
return read16(*phys_addr);
}
}
else
{
return reg16[*modrm_byte << 1 & 14];
}
}
void write_e16(int32_t value)
{
if(*modrm_byte < 0xC0)
{
if(*phys_addr_high)
{
virt_boundary_write16(*phys_addr, *phys_addr_high, value);
}
else
{
write16(*phys_addr, value);
}
}
else
{
reg16[*modrm_byte << 1 & 14] = value;
}
}
int32_t read_write_e32()
{
if(*modrm_byte < 0xC0)
{
int32_t virt_addr = modrm_resolve(*modrm_byte);
*phys_addr = translate_address_write(virt_addr);
if((virt_addr & 0xFFF) >= 0xFFD)
{
*phys_addr_high = translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3;
dbg_assert(*phys_addr_high);
return virt_boundary_read32s(*phys_addr, *phys_addr_high);
}
else
{
*phys_addr_high = 0;
return read32s(*phys_addr);
}
}
else
{
return reg32s[*modrm_byte & 7];
}
}
void write_e32(int32_t value)
{
if(*modrm_byte < 0xC0)
{
if(*phys_addr_high)
{
virt_boundary_write32(*phys_addr, *phys_addr_high, value);
}
else
{
write32(*phys_addr, value);
}
}
else
{
reg32s[*modrm_byte & 7] = value;
}
}

20
src/native/fpu.c Normal file
View file

@ -0,0 +1,20 @@
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "const.h"
#include "global_pointers.h"
void safe_tag_word(int32_t tag_word) {
*stack_empty = 0;
for(int i = 0; i < 8; i++)
{
*stack_empty |= (tag_word >> i) & (tag_word >> (i + 1)) & 1 << i;
}
//dbg_log("safe tw=" + h(tag_word) + " se=" + h(this.stack_empty[0]), LOG_FPU);
}

View file

@ -0,0 +1,69 @@
#ifndef _GLOBAL_POINTERS_H
#define _GLOBAL_POINTERS_H
uint8_t* const reg8 = (uint8_t* const) 4;
uint16_t* const reg16 = (uint16_t* const) 4;
int8_t* const reg8s = (int8_t* const) 4;
int16_t* const reg16s = (int16_t* const) 4;
int32_t* const reg32s = (int32_t* const) 4;
int32_t* const last_op1 = (int32_t* const) 512;
int32_t* const last_op2 = (int32_t* const) 516;
int32_t* const last_op_size = (int32_t* const) 520;
int32_t* const last_add_result = (int32_t* const) 524;
int32_t* const last_result = (int32_t* const) 528;
int32_t* const flags_changed = (int32_t* const) 532;
int32_t* const flags = (int32_t* const) 536;
int32_t* const modrm_byte = (int32_t* const) 540;
int32_t* const mul32_result = (int32_t* const) 544; // length 2
bool* const a20_enabled = (bool* const) 552;
int32_t* const instruction_pointer = (int32_t* const) 556;
int32_t* const previous_ip = (int32_t* const) 560;
int32_t* const idtr_size = (int32_t* const) 564;
int32_t* const idtr_offset = (int32_t* const) 568;
int32_t* const gdtr_size = (int32_t* const) 572;
int32_t* const gdtr_offset = (int32_t* const) 576;
int32_t* const cr = (int32_t* const) 580; // length 8
int32_t* const cpl = (int32_t* const) 612;
int32_t* const page_size_extensions = (int32_t* const) 616;
int32_t* const last_virt_eip = (int32_t* const) 620;
int32_t* const eip_phys = (int32_t* const) 624;
int32_t* const last_virt_esp = (int32_t* const) 628;
int32_t* const esp_phys = (int32_t* const) 632;
int32_t* const sysenter_cs = (int32_t* const) 636;
int32_t* const sysenter_esp = (int32_t* const) 640;
int32_t* const sysenter_eip = (int32_t* const) 644;
int32_t* const prefixes = (int32_t* const) 648;
int32_t* const tsc_offset = (int32_t* const) 652;
int32_t* const phys_addr = (int32_t* const) 656;
int32_t* const phys_addr_high = (int32_t* const) 660;
int32_t* const timestamp_counter = (int32_t* const) 664;
uint16_t* const sreg = (uint16_t* const) 668;
int32_t* const dreg = (int32_t* const) 684; // length 8
int32_t* const fw_value = (int32_t* const) 720;
uint8_t* const segment_is_null = (uint8_t* const) 724; // length 8
int32_t* const segment_offsets = (int32_t* const) 736; // length 8
uint32_t* const segment_limits = (uint32_t* const) 768; // length 8
bool* const protected_mode = (bool* const) 800;
bool* const is_32 = (bool* const) 804;
bool* const stack_size_32 = (bool* const) 808;
uint32_t* const memory_size = (uint32_t* const) 812;
int32_t* const stack_empty = (int32_t* const) 816;
bool* const paging = (bool* const) 820;
bool* const mxcsr = (bool* const) 824;
uint8_t* const tlb_info = (uint8_t* const) 2048; // length 0x100000
uint8_t* const tlb_info_global = (uint8_t* const) (2048 + 0x100000); // length 0x100000
int32_t* const tlb_data = (int32_t* const) (2048 + 0x100000 + 0x100000); // length 0x100000*4
uint8_t* const mem8 = (uint8_t* const) (2048 + 0x100000 * 6);
uint16_t* const mem16 = (uint16_t* const) (2048 + 0x100000 * 6);
#endif

3171
src/native/instructions.c Normal file

File diff suppressed because it is too large Load diff

3155
src/native/instructions_0f.c Normal file

File diff suppressed because it is too large Load diff

13
src/native/log.c Normal file
View file

@ -0,0 +1,13 @@
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "const.h"
#include "global_pointers.h"
#define dbg_log(...) { if(DEBUG) { printf(__VA_ARGS__); } }
#define dbg_assert(condition) { if(DEBUG) { assert(condition); } }
#define dbg_assert_message(condition, message) { if(DEBUG && !(condition)) { dbg_log(message); assert(false); } }

112
src/native/memory.c Normal file
View file

@ -0,0 +1,112 @@
#include <stdint.h>
bool in_mapped_range(uint32_t addr)
{
return (addr >= 0xA0000 && addr < 0xC0000) || addr >= *memory_size;
}
int32_t mmap_read8(uint32_t);
int32_t mmap_read16(uint32_t);
int32_t mmap_read32(uint32_t);
void mmap_write8(uint32_t, uint8_t);
void mmap_write16(uint32_t, uint16_t);
void mmap_write32(uint32_t, uint32_t);
int32_t read8(uint32_t addr)
{
if(USE_A20 && *a20_enabled) addr &= A20_MASK;
if(in_mapped_range(addr))
{
return mmap_read8(addr);
}
else
{
return mem8[addr];
}
}
int32_t read16(uint32_t addr)
{
if(USE_A20 && !*a20_enabled) addr &= A20_MASK;
if(in_mapped_range(addr))
{
return mmap_read16(addr);
}
else
{
return *(uint16_t*)(mem8 + addr);
}
}
uint16_t read_aligned16(uint32_t addr)
{
dbg_assert(addr >= 0 && addr < 0x80000000);
if(USE_A20 && !*a20_enabled) addr &= A20_MASK16;
if(in_mapped_range(addr << 1))
{
return mmap_read16(addr << 1);
}
else
{
return mem16[addr];
}
}
int32_t read32s(uint32_t addr)
{
if(USE_A20 && *a20_enabled) addr &= A20_MASK;
if(in_mapped_range(addr))
{
return mmap_read32(addr);
}
else
{
return *(int32_t*)(mem8 + addr);
}
}
void write8(uint32_t addr, uint8_t value)
{
if(USE_A20 && !*a20_enabled) addr &= A20_MASK;
if(in_mapped_range(addr))
{
mmap_write8(addr, value);
}
else
{
mem8[addr] = value;
}
}
void write16(uint32_t addr, uint16_t value)
{
if(USE_A20 && !*a20_enabled) addr &= A20_MASK;
if(in_mapped_range(addr))
{
mmap_write16(addr, value);
}
else
{
*(uint16_t*)(mem8 + addr) = value;
}
}
void write32(uint32_t addr, int32_t value)
{
if(USE_A20 && !*a20_enabled) addr &= A20_MASK;
if(in_mapped_range(addr))
{
mmap_write32(addr, value);
}
else
{
*(int32_t*)(mem8 + addr) = value;
}
}

232
src/native/misc_instr.c Normal file
View file

@ -0,0 +1,232 @@
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "const.h"
#include "global_pointers.h"
static int32_t get_stack_pointer(int32_t);
static void adjust_stack_reg(int32_t);
void branch_taken();
void branch_not_taken();
void writable_or_pagefault(int32_t, int32_t);
int32_t getcf()
{
if(*flags_changed & 1)
{
return (*last_op1 ^ (*last_op1 ^ *last_op2) & (*last_op2 ^ *last_add_result)) >> *last_op_size & 1;
}
else
{
return *flags & 1;
}
}
int32_t getpf()
{
if(*flags_changed & FLAG_PARITY)
{
// inverted lookup table
return 0x9669 << 2 >> ((*last_result ^ *last_result >> 4) & 0xF) & FLAG_PARITY;
}
else
{
return *flags & FLAG_PARITY;
}
}
int32_t getaf()
{
if(*flags_changed & FLAG_ADJUST)
{
return (*last_op1 ^ *last_op2 ^ *last_add_result) & FLAG_ADJUST;
}
else
{
return *flags & FLAG_ADJUST;
}
}
int32_t getzf()
{
if(*flags_changed & FLAG_ZERO)
{
return (~*last_result & *last_result - 1) >> *last_op_size & 1;
}
else
{
return *flags & FLAG_ZERO;
}
}
int32_t getsf()
{
if(*flags_changed & FLAG_SIGN)
{
return *last_result >> *last_op_size & 1;
}
else
{
return *flags & FLAG_SIGN;
}
}
int32_t getof()
{
if(*flags_changed & FLAG_OVERFLOW)
{
return ((*last_op1 ^ *last_add_result) & (*last_op2 ^ *last_add_result)) >> *last_op_size & 1;
}
else
{
return *flags & FLAG_OVERFLOW;
}
}
int32_t test_o() { return getof(); }
int32_t test_b() { return getcf(); }
int32_t test_z() { return getzf(); }
int32_t test_s() { return getsf(); }
int32_t test_p() { return getpf(); }
int32_t test_be() { return getcf() || getzf(); }
int32_t test_l() { return !getsf() != !getof(); }
int32_t test_le() { return getzf() || !getsf() != !getof(); }
void jmp_rel16(int32_t rel16)
{
int32_t cs_offset = get_seg(CS);
// limit ip to 16 bit
*instruction_pointer = cs_offset + ((*instruction_pointer - cs_offset + rel16) & 0xFFFF);
}
void jmpcc8(bool condition)
{
int32_t imm8 = read_imm8s();
if(condition)
{
*instruction_pointer += imm8;
branch_taken();
}
else
{
branch_not_taken();
}
}
void jmpcc16(bool condition)
{
int32_t imm16 = read_imm16();
if(condition)
{
jmp_rel16(imm16);
branch_taken();
}
else
{
branch_not_taken();
}
}
void jmpcc32(bool condition)
{
int32_t op = read_imm32s();
if(condition)
{
*instruction_pointer += op;
branch_taken();
}
else
{
branch_not_taken();
}
}
static int32_t get_stack_pointer(int32_t offset)
{
if(*stack_size_32)
{
return get_seg(SS) + reg32s[ESP] + offset;
}
else
{
return get_seg(SS) + (reg16[SP] + offset & 0xFFFF);
}
}
static void adjust_stack_reg(int32_t adjustment)
{
if(*stack_size_32)
{
reg32s[ESP] += adjustment;
}
else
{
reg16[SP] += adjustment;
}
}
void push16(int32_t imm16)
{
int32_t sp = get_stack_pointer(-2);
safe_write16(sp, imm16);
adjust_stack_reg(-2);
}
void push32(int32_t imm32)
{
int32_t sp = get_stack_pointer(-4);
safe_write32(sp, imm32);
adjust_stack_reg(-4);
}
void pusha16()
{
uint16_t temp = reg16[SP];
// make sure we don't get a pagefault after having
// pushed several registers already
writable_or_pagefault(get_stack_pointer(-16), 16);
push16(reg16[AX]);
push16(reg16[CX]);
push16(reg16[DX]);
push16(reg16[BX]);
push16(temp);
push16(reg16[BP]);
push16(reg16[SI]);
push16(reg16[DI]);
}
void pusha32()
{
int32_t temp = reg32s[ESP];
writable_or_pagefault(get_stack_pointer(-32), 32);
push32(reg32s[EAX]);
push32(reg32s[ECX]);
push32(reg32s[EDX]);
push32(reg32s[EBX]);
push32(temp);
push32(reg32s[EBP]);
push32(reg32s[ESI]);
push32(reg32s[EDI]);
}
int32_t pop32s()
{
int32_t sp = get_stack_pointer(0);
int32_t result = safe_read32s(sp);
adjust_stack_reg(4);
return result;
}

230
src/native/modrm.c Normal file
View file

@ -0,0 +1,230 @@
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "const.h"
#include "global_pointers.h"
// XXX: Remove these declarations when they are implemented in C
static int32_t resolve_sib(bool);
#define ds get_seg_prefix_ds
#define ss get_seg_prefix_ss
#define MODRM_ENTRY(n, offset)\
case (n) | 0 << 3:\
case (n) | 1 << 3:\
case (n) | 2 << 3:\
case (n) | 3 << 3:\
case (n) | 4 << 3:\
case (n) | 5 << 3:\
case (n) | 6 << 3:\
case (n) | 7 << 3:\
return offset;
#define MODRM_ENTRY16(row, seg, value)\
MODRM_ENTRY(0x00 | row, seg(((value) & 0xFFFF)))\
MODRM_ENTRY(0x40 | row, seg(((value) + read_imm8s() & 0xFFFF)))\
MODRM_ENTRY(0x80 | row, seg(((value) + read_imm16() & 0xFFFF)))\
static int32_t resolve_modrm16(int32_t modrm_byte)
{
switch(modrm_byte)
{
MODRM_ENTRY16(0, ds, reg16[BX] + reg16[SI])
MODRM_ENTRY16(1, ds, reg16[BX] + reg16[DI])
MODRM_ENTRY16(2, ss, reg16[BP] + reg16[SI])
MODRM_ENTRY16(3, ss, reg16[BP] + reg16[DI])
MODRM_ENTRY16(4, ds, reg16[SI])
MODRM_ENTRY16(5, ds, reg16[DI])
// special case
MODRM_ENTRY(0x00 | 6, ds(read_imm16()))
MODRM_ENTRY(0x40 | 6, ss(reg16[BP] + read_imm8s() & 0xFFFF))
MODRM_ENTRY(0x80 | 6, ss(reg16[BP] + read_imm16() & 0xFFFF))
MODRM_ENTRY16(7, ds, reg16[BX])
default:
assert(false);
}
return 0;
}
#undef MODRM_ENTRY16
#define MODRM_ENTRY32(row, seg, value)\
MODRM_ENTRY(0x00 | row, seg((value)))\
MODRM_ENTRY(0x40 | row, seg((value) + read_imm8s()))\
MODRM_ENTRY(0x80 | row, seg((value) + read_imm32s()))\
static int32_t resolve_modrm32(int32_t modrm_byte)
{
switch(modrm_byte)
{
MODRM_ENTRY32(0, ds, reg32s[EAX])
MODRM_ENTRY32(1, ds, reg32s[ECX])
MODRM_ENTRY32(2, ds, reg32s[EDX])
MODRM_ENTRY32(3, ds, reg32s[EBX])
// special cases
MODRM_ENTRY(0x00 | 4, resolve_sib(false))
MODRM_ENTRY(0x40 | 4, resolve_sib(true) + read_imm8s())
MODRM_ENTRY(0x80 | 4, resolve_sib(true) + read_imm32s())
MODRM_ENTRY(0x00 | 5, ds(read_imm32s()))
MODRM_ENTRY(0x40 | 5, ss(reg32s[EBP] + read_imm8s()))
MODRM_ENTRY(0x80 | 5, ss(reg32s[EBP] + read_imm32s()))
MODRM_ENTRY32(6, ds, reg32s[ESI])
MODRM_ENTRY32(7, ds, reg32s[EDI])
default:
assert(false);
}
return 0;
}
#undef MODRM_ENTRY32
#undef MODRM_ENTRY
#define SIB_ENTRY_LEVEL3(n, offset)\
case n: return offset;
#define SIB_ENTRY_LEVEL2(n, offset)\
SIB_ENTRY_LEVEL3(n | 0, ds((offset) + reg32s[EAX]))\
SIB_ENTRY_LEVEL3(n | 1, ds((offset) + reg32s[ECX]))\
SIB_ENTRY_LEVEL3(n | 2, ds((offset) + reg32s[EDX]))\
SIB_ENTRY_LEVEL3(n | 3, ds((offset) + reg32s[EBX]))\
SIB_ENTRY_LEVEL3(n | 4, ss((offset) + reg32s[ESP]))\
SIB_ENTRY_LEVEL3(n | 5, (mod ? ss((offset) + reg32s[EBP]) : ds((offset) + read_imm32s())))\
SIB_ENTRY_LEVEL3(n | 6, ds((offset) + reg32s[ESI]))\
SIB_ENTRY_LEVEL3(n | 7, ds((offset) + reg32s[EDI]))
#define SIB_ENTRY_LEVEL1(n, reg1)\
SIB_ENTRY_LEVEL2(0x00 | (n) << 3, (reg1))\
SIB_ENTRY_LEVEL2(0x40 | (n) << 3, (reg1) << 1)\
SIB_ENTRY_LEVEL2(0x80 | (n) << 3, (reg1) << 2)\
SIB_ENTRY_LEVEL2(0xC0 | (n) << 3, (reg1) << 3)
static int32_t resolve_sib_(bool mod)
{
switch(read_imm8())
{
SIB_ENTRY_LEVEL1(0, reg32s[EAX]);
SIB_ENTRY_LEVEL1(1, reg32s[ECX]);
SIB_ENTRY_LEVEL1(2, reg32s[EDX]);
SIB_ENTRY_LEVEL1(3, reg32s[EBX]);
SIB_ENTRY_LEVEL1(4, 0 );
SIB_ENTRY_LEVEL1(5, reg32s[EBP]);
SIB_ENTRY_LEVEL1(6, reg32s[ESI]);
SIB_ENTRY_LEVEL1(7, reg32s[EDI]);
default:
assert(false);
}
return 0;
}
#undef SIB_ENTRY_LEVEL3
#undef SIB_ENTRY_LEVEL2
#undef SIB_ENTRY_LEVEL1
#undef ds
#undef ss
static int32_t resolve_sib(bool mod)
{
uint8_t sib_byte = read_imm8();
uint8_t r = sib_byte & 7;
uint8_t m = sib_byte >> 3 & 7;
int32_t base;
int32_t seg;
if(r == 4)
{
base = reg32s[ESP];
seg = SS;
}
else if(r == 5)
{
if(mod)
{
base = reg32s[EBP];
seg = SS;
}
else
{
base = read_imm32s();
seg = DS;
}
}
else
{
base = reg32s[r];
seg = DS;
}
int32_t offset;
if(m == 4)
{
offset = 0;
}
else
{
uint8_t s = sib_byte >> 6 & 3;
offset = reg32s[m] << s;
}
return get_seg_prefix(seg) + base + offset;
}
static int32_t resolve_modrm32_(int32_t modrm_byte)
{
uint8_t r = modrm_byte & 7;
assert(modrm_byte < 0xC0);
if(r == 4)
{
if(modrm_byte < 0x40)
{
return resolve_sib(false);
}
else
{
return resolve_sib(true) + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s());
}
}
else if(r == 5)
{
if(modrm_byte < 0x40)
{
return get_seg_prefix_ds(read_imm32s());
}
else
{
return get_seg_prefix_ss(reg32s[EBP] + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s()));
}
}
else
{
if(modrm_byte < 0x40)
{
return get_seg_prefix_ds(reg32s[r]);
}
else
{
return get_seg_prefix_ds(reg32s[r] + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s()));
}
}
}

View file

@ -446,6 +446,11 @@ PCI.prototype.pci_write32 = function(address, written)
space[addr >> 2] = 0;
}
}
else if(addr === 0x04)
{
dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) +
" value=" + h(written >>> 0, 8), LOG_PCI);
}
else
{
dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) +

View file

@ -46,9 +46,9 @@ CPU.prototype.movsb = function()
var cpu = this;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var size = cpu.flags[0] & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -57,7 +57,7 @@ CPU.prototype.movsb = function()
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
var phys_dest = cpu.translate_address_write(dest);
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
@ -73,10 +73,10 @@ CPU.prototype.movsb = function()
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -93,9 +93,9 @@ CPU.prototype.movsw = function()
var cpu = this;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
var size = cpu.flags[0] & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -107,7 +107,7 @@ CPU.prototype.movsw = function()
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 1;
var phys_dest = cpu.translate_address_write(dest) >>> 1;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
@ -123,7 +123,7 @@ CPU.prototype.movsw = function()
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -140,7 +140,7 @@ CPU.prototype.movsw = function()
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -156,7 +156,7 @@ CPU.prototype.movsd = function()
{
var cpu = this;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
// often used by memcpy, well worth optimizing
// using cpu.mem32s.set
@ -173,16 +173,16 @@ CPU.prototype.movsd = function()
// must be page-aligned if cpu.paging is enabled
// and dword-aligned in general
var align_mask = cpu.paging ? 0xFFF : 3;
var align_mask = cpu.paging[0] ? 0xFFF : 3;
if((dest & align_mask) === 0 &&
(src & align_mask) === 0 &&
// If df is set, alignment works a different
// This should be unlikely
(cpu.flags & flag_direction) === 0)
(cpu.flags[0] & flag_direction) === 0)
{
var cont = false;
if(cpu.paging)
if(cpu.paging[0])
{
src = cpu.translate_address_read(src);
dest = cpu.translate_address_write(dest);
@ -208,7 +208,7 @@ CPU.prototype.movsd = function()
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
return;
@ -218,9 +218,9 @@ CPU.prototype.movsd = function()
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
var size = cpu.flags[0] & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -232,7 +232,7 @@ CPU.prototype.movsd = function()
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 2;
var phys_dest = cpu.translate_address_write(dest) >>> 2;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
@ -248,7 +248,7 @@ CPU.prototype.movsd = function()
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -265,7 +265,7 @@ CPU.prototype.movsd = function()
}
if(cont)
{
this.instruction_pointer = this.previous_ip;
this.instruction_pointer[0] = this.previous_ip[0];
}
}
else
@ -282,19 +282,19 @@ function cmpsb(cpu)
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -1 : 1;
var size = cpu.flags[0] & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
var phys_dest = cpu.translate_address_read(dest);
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
@ -311,10 +311,10 @@ function cmpsb(cpu)
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -334,22 +334,22 @@ function cmpsw(cpu)
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -2 : 2;
var size = cpu.flags[0] & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1) && !(src & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 1;
var phys_dest = cpu.translate_address_read(dest) >>> 1;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
@ -366,7 +366,7 @@ function cmpsw(cpu)
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -384,7 +384,7 @@ function cmpsw(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -404,22 +404,22 @@ function cmpsd(cpu)
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -4 : 4;
var size = cpu.flags[0] & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3) && !(src & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 2;
var phys_dest = cpu.translate_address_read(dest) >>> 2;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
@ -436,7 +436,7 @@ function cmpsd(cpu)
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -454,7 +454,7 @@ function cmpsd(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -473,9 +473,9 @@ function stosb(cpu)
{
var data = cpu.reg8[reg_al];
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var size = cpu.flags[0] & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -483,7 +483,7 @@ function stosb(cpu)
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_dest = cpu.translate_address_write(dest);
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -497,10 +497,10 @@ function stosb(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -515,9 +515,9 @@ function stosw(cpu)
{
var data = cpu.reg16[reg_ax];
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
var size = cpu.flags[0] & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -528,7 +528,7 @@ function stosw(cpu)
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >>> 1;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -542,7 +542,7 @@ function stosw(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -557,7 +557,7 @@ function stosw(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -572,9 +572,9 @@ function stosd(cpu)
{
var data = cpu.reg32s[reg_eax];
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
var size = cpu.flags[0] & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -585,7 +585,7 @@ function stosd(cpu)
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >>> 2;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -599,7 +599,7 @@ function stosd(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -614,7 +614,7 @@ function stosd(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -628,9 +628,9 @@ function stosd(cpu)
function lodsb(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var size = cpu.flags[0] & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -638,7 +638,7 @@ function lodsb(cpu)
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, src);
}
@ -652,10 +652,10 @@ function lodsb(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -669,9 +669,9 @@ function lodsb(cpu)
function lodsw(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
var size = cpu.flags[0] & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -687,7 +687,7 @@ function lodsw(cpu)
while(cont && cycle_counter--);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -701,9 +701,9 @@ function lodsw(cpu)
function lodsd(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
var size = cpu.flags[0] & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -719,7 +719,7 @@ function lodsd(cpu)
while(cont && cycle_counter--);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -733,20 +733,20 @@ function lodsd(cpu)
function scasb(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var size = cpu.flags[0] & flag_direction ? -1 : 1;
var data_dest;
var data_src = cpu.reg8[reg_al];
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_dest = cpu.translate_address_read(dest);
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -760,10 +760,10 @@ function scasb(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -779,23 +779,23 @@ function scasb(cpu)
function scasw(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
var size = cpu.flags[0] & flag_direction ? -2 : 2;
var data_dest;
var data_src = cpu.reg16[reg_al];
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_read(dest) >>> 1;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -809,7 +809,7 @@ function scasw(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -824,7 +824,7 @@ function scasw(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -840,23 +840,23 @@ function scasw(cpu)
function scasd(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
var size = cpu.flags[0] & flag_direction ? -4 : 4;
var data_dest;
var data_src = cpu.reg32s[reg_eax];
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_read(dest) >>> 2;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -870,7 +870,7 @@ function scasd(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -885,7 +885,7 @@ function scasd(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -904,9 +904,9 @@ function insb(cpu)
cpu.test_privileges_for_io(port, 1);
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var size = cpu.flags[0] & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -914,7 +914,7 @@ function insb(cpu)
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_dest = cpu.translate_address_write(dest);
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -928,10 +928,10 @@ function insb(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -949,9 +949,9 @@ function insw(cpu)
cpu.test_privileges_for_io(port, 2);
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
var size = cpu.flags[0] & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -962,7 +962,7 @@ function insw(cpu)
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >>> 1;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -976,7 +976,7 @@ function insw(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -991,7 +991,7 @@ function insw(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -1009,9 +1009,9 @@ function insd(cpu)
cpu.test_privileges_for_io(port, 4);
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
var size = cpu.flags[0] & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -1022,7 +1022,7 @@ function insd(cpu)
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >>> 2;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, dest);
}
@ -1036,7 +1036,7 @@ function insd(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -1051,7 +1051,7 @@ function insd(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -1069,9 +1069,9 @@ function outsb(cpu)
cpu.test_privileges_for_io(port, 1);
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var size = cpu.flags[0] & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -1079,7 +1079,7 @@ function outsb(cpu)
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, src);
}
@ -1093,10 +1093,10 @@ function outsb(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -1113,9 +1113,9 @@ function outsw(cpu)
cpu.test_privileges_for_io(port, 2);
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
var size = cpu.flags[0] & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -1126,7 +1126,7 @@ function outsw(cpu)
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 1;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, src);
}
@ -1140,7 +1140,7 @@ function outsw(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -1155,7 +1155,7 @@ function outsw(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -1172,9 +1172,9 @@ function outsd(cpu)
cpu.test_privileges_for_io(port, 4);
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
var size = cpu.flags[0] & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
if(cpu.prefixes[0] & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
@ -1185,7 +1185,7 @@ function outsd(cpu)
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 2;
if(cpu.paging)
if(cpu.paging[0])
{
cycle_counter = string_get_cycle_count(size, src);
}
@ -1199,7 +1199,7 @@ function outsd(cpu)
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
cpu.timestamp_counter[0] += start_count - count;
}
else
{
@ -1214,7 +1214,7 @@ function outsd(cpu)
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
cpu.instruction_pointer[0] = cpu.previous_ip[0];
}
}
else
@ -1224,3 +1224,27 @@ function outsd(cpu)
}
cpu.diverged();
}
CPU.prototype.stosb = function() { stosb(this); }
CPU.prototype.stosw = function() { stosw(this); }
CPU.prototype.stosd = function() { stosd(this); }
CPU.prototype.lodsb = function() { lodsb(this); }
CPU.prototype.lodsw = function() { lodsw(this); }
CPU.prototype.lodsd = function() { lodsd(this); }
CPU.prototype.cmpsb = function() { cmpsb(this); }
CPU.prototype.cmpsw = function() { cmpsw(this); }
CPU.prototype.cmpsd = function() { cmpsd(this); }
CPU.prototype.scasb = function() { scasb(this); }
CPU.prototype.scasw = function() { scasw(this); }
CPU.prototype.scasd = function() { scasd(this); }
CPU.prototype.insb = function() { insb(this); }
CPU.prototype.insw = function() { insw(this); }
CPU.prototype.insd = function() { insd(this); }
CPU.prototype.outsb = function() { outsb(this); }
CPU.prototype.outsw = function() { outsw(this); }
CPU.prototype.outsd = function() { outsd(this); }

View file

@ -11,6 +11,8 @@ function VirtIO(cpu, bus, filesystem)
{
// http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf
this.irq = 10;
this.pci_space = [
0xf4, 0x1a, 0x09, 0x10, 0x07, 0x05, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xa8, 0x00, 0x00, 0x00, 0x10, 0xbf, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View file

@ -33,7 +33,7 @@ var emulator = new V86({
emulator.bus.register("emulator-started", function()
{
emulator.v86.cpu.io.register_write_consecutive(0xF4, this,
emulator.v86.cpu.io.register_write_consecutive(0xF4, {},
function(value)
{
console.log("Test exited with code " + value);