@aptre/v86 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. package/src/virtio_net.ts +326 -0
@@ -0,0 +1,701 @@
1
+ // string operations
2
+ //
3
+ // cmp si di
4
+ // movs 0 1 1/w A4
5
+ // cmps 1 1 1/r A6
6
+ // stos 0 0 1/w AA
7
+ // lods 0 1 0 AC
8
+ // scas 1 0 1/r AE
9
+ // ins 0 0 1/w
10
+ // outs 0 1 0
11
+
12
+ use crate::cpu::arith::{cmp16, cmp32, cmp8};
13
+ use crate::cpu::cpu::{
14
+ get_seg, io_port_read16, io_port_read32, io_port_read8, io_port_write16, io_port_write32,
15
+ io_port_write8, read_reg16, read_reg32, safe_read16, safe_read32s, safe_read8, safe_write16,
16
+ safe_write32, safe_write8, set_reg_asize, test_privileges_for_io, translate_address_read,
17
+ translate_address_write_and_can_skip_dirty, writable_or_pagefault, write_reg16, write_reg32,
18
+ write_reg8, AL, AX, DX, EAX, ECX, EDI, ES, ESI, FLAG_DIRECTION,
19
+ };
20
+ use crate::cpu::global_pointers::{flags, instruction_pointer, previous_ip};
21
+ use crate::cpu::memory;
22
+ use crate::jit;
23
+ use crate::page::Page;
24
+
25
+ fn count_until_end_of_page(direction: i32, size: i32, addr: u32) -> u32 {
26
+ (if direction == 1 {
27
+ (0x1000 - (addr & 0xFFF)) / size as u32
28
+ }
29
+ else {
30
+ (addr & 0xFFF) / size as u32 + 1
31
+ }) as u32
32
+ }
33
+
34
+ #[derive(Copy, Clone, PartialEq)]
35
+ enum Instruction {
36
+ Movs,
37
+ Lods,
38
+ Stos,
39
+ Scas,
40
+ Cmps,
41
+ Ins,
42
+ Outs,
43
+ }
44
+ #[derive(PartialEq)]
45
+ enum Size {
46
+ B,
47
+ W,
48
+ D,
49
+ }
50
+ #[derive(Copy, Clone)]
51
+ enum Rep {
52
+ None,
53
+ Z,
54
+ NZ,
55
+ }
56
+
57
+ // We implement all string instructions here and rely on the inliner on doing its job of optimising
58
+ // away anything known at compile time (check with `wasm-dis build/v86.wasm`)
59
+ #[inline(always)]
60
+ unsafe fn string_instruction(
61
+ is_asize_32: bool,
62
+ ds_or_prefix: i32,
63
+ instruction: Instruction,
64
+ size: Size,
65
+ rep: Rep,
66
+ ) {
67
+ let asize_mask = if is_asize_32 { -1 } else { 0xFFFF };
68
+
69
+ let direction = if 0 != *flags & FLAG_DIRECTION { -1 } else { 1 };
70
+
71
+ let mut count = match rep {
72
+ Rep::Z | Rep::NZ => {
73
+ let c = (read_reg32(ECX) & asize_mask) as u32;
74
+ if c == 0 {
75
+ return;
76
+ };
77
+ c
78
+ },
79
+ Rep::None => 0,
80
+ };
81
+
82
+ let es = match instruction {
83
+ Instruction::Movs
84
+ | Instruction::Cmps
85
+ | Instruction::Stos
86
+ | Instruction::Scas
87
+ | Instruction::Ins => return_on_pagefault!(get_seg(ES)),
88
+ _ => 0,
89
+ };
90
+ let ds = match instruction {
91
+ Instruction::Movs
92
+ | Instruction::Cmps
93
+ | Instruction::Lods
94
+ | Instruction::Scas
95
+ | Instruction::Outs => return_on_pagefault!(get_seg(ds_or_prefix)),
96
+ _ => 0,
97
+ };
98
+
99
+ let size_bytes = match size {
100
+ Size::B => 1,
101
+ Size::W => 2,
102
+ Size::D => 4,
103
+ };
104
+ let size_mask = match size {
105
+ Size::B => 0xFF,
106
+ Size::W => 0xFFFF,
107
+ Size::D => -1,
108
+ };
109
+
110
+ let increment = direction * size_bytes;
111
+
112
+ let data = match instruction {
113
+ Instruction::Stos | Instruction::Scas => read_reg32(EAX),
114
+ _ => 0,
115
+ };
116
+
117
+ let mut src = match instruction {
118
+ Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
119
+ read_reg32(ESI) & asize_mask
120
+ },
121
+ _ => 0,
122
+ };
123
+ let mut dst = match instruction {
124
+ Instruction::Movs
125
+ | Instruction::Cmps
126
+ | Instruction::Stos
127
+ | Instruction::Scas
128
+ | Instruction::Ins => read_reg32(EDI) & asize_mask,
129
+ _ => 0,
130
+ };
131
+
132
+ let port = match instruction {
133
+ Instruction::Ins | Instruction::Outs => {
134
+ let port = read_reg16(DX);
135
+ if !test_privileges_for_io(port, size_bytes) {
136
+ return;
137
+ }
138
+ port
139
+ },
140
+ _ => 0,
141
+ };
142
+
143
+ let is_aligned = (ds + src) & (size_bytes - 1) == 0 && (es + dst) & (size_bytes - 1) == 0;
144
+
145
+ // unaligned movs is properly handled in the fast path
146
+ let mut rep_fast = (instruction == Instruction::Movs || is_aligned)
147
+ && is_asize_32 // 16-bit address wraparound
148
+ && match rep {
149
+ Rep::NZ | Rep::Z => true,
150
+ Rep::None => false,
151
+ };
152
+
153
+ let mut phys_dst = 0;
154
+ let mut phys_src = 0;
155
+ let mut skip_dirty_page = false;
156
+
157
+ let mut movs_into_svga_lfb = false;
158
+ let mut movs_reenter_fast_path = false;
159
+
160
+ let count_until_end_of_page = if rep_fast {
161
+ match instruction {
162
+ Instruction::Movs => {
163
+ let (addr, skip) =
164
+ return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst));
165
+ movs_into_svga_lfb = memory::in_svga_lfb(addr);
166
+ rep_fast = rep_fast && (!memory::in_mapped_range(addr) || movs_into_svga_lfb);
167
+ phys_dst = addr;
168
+ skip_dirty_page = skip;
169
+ },
170
+ Instruction::Stos | Instruction::Ins => {
171
+ let (addr, skip) =
172
+ return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst));
173
+ rep_fast = rep_fast && !memory::in_mapped_range(addr);
174
+ phys_dst = addr;
175
+ skip_dirty_page = skip;
176
+ },
177
+ Instruction::Cmps | Instruction::Scas => {
178
+ let addr = return_on_pagefault!(translate_address_read(es + dst));
179
+ rep_fast = rep_fast && !memory::in_mapped_range(addr);
180
+ phys_dst = addr;
181
+ skip_dirty_page = true;
182
+ },
183
+ _ => {},
184
+ };
185
+
186
+ match instruction {
187
+ Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
188
+ let addr = return_on_pagefault!(translate_address_read(ds + src));
189
+ rep_fast = rep_fast && !memory::in_mapped_range(addr);
190
+ phys_src = addr;
191
+ },
192
+ _ => {},
193
+ };
194
+
195
+ let count_until_end_of_page = u32::min(
196
+ count,
197
+ match instruction {
198
+ Instruction::Movs | Instruction::Cmps => u32::min(
199
+ count_until_end_of_page(direction, size_bytes, phys_src),
200
+ count_until_end_of_page(direction, size_bytes, phys_dst),
201
+ ),
202
+ Instruction::Stos | Instruction::Ins | Instruction::Scas => {
203
+ count_until_end_of_page(direction, size_bytes, phys_dst)
204
+ },
205
+ Instruction::Lods | Instruction::Outs => {
206
+ count_until_end_of_page(direction, size_bytes, phys_src)
207
+ },
208
+ },
209
+ );
210
+
211
+ match instruction {
212
+ Instruction::Movs => {
213
+ let c = count_until_end_of_page * size_bytes as u32;
214
+
215
+ let overlap_interferes = if phys_src < phys_dst {
216
+ // backward moves may overlap at the front of the destination string
217
+ phys_dst - phys_src < c && direction == 1
218
+ }
219
+ else if phys_src > phys_dst {
220
+ // forward moves may overlap at the front of the source string
221
+ phys_src - phys_dst < c && direction == -1
222
+ }
223
+ else {
224
+ false
225
+ };
226
+ rep_fast = rep_fast && !overlap_interferes;
227
+
228
+ // In case the following page-boundary check fails, re-enter instruction after
229
+ // one iteration of the slow path
230
+ movs_reenter_fast_path = rep_fast;
231
+ rep_fast = rep_fast
232
+ && (phys_src & 0xFFF <= 0x1000 - size_bytes as u32)
233
+ && (phys_dst & 0xFFF <= 0x1000 - size_bytes as u32);
234
+ },
235
+ _ => {},
236
+ }
237
+
238
+ count_until_end_of_page
239
+ }
240
+ else {
241
+ 0 // not used
242
+ };
243
+
244
+ if rep_fast {
245
+ dbg_assert!(count_until_end_of_page > 0);
246
+
247
+ if !skip_dirty_page {
248
+ jit::jit_dirty_page(Page::page_of(phys_dst));
249
+ }
250
+
251
+ let mut rep_cmp_finished = false;
252
+
253
+ let mut i = 0;
254
+ while i < count_until_end_of_page {
255
+ i += 1;
256
+
257
+ let src_val = match instruction {
258
+ Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
259
+ match size {
260
+ Size::B => memory::read8_no_mmap_check(phys_src),
261
+ Size::W => memory::read16_no_mmap_check(phys_src),
262
+ Size::D => memory::read32_no_mmap_check(phys_src),
263
+ }
264
+ },
265
+ Instruction::Scas | Instruction::Stos => data & size_mask,
266
+ Instruction::Ins => match size {
267
+ Size::B => io_port_read8(port),
268
+ Size::W => io_port_read16(port),
269
+ Size::D => io_port_read32(port),
270
+ },
271
+ };
272
+
273
+ let mut dst_val = 0;
274
+
275
+ match instruction {
276
+ Instruction::Cmps | Instruction::Scas => match size {
277
+ Size::B => dst_val = memory::read8_no_mmap_check(phys_dst),
278
+ Size::W => dst_val = memory::read16_no_mmap_check(phys_dst),
279
+ Size::D => dst_val = memory::read32_no_mmap_check(phys_dst),
280
+ },
281
+ Instruction::Outs => match size {
282
+ Size::B => io_port_write8(port, src_val),
283
+ Size::W => io_port_write16(port, src_val),
284
+ Size::D => io_port_write32(port, src_val),
285
+ },
286
+ Instruction::Lods => match size {
287
+ Size::B => write_reg8(AL, src_val),
288
+ Size::W => write_reg16(AX, src_val),
289
+ Size::D => write_reg32(EAX, src_val),
290
+ },
291
+ Instruction::Ins => match size {
292
+ Size::B => memory::write8_no_mmap_or_dirty_check(phys_dst, src_val),
293
+ Size::W => memory::write16_no_mmap_or_dirty_check(phys_dst, src_val),
294
+ Size::D => memory::write32_no_mmap_or_dirty_check(phys_dst, src_val),
295
+ },
296
+ Instruction::Movs => {
297
+ if direction == -1 {
298
+ phys_src -= (count_until_end_of_page - 1) * size_bytes as u32;
299
+ phys_dst -= (count_until_end_of_page - 1) * size_bytes as u32;
300
+ }
301
+ if movs_into_svga_lfb {
302
+ memory::memcpy_into_svga_lfb(
303
+ phys_src,
304
+ phys_dst,
305
+ count_until_end_of_page * size_bytes as u32,
306
+ );
307
+ }
308
+ else {
309
+ memory::memcpy_no_mmap_or_dirty_check(
310
+ phys_src,
311
+ phys_dst,
312
+ count_until_end_of_page * size_bytes as u32,
313
+ );
314
+ }
315
+ i = count_until_end_of_page;
316
+ break;
317
+ },
318
+ Instruction::Stos => match size {
319
+ Size::B => {
320
+ if direction == -1 {
321
+ phys_dst -= count_until_end_of_page - 1
322
+ }
323
+ memory::memset_no_mmap_or_dirty_check(
324
+ phys_dst,
325
+ src_val as u8,
326
+ count_until_end_of_page,
327
+ );
328
+ i = count_until_end_of_page;
329
+ break;
330
+ },
331
+ Size::W => memory::write16_no_mmap_or_dirty_check(phys_dst, src_val),
332
+ Size::D => memory::write32_no_mmap_or_dirty_check(phys_dst, src_val),
333
+ },
334
+ };
335
+
336
+ match instruction {
337
+ Instruction::Movs
338
+ | Instruction::Cmps
339
+ | Instruction::Stos
340
+ | Instruction::Scas
341
+ | Instruction::Ins => {
342
+ phys_dst += increment as u32;
343
+ },
344
+ _ => {},
345
+ }
346
+ match instruction {
347
+ Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
348
+ phys_src += increment as u32;
349
+ },
350
+ _ => {},
351
+ };
352
+
353
+ match instruction {
354
+ Instruction::Scas | Instruction::Cmps => {
355
+ let rep_cmp = match rep {
356
+ Rep::Z => src_val == dst_val,
357
+ Rep::NZ => src_val != dst_val,
358
+ Rep::None => {
359
+ dbg_assert!(false);
360
+ true
361
+ },
362
+ };
363
+ if !rep_cmp || count == i {
364
+ match size {
365
+ Size::B => cmp8(src_val, dst_val),
366
+ Size::W => cmp16(src_val, dst_val),
367
+ Size::D => cmp32(src_val, dst_val),
368
+ };
369
+ rep_cmp_finished = true;
370
+ break;
371
+ }
372
+ },
373
+ _ => {},
374
+ }
375
+ }
376
+
377
+ dbg_assert!(i <= count);
378
+ count -= i;
379
+
380
+ if !rep_cmp_finished && count != 0 {
381
+ // go back to the current instruction, since this loop just handles a single page
382
+ *instruction_pointer = *previous_ip;
383
+ }
384
+
385
+ src += i as i32 * increment;
386
+ dst += i as i32 * increment;
387
+ }
388
+ else {
389
+ loop {
390
+ match instruction {
391
+ Instruction::Ins => {
392
+ // check fault *before* reading from port
393
+ // (technically not necessary according to Intel manuals)
394
+ break_on_pagefault!(writable_or_pagefault(es + dst, size_bytes));
395
+ },
396
+ _ => {},
397
+ };
398
+ let src_val = match instruction {
399
+ Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
400
+ break_on_pagefault!(match size {
401
+ Size::B => safe_read8(ds + src),
402
+ Size::W => safe_read16(ds + src),
403
+ Size::D => safe_read32s(ds + src),
404
+ })
405
+ },
406
+ Instruction::Scas | Instruction::Stos => data & size_mask,
407
+ Instruction::Ins => match size {
408
+ Size::B => io_port_read8(port),
409
+ Size::W => io_port_read16(port),
410
+ Size::D => io_port_read32(port),
411
+ },
412
+ };
413
+
414
+ let mut dst_val = 0;
415
+
416
+ match instruction {
417
+ Instruction::Cmps | Instruction::Scas => match size {
418
+ Size::B => dst_val = break_on_pagefault!(safe_read8(es + dst)),
419
+ Size::W => dst_val = break_on_pagefault!(safe_read16(es + dst)),
420
+ Size::D => dst_val = break_on_pagefault!(safe_read32s(es + dst)),
421
+ },
422
+ Instruction::Outs => match size {
423
+ Size::B => io_port_write8(port, src_val),
424
+ Size::W => io_port_write16(port, src_val),
425
+ Size::D => io_port_write32(port, src_val),
426
+ },
427
+ Instruction::Lods => match size {
428
+ Size::B => write_reg8(AL, src_val),
429
+ Size::W => write_reg16(AX, src_val),
430
+ Size::D => write_reg32(EAX, src_val),
431
+ },
432
+ Instruction::Movs | Instruction::Stos | Instruction::Ins => match size {
433
+ Size::B => break_on_pagefault!(safe_write8(es + dst, src_val)),
434
+ Size::W => break_on_pagefault!(safe_write16(es + dst, src_val)),
435
+ Size::D => break_on_pagefault!(safe_write32(es + dst, src_val)),
436
+ },
437
+ };
438
+
439
+ match instruction {
440
+ Instruction::Movs
441
+ | Instruction::Cmps
442
+ | Instruction::Stos
443
+ | Instruction::Scas
444
+ | Instruction::Ins => dst = dst + increment & asize_mask,
445
+ _ => {},
446
+ }
447
+ match instruction {
448
+ Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
449
+ src = src + increment & asize_mask
450
+ },
451
+ _ => {},
452
+ };
453
+
454
+ count -= 1;
455
+
456
+ let finished = match rep {
457
+ Rep::Z | Rep::NZ => match (rep, instruction) {
458
+ (Rep::Z, Instruction::Cmps) => src_val != dst_val || count == 0,
459
+ (Rep::Z, Instruction::Scas) => src_val != dst_val || count == 0,
460
+ (Rep::NZ, Instruction::Cmps) => src_val == dst_val || count == 0,
461
+ (Rep::NZ, Instruction::Scas) => src_val == dst_val || count == 0,
462
+ (Rep::NZ | Rep::Z, Instruction::Movs) => {
463
+ if count == 0 {
464
+ true
465
+ }
466
+ else if movs_reenter_fast_path {
467
+ *instruction_pointer = *previous_ip;
468
+ true
469
+ }
470
+ else {
471
+ false
472
+ }
473
+ },
474
+ _ => count == 0,
475
+ },
476
+ Rep::None => true,
477
+ };
478
+
479
+ if finished {
480
+ match instruction {
481
+ Instruction::Scas | Instruction::Cmps => match size {
482
+ Size::B => cmp8(src_val, dst_val),
483
+ Size::W => cmp16(src_val, dst_val),
484
+ Size::D => cmp32(src_val, dst_val),
485
+ },
486
+ _ => {},
487
+ }
488
+ break;
489
+ }
490
+ }
491
+ }
492
+
493
+ match instruction {
494
+ Instruction::Movs
495
+ | Instruction::Cmps
496
+ | Instruction::Stos
497
+ | Instruction::Scas
498
+ | Instruction::Ins => set_reg_asize(is_asize_32, EDI, dst),
499
+ _ => {},
500
+ }
501
+ match instruction {
502
+ Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
503
+ set_reg_asize(is_asize_32, ESI, src)
504
+ },
505
+ _ => {},
506
+ };
507
+
508
+ match rep {
509
+ Rep::Z | Rep::NZ => {
510
+ set_reg_asize(is_asize_32, ECX, count as i32);
511
+ },
512
+ Rep::None => {},
513
+ }
514
+ }
515
+
516
+ #[no_mangle]
517
+ pub unsafe fn movsb_rep(is_asize_32: bool, seg: i32) {
518
+ string_instruction(is_asize_32, seg, Instruction::Movs, Size::B, Rep::Z)
519
+ }
520
+ #[no_mangle]
521
+ pub unsafe fn movsw_rep(is_asize_32: bool, seg: i32) {
522
+ string_instruction(is_asize_32, seg, Instruction::Movs, Size::W, Rep::Z)
523
+ }
524
+ #[no_mangle]
525
+ pub unsafe fn movsd_rep(is_asize_32: bool, seg: i32) {
526
+ string_instruction(is_asize_32, seg, Instruction::Movs, Size::D, Rep::Z)
527
+ }
528
+ pub unsafe fn movsb_no_rep(is_asize_32: bool, seg: i32) {
529
+ string_instruction(is_asize_32, seg, Instruction::Movs, Size::B, Rep::None)
530
+ }
531
+ pub unsafe fn movsw_no_rep(is_asize_32: bool, seg: i32) {
532
+ string_instruction(is_asize_32, seg, Instruction::Movs, Size::W, Rep::None)
533
+ }
534
+ pub unsafe fn movsd_no_rep(is_asize_32: bool, seg: i32) {
535
+ string_instruction(is_asize_32, seg, Instruction::Movs, Size::D, Rep::None)
536
+ }
537
+
538
+ #[no_mangle]
539
+ pub unsafe fn lodsb_rep(is_asize_32: bool, seg: i32) {
540
+ string_instruction(is_asize_32, seg, Instruction::Lods, Size::B, Rep::Z)
541
+ }
542
+ #[no_mangle]
543
+ pub unsafe fn lodsw_rep(is_asize_32: bool, seg: i32) {
544
+ string_instruction(is_asize_32, seg, Instruction::Lods, Size::W, Rep::Z)
545
+ }
546
+ #[no_mangle]
547
+ pub unsafe fn lodsd_rep(is_asize_32: bool, seg: i32) {
548
+ string_instruction(is_asize_32, seg, Instruction::Lods, Size::D, Rep::Z)
549
+ }
550
+ pub unsafe fn lodsb_no_rep(is_asize_32: bool, seg: i32) {
551
+ string_instruction(is_asize_32, seg, Instruction::Lods, Size::B, Rep::None)
552
+ }
553
+ pub unsafe fn lodsw_no_rep(is_asize_32: bool, seg: i32) {
554
+ string_instruction(is_asize_32, seg, Instruction::Lods, Size::W, Rep::None)
555
+ }
556
+ pub unsafe fn lodsd_no_rep(is_asize_32: bool, seg: i32) {
557
+ string_instruction(is_asize_32, seg, Instruction::Lods, Size::D, Rep::None)
558
+ }
559
+
560
+ #[no_mangle]
561
+ pub unsafe fn stosb_rep(is_asize_32: bool) {
562
+ string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::Z)
563
+ }
564
+ #[no_mangle]
565
+ pub unsafe fn stosw_rep(is_asize_32: bool) {
566
+ string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::Z)
567
+ }
568
+ #[no_mangle]
569
+ pub unsafe fn stosd_rep(is_asize_32: bool) {
570
+ string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::Z)
571
+ }
572
+ pub unsafe fn stosb_no_rep(is_asize_32: bool) {
573
+ string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::None)
574
+ }
575
+ pub unsafe fn stosw_no_rep(is_asize_32: bool) {
576
+ string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::None)
577
+ }
578
+ pub unsafe fn stosd_no_rep(is_asize_32: bool) {
579
+ string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::None)
580
+ }
581
+
582
+ #[no_mangle]
583
+ pub unsafe fn cmpsb_repz(is_asize_32: bool, seg: i32) {
584
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::B, Rep::Z)
585
+ }
586
+ #[no_mangle]
587
+ pub unsafe fn cmpsw_repz(is_asize_32: bool, seg: i32) {
588
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::W, Rep::Z)
589
+ }
590
+ #[no_mangle]
591
+ pub unsafe fn cmpsd_repz(is_asize_32: bool, seg: i32) {
592
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::D, Rep::Z)
593
+ }
594
+ #[no_mangle]
595
+ pub unsafe fn cmpsb_repnz(is_asize_32: bool, seg: i32) {
596
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::B, Rep::NZ)
597
+ }
598
+ #[no_mangle]
599
+ pub unsafe fn cmpsw_repnz(is_asize_32: bool, seg: i32) {
600
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::W, Rep::NZ)
601
+ }
602
+ #[no_mangle]
603
+ pub unsafe fn cmpsd_repnz(is_asize_32: bool, seg: i32) {
604
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::D, Rep::NZ)
605
+ }
606
+ #[no_mangle]
607
+ pub unsafe fn cmpsb_no_rep(is_asize_32: bool, seg: i32) {
608
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::B, Rep::None)
609
+ }
610
+ #[no_mangle]
611
+ pub unsafe fn cmpsw_no_rep(is_asize_32: bool, seg: i32) {
612
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::W, Rep::None)
613
+ }
614
+ #[no_mangle]
615
+ pub unsafe fn cmpsd_no_rep(is_asize_32: bool, seg: i32) {
616
+ string_instruction(is_asize_32, seg, Instruction::Cmps, Size::D, Rep::None)
617
+ }
618
+
619
+ #[no_mangle]
620
+ pub unsafe fn scasb_repz(is_asize_32: bool) {
621
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::Z)
622
+ }
623
+ #[no_mangle]
624
+ pub unsafe fn scasw_repz(is_asize_32: bool) {
625
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::Z)
626
+ }
627
+ #[no_mangle]
628
+ pub unsafe fn scasd_repz(is_asize_32: bool) {
629
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::Z)
630
+ }
631
+ #[no_mangle]
632
+ pub unsafe fn scasb_repnz(is_asize_32: bool) {
633
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::NZ)
634
+ }
635
+ #[no_mangle]
636
+ pub unsafe fn scasw_repnz(is_asize_32: bool) {
637
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::NZ)
638
+ }
639
+ #[no_mangle]
640
+ pub unsafe fn scasd_repnz(is_asize_32: bool) {
641
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::NZ)
642
+ }
643
+ pub unsafe fn scasb_no_rep(is_asize_32: bool) {
644
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::None)
645
+ }
646
+ pub unsafe fn scasw_no_rep(is_asize_32: bool) {
647
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::None)
648
+ }
649
+ pub unsafe fn scasd_no_rep(is_asize_32: bool) {
650
+ string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::None)
651
+ }
652
+
653
+ #[no_mangle]
654
+ pub unsafe fn outsb_rep(is_asize_32: bool, seg: i32) {
655
+ string_instruction(is_asize_32, seg, Instruction::Outs, Size::B, Rep::Z)
656
+ }
657
+ #[no_mangle]
658
+ pub unsafe fn outsw_rep(is_asize_32: bool, seg: i32) {
659
+ string_instruction(is_asize_32, seg, Instruction::Outs, Size::W, Rep::Z)
660
+ }
661
+ #[no_mangle]
662
+ pub unsafe fn outsd_rep(is_asize_32: bool, seg: i32) {
663
+ string_instruction(is_asize_32, seg, Instruction::Outs, Size::D, Rep::Z)
664
+ }
665
+ #[no_mangle]
666
+ pub unsafe fn outsb_no_rep(is_asize_32: bool, seg: i32) {
667
+ string_instruction(is_asize_32, seg, Instruction::Outs, Size::B, Rep::None)
668
+ }
669
+ #[no_mangle]
670
+ pub unsafe fn outsw_no_rep(is_asize_32: bool, seg: i32) {
671
+ string_instruction(is_asize_32, seg, Instruction::Outs, Size::W, Rep::None)
672
+ }
673
+ #[no_mangle]
674
+ pub unsafe fn outsd_no_rep(is_asize_32: bool, seg: i32) {
675
+ string_instruction(is_asize_32, seg, Instruction::Outs, Size::D, Rep::None)
676
+ }
677
+
678
+ #[no_mangle]
679
+ pub unsafe fn insb_rep(is_asize_32: bool) {
680
+ string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::Z)
681
+ }
682
+ #[no_mangle]
683
+ pub unsafe fn insw_rep(is_asize_32: bool) {
684
+ string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::Z)
685
+ }
686
+ #[no_mangle]
687
+ pub unsafe fn insd_rep(is_asize_32: bool) {
688
+ string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::Z)
689
+ }
690
+ #[no_mangle]
691
+ pub unsafe fn insb_no_rep(is_asize_32: bool) {
692
+ string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::None)
693
+ }
694
+ #[no_mangle]
695
+ pub unsafe fn insw_no_rep(is_asize_32: bool) {
696
+ string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::None)
697
+ }
698
+ #[no_mangle]
699
+ pub unsafe fn insd_no_rep(is_asize_32: bool) {
700
+ string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::None)
701
+ }