summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/i386/i386dasm.cpp
blob: 3c815612ffaa9ba8df263d58054655d92e9ba3db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
 * nlbase.c
 *
 */

#include "solver/nld_matrix_solver.h"
#include "solver/nld_solver.h"

#include "plib/palloc.h"
#include "plib/pmempool.h"
#include "plib/putil.h"

#include "devices/nlid_proxy.h"
#include "devices/nlid_system.h"
#include "macro/nlm_base.h"
#include "nl_base.h"

#include "nl_errstr.h"

#include <cmath>
#include <cstring>
#include <limits>

namespace netlist
{

// ----------------------------------------------------------------------------------------
// logic_family_ttl_t
// ----------------------------------------------------------------------------------------

// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, modernize-use-equals-default)
logic_family_desc_t::logic_family_desc_t()
{
}

class logic_family_ttl_t : public logic_family_desc_t
{
public:
	logic_family_ttl_t() : logic_family_desc_t()
	{
		m_fixed_V = 5.0;
		m_low_thresh_PCNT = 0.8 / 5.0;
		m_high_thresh_PCNT = 2.0 / 5.0;
		// m_low_V  - these depend on sinked/sourced current. Values should be suitable for typical applications.
		m_low_VO = 0.1;
		m_high_VO = 1.0; // 4.0
		m_R_low = 1.0;
		m_R_high = 130.0;
	}
	pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
	pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
};

pool_owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_ttl_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const
{
	return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
}
pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_ttl_t::create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const
{
	return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
}

class logic_family_cd4xxx_t : public logic_family_desc_t
{
public:
	logic_family_cd4xxx_t() : logic_family_desc_t()
	{
		m_fixed_V = 0.0;
		m_low_thresh_PCNT = 1.5 / 5.0;
		m_high_thresh_PCNT = 3.5 / 5.0;
		// m_low_V  - these depend on sinked/sourced current. Values should be suitable for typical applications.
		m_low_VO = 0.05;
		m_high_VO = 0.05; // 4.95
		m_R_low = 10.0;
		m_R_high = 10.0;
	}
	pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
	pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
};

pool_owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_cd4xxx_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const
{
	return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
}

pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_cd4xxx_t::create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const
{
	return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
}

const logic_family_desc_t *family_TTL()
{
	static logic_family_ttl_t obj;
	return &obj;
}
const logic_family_desc_t *family_CD4XXX()
{
	static logic_family_cd4xxx_t obj;
	return &obj;
}


// ----------------------------------------------------------------------------------------
// queue_t
// ----------------------------------------------------------------------------------------

detail::queue_t::queue_t(netlist_state_t &nl)
	: timed_queue<pqentry_t<net_t *, netlist_time>, false, true>(512)
	, netlist_ref(nl)
	, m_qsize(0)
	, m_times(512)
	, m_net_ids(512)
{
}

void detail::queue_t::register_state(plib::state_manager_t &manager, const pstring &module)
{
	//state().log().debug("register_state\n");
	manager.save_item(this, m_qsize, module + "." + "qsize");
	manager.save_item(this, &m_times[0], module + "." + "times", m_times.size());
	manager.save_item(this, &m_net_ids[0], module + "." + "names", m_net_ids.size());
}

void detail::queue_t::on_pre_save(plib::state_manager_t &manager)
{
	plib::unused_var(manager);
	m_qsize = this->size();
	for (std::size_t i = 0; i < m_qsize; i++ )
	{
		m_times[i] =  this->listptr()[i].m_exec_time.as_raw();
		m_net_ids[i] = state().find_net_id(this->listptr()[i].m_object);
	}
}


void detail::queue_t::on_post_load(plib::state_manager_t &manager)
{
	plib::unused_var(manager);
	this->clear();
	for (std::size_t i = 0; i < m_qsize; i++ )
	{
		detail::net_t *n = state().nets()[m_net_ids[i]].get();
		this->push(queue_t::entry_t(netlist_time::from_raw(m_times[i]),n));
	}
}

// ----------------------------------------------------------------------------------------
// netlist_ref_t
// ----------------------------------------------------------------------------------------

detail::netlist_ref::netlist_ref(netlist_state_t &nl)
: m_netlist(nl.exec()) { }

// ----------------------------------------------------------------------------------------
// device_object_t
// ----------------------------------------------------------------------------------------

detail::device_object_t::device_object_t(core_device_t &dev, const pstring &aname)
: object_t(aname)
, m_device(dev)
{
}

detail::terminal_type detail::core_terminal_t::type() const
{
	if (dynamic_cast<const terminal_t *>(this) != nullptr)
		return terminal_type::TERMINAL;
	else if (dynamic_cast<const logic_input_t *>(this) != nullptr)
		return terminal_type::INPUT;
	else if (dynamic_cast<const logic_output_t *>(this) != nullptr)
		return terminal_type::OUTPUT;
	else if (dynamic_cast<const analog_input_t *>(this) != nullptr)
		return terminal_type::INPUT;
	else if (dynamic_cast<const analog_output_t *>(this) != nullptr)
		return terminal_type::OUTPUT;
	else
	{
		state().log().fatal(MF_UNKNOWN_TYPE_FOR_OBJECT(name()));
		return terminal_type::TERMINAL; // please compiler
	}
}

// ----------------------------------------------------------------------------------------
// netlist_t
// ----------------------------------------------------------------------------------------

netlist_t::netlist_t(const pstring &aname, plib::unique_ptr<callbacks_t> callbacks)
	: m_state(plib::make_unique<netlist_state_t>(aname, *this, std::move(callbacks)))
	, m_solver(nullptr)
	, m_time(netlist_time::zero())
	, m_mainclock(nullptr)
	, m_queue(*m_state)
	, m_stats(false)
{
	devices::initialize_factory(nlstate().setup().factory());
	NETLIST_NAME(base)(nlstate().setup());
	run_state_manager().save_item(this, static_cast<plib::state_manager_t::callback_t &>(m_queue), "m_queue");
	run_state_manager().save_item(this, m_time, "m_time");
}

// ----------------------------------------------------------------------------------------
// netlist_t
// ----------------------------------------------------------------------------------------

netlist_state_t::netlist_state_t(const pstring &aname,
	netlist_t & anetlist,
	plib::unique_ptr<callbacks_t> &&callbacks)
: m_name(aname)
, m_netlist(anetlist)
, m_state()
, m_callbacks(std::move(callbacks)) // Order is important here
, m_log(*m_callbacks)
, m_setup(plib::make_unique<setup_t>(*this))
{
	pstring libpath = plib::util::environment("NL_BOOSTLIB", plib::util::buildpath({".", "nlboost.so"}));
	m_lib = plib::make_unique<plib::dynlib>(libpath);
}


void netlist_t::stop()
{
	log().debug("Printing statistics ...\n");
	print_stats();
	log().debug("Stopping solver device ...\n");
	if (m_solver != nullptr)
		m_solver->stop();
}

detail::net_t *netlist_state_t::find_net(const pstring &name) const
{
	for (auto & net : m_nets)
		if (net->name() == name)
			return net.get();

	return nullptr;
}

std::size_t netlist_state_t::find_net_id(const detail::net_t *net) const
{
	for (std::size_t i = 0; i < m_nets.size(); i++)
		if (m_nets[i].get() == net)
			return i;
	return std::numeric_limits<std::size_t>::max();
}



void netlist_state_t::rebuild_lists()
{
	for (auto & net : m_nets)
		net->rebuild_list();
}


void netlist_t::reset()
{
	log().debug("Searching for mainclock\n");
	m_mainclock = m_state->get_single_device<devices::NETLIB_NAME(mainclock)>("mainclock");

	log().debug("Searching for solver\n");
	m_solver = m_state->get_single_device<devices::NETLIB_NAME(solver)>("solver");

	m_time = netlist_time::zero();
	m_queue.clear();
	if (m_mainclock != nullptr)
		m_mainclock->m_Q.net().set_next_scheduled_time(netlist_time::zero());
	//if (m_solver != nullptr)
	//  m_solver->reset();

	m_state->reset();
}

void netlist_state_t::reset()
{
	//FIXME: never used ???
	std::unordered_map<core_device_t *, bool> m;

	// Reset all nets once !
	log().verbose("Call reset on all nets:");
	for (auto & n : nets())
		n->reset();

	// Reset all devices once !
	log().verbose("Call reset on all devices:");
	for (auto & dev : m_devices)
		dev.second->reset();

	// Make sure everything depending on parameters is set
	// Currently analog input and logic input also
	// push their outputs to queue.

	log().verbose("Call update_param on all devices:");
	for (auto & dev : m_devices)
		dev.second->update_param();

	// Step all devices once !
	/*
	 * INFO: The order here affects power up of e.g. breakout. However, such
	 * variations are explicitly stated in the breakout manual.
	 */

	auto *netlist_params = get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");

	switch (netlist_params->m_startup_strategy())
	{
		case 0:
		{
			std::vector<core_device_t *> d;
			std::vector<nldelegate *> t;
			log().verbose("Using default startup strategy");
			for (auto &n : m_nets)
				for (auto & term : n->core_terms())
					if (term->m_delegate.has_object())
					{
						if (!plib::container::contains(t, &term->m_delegate))
						{
							t.push_back(&term->m_delegate);
							term->m_delegate();
						}
						auto *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object());
						if (!plib::container::contains(d, dev))
							d.push_back(dev);
					}
			log().verbose("Devices not yet updated:");
			for (auto &dev : m_devices)
				if (!plib::container::contains(d, dev.second.get()))
				{
					log().verbose("\t ...{1}", dev.second->name());
					dev.second->update();
				}
		}
		break;
		case 1:     // brute force backward
		{
			log().verbose("Using brute force backward startup strategy");

			for (auto &n : m_nets)  // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
				n->update_inputs();

			std::size_t i = m_devices.size();
			while (i>0)
				m_devices[--i].second->update();

			for (auto &n : m_nets)  // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
				n->update_inputs();

		}
		break;
		case 2:     // brute force forward
		{
			log().verbose("Using brute force forward startup strategy");
			for (auto &d : m_devices)
				d.second->update();
		}
		break;
	}

#if 1
	/* the above may screw up m_active and the list */
	rebuild_lists();
#endif
}

void netlist_t::process_queue(const netlist_time delta) NL_NOEXCEPT
{
	if (!m_stats)
		process_queue_stats<false>(delta);
	else
	{
		auto sm_guard(m_stat_mainloop.guard());
		process_queue_stats<true>(delta);
	}
}

template <bool KEEP_STATS>
void netlist_t::process_queue_stats(const netlist_time delta) NL_NOEXCEPT
{
	netlist_time stop(m_time + delta);

	qpush(detail::queue_t::entry_t(stop, nullptr));

	if (m_mainclock == nullptr)
	{
		detail::queue_t::entry_t e(m_queue.pop());
		m_time = e.m_exec_time;
		while (e.m_object != nullptr)
		{
			e.m_object->template update_devs<KEEP_STATS>();
			if (KEEP_STATS) m_perf_out_processed.inc();
			e = m_queue.pop();
			m_time = e.m_exec_time;
		}
	}
	else
	{
		logic_net_t &mc_net(m_mainclock->m_Q.net());
<
// license:BSD-3-Clause
// copyright-holders:Ville Linde, Peter Ferrie
/*
   i386 Disassembler

   Written by Ville Linde
*/

#include "emu.h"

enum
{
	PARAM_REG = 1,      /* 16 or 32-bit register */
	PARAM_REG8,         /* 8-bit register */
	PARAM_REG16,        /* 16-bit register */
	PARAM_REG32,        /* 32-bit register */
	PARAM_REG3264,      /* 32-bit or 64-bit register */
	PARAM_REG2_32,      /* 32-bit register */
	PARAM_MMX,          /* MMX register */
	PARAM_MMX2,         /* MMX register in modrm */
	PARAM_XMM,          /* XMM register */
	PARAM_RM,           /* 16 or 32-bit memory or register */
	PARAM_RM8,          /* 8-bit memory or register */
	PARAM_RM16,         /* 16-bit memory or register */
	PARAM_RM32,         /* 32-bit memory or register */
	PARAM_RMPTR,        /* 16 or 32-bit memory or register */
	PARAM_RMPTR8,       /* 8-bit memory or register */
	PARAM_RMPTR16,      /* 16-bit memory or register */
	PARAM_RMPTR32,      /* 32-bit memory or register */
	PARAM_RMXMM,        /* 32 or 64-bit memory or register */
	PARAM_REGORXMM,     /* 32 or 64-bit register or XMM register */
	PARAM_M64,          /* 64-bit memory */
	PARAM_M64PTR,       /* 64-bit memory */
	PARAM_MMXM,         /* 64-bit memory or MMX register */
	PARAM_XMMM,         /* 128-bit memory or XMM register */
	PARAM_I4,           /* 4-bit signed immediate */
	PARAM_I8,           /* 8-bit signed immediate */
	PARAM_I16,          /* 16-bit signed immediate */
	PARAM_UI8,          /* 8-bit unsigned immediate */
	PARAM_UI16,         /* 16-bit unsigned immediate */
	PARAM_IMM,          /* 16 or 32-bit immediate */
	PARAM_IMM64,        /* 16, 32 or 64-bit immediate */
	PARAM_ADDR,         /* 16:16 or 16:32 address */
	PARAM_REL,          /* 16 or 32-bit PC-relative displacement */
	PARAM_REL8,         /* 8-bit PC-relative displacement */
	PARAM_MEM_OFFS,     /* 16 or 32-bit mem offset */
	PARAM_PREIMP,       /* prefix with implicit register */
	PARAM_SREG,         /* segment register */
	PARAM_CREG,         /* control register */
	PARAM_DREG,         /* debug register */
	PARAM_TREG,         /* test register */
	PARAM_1,            /* used by shift/rotate instructions */
	PARAM_AL,
	PARAM_CL,
	PARAM_DL,
	PARAM_BL,
	PARAM_AH,
	PARAM_CH,
	PARAM_DH,
	PARAM_BH,
	PARAM_DX,
	PARAM_EAX,          /* EAX or AX */
	PARAM_ECX,          /* ECX or CX */
	PARAM_EDX,          /* EDX or DX */
	PARAM_EBX,          /* EBX or BX */
	PARAM_ESP,          /* ESP or SP */
	PARAM_EBP,          /* EBP or BP */
	PARAM_ESI,          /* ESI or SI */
	PARAM_EDI,          /* EDI or DI */
	PARAM_XMM0,
	PARAM_XMM64,            /* 64-bit memory or XMM register */
	PARAM_XMM32,            /* 32-bit memory or XMM register */
	PARAM_XMM16             /* 16-bit memory or XMM register */
};

enum
{
	MODRM = 1,
	GROUP,
	FPU,
	OP_SIZE,
	ADDR_SIZE,
	TWO_BYTE,
	PREFIX,
	SEG_CS,
	SEG_DS,
	SEG_ES,
	SEG_FS,
	SEG_GS,
	SEG_SS,
	ISREX,
	THREE_BYTE          /* [prefix] 0f op1 op2 and then mod/rm */
};

#define FLAGS_MASK          0x0ff
#define VAR_NAME            0x100
#define VAR_NAME4           0x200
#define ALWAYS64            0x400
#define SPECIAL64           0x800
#define SPECIAL64_ENT(x)    (SPECIAL64 | ((x) << 24))
#define GROUP_MOD           0x1000

struct I386_OPCODE {
	const char *mnemonic;
	uint32_t flags;
	uint32_t param1;
	uint32_t param2;
	uint32_t param3;
	offs_t dasm_flags;
};

struct GROUP_OP {
	char mnemonic[32];
	const I386_OPCODE *opcode;
};

static const uint8_t *opcode_ptr;
static const uint8_t *opcode_ptr_base;

static const I386_OPCODE i386_opcode_table1[256] =
{
	// 0x00
	{"add",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"add",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"add",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"add",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"add",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"add",             0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"push    es",      0,              0,                  0,                  0               },
	{"pop     es",      0,              0,                  0,                  0               },
	{"or",              MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"or",              MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"or",              MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"or",              MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"or",              0,              PARAM_AL,           PARAM_UI8,          0               },
	{"or",              0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"push    cs",      0,              0,                  0,                  0               },
	{"two_byte",        TWO_BYTE,       0,                  0,                  0               },
	// 0x10
	{"adc",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"adc",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"adc",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"adc",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"adc",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"adc",             0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"push    ss",      0,              0,                  0,                  0               },
	{"pop     ss",      0,              0,                  0,                  0               },
	{"sbb",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"sbb",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"sbb",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"sbb",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"sbb",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"sbb",             0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"push    ds",      0,              0,                  0,                  0               },
	{"pop     ds",      0,              0,                  0,                  0               },
	// 0x20
	{"and",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"and",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"and",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"and",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"and",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"and",             0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"seg_es",          SEG_ES,         0,                  0,                  0               },
	{"daa",             0,              0,                  0,                  0               },
	{"sub",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"sub",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"sub",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"sub",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"sub",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"sub",             0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"seg_cs",          SEG_CS,         0,                  0,                  0               },
	{"das",             0,              0,                  0,                  0               },
	// 0x30
	{"xor",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"xor",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"xor",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"xor",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"xor",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"xor",             0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"seg_ss",          SEG_SS,         0,                  0,                  0               },
	{"aaa",             0,              0,                  0,                  0               },
	{"cmp",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"cmp",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"cmp",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"cmp",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmp",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"cmp",             0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"seg_ds",          SEG_DS,         0,                  0,                  0               },
	{"aas",             0,              0,                  0,                  0               },
	// 0x40
	{"inc",             ISREX,          PARAM_EAX,          0,                  0               },
	{"inc",             ISREX,          PARAM_ECX,          0,                  0               },
	{"inc",             ISREX,          PARAM_EDX,          0,                  0               },
	{"inc",             ISREX,          PARAM_EBX,          0,                  0               },
	{"inc",             ISREX,          PARAM_ESP,          0,                  0               },
	{"inc",             ISREX,          PARAM_EBP,          0,                  0               },
	{"inc",             ISREX,          PARAM_ESI,          0,                  0               },
	{"inc",             ISREX,          PARAM_EDI,          0,                  0               },
	{"dec",             ISREX,          PARAM_EAX,          0,                  0               },
	{"dec",             ISREX,          PARAM_ECX,          0,                  0               },
	{"dec",             ISREX,          PARAM_EDX,          0,                  0               },
	{"dec",             ISREX,          PARAM_EBX,          0,                  0               },
	{"dec",             ISREX,          PARAM_ESP,          0,                  0               },
	{"dec",             ISREX,          PARAM_EBP,          0,                  0               },
	{"dec",             ISREX,          PARAM_ESI,          0,                  0               },
	{"dec",             ISREX,          PARAM_EDI,          0,                  0               },
	// 0x50
	{"push",            ALWAYS64,       PARAM_EAX,          0,                  0               },
	{"push",            ALWAYS64,       PARAM_ECX,          0,                  0               },
	{"push",            ALWAYS64,       PARAM_EDX,          0,                  0               },
	{"push",            ALWAYS64,       PARAM_EBX,          0,                  0               },
	{"push",            ALWAYS64,       PARAM_ESP,          0,                  0               },
	{"push",            ALWAYS64,       PARAM_EBP,          0,                  0               },
	{"push",            ALWAYS64,       PARAM_ESI,          0,                  0               },
	{"push",            ALWAYS64,       PARAM_EDI,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_EAX,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_ECX,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_EDX,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_EBX,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_ESP,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_EBP,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_ESI,          0,                  0               },
	{"pop",             ALWAYS64,       PARAM_EDI,          0,                  0               },
	// 0x60
	{"pusha\0pushad\0<invalid>",VAR_NAME,0,                 0,                  0               },
	{"popa\0popad\0<invalid>",  VAR_NAME,0,                 0,                  0               },
	{"bound",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"arpl",            MODRM | SPECIAL64_ENT(0),PARAM_RM,  PARAM_REG16,        0               },
	{"seg_fs",          SEG_FS,         0,                  0,                  0               },
	{"seg_gs",          SEG_GS,         0,                  0,                  0               },
	{"op_size",         OP_SIZE,        0,                  0,                  0               },
	{"addr_size",       ADDR_SIZE,      0,                  0,                  0               },
	{"push",            0,              PARAM_IMM,          0,                  0               },
	{"imul",            MODRM,          PARAM_REG,          PARAM_RM,           PARAM_IMM       },
	{"push",            0,              PARAM_I8,           0,                  0               },
	{"imul",            MODRM,          PARAM_REG,          PARAM_RM,           PARAM_I8        },
	{"insb",            0,              0,                  0,                  0               },
	{"insw\0insd\0insd",VAR_NAME,       0,                  0,                  0               },
	{"outsb",           0,              PARAM_PREIMP,       0,                  0               },
	{"outsw\0outsd\0outsd",VAR_NAME,    PARAM_PREIMP,       0,                  0               },
	// 0x70
	{"jo",              0,              PARAM_REL8,         0,                  0               },
	{"jno",             0,              PARAM_REL8,         0,                  0               },
	{"jb",              0,              PARAM_REL8,         0,                  0               },
	{"jae",             0,              PARAM_REL8,         0,                  0               },
	{"je",              0,              PARAM_REL8,         0,                  0               },
	{"jne",             0,              PARAM_REL8,         0,                  0               },
	{"jbe",             0,              PARAM_REL8,         0,                  0               },
	{"ja",              0,              PARAM_REL8,         0,                  0               },
	{"js",              0,              PARAM_REL8,         0,                  0               },
	{"jns",             0,              PARAM_REL8,         0,                  0               },
	{"jp",              0,              PARAM_REL8,         0,                  0               },
	{"jnp",             0,              PARAM_REL8,         0,                  0               },
	{"jl",              0,              PARAM_REL8,         0,                  0               },
	{"jge",             0,              PARAM_REL8,         0,                  0               },
	{"jle",             0,              PARAM_REL8,         0,                  0               },
	{"jg",              0,              PARAM_REL8,         0,                  0               },
	// 0x80
	{"group80",         GROUP,          0,                  0,                  0               },
	{"group81",         GROUP,          0,                  0,                  0               },
	{"group80",         GROUP,          0,                  0,                  0               },
	{"group83",         GROUP,          0,                  0,                  0               },
	{"test",            MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"test",            MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"xchg",            MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"xchg",            MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"mov",             MODRM,          PARAM_RM8,          PARAM_REG8,         0               },
	{"mov",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"mov",             MODRM,          PARAM_REG8,         PARAM_RM8,          0               },
	{"mov",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"mov",             MODRM,          PARAM_RM,           PARAM_SREG,         0               },
	{"lea",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"mov",             MODRM,          PARAM_SREG,         PARAM_RM,           0               },
	{"pop",             MODRM,          PARAM_RM,           0,                  0               },
	// 0x90
	{"nop\0???\0???\0pause",    VAR_NAME4,          0,                  0,                  0               },
	{"xchg",            0,              PARAM_EAX,          PARAM_ECX,          0               },
	{"xchg",            0,              PARAM_EAX,          PARAM_EDX,          0               },
	{"xchg",            0,              PARAM_EAX,          PARAM_EBX,          0               },
	{"xchg",            0,              PARAM_EAX,          PARAM_ESP,          0               },
	{"xchg",            0,              PARAM_EAX,          PARAM_EBP,          0               },
	{"xchg",            0,              PARAM_EAX,          PARAM_ESI,          0               },
	{"xchg",            0,              PARAM_EAX,          PARAM_EDI,          0               },
	{"cbw\0cwde\0cdqe", VAR_NAME,       0,                  0,                  0               },
	{"cwd\0cdq\0cqo",   VAR_NAME,       0,                  0,                  0               },
	{"call",            ALWAYS64,       PARAM_ADDR,         0,                  0,              DASMFLAG_STEP_OVER},
	{"wait",            0,              0,                  0,                  0               },
	{"pushf\0pushfd\0pushfq",VAR_NAME,  0,                  0,                  0               },
	{"popf\0popfd\0popfq",VAR_NAME,     0,                  0,                  0               },
	{"sahf",            0,              0,                  0,                  0               },
	{"lahf",            0,              0,                  0,                  0               },
	// 0xa0
	{"mov",             0,              PARAM_AL,           PARAM_MEM_OFFS,     0               },
	{"mov",             0,              PARAM_EAX,          PARAM_MEM_OFFS,     0               },
	{"mov",             0,              PARAM_MEM_OFFS,     PARAM_AL,           0               },
	{"mov",             0,              PARAM_MEM_OFFS,     PARAM_EAX,          0               },
	{"movsb",           0,              PARAM_PREIMP,       0,                  0               },
	{"movsw\0movsd\0movsq",VAR_NAME,    PARAM_PREIMP,       0,                  0               },
	{"cmpsb",           0,              PARAM_PREIMP,       0,                  0               },
	{"cmpsw\0cmpsd\0cmpsq",VAR_NAME,    PARAM_PREIMP,       0,                  0               },
	{"test",            0,              PARAM_AL,           PARAM_UI8,          0               },
	{"test",            0,              PARAM_EAX,          PARAM_IMM,          0               },
	{"stosb",           0,              0,                  0,                  0               },
	{"stosw\0stosd\0stosq",VAR_NAME,    0,                  0,                  0               },
	{"lodsb",           0,              PARAM_PREIMP,       0,                  0               },
	{"lodsw\0lodsd\0lodsq",VAR_NAME,    PARAM_PREIMP,       0,                  0               },
	{"scasb",           0,              0,                  0,                  0               },
	{"scasw\0scasd\0scasq",VAR_NAME,    0,                  0,                  0               },
	// 0xb0
	{"mov",             0,              PARAM_AL,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_CL,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_DL,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_BL,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_AH,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_CH,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_DH,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_BH,           PARAM_UI8,          0               },
	{"mov",             0,              PARAM_EAX,          PARAM_IMM64,        0               },
	{"mov",             0,              PARAM_ECX,          PARAM_IMM64,        0               },
	{"mov",             0,              PARAM_EDX,          PARAM_IMM64,        0               },
	{"mov",             0,              PARAM_EBX,          PARAM_IMM64,        0               },
	{"mov",             0,              PARAM_ESP,          PARAM_IMM64,        0               },
	{"mov",             0,              PARAM_EBP,          PARAM_IMM64,        0               },
	{"mov",             0,              PARAM_ESI,          PARAM_IMM64,        0               },
	{"mov",             0,              PARAM_EDI,          PARAM_IMM64,        0               },
	// 0xc0
	{"groupC0",         GROUP,          0,                  0,                  0               },
	{"groupC1",         GROUP,          0,                  0,                  0               },
	{"ret",             0,              PARAM_UI16,         0,                  0,              DASMFLAG_STEP_OUT},
	{"ret",             0,              0,                  0,                  0,              DASMFLAG_STEP_OUT},
	{"les",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"lds",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"mov",             MODRM,          PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"mov",             MODRM,          PARAM_RMPTR,        PARAM_IMM,          0               },
	{"enter",           0,              PARAM_UI16,         PARAM_UI8,          0               },
	{"leave",           0,              0,                  0,                  0               },
	{"retf",            0,              PARAM_UI16,         0,                  0,              DASMFLAG_STEP_OUT},
	{"retf",            0,              0,                  0,                  0,              DASMFLAG_STEP_OUT},
	{"int 3",           0,              0,                  0,                  0,              DASMFLAG_STEP_OVER},
	{"int",             0,              PARAM_UI8,          0,                  0,              DASMFLAG_STEP_OVER},
	{"into",            0,              0,                  0,                  0               },
	{"iret",            0,              0,                  0,                  0,              DASMFLAG_STEP_OUT},
	// 0xd0
	{"groupD0",         GROUP,          0,                  0,                  0               },
	{"groupD1",         GROUP,          0,                  0,                  0               },
	{"groupD2",         GROUP,          0,                  0,                  0               },
	{"groupD3",         GROUP,          0,                  0,                  0               },
	{"aam",             0,              PARAM_UI8,          0,                  0               },
	{"aad",             0,              PARAM_UI8,          0,                  0               },
	{"salc",            0,              0,                  0,                  0               }, //AMD docs name it
	{"xlat",            0,              0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	{"escape",          FPU,            0,                  0,                  0               },
	// 0xe0
	{"loopne",          0,              PARAM_REL8,         0,                  0,              DASMFLAG_STEP_OVER},
	{"loopz",           0,              PARAM_REL8,         0,                  0,              DASMFLAG_STEP_OVER},
	{"loop",            0,              PARAM_REL8,         0,                  0,              DASMFLAG_STEP_OVER},
	{"jcxz\0jecxz\0jrcxz",VAR_NAME,     PARAM_REL8,         0,                  0               },
	{"in",              0,              PARAM_AL,           PARAM_UI8,          0               },
	{"in",              0,              PARAM_EAX,          PARAM_UI8,          0               },
	{"out",             0,              PARAM_UI8,          PARAM_AL,           0               },
	{"out",             0,              PARAM_UI8,          PARAM_EAX,          0               },
	{"call",            0,              PARAM_REL,          0,                  0,              DASMFLAG_STEP_OVER},
	{"jmp",             0,              PARAM_REL,          0,                  0               },
	{"jmp",             0,              PARAM_ADDR,         0,                  0               },
	{"jmp",             0,              PARAM_REL8,         0,                  0               },
	{"in",              0,              PARAM_AL,           PARAM_DX,           0               },
	{"in",              0,              PARAM_EAX,          PARAM_DX,           0               },
	{"out",             0,              PARAM_DX,           PARAM_AL,           0               },
	{"out",             0,              PARAM_DX,           PARAM_EAX,          0               },
	// 0xf0
	{"lock",            0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"repne",           PREFIX,         0,                  0,                  0               },
	{"rep",             PREFIX,         0,                  0,                  0               },
	{"hlt",             0,              0,                  0,                  0               },
	{"cmc",             0,              0,                  0,                  0               },
	{"groupF6",         GROUP,          0,                  0,                  0               },
	{"groupF7",         GROUP,          0,                  0,                  0               },
	{"clc",             0,              0,                  0,                  0               },
	{"stc",             0,              0,                  0,                  0               },
	{"cli",             0,              0,                  0,                  0               },
	{"sti",             0,              0,                  0,                  0               },
	{"cld",             0,              0,                  0,                  0               },
	{"std",             0,              0,                  0,                  0               },
	{"groupFE",         GROUP,          0,                  0,                  0               },
	{"groupFF",         GROUP,          0,                  0,                  0               }
};

static const I386_OPCODE x64_opcode_alt[] =
{
	{"movsxd",          MODRM | ALWAYS64,PARAM_REG,         PARAM_RMPTR32,      0               },
};

static const I386_OPCODE i386_opcode_table2[256] =
{
	// 0x00
	{"group0F00",       GROUP,          0,                  0,                  0               },
	{"group0F01",       GROUP,          0,                  0,                  0               },
	{"lar",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"lsl",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"???",             0,              0,                  0,                  0               },
	{"syscall",         0,              0,                  0,                  0               },
	{"clts",            0,              0,                  0,                  0               },
	{"sysret",          0,              0,                  0,                  0               },
	{"invd",            0,              0,                  0,                  0               },
	{"wbinvd",          0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"ud2",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"group0F0D",           GROUP,              0,                  0,                  0               }, //AMD only
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	// 0x10
	{"movups\0"
		"movupd\0"
		"movsd\0"
		"movss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"movups\0"
		"movupd\0"
		"movsd\0"
		"movss",            MODRM|VAR_NAME4,PARAM_XMMM,         PARAM_XMM,          0               },
	{"group0F12",      GROUP|GROUP_MOD, 0,                  0,                  0                   },
	{"movlps\0"
		"movlpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMMM,         PARAM_XMM,          0               },
	{"unpcklps\0"
		"unpcklpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"unpckhps\0"
		"unpckhpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{ "group0F16",     GROUP|GROUP_MOD, 0,                  0,                  0                   },
	{"movhps\0"
		"movhpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMMM,          PARAM_XMM,         0               },
	{"group0F18",       GROUP,          0,                  0,                  0               },
	{"nop_hint",        0,              PARAM_RMPTR8,               0,                  0               },
	{"nop_hint",        0,              PARAM_RMPTR8,               0,                  0               },
	{"nop_hint",        0,              PARAM_RMPTR8,               0,                  0               },
	{"nop_hint",        0,              PARAM_RMPTR8,               0,                  0               },
	{"nop_hint",        0,              PARAM_RMPTR8,               0,                  0               },
	{"nop_hint",        0,              PARAM_RMPTR8,               0,                  0               },
	{"nop_hint",        0,              PARAM_RMPTR8,               0,                  0               },
	// 0x20
	{"mov",             MODRM,          PARAM_REG2_32,      PARAM_CREG,         0               },
	{"mov",             MODRM,          PARAM_REG2_32,      PARAM_DREG,         0               },
	{"mov",             MODRM,          PARAM_CREG,         PARAM_REG2_32,      0               },
	{"mov",             MODRM,          PARAM_DREG,         PARAM_REG2_32,      0               },
	{"mov",             MODRM,          PARAM_REG2_32,      PARAM_TREG,         0               },
	{"???",             0,              0,                  0,                  0               },
	{"mov",             MODRM,          PARAM_TREG,         PARAM_REG2_32,      0               },
	{"???",             0,              0,                  0,                  0               },
	{"movaps\0"
		"movapd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"movaps\0"
		"movapd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMMM,         PARAM_XMM,          0               },
	{"cvtpi2ps\0"
		"cvtpi2pd\0"
		"cvtsi2sd\0"
		"cvtsi2ss",     MODRM|VAR_NAME4,PARAM_XMM,          PARAM_RMXMM,        0               },
	{"movntps\0"
		"movntpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMMM,         PARAM_XMM,          0               },
	{"cvttps2pi\0"
		"cvttpd2pi\0"
		"cvttsd2si\0"
		"cvttss2si",        MODRM|VAR_NAME4,PARAM_REGORXMM,     PARAM_XMMM,         0               },
	{"cvtps2pi\0"
		"cvtpd2pi\0"
		"cvtsd2si\0"
		"cvtss2si",     MODRM|VAR_NAME4,PARAM_REGORXMM,     PARAM_XMMM,         0               },
	{"ucomiss\0"
		"ucomisd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"comiss\0"
		"comisd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	// 0x30
	{"wrmsr",           0,              0,                  0,                  0               },
	{"rdtsc",           0,              0,                  0,                  0               },
	{"rdmsr",           0,              0,                  0,                  0               },
	{"rdpmc",           0,              0,                  0,                  0               },
	{"sysenter",        0,              0,                  0,                  0               },
	{"sysexit",         0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"three_byte",          THREE_BYTE,         0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"three_byte",          THREE_BYTE,         0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	// 0x40
	{"cmovo",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovno",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovb",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovae",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmove",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovne",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovbe",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmova",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovs",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovns",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovpe",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovpo",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovl",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovge",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovle",          MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"cmovg",           MODRM,          PARAM_REG,          PARAM_RM,           0               },
	// 0x50
	{"movmskps\0"
		"movmskpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_REG3264,      PARAM_XMMM,         0               },
	{"sqrtps\0"
		"sqrtpd\0"
		"sqrtsd\0"
		"sqrtss",           MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"rsqrtps\0"
		"???\0"
		"???\0"
		"rsqrtss",          MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"rcpps\0"
		"???\0"
		"???\0"
		"rcpss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"andps\0"
		"andpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"andnps\0"
		"andnpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"orps\0"
		"orpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"xorps\0"
		"xorpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"addps\0"
		"addpd\0"
		"addsd\0"
		"addss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"mulps\0"
		"mulpd\0"
		"mulsd\0"
		"mulss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"cvtps2pd\0"
		"cvtpd2ps\0"
		"cvtsd2ss\0"
		"cvtss2sd",     MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"cvtdq2ps\0"
		"cvtps2dq\0"
		"???\0"
		"cvttps2dq",        MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"subps\0"
		"subpd\0"
		"subsd\0"
		"subss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"minps\0"
		"minpd\0"
		"minsd\0"
		"minss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"divps\0"
		"divpd\0"
		"divsd\0"
		"divss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"maxps\0"
		"maxpd\0"
		"maxsd\0"
		"maxss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	// 0x60
	{"punpcklbw",       MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"punpcklwd",       MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"punpckldq",       MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"packsswb",        MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pcmpgtb",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pcmpgtw",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pcmpgtd",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"packuswb",        MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"punpckhbw",       MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"punpckhwd",       MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"punpckhdq",       MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"packssdw",        MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"???\0"
		"punpcklqdq\0"
		"???\0"
		"???\0",        MODRM|VAR_NAME4,            PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"punpckhqdq\0"
		"???\0"
		"???\0",        MODRM|VAR_NAME4,            PARAM_XMM,          PARAM_XMMM,         0               },
	{"movd",            MODRM,          PARAM_MMX,          PARAM_RM,           0               },
	{"movq\0"
		"movdqa\0"
		"???\0"
		"movdqu",           MODRM|VAR_NAME4,PARAM_MMX,          PARAM_MMXM,         0               },
	// 0x70
	{"pshufw\0"
		"pshufd\0"
		"pshuflw\0"
		"pshufhw",          MODRM|VAR_NAME4,PARAM_MMX,          PARAM_MMXM,         PARAM_UI8       },
	{"group0F71",       GROUP,          0,                  0,                  0               },
	{"group0F72",       GROUP,          0,                  0,                  0               },
	{"group0F73",       GROUP,          0,                  0,                  0               },
	{"pcmpeqb",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pcmpeqw",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pcmpeqd",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"emms",            0,              0,                  0,                  0               },
	{"vmread",          MODRM,              PARAM_RM,               PARAM_REG,              0               },
	{"vmwrite",         MODRM,              PARAM_RM,               PARAM_REG,              0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???\0"
		"haddpd\0"
		"haddps\0"
		"???",              MODRM|VAR_NAME4,PARAM_MMX,          PARAM_MMXM,         0               },
	{"???\0"
		"hsubpd\0"
		"hsubps\0"
		"???",              MODRM|VAR_NAME4,PARAM_MMX,          PARAM_MMXM,         0               },
	{"movd\0"
		"movd\0"
		"???\0"
		"movq",         MODRM|VAR_NAME4,PARAM_RM,           PARAM_MMX,          0               },
	{"movq\0"
		"movdqa\0"
		"???\0"
		"movdqu",           MODRM|VAR_NAME4,PARAM_MMXM,         PARAM_MMX,          0               },
	// 0x80
	{"jo",              0,              PARAM_REL,          0,                  0               },
	{"jno",             0,              PARAM_REL,          0,                  0               },
	{"jb",              0,              PARAM_REL,          0,                  0               },
	{"jae",             0,              PARAM_REL,          0,                  0               },
	{"je",              0,              PARAM_REL,          0,                  0               },
	{"jne",             0,              PARAM_REL,          0,                  0               },
	{"jbe",             0,              PARAM_REL,          0,                  0               },
	{"ja",              0,              PARAM_REL,          0,                  0               },
	{"js",              0,              PARAM_REL,          0,                  0               },
	{"jns",             0,              PARAM_REL,          0,                  0               },
	{"jp",              0,              PARAM_REL,          0,                  0               },
	{"jnp",             0,              PARAM_REL,          0,                  0               },
	{"jl",              0,              PARAM_REL,          0,                  0               },
	{"jge",             0,              PARAM_REL,          0,                  0               },
	{"jle",             0,              PARAM_REL,          0,                  0               },
	{"jg",              0,              PARAM_REL,          0,                  0               },
	// 0x90
	{"seto",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setno",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setb",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setae",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"sete",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setne",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setbe",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"seta",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"sets",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setns",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setp",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setnp",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setl",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setge",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setle",           MODRM,          PARAM_RMPTR8,       0,                  0               },
	{"setg",            MODRM,          PARAM_RMPTR8,       0,                  0               },
	// 0xa0
	{"push    fs",      0,              0,                  0,                  0               },
	{"pop     fs",      0,              0,                  0,                  0               },
	{"cpuid",           0,              0,                  0,                  0               },
	{"bt",              MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"shld",            MODRM,          PARAM_RM,           PARAM_REG,          PARAM_UI8       },
	{"shld",            MODRM,          PARAM_RM,           PARAM_REG,          PARAM_CL        },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"push    gs",      0,              0,                  0,                  0               },
	{"pop     gs",      0,              0,                  0,                  0               },
	{"rsm",             0,              0,                  0,                  0               },
	{"bts",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"shrd",            MODRM,          PARAM_RM,           PARAM_REG,          PARAM_UI8       },
	{"shrd",            MODRM,          PARAM_RM,           PARAM_REG,          PARAM_CL        },
	{"group0FAE",       GROUP,          0,                  0,                  0               },
	{"imul",            MODRM,          PARAM_REG,          PARAM_RM,           0               },
	// 0xb0
	{"cmpxchg",         MODRM,          PARAM_RM8,          PARAM_REG,          0               },
	{"cmpxchg",         MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"lss",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"btr",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"lfs",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"lgs",             MODRM,          PARAM_REG,          PARAM_RM,           0               },
	{"movzx",           MODRM,          PARAM_REG,          PARAM_RMPTR8,       0               },
	{"movzx",           MODRM,          PARAM_REG,          PARAM_RMPTR16,      0               },
	{"???\0"
		"???\0"
		"???\0"
		"popcnt",           MODRM|VAR_NAME4,        PARAM_REG,              PARAM_RM16,             0               },
	{"ud2",             0,              0,                  0,                  0               },
	{"group0FBA",       GROUP,          0,                  0,                  0               },
	{"btc",             MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"bsf\0"
		"???\0"
		"???\0"
		"tzcnt",            MODRM|VAR_NAME4,    PARAM_REG,          PARAM_RM,           0               },
	{"bsr\0"
		"???\0"
		"???\0"
		"lzcnt",            MODRM|VAR_NAME4,    PARAM_REG,          PARAM_RM,           0,              DASMFLAG_STEP_OVER},
	{"movsx",           MODRM,          PARAM_REG,          PARAM_RMPTR8,       0               },
	{"movsx",           MODRM,          PARAM_REG,          PARAM_RMPTR16,      0               },
	// 0xc0
	{"xadd",            MODRM,          PARAM_RM8,          PARAM_REG,          0               },
	{"xadd",            MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"cmpps\0"
		"cmppd\0"
		"cmpsd\0"
		"cmpss",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"movnti",          MODRM,          PARAM_RM,           PARAM_REG,          0               },
	{"pinsrw",          MODRM,          PARAM_MMX,          PARAM_RM,           PARAM_UI8       },
	{"pextrw",          MODRM,          PARAM_MMX,          PARAM_RM,           PARAM_UI8       },
	{"shufps\0"
		"shufpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         PARAM_UI8       },
	{"group0FC7",           GROUP,          0,          0,                  0               },
	{"bswap",           0,              PARAM_EAX,          0,                  0               },
	{"bswap",           0,              PARAM_ECX,          0,                  0               },
	{"bswap",           0,              PARAM_EDX,          0,                  0               },
	{"bswap",           0,              PARAM_EBX,          0,                  0               },
	{"bswap",           0,              PARAM_ESP,          0,                  0               },
	{"bswap",           0,              PARAM_EBP,          0,                  0               },
	{"bswap",           0,              PARAM_ESI,          0,                  0               },
	{"bswap",           0,              PARAM_EDI,          0,                  0               },
	// 0xd0
	{"???\0"
		"addsubpd\0"
		"addsubps\0"
		"???\0",            MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"psrlw",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psrld",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psrlq",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddq",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmullw",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"???\0"
		"movq\0"
		"movdq2q\0"
		"movq2dq",          MODRM|VAR_NAME4,PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmovmskb",        MODRM,          PARAM_REG3264,      PARAM_MMXM,         0               },
	{"psubusb",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psubusw",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pminub",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pand",            MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddusb",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddusw",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmaxub",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pandn",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	// 0xe0
	{"pavgb",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psraw",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psrad",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pavgw",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmulhuw",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmulhw",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"???\0"
		"cvttpd2dq\0"
		"cvtpd2dq\0"
		"cvtdq2pd",     MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"movntq\0"
		"movntdq\0"
		"???\0"
		"???\0",            MODRM|VAR_NAME4,    PARAM_M64,          PARAM_MMX,          0               },
	{"psubsb",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psubsw",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pminsw",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"por",             MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddsb",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddsw",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmaxsw",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pxor",            MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	// 0xf0
	{"???\0"
		"???\0"
		"lddqu\0"
		"???",              MODRM|VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{"psllw",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pslld",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psllq",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmuludq",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"pmaddwd",         MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psadbw",          MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"maskmovq\0"
		"maskmovdqu\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,PARAM_MMX,          PARAM_MMXM,         0               },
	{"psubb",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psubw",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psubd",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"psubq",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddb",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddw",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"paddd",           MODRM,          PARAM_MMX,          PARAM_MMXM,         0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE i386_opcode_table0F38[256] =
{
	// 0x00
	{"pshufb\0"
		"pshufb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"phaddw\0"
		"phaddw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"phaddd\0"
		"phadd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"phaddsw\0"
		"phaddsw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"pmaddubsw\0"
		"pmaddubsw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"phsubw\0"
		"phsubw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"phsubd\0"
		"phsubd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"phsubsw\0"
		"phsubsw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"psignb\0"
		"psignb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"psignw\0"
		"psignw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"psignd\0"
		"psignd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"pmulhrsw\0"
		"pmulhrsw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x10
	{"???\0"
		"pblendvb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_XMM0          },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"blendvps\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_XMM0          },
	{"???\0"
		"blendvpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_XMM0          },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"ptest\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"pabsb\0"
		"pabsb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"pabsw\0"
		"pabsw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"pabsd\0"
		"pabsd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???",             0,              0,          0,              0               },
	// 0x20
	{"???\0"
		"pmovsxbw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM64,            0               },
	{"???\0"
		"pmovsxbd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM32,            0               },
	{"???\0"
		"pmovsxbq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM16,            0               },
	{"???\0"
		"pmovsxwd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM64,            0               },
	{"???\0"
		"pmovsxwq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM32,            0               },
	{"???\0"
		"pmovsxdq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM64,            0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"pmuldq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pcmpeqq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"movntdqa\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"packusdw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x30
	{"???\0"
		"pmovzxbw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM64,            0               },
	{"???\0"
		"pmovzxbd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM32,            0               },
	{"???\0"
		"pmovzxbq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM16,            0               },
	{"???\0"
		"pmovzxwd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM64,            0               },
	{"???\0"
		"pmovzxwq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM32,            0               },
	{"???\0"
		"pmovzxdq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMM64,            0               },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"pcmpgtq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pminsb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pminsd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pminuw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pminud\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pmaxsb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pmaxsd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pmaxuw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"pmaxud\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	// 0x40
	{"???\0"
		"pmulld\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"phminposuw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x50
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x60
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x70
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x80
	{"???\0"
		"invept\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_REG32,            PARAM_XMMM,         0               },
	{"???\0"
		"invvpid\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_REG32,            PARAM_XMMM,         0               },
	{"???\0"
		"invpcid\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_REG32,            PARAM_XMMM,         0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x90
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xa0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xb0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xc0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xd0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"aesimc\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"aesenc\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"aesenclast\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"aesdec\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	{"???\0"
		"aesdeclast\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         0               },
	// 0xe0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xf0
	{"movbe\0"
		"???\0"
		"crc32\0"
		"???",              MODRM|VAR_NAME4,    PARAM_REG32,            PARAM_RMPTR,            0               }, // not quite correct
	{"movbe\0"
		"???\0"
		"crc32\0"
		"???",              MODRM|VAR_NAME4,    PARAM_RMPTR,            PARAM_REG32,            0               }, // not quite correct
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
};

static const I386_OPCODE i386_opcode_table0F3A[256] =
{
	// 0x00
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"roundps\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"roundpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"roundss\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"roundsd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"blendps\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"blendpd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"pblendw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"palignr\0"
		"palignr\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	// 0x10
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"pextrb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_RM8,          PARAM_XMM,          PARAM_UI8           },
	{"???\0"
		"pextrw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_RM16,         PARAM_XMM,          PARAM_UI8           },
	{"???\0"
		"pextrd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_RM8,          PARAM_XMM,          PARAM_UI8           },
	{"???\0"
		"extractps\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_RM32,         PARAM_XMM,          PARAM_UI8           },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x20
	{"???\0"
		"pinsrb\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_RM8,          PARAM_UI8           },
	{"???\0"
		"insertps\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_RM8,          PARAM_UI8           },
	{"???\0"
		"pinsrd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_RM32,         PARAM_UI8           },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x30
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x40
	{"???\0"
		"dpps\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"dppd\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"mpsadbw\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"pclmulqdq\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x50
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x60
	{"???\0"
		"pcmestrm\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"pcmestri\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"pcmistrm\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???\0"
		"pcmistri\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x70
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x80
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0x90
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xa0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xb0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xc0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xd0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???\0"
		"aeskeygenassist\0"
		"???\0"
		"???",              MODRM|VAR_NAME4,    PARAM_XMM,          PARAM_XMMM,         PARAM_UI8           },
	// 0xe0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	// 0xf0
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
	{"???",             0,              0,          0,              0               },
};

static const I386_OPCODE group80_table[8] =
{
	{"add",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"or",              0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"adc",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"sbb",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"and",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"sub",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"xor",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"cmp",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               }
};

static const I386_OPCODE group81_table[8] =
{
	{"add",             0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"or",              0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"adc",             0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"sbb",             0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"and",             0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"sub",             0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"xor",             0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"cmp",             0,              PARAM_RMPTR,        PARAM_IMM,          0               }
};

static const I386_OPCODE group83_table[8] =
{
	{"add",             0,              PARAM_RMPTR,        PARAM_I8,           0               },
	{"or",              0,              PARAM_RMPTR,        PARAM_I8,           0               },
	{"adc",             0,              PARAM_RMPTR,        PARAM_I8,           0               },
	{"sbb",             0,              PARAM_RMPTR,        PARAM_I8,           0               },
	{"and",             0,              PARAM_RMPTR,        PARAM_I8,           0               },
	{"sub",             0,              PARAM_RMPTR,        PARAM_I8,           0               },
	{"xor",             0,              PARAM_RMPTR,        PARAM_I8,           0               },
	{"cmp",             0,              PARAM_RMPTR,        PARAM_I8,           0               }
};

static const I386_OPCODE groupC0_table[8] =
{
	{"rol",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"ror",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"rcl",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"rcr",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"shl",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"shr",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"sal",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"sar",             0,              PARAM_RMPTR8,       PARAM_UI8,          0               }
};

static const I386_OPCODE groupC1_table[8] =
{
	{"rol",             0,              PARAM_RMPTR,        PARAM_UI8,          0               },
	{"ror",             0,              PARAM_RMPTR,        PARAM_UI8,          0               },
	{"rcl",             0,              PARAM_RMPTR,        PARAM_UI8,          0               },
	{"rcr",             0,              PARAM_RMPTR,        PARAM_UI8,          0               },
	{"shl",             0,              PARAM_RMPTR,        PARAM_UI8,          0               },
	{"shr",             0,              PARAM_RMPTR,        PARAM_UI8,          0               },
	{"sal",             0,              PARAM_RMPTR,        PARAM_UI8,          0               },
	{"sar",             0,              PARAM_RMPTR,        PARAM_UI8,          0               }
};

static const I386_OPCODE groupD0_table[8] =
{
	{"rol",             0,              PARAM_RMPTR8,       PARAM_1,            0               },
	{"ror",             0,              PARAM_RMPTR8,       PARAM_1,            0               },
	{"rcl",             0,              PARAM_RMPTR8,       PARAM_1,            0               },
	{"rcr",             0,              PARAM_RMPTR8,       PARAM_1,            0               },
	{"shl",             0,              PARAM_RMPTR8,       PARAM_1,            0               },
	{"shr",             0,              PARAM_RMPTR8,       PARAM_1,            0               },
	{"sal",             0,              PARAM_RMPTR8,       PARAM_1,            0               },
	{"sar",             0,              PARAM_RMPTR8,       PARAM_1,            0               }
};

static const I386_OPCODE groupD1_table[8] =
{
	{"rol",             0,              PARAM_RMPTR,        PARAM_1,            0               },
	{"ror",             0,              PARAM_RMPTR,        PARAM_1,            0               },
	{"rcl",             0,              PARAM_RMPTR,        PARAM_1,            0               },
	{"rcr",             0,              PARAM_RMPTR,        PARAM_1,            0               },
	{"shl",             0,              PARAM_RMPTR,        PARAM_1,            0               },
	{"shr",             0,              PARAM_RMPTR,        PARAM_1,            0               },
	{"sal",             0,              PARAM_RMPTR,        PARAM_1,            0               },
	{"sar",             0,              PARAM_RMPTR,        PARAM_1,            0               }
};

static const I386_OPCODE groupD2_table[8] =
{
	{"rol",             0,              PARAM_RMPTR8,       PARAM_CL,           0               },
	{"ror",             0,              PARAM_RMPTR8,       PARAM_CL,           0               },
	{"rcl",             0,              PARAM_RMPTR8,       PARAM_CL,           0               },
	{"rcr",             0,              PARAM_RMPTR8,       PARAM_CL,           0               },
	{"shl",             0,              PARAM_RMPTR8,       PARAM_CL,           0               },
	{"shr",             0,              PARAM_RMPTR8,       PARAM_CL,           0               },
	{"sal",             0,              PARAM_RMPTR8,       PARAM_CL,           0               },
	{"sar",             0,              PARAM_RMPTR8,       PARAM_CL,           0               }
};

static const I386_OPCODE groupD3_table[8] =
{
	{"rol",             0,              PARAM_RMPTR,        PARAM_CL,           0               },
	{"ror",             0,              PARAM_RMPTR,        PARAM_CL,           0               },
	{"rcl",             0,              PARAM_RMPTR,        PARAM_CL,           0               },
	{"rcr",             0,              PARAM_RMPTR,        PARAM_CL,           0               },
	{"shl",             0,              PARAM_RMPTR,        PARAM_CL,           0               },
	{"shr",             0,              PARAM_RMPTR,        PARAM_CL,           0               },
	{"sal",             0,              PARAM_RMPTR,        PARAM_CL,           0               },
	{"sar",             0,              PARAM_RMPTR,        PARAM_CL,           0               }
};

static const I386_OPCODE groupF6_table[8] =
{
	{"test",            0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"test",            0,              PARAM_RMPTR8,       PARAM_UI8,          0               },
	{"not",             0,              PARAM_RMPTR8,       0,                  0               },
	{"neg",             0,              PARAM_RMPTR8,       0,                  0               },
	{"mul",             0,              PARAM_RMPTR8,       0,                  0               },
	{"imul",            0,              PARAM_RMPTR8,       0,                  0               },
	{"div",             0,              PARAM_RMPTR8,       0,                  0               },
	{"idiv",            0,              PARAM_RMPTR8,       0,                  0               }
};

static const I386_OPCODE groupF7_table[8] =
{
	{"test",            0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"test",            0,              PARAM_RMPTR,        PARAM_IMM,          0               },
	{"not",             0,              PARAM_RMPTR,        0,                  0               },
	{"neg",             0,              PARAM_RMPTR,        0,                  0               },
	{"mul",             0,              PARAM_RMPTR,        0,                  0               },
	{"imul",            0,              PARAM_RMPTR,        0,                  0               },
	{"div",             0,              PARAM_RMPTR,        0,                  0               },
	{"idiv",            0,              PARAM_RMPTR,        0,                  0               }
};

static const I386_OPCODE groupFE_table[8] =
{
	{"inc",             0,              PARAM_RMPTR8,       0,                  0               },
	{"dec",             0,              PARAM_RMPTR8,       0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE groupFF_table[8] =
{
	{"inc",             0,              PARAM_RMPTR,        0,                  0               },
	{"dec",             0,              PARAM_RMPTR,        0,                  0               },
	{"call",            ALWAYS64,       PARAM_RMPTR,        0,                  0,              DASMFLAG_STEP_OVER},
	{"call    far ptr ",0,              PARAM_RM,           0,                  0,              DASMFLAG_STEP_OVER},
	{"jmp",             ALWAYS64,       PARAM_RMPTR,        0,                  0               },
	{"jmp     far ptr ",0,              PARAM_RM,           0,                  0               },
	{"push",            0,              PARAM_RMPTR,        0,                  0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE group0F00_table[8] =
{
	{"sldt",            0,              PARAM_RM,           0,                  0               },
	{"str",             0,              PARAM_RM,           0,                  0               },
	{"lldt",            0,              PARAM_RM,           0,                  0               },
	{"ltr",             0,              PARAM_RM,           0,                  0               },
	{"verr",            0,              PARAM_RM,           0,                  0               },
	{"verw",            0,              PARAM_RM,           0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE group0F01_table[8] =
{
	{"sgdt",            0,              PARAM_RM,           0,                  0               },
	{"sidt",            0,              PARAM_RM,           0,                  0               },
	{"lgdt",            0,              PARAM_RM,           0,                  0               },
	{"lidt",            0,              PARAM_RM,           0,                  0               },
	{"smsw",            0,              PARAM_RM,           0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"lmsw",            0,              PARAM_RM,           0,                  0               },
	{"invlpg",          0,              PARAM_RM,           0,                  0               }
};

static const I386_OPCODE group0F0D_table[8] =
{
	{"prefetch",        0,              PARAM_RM8,          0,                  0               },
	{"prefetchw",       0,              PARAM_RM8,          0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE group0F12_table[4] =
{
	{ "movlps\0"
		"movlpd\0"
		"movddup\0"
		"movsldup",     VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{ "movlps\0"
		"movlpd\0"
		"movddup\0"
		"movsldup",     VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{ "movlps\0"
		"movlpd\0"
		"movddup\0"
		"movsldup",     VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               },
	{ "movhlps\0"
		"???\0"
		"movddup\0"
		"movsldup",     VAR_NAME4,PARAM_XMM,          PARAM_XMMM,         0               }
};

static const I386_OPCODE group0F16_table[4] =
{
	{ "movhps\0"
		"movhpd\0"
		"???\0"
		"movshdup",     VAR_NAME4,PARAM_XMM,         PARAM_XMMM,          0               },
	{ "movhps\0"
		"movhpd\0"
		"???\0"
		"movshdup",     VAR_NAME4,PARAM_XMM,         PARAM_XMMM,          0               },
	{ "movhps\0"
		"movhpd\0"
		"???\0"
		"movshdup",     VAR_NAME4,PARAM_XMM,         PARAM_XMMM,          0               },
	{ "movlhps\0"
		"movhpd\0"
		"???\0"
		"movshdup",     VAR_NAME4,PARAM_XMM,         PARAM_XMMM,          0               }
};

static const I386_OPCODE group0F18_table[8] =
{
	{"prefetchnta",     0,              PARAM_RM8,          0,                  0               },
	{"prefetch0",       0,              PARAM_RM8,          0,                  0               },
	{"prefetch1",       0,              PARAM_RM8,          0,                  0               },
	{"prefetch2",       0,              PARAM_RM8,          0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE group0F71_table[8] =
{
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"psrlw",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"???",             0,              0,                  0,                  0               },
	{"psraw",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"???",             0,              0,                  0,                  0               },
	{"psllw",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE group0F72_table[8] =
{
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"psrld",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"???",             0,              0,                  0,                  0               },
	{"psrad",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"???",             0,              0,                  0,                  0               },
	{"pslld",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"???",             0,              0,                  0,                  0               }
};

static const I386_OPCODE group0F73_table[8] =
{
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"psrlq",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"psrldq",          0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"psllq",           0,              PARAM_MMX2,         PARAM_UI8,          0               },
	{"pslldq",          0,              PARAM_MMX2,         PARAM_UI8,          0               },
};

static const I386_OPCODE group0FAE_table[8] =
{
	{"fxsave",          0,              PARAM_RM,           0,                  0               },
	{"fxrstor",         0,              PARAM_RM,           0,                  0               },
	{"ldmxcsr",         0,              PARAM_RM,           0,                  0               },
	{"stmxscr",         0,              PARAM_RM,           0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"lfence",          0,              0,                  0,                  0               },
	{"mfence",          0,              0,                  0,                  0               },
	{"sfence",          0,              0,                  0,                  0               }
};


static const I386_OPCODE group0FBA_table[8] =
{
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"bt",              0,              PARAM_RM,           PARAM_UI8,          0               },
	{"bts",             0,              PARAM_RM,           PARAM_UI8,          0               },
	{"btr",             0,              PARAM_RM,           PARAM_UI8,          0               },
	{"btc",             0,              PARAM_RM,           PARAM_UI8,          0               }
};

static const I386_OPCODE group0FC7_table[8] =
{
	{"???",             0,              0,                  0,                  0               },
	{"cmpxchg8b",           MODRM,              PARAM_M64PTR,               0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"???",             0,              0,                  0,                  0               },
	{"vmptrld\0"
		"vmclear\0"
		"???\0"
		"vmxon",            MODRM|VAR_NAME4,        PARAM_M64PTR,               0,                  0               },
	{"vmptrtst",            MODRM,              PARAM_M64PTR,               0,                  0               }
};

static const GROUP_OP group_op_table[] =
{
	{ "group80",            group80_table           },
	{ "group81",            group81_table           },
	{ "group83",            group83_table           },
	{ "groupC0",            groupC0_table           },
	{ "groupC1",            groupC1_table           },
	{ "groupD0",            groupD0_table           },
	{ "groupD1",            groupD1_table           },
	{ "groupD2",            groupD2_table           },
	{ "groupD3",            groupD3_table           },
	{ "groupF6",            groupF6_table           },
	{ "groupF7",            groupF7_table           },
	{ "groupFE",            groupFE_table           },
	{ "groupFF",            groupFF_table           },
	{ "group0F00",          group0F00_table         },
	{ "group0F01",          group0F01_table         },
	{ "group0F0D",          group0F0D_table         },
	{ "group0F12",          group0F12_table         },
	{ "group0F16",          group0F16_table         },
	{ "group0F18",          group0F18_table         },
	{ "group0F71",          group0F71_table         },
	{ "group0F72",          group0F72_table         },
	{ "group0F73",          group0F73_table         },
	{ "group0FAE",          group0FAE_table         },
	{ "group0FBA",          group0FBA_table         },
	{ "group0FC7",          group0FC7_table         }
};



static const char *const i386_reg[3][16] =
{
	{"ax",  "cx",  "dx",  "bx",  "sp",  "bp",  "si",  "di",  "r8w", "r9w", "r10w","r11w","r12w","r13w","r14w","r15w"},
	{"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d","r11d","r12d","r13d","r14d","r15d"},
	{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15"}
};

static const char *const i386_reg8[8] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
static const char *const i386_reg8rex[16] = {"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"};
static const char *const i386_sreg[8] = {"es", "cs", "ss", "ds", "fs", "gs", "???", "???"};

static int address_size;
static int operand_size;
static int address_prefix;
static int operand_prefix;
static int max_length;
static uint64_t pc;
static uint8_t modrm;
static uint32_t segment;
static offs_t dasm_flags;
static std::string modrm_string;
static uint8_t rex, regex, sibex, rmex;
static uint8_t pre0f;
static uint8_t curmode;

#define MODRM_REG1  ((modrm >> 3) & 0x7)
#define MODRM_REG2  (modrm & 0x7)
#define MODRM_MOD   ((modrm >> 6) & 0x3)

static inline uint8_t FETCH(void)
{
	if ((opcode_ptr - opcode_ptr_base) + 1 > max_length)
		return 0xff;
	pc++;
	return *opcode_ptr++;
}

#if 0
static inline uint16_t FETCH16(void)
{
	uint16_t d;
	if ((opcode_ptr - opcode_ptr_base) + 2 > max_length)
		return 0xffff;
	d = opcode_ptr[0] | (opcode_ptr[1] << 8);
	opcode_ptr += 2;
	pc += 2;
	return d;
}
#endif

static inline uint32_t FETCH32(void)
{
	uint32_t d;
	if ((opcode_ptr - opcode_ptr_base) + 4 > max_length)
		return 0xffffffff;
	d = opcode_ptr[0] | (opcode_ptr[1] << 8) | (opcode_ptr[2] << 16) | (opcode_ptr[3] << 24);
	opcode_ptr += 4;
	pc += 4;
	return d;
}

static inline uint8_t FETCHD(void)
{
	if ((opcode_ptr - opcode_ptr_base) + 1 > max_length)
		return 0xff;
	pc++;
	return *opcode_ptr++;
}

static inline uint16_t FETCHD16(void)
{
	uint16_t d;
	if ((opcode_ptr - opcode_ptr_base) + 2 > max_length)
		return 0xffff;
	d = opcode_ptr[0] | (opcode_ptr[1] << 8);
	opcode_ptr += 2;
	pc += 2;
	return d;
}

static inline uint32_t FETCHD32(void)
{
	uint32_t d;
	if ((opcode_ptr - opcode_ptr_base) + 4 > max_length)
		return 0xffffffff;
	d = opcode_ptr[0] | (opcode_ptr[1] << 8) | (opcode_ptr[2] << 16) | (opcode_ptr[3] << 24);
	opcode_ptr += 4;
	pc += 4;
	return d;
}

static char *hexstring(uint32_t value, int digits)
{
	static char buffer[20];
	buffer[0] = '0';
	if (digits)
		sprintf(&buffer[1], "%0*Xh", digits, value);
	else
		sprintf(&buffer[1], "%Xh", value);
	return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0];
}

static char *hexstring64(uint32_t lo, uint32_t hi)
{
	static char buffer[40];
	buffer[0] = '0';
	if (hi != 0)
		sprintf(&buffer[1], "%X%08Xh", hi, lo);
	else
		sprintf(&buffer[1], "%Xh", lo);
	return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0];
}

static char *hexstringpc(uint64_t pc)
{
	if (curmode == 64)
		return hexstring64((uint32_t)pc, (uint32_t)(pc >> 32));
	else
		return hexstring((uint32_t)pc, 0);
}

static char *shexstring(uint32_t value, int digits, bool always)
{
	static char buffer[20];
	if (value >= 0x80000000)
		sprintf(buffer, "-%s", hexstring(-value, digits));
	else if (always)
		sprintf(buffer, "+%s", hexstring(value, digits));
	else
		return hexstring(value, digits);
	return buffer;
}

static void handle_sib_byte(std::ostream &stream, uint8_t mod)
{
	uint32_t i32;
	uint8_t scale, i, base;
	uint8_t sib = FETCHD();

	scale = (sib >> 6) & 0x3;
	i = ((sib >> 3) & 0x7) | sibex;
	base = (sib & 0x7) | rmex;

	if (base == 5 && mod == 0) {
		i32 = FETCH32();
		util::stream_format(stream, "%s", hexstring(i32, 0));
	} else if (base != 5 || mod != 3)
		util::stream_format(stream, "%s", i386_reg[address_size][base]);

	if ( i != 4 ) {
		util::stream_format(stream, "+%s", i386_reg[address_size][i]);
		if (scale)
			util::stream_format(stream, "*%d", 1 << scale);
	}
}

static void handle_modrm(std::ostream &stream)
{
	int8_t disp8;
	int16_t disp16;
	int32_t disp32;
	uint8_t mod, rm;

	modrm = FETCHD();
	mod = (modrm >> 6) & 0x3;
	rm = (modrm & 0x7) | rmex;

	if( modrm >= 0xc0 )
		return;

	switch(segment)
	{
		case SEG_CS: util::stream_format(stream, "cs:"); break;
		case SEG_DS: util::stream_format(stream, "ds:"); break;
		case SEG_ES: util::stream_format(stream, "es:"); break;
		case SEG_FS: util::stream_format(stream, "fs:"); break;
		case SEG_GS: util::stream_format(stream, "gs:"); break;
		case SEG_SS: util::stream_format(stream, "ss:"); break;
	}

	util::stream_format(stream, "[" );
	if( address_size == 2 ) {
		if ((rm & 7) == 4)
			handle_sib_byte(stream, mod );
		else if ((rm & 7) == 5 && mod == 0) {
			disp32 = FETCHD32();
			util::stream_format(stream, "rip%s", shexstring(disp32, 0, true));
		} else
			util::stream_format(stream, "%s", i386_reg[2][rm]);
		if( mod == 1 ) {
			disp8 = FETCHD();
			if (disp8 != 0)
				util::stream_format(stream, "%s", shexstring((int32_t)disp8, 0, true) );
		} else if( mod == 2 ) {
			disp32 = FETCHD32();
			if (disp32 != 0)
				util::stream_format(stream, "%s", shexstring(disp32, 0, true) );
		}
	} else if (address_size == 1) {
		if ((rm & 7) == 4)
			handle_sib_byte(stream, mod );
		else if ((rm & 7) == 5 && mod == 0) {
			disp32 = FETCHD32();
			if (curmode == 64)
				util::stream_format(stream, "eip%s", shexstring(disp32, 0, true) );
			else
				util::stream_format(stream, "%s", hexstring(disp32, 0) );
		} else
			util::stream_format(stream, "%s", i386_reg[1][rm]);
		if( mod == 1 ) {
			disp8 = FETCHD();
			if (disp8 != 0)
				util::stream_format(stream, "%s", shexstring((int32_t)disp8, 0, true) );
		} else if( mod == 2 ) {
			disp32 = FETCHD32();
			if (disp32 != 0)
				util::stream_format(stream, "%s", shexstring(disp32, 0, true) );
		}
	} else {
		switch( rm )
		{
			case 0: util::stream_format(stream, "bx+si" ); break;
			case 1: util::stream_format(stream, "bx+di" ); break;
			case 2: util::stream_format(stream, "bp+si" ); break;
			case 3: util::stream_format(stream, "bp+di" ); break;
			case 4: util::stream_format(stream, "si" ); break;
			case 5: util::stream_format(stream, "di" ); break;
			case 6:
				if( mod == 0 ) {
					disp16 = FETCHD16();
					util::stream_format(stream, "%s", hexstring((unsigned) (uint16_t) disp16, 0) );
				} else {
					util::stream_format(stream, "bp" );
				}
				break;
			case 7: util::stream_format(stream, "bx" ); break;
		}
		if( mod == 1 ) {
			disp8 = FETCHD();
			if (disp8 != 0)
				util::stream_format(stream, "%s", shexstring((int32_t)disp8, 0, true) );
		} else if( mod == 2 ) {
			disp16 = FETCHD16();
			if (disp16 != 0)
				util::stream_format(stream, "%s", shexstring((int32_t)disp16, 0, true) );
		}
	}
	util::stream_format(stream, "]" );
}

static void handle_modrm(std::string &buffer)
{
	std::stringstream stream;
	handle_modrm(stream);
	buffer = stream.str();
}

static void handle_param(std::ostream &stream, uint32_t param)
{
	uint8_t i8;
	uint16_t i16;
	uint32_t i32;
	uint16_t ptr;
	uint32_t addr;
	int8_t d8;
	int16_t d16;
	int32_t d32;

	switch(param)
	{
		case PARAM_REG:
			util::stream_format(stream, "%s", i386_reg[operand_size][MODRM_REG1 | regex] );
			break;

		case PARAM_REG8:
			util::stream_format(stream, "%s", (rex ? i386_reg8rex : i386_reg8)[MODRM_REG1 | regex] );
			break;

		case PARAM_REG16:
			util::stream_format(stream, "%s", i386_reg[0][MODRM_REG1 | regex] );
			break;

		case PARAM_REG32:
			util::stream_format(stream, "%s", i386_reg[1][MODRM_REG1 | regex] );
			break;

		case PARAM_REG3264:
			util::stream_format(stream, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG1 | regex] );
			break;

		case PARAM_MMX:
			if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3)
				util::stream_format(stream, "xmm%d", MODRM_REG1 | regex );
			else
				util::stream_format(stream, "mm%d", MODRM_REG1 | regex );
			break;

		case PARAM_MMX2:
			if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3)
				util::stream_format(stream, "xmm%d", MODRM_REG2 | regex );
			else
				util::stream_format(stream, "mm%d", MODRM_REG2 | regex );
			break;

		case PARAM_XMM:
			util::stream_format(stream, "xmm%d", MODRM_REG1 | regex );
			break;

		case PARAM_REGORXMM:
			if (pre0f != 0xf2 && pre0f != 0xf3)
				util::stream_format(stream, "xmm%d", MODRM_REG1 | regex );
			else
				util::stream_format(stream, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG1 | regex] );
			break;

		case PARAM_REG2_32:
			util::stream_format(stream, "%s", i386_reg[1][MODRM_REG2 | rmex] );
			break;

		case PARAM_RM:
		case PARAM_RMPTR:
			if( modrm >= 0xc0 ) {
				util::stream_format(stream, "%s", i386_reg[operand_size][MODRM_REG2 | rmex] );
			} else {
				if (param == PARAM_RMPTR)
				{
					if( operand_size == 2 )
						util::stream_format(stream, "qword ptr " );
					else if (operand_size == 1)
						util::stream_format(stream, "dword ptr " );
					else
						util::stream_format(stream, "word ptr " );
				}
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_RM8:
		case PARAM_RMPTR8:
			if( modrm >= 0xc0 ) {
				util::stream_format(stream, "%s", (rex ? i386_reg8rex : i386_reg8)[MODRM_REG2 | rmex] );
			} else {
				if (param == PARAM_RMPTR8)
					util::stream_format(stream, "byte ptr " );
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_RM16:
		case PARAM_RMPTR16:
			if( modrm >= 0xc0 ) {
				util::stream_format(stream, "%s", i386_reg[0][MODRM_REG2 | rmex] );
			} else {
				if (param == PARAM_RMPTR16)
					util::stream_format(stream, "word ptr " );
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_RM32:
		case PARAM_RMPTR32:
			if( modrm >= 0xc0 ) {
				util::stream_format(stream, "%s", i386_reg[1][MODRM_REG2 | rmex] );
			} else {
				if (param == PARAM_RMPTR32)
					util::stream_format(stream, "dword ptr " );
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_RMXMM:
			if( modrm >= 0xc0 ) {
				if (pre0f != 0xf2 && pre0f != 0xf3)
					util::stream_format(stream, "xmm%d", MODRM_REG2 | rmex );
				else
					util::stream_format(stream, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG2 | rmex] );
			} else {
				if (param == PARAM_RMPTR32)
					util::stream_format(stream, "dword ptr " );
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_M64:
		case PARAM_M64PTR:
			if( modrm >= 0xc0 ) {
				util::stream_format(stream, "???" );
			} else {
				if (param == PARAM_M64PTR)
					util::stream_format(stream, "qword ptr " );
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_MMXM:
			if( modrm >= 0xc0 ) {
				if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3)
					util::stream_format(stream, "xmm%d", MODRM_REG2 | rmex );
				else
					util::stream_format(stream, "mm%d", MODRM_REG2 | rmex );
			} else {
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_XMMM:
			if( modrm >= 0xc0 ) {
				util::stream_format(stream, "xmm%d", MODRM_REG2 | rmex );
			} else {
				util::stream_format(stream, "%s", modrm_string );
			}
			break;

		case PARAM_I4:
			i8 = FETCHD();
			util::stream_format(stream, "%d", i8 & 0x0f );
			break;

		case PARAM_I8:
			i8 = FETCHD();
			util::stream_format(stream, "%s", shexstring((int8_t)i8, 0, false) );
			break;

		case PARAM_I16:
			i16 = FETCHD16();
			util::stream_format(stream, "%s", shexstring((int16_t)i16, 0, false) );
			break;

		case PARAM_UI8:
			i8 = FETCHD();
			util::stream_format(stream, "%s", shexstring((uint8_t)i8, 0, false) );
			break;

		case PARAM_UI16:
			i16 = FETCHD16();
			util::stream_format(stream, "%s", shexstring((uint16_t)i16, 0, false) );
			break;

		case PARAM_IMM64:
			if (operand_size == 2) {
				uint32_t lo32 = FETCHD32();
				i32 = FETCHD32();
				util::stream_format(stream, "%s", hexstring64(lo32, i32) );
			} else if( operand_size ) {
				i32 = FETCHD32();
				util::stream_format(stream, "%s", hexstring(i32, 0) );
			} else {
				i16 = FETCHD16();
				util::stream_format(stream, "%s", hexstring(i16, 0) );
			}
			break;

		case PARAM_IMM:
			if( operand_size ) {
				i32 = FETCHD32();
				util::stream_format(stream, "%s", hexstring(i32, 0) );
			} else {
				i16 = FETCHD16();
				util::stream_format(stream, "%s", hexstring(i16, 0) );
			}
			break;

		case PARAM_ADDR:
			if( operand_size ) {
				addr = FETCHD32();
				ptr = FETCHD16();
				util::stream_format(stream, "%s:", hexstring(ptr, 4) );
				util::stream_format(stream, "%s", hexstring(addr, 0) );
			} else {
				addr = FETCHD16();
				ptr = FETCHD16();
				util::stream_format(stream, "%s:", hexstring(ptr, 4) );
				util::stream_format(stream, "%s", hexstring(addr, 0) );
			}
			break;

		case PARAM_REL:
			if( operand_size ) {
				d32 = FETCHD32();
				util::stream_format(stream, "%s", hexstringpc(pc + d32) );
			} else {
				/* make sure to keep the relative offset within the segment */
				d16 = FETCHD16();
				util::stream_format(stream, "%s", hexstringpc((pc & 0xFFFF0000) | ((pc + d16) & 0x0000FFFF)) );
			}
			break;

		case PARAM_REL8:
			d8 = FETCHD();
			util::stream_format(stream, "%s", hexstringpc(pc + d8) );
			break;

		case PARAM_MEM_OFFS:
			switch(segment)
			{
				case SEG_CS: util::stream_format(stream, "cs:" ); break;
				case SEG_DS: util::stream_format(stream, "ds:" ); break;
				case SEG_ES: util::stream_format(stream, "es:" ); break;
				case SEG_FS: util::stream_format(stream, "fs:" ); break;
				case SEG_GS: util::stream_format(stream, "gs:" ); break;
				case SEG_SS: util::stream_format(stream, "ss:" ); break;
			}

			if( address_size ) {
				i32 = FETCHD32();
				util::stream_format(stream, "[%s]", hexstring(i32, 0) );
			} else {
				i16 = FETCHD16();
				util::stream_format(stream, "[%s]", hexstring(i16, 0) );
			}
			break;

		case PARAM_PREIMP:
			switch(segment)
			{
				case SEG_CS: util::stream_format(stream, "cs:" ); break;
				case SEG_DS: util::stream_format(stream, "ds:" ); break;
				case SEG_ES: util::stream_format(stream, "es:" ); break;
				case SEG_FS: util::stream_format(stream, "fs:" ); break;
				case SEG_GS: util::stream_format(stream, "gs:" ); break;
				case SEG_SS: util::stream_format(stream, "ss:" ); break;
			}
			break;

		case PARAM_SREG:
			util::stream_format(stream, "%s", i386_sreg[MODRM_REG1] );
			break;

		case PARAM_CREG:
			util::stream_format(stream, "cr%d", MODRM_REG1 | regex );
			break;

		case PARAM_TREG:
			util::stream_format(stream, "tr%d", MODRM_REG1 | regex );
			break;

		case PARAM_DREG:
			util::stream_format(stream, "dr%d", MODRM_REG1 | regex );
			break;

		case PARAM_1:
			util::stream_format(stream, "1" );
			break;

		case PARAM_DX:
			util::stream_format(stream, "dx" );
			break;

		case PARAM_XMM0:
			util::stream_format(stream, "xmm0" );
			break;

		case PARAM_AL: util::stream_format(stream, "al" ); break;
		case PARAM_CL: util::stream_format(stream, "cl" ); break;
		case PARAM_DL: util::stream_format(stream, "dl" ); break;
		case PARAM_BL: util::stream_format(stream, "bl" ); break;
		case PARAM_AH: util::stream_format(stream, "ah" ); break;
		case PARAM_CH: util::stream_format(stream, "ch" ); break;
		case PARAM_DH: util::stream_format(stream, "dh" ); break;
		case PARAM_BH: util::stream_format(stream, "bh" ); break;

		case PARAM_EAX: util::stream_format(stream, "%s", i386_reg[operand_size][0 | rmex] ); break;
		case PARAM_ECX: util::stream_format(stream, "%s", i386_reg[operand_size][1 | rmex] ); break;
		case PARAM_EDX: util::stream_format(stream, "%s", i386_reg[operand_size][2 | rmex] ); break;
		case PARAM_EBX: util::stream_format(stream, "%s", i386_reg[operand_size][3 | rmex] ); break;
		case PARAM_ESP: util::stream_format(stream, "%s", i386_reg[operand_size][4 | rmex] ); break;
		case PARAM_EBP: util::stream_format(stream, "%s", i386_reg[operand_size][5 | rmex] ); break;
		case PARAM_ESI: util::stream_format(stream, "%s", i386_reg[operand_size][6 | rmex] ); break;
		case PARAM_EDI: util::stream_format(stream, "%s", i386_reg[operand_size][7 | rmex] ); break;
	}
}

static void handle_fpu(std::ostream &stream, uint8_t op1, uint8_t op2)
{
	switch (op1 & 0x7)
	{
		case 0:     // Group D8
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fadd    dword ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "fmul    dword ptr %s", modrm_string); break;
					case 2: util::stream_format(stream, "fcom    dword ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "fcomp   dword ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "fsub    dword ptr %s", modrm_string); break;
					case 5: util::stream_format(stream, "fsubr   dword ptr %s", modrm_string); break;
					case 6: util::stream_format(stream, "fdiv    dword ptr %s", modrm_string); break;
					case 7: util::stream_format(stream, "fdivr   dword ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fadd    st(0),st(%d)", op2 & 0x7); break;
					case 1: util::stream_format(stream, "fmul    st(0),st(%d)", op2 & 0x7); break;
					case 2: util::stream_format(stream, "fcom    st(0),st(%d)", op2 & 0x7); break;
					case 3: util::stream_format(stream, "fcomp   st(0),st(%d)", op2 & 0x7); break;
					case 4: util::stream_format(stream, "fsub    st(0),st(%d)", op2 & 0x7); break;
					case 5: util::stream_format(stream, "fsubr   st(0),st(%d)", op2 & 0x7); break;
					case 6: util::stream_format(stream, "fdiv    st(0),st(%d)", op2 & 0x7); break;
					case 7: util::stream_format(stream, "fdivr   st(0),st(%d)", op2 & 0x7); break;
				}
			}
			break;
		}

		case 1:     // Group D9
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fld     dword ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "??? (FPU)"); break;
					case 2: util::stream_format(stream, "fst     dword ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "fstp    dword ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "fldenv  word ptr %s", modrm_string); break;
					case 5: util::stream_format(stream, "fldcw   word ptr %s", modrm_string); break;
					case 6: util::stream_format(stream, "fstenv  word ptr %s", modrm_string); break;
					case 7: util::stream_format(stream, "fstcw   word ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch (op2 & 0x3f)
				{
					case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
						util::stream_format(stream, "fld     st(0),st(%d)", op2 & 0x7); break;

					case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
						util::stream_format(stream, "fxch    st(0),st(%d)", op2 & 0x7); break;

					case 0x10: util::stream_format(stream, "fnop"); break;
					case 0x20: util::stream_format(stream, "fchs"); break;
					case 0x21: util::stream_format(stream, "fabs"); break;
					case 0x24: util::stream_format(stream, "ftst"); break;
					case 0x25: util::stream_format(stream, "fxam"); break;
					case 0x28: util::stream_format(stream, "fld1"); break;
					case 0x29: util::stream_format(stream, "fldl2t"); break;
					case 0x2a: util::stream_format(stream, "fldl2e"); break;
					case 0x2b: util::stream_format(stream, "fldpi"); break;
					case 0x2c: util::stream_format(stream, "fldlg2"); break;
					case 0x2d: util::stream_format(stream, "fldln2"); break;
					case 0x2e: util::stream_format(stream, "fldz"); break;
					case 0x30: util::stream_format(stream, "f2xm1"); break;
					case 0x31: util::stream_format(stream, "fyl2x"); break;
					case 0x32: util::stream_format(stream, "fptan"); break;
					case 0x33: util::stream_format(stream, "fpatan"); break;
					case 0x34: util::stream_format(stream, "fxtract"); break;
					case 0x35: util::stream_format(stream, "fprem1"); break;
					case 0x36: util::stream_format(stream, "fdecstp"); break;
					case 0x37: util::stream_format(stream, "fincstp"); break;
					case 0x38: util::stream_format(stream, "fprem"); break;
					case 0x39: util::stream_format(stream, "fyl2xp1"); break;
					case 0x3a: util::stream_format(stream, "fsqrt"); break;
					case 0x3b: util::stream_format(stream, "fsincos"); break;
					case 0x3c: util::stream_format(stream, "frndint"); break;
					case 0x3d: util::stream_format(stream, "fscale"); break;
					case 0x3e: util::stream_format(stream, "fsin"); break;
					case 0x3f: util::stream_format(stream, "fcos"); break;

					default: util::stream_format(stream, "??? (FPU)"); break;
				}
			}
			break;
		}

		case 2:     // Group DA
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fiadd   dword ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "fimul   dword ptr %s", modrm_string); break;
					case 2: util::stream_format(stream, "ficom   dword ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "ficomp  dword ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "fisub   dword ptr %s", modrm_string); break;
					case 5: util::stream_format(stream, "fisubr  dword ptr %s", modrm_string); break;
					case 6: util::stream_format(stream, "fidiv   dword ptr %s", modrm_string); break;
					case 7: util::stream_format(stream, "fidivr  dword ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch (op2 & 0x3f)
				{
					case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
						util::stream_format(stream, "fcmovb  st(0),st(%d)", op2 & 0x7); break;

					case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
						util::stream_format(stream, "fcmove  st(0),st(%d)", op2 & 0x7); break;

					case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
						util::stream_format(stream, "fcmovbe st(0),st(%d)", op2 & 0x7); break;

					case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
						util::stream_format(stream, "fcmovu  st(0),st(%d)", op2 & 0x7); break;
					case 0x29:
						util::stream_format(stream, "fucompp"); break;

					default: util::stream_format(stream, "??? (FPU)"); break;

				}
			}
			break;
		}

		case 3:     // Group DB
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fild    dword ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "fisttp  dword ptr %s", modrm_string); break;
					case 2: util::stream_format(stream, "fist    dword ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "fistp   dword ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "??? (FPU)"); break;
					case 5: util::stream_format(stream, "fld     tword ptr %s", modrm_string); break;
					case 6: util::stream_format(stream, "??? (FPU)"); break;
					case 7: util::stream_format(stream, "fstp    tword ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch (op2 & 0x3f)
				{
					case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
						util::stream_format(stream, "fcmovnb st(0),st(%d)", op2 & 0x7); break;

					case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
						util::stream_format(stream, "fcmovne st(0),st(%d)", op2 & 0x7); break;

					case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
						util::stream_format(stream, "fcmovnbe st(0),st(%d)", op2 & 0x7); break;

					case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
						util::stream_format(stream, "fcmovnu st(0),st(%d)", op2 & 0x7); break;

					case 0x22: util::stream_format(stream, "fclex"); break;
					case 0x23: util::stream_format(stream, "finit"); break;

					case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
						util::stream_format(stream, "fucomi  st(0),st(%d)", op2 & 0x7); break;

					case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
						util::stream_format(stream, "fcomi   st(0),st(%d)", op2 & 0x7); break;

					default: util::stream_format(stream, "??? (FPU)"); break;
				}
			}
			break;
		}

		case 4:     // Group DC
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fadd    qword ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "fmul    qword ptr %s", modrm_string); break;
					case 2: util::stream_format(stream, "fcom    qword ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "fcomp   qword ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "fsub    qword ptr %s", modrm_string); break;
					case 5: util::stream_format(stream, "fsubr   qword ptr %s", modrm_string); break;
					case 6: util::stream_format(stream, "fdiv    qword ptr %s", modrm_string); break;
					case 7: util::stream_format(stream, "fdivr   qword ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch (op2 & 0x3f)
				{
					case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
						util::stream_format(stream, "fadd    st(%d),st(0)", op2 & 0x7); break;

					case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
						util::stream_format(stream, "fmul    st(%d),st(0)", op2 & 0x7); break;

					case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
						util::stream_format(stream, "fsubr   st(%d),st(0)", op2 & 0x7); break;

					case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
						util::stream_format(stream, "fsub    st(%d),st(0)", op2 & 0x7); break;

					case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
						util::stream_format(stream, "fdivr   st(%d),st(0)", op2 & 0x7); break;

					case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
						util::stream_format(stream, "fdiv    st(%d),st(0)", op2 & 0x7); break;

					default: util::stream_format(stream, "??? (FPU)"); break;
				}
			}
			break;
		}

		case 5:     // Group DD
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fld     qword ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "fisttp  qword ptr %s", modrm_string); break;
					case 2: util::stream_format(stream, "fst     qword ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "fstp    qword ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "frstor  %s", modrm_string); break;
					case 5: util::stream_format(stream, "??? (FPU)"); break;
					case 6: util::stream_format(stream, "fsave   %s", modrm_string); break;
					case 7: util::stream_format(stream, "fstsw   word ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch (op2 & 0x3f)
				{
					case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
						util::stream_format(stream, "ffree   st(%d)", op2 & 0x7); break;

					case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
						util::stream_format(stream, "fst     st(%d)", op2 & 0x7); break;

					case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
						util::stream_format(stream, "fstp    st(%d)", op2 & 0x7); break;

					case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
						util::stream_format(stream, "fucom   st(%d), st(0)", op2 & 0x7); break;

					case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
						util::stream_format(stream, "fucomp  st(%d)", op2 & 0x7); break;

					default: util::stream_format(stream, "??? (FPU)"); break;
				}
			}
			break;
		}

		case 6:     // Group DE
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fiadd   word ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "fimul   word ptr %s", modrm_string); break;
					case 2: util::stream_format(stream, "ficom   word ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "ficomp  word ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "fisub   word ptr %s", modrm_string); break;
					case 5: util::stream_format(stream, "fisubr  word ptr %s", modrm_string); break;
					case 6: util::stream_format(stream, "fidiv   word ptr %s", modrm_string); break;
					case 7: util::stream_format(stream, "fidivr  word ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch (op2 & 0x3f)
				{
					case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
						util::stream_format(stream, "faddp   st(%d)", op2 & 0x7); break;

					case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
						util::stream_format(stream, "fmulp   st(%d)", op2 & 0x7); break;

					case 0x19: util::stream_format(stream, "fcompp"); break;

					case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
						util::stream_format(stream, "fsubrp  st(%d)", op2 & 0x7); break;

					case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
						util::stream_format(stream, "fsubp   st(%d)", op2 & 0x7); break;

					case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
						util::stream_format(stream, "fdivrp  st(%d), st(0)", op2 & 0x7); break;

					case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
						util::stream_format(stream, "fdivp   st(%d)", op2 & 0x7); break;

					default: util::stream_format(stream, "??? (FPU)"); break;
				}
			}
			break;
		}

		case 7:     // Group DF
		{
			if (op2 < 0xc0)
			{
				pc--;       // adjust fetch pointer, so modrm byte read again
				opcode_ptr--;
				handle_modrm( modrm_string );
				switch ((op2 >> 3) & 0x7)
				{
					case 0: util::stream_format(stream, "fild    word ptr %s", modrm_string); break;
					case 1: util::stream_format(stream, "fisttp  word ptr %s", modrm_string); break;
					case 2: util::stream_format(stream, "fist    word ptr %s", modrm_string); break;
					case 3: util::stream_format(stream, "fistp   word ptr %s", modrm_string); break;
					case 4: util::stream_format(stream, "fbld    %s", modrm_string); break;
					case 5: util::stream_format(stream, "fild    qword ptr %s", modrm_string); break;
					case 6: util::stream_format(stream, "fbstp   %s", modrm_string); break;
					case 7: util::stream_format(stream, "fistp   qword ptr %s", modrm_string); break;
				}
			}
			else
			{
				switch (op2 & 0x3f)
				{
					case 0x20: util::stream_format(stream, "fstsw   ax"); break;

					case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
						util::stream_format(stream, "fucomip st(%d)", op2 & 0x7); break;

					case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
						util::stream_format(stream, "fcomip  st(%d),st(0)", op2 & 0x7); break;

					default: util::stream_format(stream, "??? (FPU)"); break;
				}
			}
			break;
		}
	}
}

static void decode_opcode(std::ostream &stream, const I386_OPCODE *op, uint8_t op1)
{
	int i;
	uint8_t op2;

	if ((op->flags & SPECIAL64) && (address_size == 2))
		op = &x64_opcode_alt[op->flags >> 24];

	switch( op->flags & FLAGS_MASK )
	{
		case ISREX:
			if (curmode == 64)
			{
				rex = op1;
				operand_size = (op1 & 8) ? 2 : 1;
				regex = (op1 << 1) & 8;
				sibex = (op1 << 2) & 8;
				rmex = (op1 << 3) & 8;
				op2 = FETCH();
				decode_opcode(stream, &i386_opcode_table1[op2], op1 );
				return;
			}
			break;

		case OP_SIZE:
			rex = regex = sibex = rmex = 0;
			if (operand_size < 2 && operand_prefix == 0)
			{
				operand_size ^= 1;
				operand_prefix = 1;
			}
			op2 = FETCH();
			decode_opcode(stream, &i386_opcode_table1[op2], op2 );
			return;

		case ADDR_SIZE:
			rex = regex = sibex = rmex = 0;
			if(address_prefix == 0)
			{
				if (curmode != 64)
					address_size ^= 1;
				else
					address_size ^= 3;
				address_prefix = 1;
			}
			op2 = FETCH();
			decode_opcode(stream, &i386_opcode_table1[op2], op2 );
			return;

		case TWO_BYTE:
			if (&opcode_ptr[-2] >= opcode_ptr_base)
				pre0f = opcode_ptr[-2];
			op2 = FETCHD();
			decode_opcode(stream, &i386_opcode_table2[op2], op1 );
			return;

		case THREE_BYTE:
			op2 = FETCHD();
			if (opcode_ptr[-2] == 0x38)
				decode_opcode(stream, &i386_opcode_table0F38[op2], op1 );
			else
				decode_opcode(stream, &i386_opcode_table0F3A[op2], op1 );
			return;

		case SEG_CS:
		case SEG_DS:
		case SEG_ES:
		case SEG_FS:
		case SEG_GS:
		case SEG_SS:
			rex = regex = sibex = rmex = 0;
			segment = op->flags;
			op2 = FETCH();
			decode_opcode(stream, &i386_opcode_table1[op2], op2 );
			return;

		case PREFIX:
			op2 = FETCH();
			if ((op2 != 0x0f) && (op2 != 0x90))
				util::stream_format(stream, "%-7s ", op->mnemonic );
			if ((op2 == 0x90) && !pre0f)
				pre0f = op1;
			decode_opcode(stream, &i386_opcode_table1[op2], op2 );
			return;

		case GROUP:
			handle_modrm( modrm_string );
			for( i=0; i < ARRAY_LENGTH(group_op_table); i++ ) {
				if( strcmp(op->mnemonic, group_op_table[i].mnemonic) == 0 ) {
					if (op->flags & GROUP_MOD)
						decode_opcode(stream, &group_op_table[i].opcode[MODRM_MOD], op1 );
					else
						decode_opcode(stream, &group_op_table[i].opcode[MODRM_REG1], op1 );
					return;
				}
			}
			goto handle_unknown;

		case FPU:
			op2 = FETCHD();
			handle_fpu(stream, op1, op2);
			return;

		case MODRM:
			handle_modrm( modrm_string );
			break;
	}

	if ((op->flags & ALWAYS64) && curmode == 64)
		operand_size = 2;

	if ((op->flags & VAR_NAME) && operand_size > 0)
	{
		const char *mnemonic = op->mnemonic + strlen(op->mnemonic) + 1;
		if (operand_size == 2)
			mnemonic += strlen(mnemonic) + 1;
		util::stream_format(stream, "%-7s ", mnemonic );
	}
	else if (op->flags & VAR_NAME4)
	{
		const char *mnemonic = op->mnemonic;
		int which = (pre0f == 0xf3) ? 3 : (pre0f == 0xf2) ? 2 : (pre0f == 0x66) ? 1 : 0;
		while (which--)
			mnemonic += strlen(mnemonic) + 1;
		util::stream_format(stream, "%-7s ", mnemonic );
	}
	else
		util::stream_format(stream, "%-7s ", op->mnemonic );
	dasm_flags = op->dasm_flags;

	if( op->param1 != 0 ) {
		handle_param(stream, op->param1 );
	}

	if( op->param2 != 0 ) {
		util::stream_format(stream, "," );
		handle_param(stream, op->param2 );
	}

	if( op->param3 != 0 ) {
		util::stream_format(stream, "," );
		handle_param(stream, op->param3 );
	}
	return;

handle_unknown:
	util::stream_format(stream, "???");
}

int i386_dasm_one_ex(std::ostream &stream, uint64_t eip, const uint8_t *oprom, int mode)
{
	uint8_t op;

	opcode_ptr = opcode_ptr_base = oprom;
	switch(mode)
	{
		case 1: /* 8086/8088/80186/80188 */
			address_size = 0;
			operand_size = 0;
			max_length = 8; /* maximum without redundant prefixes - not enforced by chip */
			break;
		case 2: /* 80286 */
			address_size = 0;
			operand_size = 0;
			max_length = 10;
			break;
		case 16: /* 80386+ 16-bit code segment */
			address_size = 0;
			operand_size = 0;
			max_length = 15;
			break;
		case 32: /* 80386+ 32-bit code segment */
			address_size = 1;
			operand_size = 1;
			max_length = 15;
			break;
		case 64: /* x86_64 */
			address_size = 2;
			operand_size = 1;
			max_length = 15;
			break;
	}
	pc = eip;
	dasm_flags = 0;
	segment = 0;
	curmode = mode;
	pre0f = 0;
	rex = regex = sibex = rmex = 0;
	address_prefix = 0;
	operand_prefix = 0;

	op = FETCH();

	decode_opcode( stream, &i386_opcode_table1[op], op );
	return (pc-eip) | dasm_flags | DASMFLAG_SUPPORTED;
}

int i386_dasm_one(std::ostream &stream, offs_t eip, const uint8_t *oprom, int mode)
{
	return i386_dasm_one_ex(stream, eip, oprom, mode);
}

CPU_DISASSEMBLE( x86_16 )
{
	return i386_dasm_one_ex(stream, pc, oprom, 16);
}

CPU_DISASSEMBLE( x86_32 )
{
	return i386_dasm_one_ex(stream, pc, oprom, 32);
}

CPU_DISASSEMBLE( x86_64 )
{
	return i386_dasm_one_ex(stream, pc, oprom, 64);
}