string.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  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. use cpu::arith::{cmp8, cmp16, cmp32};
  12. use cpu::cpu::{
  13. get_seg, io_port_read8, io_port_read16, io_port_read32, io_port_write8, io_port_write16,
  14. io_port_write32, read_reg16, read_reg32, safe_read8, safe_read16, safe_read32s, safe_write8,
  15. safe_write16, safe_write32, set_reg_asize, test_privileges_for_io, translate_address_read,
  16. translate_address_write_and_can_skip_dirty, writable_or_pagefault, write_reg8, write_reg16,
  17. write_reg32, AL, AX, DX, EAX, ECX, EDI, ES, ESI, FLAG_DIRECTION,
  18. };
  19. use cpu::global_pointers::{flags, instruction_pointer, previous_ip};
  20. use cpu::memory::{
  21. in_mapped_range, in_svga_lfb, memcpy_into_svga_lfb, memcpy_no_mmap_or_dirty_check,
  22. memset_no_mmap_or_dirty_check, read8_no_mmap_check, read16_no_mmap_check, read32_no_mmap_check,
  23. write8_no_mmap_or_dirty_check, write16_no_mmap_or_dirty_check, write32_no_mmap_or_dirty_check,
  24. };
  25. use page::Page;
  26. fn count_until_end_of_page(direction: i32, size: i32, addr: u32) -> u32 {
  27. (if direction == 1 {
  28. (0x1000 - (addr & 0xFFF)) / size as u32
  29. }
  30. else {
  31. (addr & 0xFFF) / size as u32 + 1
  32. }) as u32
  33. }
  34. #[derive(Copy, Clone)]
  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. // We implement all string instructions here and rely on the inliner on doing its job of optimising
  57. // away anything known at compile time (check with `wasm-dis build/v86.wasm`)
  58. #[inline(always)]
  59. unsafe fn string_instruction(
  60. is_asize_32: bool,
  61. ds: i32,
  62. instruction: Instruction,
  63. size: Size,
  64. rep: Rep,
  65. ) {
  66. let asize_mask = if is_asize_32 { -1 } else { 0xFFFF };
  67. let direction = if 0 != *flags & FLAG_DIRECTION { -1 } else { 1 };
  68. let es = match instruction {
  69. Instruction::Movs
  70. | Instruction::Cmps
  71. | Instruction::Stos
  72. | Instruction::Scas
  73. | Instruction::Ins => return_on_pagefault!(get_seg(ES)),
  74. _ => 0,
  75. };
  76. let size_bytes = match size {
  77. Size::B => 1,
  78. Size::W => 2,
  79. Size::D => 4,
  80. };
  81. let size_mask = match size {
  82. Size::B => 0xFF,
  83. Size::W => 0xFFFF,
  84. Size::D => -1,
  85. };
  86. let increment = direction * size_bytes;
  87. let data = match instruction {
  88. Instruction::Stos | Instruction::Scas => read_reg32(EAX),
  89. _ => 0,
  90. };
  91. let mut src = match instruction {
  92. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  93. read_reg32(ESI) & asize_mask
  94. },
  95. _ => 0,
  96. };
  97. let mut dst = match instruction {
  98. Instruction::Movs
  99. | Instruction::Cmps
  100. | Instruction::Stos
  101. | Instruction::Scas
  102. | Instruction::Ins => read_reg32(EDI) & asize_mask,
  103. _ => 0,
  104. };
  105. let mut count = match rep {
  106. Rep::Z | Rep::NZ => {
  107. let c = (read_reg32(ECX) & asize_mask) as u32;
  108. if c == 0 {
  109. return;
  110. };
  111. c
  112. },
  113. Rep::None => 0,
  114. };
  115. let port = match instruction {
  116. Instruction::Ins | Instruction::Outs => {
  117. let port = read_reg16(DX);
  118. if !test_privileges_for_io(port, size_bytes) {
  119. return;
  120. }
  121. port
  122. },
  123. _ => 0,
  124. };
  125. let is_aligned = (ds + src) & (size_bytes - 1) == 0 && (es + dst) & (size_bytes - 1) == 0;
  126. let mut rep_fast = is_aligned
  127. && is_asize_32 // 16-bit address wraparound
  128. && match rep {
  129. Rep::NZ | Rep::Z => true,
  130. Rep::None => false,
  131. };
  132. let mut phys_dst = 0;
  133. let mut phys_src = 0;
  134. let mut skip_dirty_page = false;
  135. let mut movs_into_svga_lfb = false;
  136. if rep_fast {
  137. match instruction {
  138. Instruction::Movs => {
  139. let (addr, skip) =
  140. return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst));
  141. movs_into_svga_lfb = in_svga_lfb(addr);
  142. rep_fast = rep_fast && (!in_mapped_range(addr) || movs_into_svga_lfb);
  143. phys_dst = addr;
  144. skip_dirty_page = skip;
  145. },
  146. Instruction::Stos | Instruction::Ins => {
  147. let (addr, skip) =
  148. return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst));
  149. rep_fast = rep_fast && !in_mapped_range(addr);
  150. phys_dst = addr;
  151. skip_dirty_page = skip;
  152. },
  153. Instruction::Cmps | Instruction::Scas => {
  154. let addr = return_on_pagefault!(translate_address_read(es + dst));
  155. rep_fast = rep_fast && !in_mapped_range(addr);
  156. phys_dst = addr;
  157. skip_dirty_page = true;
  158. },
  159. _ => {},
  160. };
  161. match instruction {
  162. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  163. let addr = return_on_pagefault!(translate_address_read(ds + src));
  164. rep_fast = rep_fast && !in_mapped_range(addr);
  165. phys_src = addr;
  166. },
  167. _ => {},
  168. };
  169. match instruction {
  170. Instruction::Movs => {
  171. // note: This check is also valid for both direction == 1 and direction == -1
  172. let overlap = u32::max(phys_src, phys_dst) - u32::min(phys_src, phys_dst)
  173. < count * size_bytes as u32;
  174. rep_fast = rep_fast && !overlap;
  175. },
  176. _ => {},
  177. }
  178. }
  179. if rep_fast {
  180. let count_until_end_of_page = u32::min(
  181. count,
  182. match instruction {
  183. Instruction::Movs | Instruction::Cmps => u32::min(
  184. count_until_end_of_page(direction, size_bytes, phys_src),
  185. count_until_end_of_page(direction, size_bytes, phys_dst),
  186. ),
  187. Instruction::Stos | Instruction::Ins | Instruction::Scas => {
  188. count_until_end_of_page(direction, size_bytes, phys_dst)
  189. },
  190. Instruction::Lods | Instruction::Outs => {
  191. count_until_end_of_page(direction, size_bytes, phys_src)
  192. },
  193. },
  194. );
  195. dbg_assert!(count_until_end_of_page > 0);
  196. if !skip_dirty_page {
  197. ::jit::jit_dirty_page(::jit::get_jit_state(), Page::page_of(phys_dst));
  198. }
  199. let mut rep_cmp_finished = false;
  200. let mut i = 0;
  201. while i < count_until_end_of_page {
  202. i += 1;
  203. let src_val = match instruction {
  204. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  205. match size {
  206. Size::B => read8_no_mmap_check(phys_src),
  207. Size::W => read16_no_mmap_check(phys_src),
  208. Size::D => read32_no_mmap_check(phys_src),
  209. }
  210. },
  211. Instruction::Scas | Instruction::Stos => data & size_mask,
  212. Instruction::Ins => match size {
  213. Size::B => io_port_read8(port),
  214. Size::W => io_port_read16(port),
  215. Size::D => io_port_read32(port),
  216. },
  217. };
  218. let mut dst_val = 0;
  219. match instruction {
  220. Instruction::Cmps | Instruction::Scas => match size {
  221. Size::B => dst_val = read8_no_mmap_check(phys_dst),
  222. Size::W => dst_val = read16_no_mmap_check(phys_dst),
  223. Size::D => dst_val = read32_no_mmap_check(phys_dst),
  224. },
  225. Instruction::Outs => match size {
  226. Size::B => io_port_write8(port, src_val),
  227. Size::W => io_port_write16(port, src_val),
  228. Size::D => io_port_write32(port, src_val),
  229. },
  230. Instruction::Lods => match size {
  231. Size::B => write_reg8(AL, src_val),
  232. Size::W => write_reg16(AX, src_val),
  233. Size::D => write_reg32(EAX, src_val),
  234. },
  235. Instruction::Ins => match size {
  236. Size::B => write8_no_mmap_or_dirty_check(phys_dst, src_val),
  237. Size::W => write16_no_mmap_or_dirty_check(phys_dst, src_val),
  238. Size::D => write32_no_mmap_or_dirty_check(phys_dst, src_val),
  239. },
  240. Instruction::Movs => {
  241. if direction == -1 {
  242. phys_src -= (count_until_end_of_page - 1) * size_bytes as u32;
  243. phys_dst -= (count_until_end_of_page - 1) * size_bytes as u32;
  244. }
  245. if movs_into_svga_lfb {
  246. ::cpu::vga::mark_dirty(phys_dst);
  247. memcpy_into_svga_lfb(
  248. phys_src,
  249. phys_dst,
  250. count_until_end_of_page * size_bytes as u32,
  251. );
  252. }
  253. else {
  254. memcpy_no_mmap_or_dirty_check(
  255. phys_src,
  256. phys_dst,
  257. count_until_end_of_page * size_bytes as u32,
  258. );
  259. }
  260. i = count_until_end_of_page;
  261. break;
  262. },
  263. Instruction::Stos => match size {
  264. Size::B => {
  265. if direction == -1 {
  266. phys_dst -= count_until_end_of_page - 1
  267. }
  268. memset_no_mmap_or_dirty_check(
  269. phys_dst,
  270. src_val as u8,
  271. count_until_end_of_page,
  272. );
  273. i = count_until_end_of_page;
  274. break;
  275. },
  276. Size::W => write16_no_mmap_or_dirty_check(phys_dst, src_val),
  277. Size::D => write32_no_mmap_or_dirty_check(phys_dst, src_val),
  278. },
  279. };
  280. match instruction {
  281. Instruction::Movs
  282. | Instruction::Cmps
  283. | Instruction::Stos
  284. | Instruction::Scas
  285. | Instruction::Ins => {
  286. phys_dst += increment as u32;
  287. },
  288. _ => {},
  289. }
  290. match instruction {
  291. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  292. phys_src += increment as u32;
  293. },
  294. _ => {},
  295. };
  296. match instruction {
  297. Instruction::Scas | Instruction::Cmps => {
  298. let rep_cmp = match rep {
  299. Rep::Z => src_val == dst_val,
  300. Rep::NZ => src_val != dst_val,
  301. Rep::None => {
  302. dbg_assert!(false);
  303. true
  304. },
  305. };
  306. if !rep_cmp || count == i {
  307. match size {
  308. Size::B => cmp8(src_val, dst_val),
  309. Size::W => cmp16(src_val, dst_val),
  310. Size::D => cmp32(src_val, dst_val),
  311. };
  312. rep_cmp_finished = true;
  313. break;
  314. }
  315. },
  316. _ => {},
  317. }
  318. }
  319. dbg_assert!(i <= count);
  320. count -= i;
  321. if !rep_cmp_finished && count != 0 {
  322. // go back to the current instruction, since this loop just handles a single page
  323. *instruction_pointer = *previous_ip;
  324. }
  325. src += i as i32 * increment;
  326. dst += i as i32 * increment;
  327. }
  328. else {
  329. loop {
  330. match instruction {
  331. Instruction::Ins => {
  332. // check fault *before* reading from port
  333. // (technically not necessary according to Intel manuals)
  334. break_on_pagefault!(writable_or_pagefault(es + dst, size_bytes));
  335. },
  336. _ => {},
  337. };
  338. let src_val = match instruction {
  339. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  340. break_on_pagefault!(match size {
  341. Size::B => safe_read8(ds + src),
  342. Size::W => safe_read16(ds + src),
  343. Size::D => safe_read32s(ds + src),
  344. })
  345. },
  346. Instruction::Scas | Instruction::Stos => data & size_mask,
  347. Instruction::Ins => match size {
  348. Size::B => io_port_read8(port),
  349. Size::W => io_port_read16(port),
  350. Size::D => io_port_read32(port),
  351. },
  352. };
  353. let mut dst_val = 0;
  354. match instruction {
  355. Instruction::Cmps | Instruction::Scas => match size {
  356. Size::B => dst_val = break_on_pagefault!(safe_read8(es + dst)),
  357. Size::W => dst_val = break_on_pagefault!(safe_read16(es + dst)),
  358. Size::D => dst_val = break_on_pagefault!(safe_read32s(es + dst)),
  359. },
  360. Instruction::Outs => match size {
  361. Size::B => io_port_write8(port, src_val),
  362. Size::W => io_port_write16(port, src_val),
  363. Size::D => io_port_write32(port, src_val),
  364. },
  365. Instruction::Lods => match size {
  366. Size::B => write_reg8(AL, src_val),
  367. Size::W => write_reg16(AX, src_val),
  368. Size::D => write_reg32(EAX, src_val),
  369. },
  370. Instruction::Movs | Instruction::Stos | Instruction::Ins => match size {
  371. Size::B => break_on_pagefault!(safe_write8(es + dst, src_val)),
  372. Size::W => break_on_pagefault!(safe_write16(es + dst, src_val)),
  373. Size::D => break_on_pagefault!(safe_write32(es + dst, src_val)),
  374. },
  375. };
  376. match instruction {
  377. Instruction::Movs
  378. | Instruction::Cmps
  379. | Instruction::Stos
  380. | Instruction::Scas
  381. | Instruction::Ins => dst = dst + increment & asize_mask,
  382. _ => {},
  383. }
  384. match instruction {
  385. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  386. src = src + increment & asize_mask
  387. },
  388. _ => {},
  389. };
  390. let finished = match rep {
  391. Rep::Z | Rep::NZ => {
  392. let rep_cmp = match (rep, instruction) {
  393. (Rep::Z, Instruction::Cmps) => src_val == dst_val,
  394. (Rep::Z, Instruction::Scas) => src_val == dst_val,
  395. (Rep::NZ, Instruction::Cmps) => src_val != dst_val,
  396. (Rep::NZ, Instruction::Scas) => src_val != dst_val,
  397. _ => true,
  398. };
  399. count -= 1;
  400. if count != 0 && rep_cmp {
  401. //*instruction_pointer = *previous_ip
  402. false
  403. }
  404. else {
  405. true
  406. }
  407. },
  408. Rep::None => true,
  409. };
  410. if finished {
  411. match instruction {
  412. Instruction::Scas | Instruction::Cmps => match size {
  413. Size::B => cmp8(src_val, dst_val),
  414. Size::W => cmp16(src_val, dst_val),
  415. Size::D => cmp32(src_val, dst_val),
  416. },
  417. _ => {},
  418. }
  419. break;
  420. }
  421. }
  422. }
  423. match instruction {
  424. Instruction::Movs
  425. | Instruction::Cmps
  426. | Instruction::Stos
  427. | Instruction::Scas
  428. | Instruction::Ins => set_reg_asize(is_asize_32, EDI, dst),
  429. _ => {},
  430. }
  431. match instruction {
  432. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  433. set_reg_asize(is_asize_32, ESI, src)
  434. },
  435. _ => {},
  436. };
  437. match rep {
  438. Rep::Z | Rep::NZ => {
  439. set_reg_asize(is_asize_32, ECX, count as i32);
  440. },
  441. Rep::None => {},
  442. }
  443. }
  444. #[no_mangle]
  445. pub unsafe fn movsb_rep(is_asize_32: bool, ds: i32) {
  446. string_instruction(is_asize_32, ds, Instruction::Movs, Size::B, Rep::Z)
  447. }
  448. #[no_mangle]
  449. pub unsafe fn movsw_rep(is_asize_32: bool, ds: i32) {
  450. string_instruction(is_asize_32, ds, Instruction::Movs, Size::W, Rep::Z)
  451. }
  452. #[no_mangle]
  453. pub unsafe fn movsd_rep(is_asize_32: bool, ds: i32) {
  454. string_instruction(is_asize_32, ds, Instruction::Movs, Size::D, Rep::Z)
  455. }
  456. pub unsafe fn movsb_no_rep(is_asize_32: bool, ds: i32) {
  457. string_instruction(is_asize_32, ds, Instruction::Movs, Size::B, Rep::None)
  458. }
  459. pub unsafe fn movsw_no_rep(is_asize_32: bool, ds: i32) {
  460. string_instruction(is_asize_32, ds, Instruction::Movs, Size::W, Rep::None)
  461. }
  462. pub unsafe fn movsd_no_rep(is_asize_32: bool, ds: i32) {
  463. string_instruction(is_asize_32, ds, Instruction::Movs, Size::D, Rep::None)
  464. }
  465. #[no_mangle]
  466. pub unsafe fn lodsb_rep(is_asize_32: bool, ds: i32) {
  467. string_instruction(is_asize_32, ds, Instruction::Lods, Size::B, Rep::Z)
  468. }
  469. #[no_mangle]
  470. pub unsafe fn lodsw_rep(is_asize_32: bool, ds: i32) {
  471. string_instruction(is_asize_32, ds, Instruction::Lods, Size::W, Rep::Z)
  472. }
  473. #[no_mangle]
  474. pub unsafe fn lodsd_rep(is_asize_32: bool, ds: i32) {
  475. string_instruction(is_asize_32, ds, Instruction::Lods, Size::D, Rep::Z)
  476. }
  477. pub unsafe fn lodsb_no_rep(is_asize_32: bool, ds: i32) {
  478. string_instruction(is_asize_32, ds, Instruction::Lods, Size::B, Rep::None)
  479. }
  480. pub unsafe fn lodsw_no_rep(is_asize_32: bool, ds: i32) {
  481. string_instruction(is_asize_32, ds, Instruction::Lods, Size::W, Rep::None)
  482. }
  483. pub unsafe fn lodsd_no_rep(is_asize_32: bool, ds: i32) {
  484. string_instruction(is_asize_32, ds, Instruction::Lods, Size::D, Rep::None)
  485. }
  486. #[no_mangle]
  487. pub unsafe fn stosb_rep(is_asize_32: bool) {
  488. string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::Z)
  489. }
  490. #[no_mangle]
  491. pub unsafe fn stosw_rep(is_asize_32: bool) {
  492. string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::Z)
  493. }
  494. #[no_mangle]
  495. pub unsafe fn stosd_rep(is_asize_32: bool) {
  496. string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::Z)
  497. }
  498. pub unsafe fn stosb_no_rep(is_asize_32: bool) {
  499. string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::None)
  500. }
  501. pub unsafe fn stosw_no_rep(is_asize_32: bool) {
  502. string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::None)
  503. }
  504. pub unsafe fn stosd_no_rep(is_asize_32: bool) {
  505. string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::None)
  506. }
  507. #[no_mangle]
  508. pub unsafe fn cmpsb_repz(is_asize_32: bool, ds: i32) {
  509. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::B, Rep::Z)
  510. }
  511. #[no_mangle]
  512. pub unsafe fn cmpsw_repz(is_asize_32: bool, ds: i32) {
  513. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::W, Rep::Z)
  514. }
  515. #[no_mangle]
  516. pub unsafe fn cmpsd_repz(is_asize_32: bool, ds: i32) {
  517. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::D, Rep::Z)
  518. }
  519. #[no_mangle]
  520. pub unsafe fn cmpsb_repnz(is_asize_32: bool, ds: i32) {
  521. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::B, Rep::NZ)
  522. }
  523. #[no_mangle]
  524. pub unsafe fn cmpsw_repnz(is_asize_32: bool, ds: i32) {
  525. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::W, Rep::NZ)
  526. }
  527. #[no_mangle]
  528. pub unsafe fn cmpsd_repnz(is_asize_32: bool, ds: i32) {
  529. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::D, Rep::NZ)
  530. }
  531. #[no_mangle]
  532. pub unsafe fn cmpsb_no_rep(is_asize_32: bool, ds: i32) {
  533. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::B, Rep::None)
  534. }
  535. #[no_mangle]
  536. pub unsafe fn cmpsw_no_rep(is_asize_32: bool, ds: i32) {
  537. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::W, Rep::None)
  538. }
  539. #[no_mangle]
  540. pub unsafe fn cmpsd_no_rep(is_asize_32: bool, ds: i32) {
  541. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::D, Rep::None)
  542. }
  543. #[no_mangle]
  544. pub unsafe fn scasb_repz(is_asize_32: bool) {
  545. string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::Z)
  546. }
  547. #[no_mangle]
  548. pub unsafe fn scasw_repz(is_asize_32: bool) {
  549. string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::Z)
  550. }
  551. #[no_mangle]
  552. pub unsafe fn scasd_repz(is_asize_32: bool) {
  553. string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::Z)
  554. }
  555. #[no_mangle]
  556. pub unsafe fn scasb_repnz(is_asize_32: bool) {
  557. string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::NZ)
  558. }
  559. #[no_mangle]
  560. pub unsafe fn scasw_repnz(is_asize_32: bool) {
  561. string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::NZ)
  562. }
  563. #[no_mangle]
  564. pub unsafe fn scasd_repnz(is_asize_32: bool) {
  565. string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::NZ)
  566. }
  567. pub unsafe fn scasb_no_rep(is_asize_32: bool) {
  568. string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::None)
  569. }
  570. pub unsafe fn scasw_no_rep(is_asize_32: bool) {
  571. string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::None)
  572. }
  573. pub unsafe fn scasd_no_rep(is_asize_32: bool) {
  574. string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::None)
  575. }
  576. #[no_mangle]
  577. pub unsafe fn outsb_rep(is_asize_32: bool, ds: i32) {
  578. string_instruction(is_asize_32, ds, Instruction::Outs, Size::B, Rep::Z)
  579. }
  580. #[no_mangle]
  581. pub unsafe fn outsw_rep(is_asize_32: bool, ds: i32) {
  582. string_instruction(is_asize_32, ds, Instruction::Outs, Size::W, Rep::Z)
  583. }
  584. #[no_mangle]
  585. pub unsafe fn outsd_rep(is_asize_32: bool, ds: i32) {
  586. string_instruction(is_asize_32, ds, Instruction::Outs, Size::D, Rep::Z)
  587. }
  588. #[no_mangle]
  589. pub unsafe fn outsb_no_rep(is_asize_32: bool, ds: i32) {
  590. string_instruction(is_asize_32, ds, Instruction::Outs, Size::B, Rep::None)
  591. }
  592. #[no_mangle]
  593. pub unsafe fn outsw_no_rep(is_asize_32: bool, ds: i32) {
  594. string_instruction(is_asize_32, ds, Instruction::Outs, Size::W, Rep::None)
  595. }
  596. #[no_mangle]
  597. pub unsafe fn outsd_no_rep(is_asize_32: bool, ds: i32) {
  598. string_instruction(is_asize_32, ds, Instruction::Outs, Size::D, Rep::None)
  599. }
  600. #[no_mangle]
  601. pub unsafe fn insb_rep(is_asize_32: bool) {
  602. string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::Z)
  603. }
  604. #[no_mangle]
  605. pub unsafe fn insw_rep(is_asize_32: bool) {
  606. string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::Z)
  607. }
  608. #[no_mangle]
  609. pub unsafe fn insd_rep(is_asize_32: bool) {
  610. string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::Z)
  611. }
  612. #[no_mangle]
  613. pub unsafe fn insb_no_rep(is_asize_32: bool) {
  614. string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::None)
  615. }
  616. #[no_mangle]
  617. pub unsafe fn insw_no_rep(is_asize_32: bool) {
  618. string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::None)
  619. }
  620. #[no_mangle]
  621. pub unsafe fn insd_no_rep(is_asize_32: bool) {
  622. string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::None)
  623. }