add in_, out_
diff --git a/gen/gen_code.cpp b/gen/gen_code.cpp
index 889cb87..7feb178 100644
--- a/gen/gen_code.cpp
+++ b/gen/gen_code.cpp
@@ -965,6 +965,12 @@
 			printf("void %s(const Reg& reg, const Operand& op) { opMovxx(reg, op, 0x%02X); }\n", p->name, p->code);
 		}
 	}
+	{ // in/out
+		puts("void in_(const Reg& a, uint8 v) { opInOut(a, 0xE4, v); }");
+		puts("void in_(const Reg& a, const Reg& d) { opInOut(a, d, 0xEC); }");
+		puts("void out_(uint8 v, const Reg& a) { opInOut(a, 0xE6, v); }");
+		puts("void out_(const Reg& d, const Reg& a) { opInOut(a, d, 0xEE); }");
+	}
 	// mpx
 	{
 		puts("void bndcl(const BoundsReg& bnd, const Operand& op) { db(0xF3); opR_ModM(op, i32e, bnd.getIdx(), 0x0F, 0x1A, NONE, !op.isMEM()); }");
diff --git a/test/make_nm.cpp b/test/make_nm.cpp
index 4c52f47..2279988 100644
--- a/test/make_nm.cpp
+++ b/test/make_nm.cpp
@@ -609,6 +609,14 @@
 		put("fstcw", MEM);
 		put("fnstcw", MEM);
 		put(isXbyak_ ? "int_" : "int", IMM8);
+		put(isXbyak_ ? "in_" : "in", AL|AX|EAX, IMM8);
+		puts(isXbyak_ ? "in_(al, dx); dump();" : "in al, dx");
+		puts(isXbyak_ ? "in_(ax, dx); dump();" : "in ax, dx");
+		puts(isXbyak_ ? "in_(eax, dx); dump();" : "in eax, dx");
+		put(isXbyak_ ? "out_" : "out", IMM8, AL|AX|EAX);
+		puts(isXbyak_ ? "out_(dx, al); dump();" : "out dx, al");
+		puts(isXbyak_ ? "out_(dx, ax); dump();" : "out dx, ax");
+		puts(isXbyak_ ? "out_(dx, eax); dump();" : "out dx, eax");
 	}
 	void putJmp() const
 	{
diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h
index 64b4ee3..c8c0507 100644
--- a/xbyak/xbyak.h
+++ b/xbyak/xbyak.h
@@ -2185,6 +2185,28 @@
 		if (addr.getRegExp().getIndex().getKind() != kind) throw Error(ERR_BAD_VSIB_ADDRESSING);
 		opVex(x, 0, addr, type, code);
 	}
+	void opInOut(const Reg& a, const Reg& d, uint8 code)
+	{
+		if (a.getIdx() == Operand::AL && d.getIdx() == Operand::DX && d.getBit() == 16) {
+			switch (a.getBit()) {
+			case 8: db(code); return;
+			case 16: db(0x66); db(code + 1); return;
+			case 32: db(code + 1); return;
+			}
+		}
+		throw Error(ERR_BAD_COMBINATION);
+	}
+	void opInOut(const Reg& a, uint8 code, uint8 v)
+	{
+		if (a.getIdx() == Operand::AL) {
+			switch (a.getBit()) {
+			case 8: db(code); db(v); return;
+			case 16: db(0x66); db(code + 1); db(v); return;
+			case 32: db(code + 1); db(v); return;
+			}
+		}
+		throw Error(ERR_BAD_COMBINATION);
+	}
 public:
 	unsigned int getVersion() const { return VERSION; }
 	using CodeArray::db;
diff --git a/xbyak/xbyak_mnemonic.h b/xbyak/xbyak_mnemonic.h
index eb4bebe..55de124 100644
--- a/xbyak/xbyak_mnemonic.h
+++ b/xbyak/xbyak_mnemonic.h
@@ -309,6 +309,8 @@
 void hsubps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x7D, 0xF2, isXMM_XMMorMEM); }
 void idiv(const Operand& op) { opR_ModM(op, 0, 7, 0xF6); }
 void imul(const Operand& op) { opR_ModM(op, 0, 5, 0xF6); }
+void in_(const Reg& a, const Reg& d) { opInOut(a, d, 0xEC); }
+void in_(const Reg& a, uint8 v) { opInOut(a, 0xE4, v); }
 void inc(const Operand& op) { opIncDec(op, 0x40, 0); }
 void insertps(const Xmm& xmm, const Operand& op, uint8 imm) { opGen(xmm, op, 0x21, 0x66, isXMM_XMMorMEM, imm, 0x3A); }
 void int3() { db(0xCC); }
@@ -517,6 +519,8 @@
 void or_(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x08); }
 void orpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x56, 0x66, isXMM_XMMorMEM); }
 void orps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x56, 0x100, isXMM_XMMorMEM); }
+void out_(const Reg& d, const Reg& a) { opInOut(a, d, 0xEE); }
+void out_(uint8 v, const Reg& a) { opInOut(a, 0xE6, v); }
 void outsb() { db(0x6E); }
 void outsd() { db(0x6F); }
 void outsw() { db(0x66); db(0x6F); }