diff --git a/mach/i386/as/mach1.c b/mach/i386/as/mach1.c
index 910a3b93d..5ecaad7f2 100644
--- a/mach/i386/as/mach1.c
+++ b/mach/i386/as/mach1.c
@@ -75,3 +75,28 @@ char	regindex_ind[8][8] = {
 #endif
 
 extern int	address_long INIT(1), operand_long INIT(1);
+extern int	use32 INIT(1);
+
+/* For 16-bit addressing: copied from i86 assembler */
+#ifndef extern
+extern char     sr_m[8];
+#else
+char    sr_m[8] = {
+        -1,     -1,     -1,     7,      -1,     6,      4,      5
+};
+#endif
+
+#ifndef extern
+extern char     dr_m[8][8];
+#else
+char    dr_m[8][8] = {
+        -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+        -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+        -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+        -1,     -1,     -1,     -1,     -1,     -1,     0,      1,
+        -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+        -1,     -1,     -1,     -1,     -1,     -1,     2,      3,
+        -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+        -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1
+};
+#endif
diff --git a/mach/i386/as/mach2.c b/mach/i386/as/mach2.c
index 18c16fc55..3f899b9d5 100644
--- a/mach/i386/as/mach2.c
+++ b/mach/i386/as/mach2.c
@@ -8,6 +8,10 @@
  * INTEL 80386 tokens
  */
 
+%token <y_word> ATOGGLE
+%token <y_word> OTOGGLE
+%token <y_word> USE16
+%token <y_word> USE32
 %token <y_word> R32
 %token <y_word> R16
 %token <y_word> R8
diff --git a/mach/i386/as/mach3.c b/mach/i386/as/mach3.c
index eca3888f4..f3c06c625 100644
--- a/mach/i386/as/mach3.c
+++ b/mach/i386/as/mach3.c
@@ -10,6 +10,8 @@
  * No system registers for now ...
  */
 
+0,	USE16,		0,		".use16",
+0,	USE32,		0,		".use32",
 0,	R32,		0,		"ax",
 0,	R32,		1,		"cx",
 0,	R32,		2,		"dx",
@@ -213,10 +215,10 @@
 0,	NOTOP,		071,		"idiv",
 0,	PREFIX,		0144,		"fseg",
 0,	PREFIX,		0145,		"gseg",
-0,	PREFIX,		0146,		"o16",	/* operand size toggle */
-0,	PREFIX,		0146,		"o32",	/* operand size toggle */
-0,	PREFIX,		0147,		"a16",	/* address size toggle */
-0,	PREFIX,		0147,		"a32",	/* address size toggle */
+0,	OTOGGLE,	0146,		"o16",	/* operand size toggle */
+0,	OTOGGLE,	0346,		"o32",	/* operand size toggle */
+0,	ATOGGLE,	0147,		"a16",	/* address size toggle */
+0,	ATOGGLE,	0347,		"a32",	/* address size toggle */
 0,	PREFIX,		0360,		"lock",
 0,	PREFIX,		0362,		"rep",
 0,	PREFIX,		0362,		"repne",
diff --git a/mach/i386/as/mach4.c b/mach/i386/as/mach4.c
index 019765178..5e273e806 100644
--- a/mach/i386/as/mach4.c
+++ b/mach/i386/as/mach4.c
@@ -8,18 +8,37 @@
 
 operation
 	:
-		prefix oper
-			{	address_long = 1; operand_long = 1; }
+		USE16
+			{	use32 = 0; address_long = 0; operand_long = 0; }
+	|
+		USE32
+			{	use32 = 1; address_long = 1; operand_long = 1; }
+	|	prefix oper
+			{	address_long = use32; operand_long = use32; }
 	|	prefix1		/* to allow for only prefixes on a line */
 	;
 prefix	:	/* empty */
 	|	prefix1
 	;
-prefix1:	prefix PREFIX
-			{	if ($2 == 0146) operand_long = ! operand_long;
-				if ($2 == 0147) address_long = ! address_long;
-				emit1($2);
-			}
+prefix1:	prefix PREFIX	{ emit1($2); }
+	|
+		prefix ATOGGLE
+				{ if ((($2&0200) >> 7) == address_long) {
+					if (pass == PASS_3) warning("address size toggle ignored");
+				  } else {
+					emit1($2 & 0177);
+					address_long = ! address_long;
+				  }
+				}
+	|
+		prefix OTOGGLE
+				{ if ((($2&0200) >> 7) == operand_long) {
+					if (pass == PASS_3) warning("operand size toggle ignored");
+				  } else {
+					emit1($2 & 0177);
+					operand_long = ! operand_long;
+				  }
+				}
 	;
 oper	:	NOOP_1
 			{	emit1($1);}
@@ -177,8 +196,15 @@ st_i	:	ST '(' absexp ')'
 
 	;
 mem	:	'(' expr ')'
-			{	rm_2 = 05; exp_2 = $2; reg_2 = 05; mod_2 = 0;
+			{	if (address_long) {
+					rm_2 = 05; reg_2 = 05; mod_2 = 0;
+				}
+				else {
+					reg_2 = 06;
+				}
+				exp_2 = $2;
 				RELOMOVE(rel_2, relonami);
+					
 			}
 	|	bases
 			{	exp_2.val = 0; exp_2.typ = S_ABS; indexed();}
@@ -188,10 +214,20 @@ mem	:	'(' expr ')'
 			}
 	;
 bases	:	'(' R32 ')'
-			{	reg_2 = $2; sib_2 = 0; rm_2 = 0;}
+			{	if (address_long) {
+					reg_2 = $2; sib_2 = 0; rm_2 = 0;
+				}
+				else 	reg_2 = sr_m[$2];
+			}
 	|	'(' R32 ')' '(' R32 scale ')'
-			{	rm_2 = 04; sib_2 |= regindex_ind[$2][$5];
-				reg_2 = $2;
+			{	if (address_long) {
+					rm_2 = 04;
+					 sib_2 |= regindex_ind[$2][$5];
+					reg_2 = $2;
+				}
+				else {
+					reg_2 = dr_m[$2][$5];
+				}
 			}
 	|	'(' R32 '*' absexp ')'
 			{	if ($4 == 1) {
diff --git a/mach/i386/as/mach5.c b/mach/i386/as/mach5.c
index 88b74c8f8..bdd15afc0 100644
--- a/mach/i386/as/mach5.c
+++ b/mach/i386/as/mach5.c
@@ -8,7 +8,40 @@
  * INTEL 80386 special routines
  */
 
+ea_1_16(param)
+{
+        if ((reg_1 & 070) || (param & ~070)) {
+                serror("bad operand");
+        }
+        emit1(reg_1 | param);
+        switch(reg_1 >> 6) {
+        case 0:
+                if (reg_1 == 6 || (reg_1 & 040)) {
+#ifdef RELOCATION
+                        RELOMOVE(relonami, rel_1);
+                        newrelo(exp_1.typ, RELO2);
+#endif
+                        emit2(exp_1.val);
+                }
+                break;
+        case 1:
+                emit1(exp_1.val);
+                break;
+        case 2:
+#ifdef RELOCATION
+                RELOMOVE(relonami, rel_1);
+                newrelo(exp_1.typ, RELO2);
+#endif
+                emit2(exp_1.val);
+                break;
+        }
+}
+
 ea_1(param) {
+	if (! address_long) {
+		ea_1_16(param);
+		return;
+	}
 	if (is_expr(reg_1)) {
 		serror("bad operand");
 		return;
@@ -49,6 +82,10 @@ checkscale(val)
 {
 	int v = val;
 
+	if (! address_long) {
+		serror("scaling not allowed in 16-bit mode");
+		return 0;
+	}
 	if (v != val) v = 0;
 	switch(v) {
 	case 1:
@@ -93,24 +130,34 @@ regsize(sz)
 }
 
 indexed() {
-	mod_2 = 0;
-	if (sib_2 == -1)
-		serror("register error");
-	if (rm_2 == 0 && reg_2 == 4) {
-		/* base register sp, no index register; use
-		   indexed mode without index register
-		*/
-		rm_2 = 04;
-		sib_2 = 044;
+	if (address_long) {
+		mod_2 = 0;
+		if (sib_2 == -1)
+			serror("register error");
+		if (rm_2 == 0 && reg_2 == 4) {
+			/* base register sp, no index register; use
+		   	   indexed mode without index register
+			*/
+			rm_2 = 04;
+			sib_2 = 044;
+		}
+		if (reg_2 == 015) {
+			reg_2 = 05;
+			return;
+		}
+		if (exp_2.typ != S_ABS || fitb(exp_2.val) == 0)
+			mod_2 = 02;
+		else if (exp_2.val != 0 || reg_2 == 5)
+			mod_2 = 01;
 	}
-	if (reg_2 == 015) {
-		reg_2 = 05;
-		return;
+	else {
+        	if (reg_2 & ~7)
+                	serror("register error");
+        	if (exp_2.typ != S_ABS || fitb(exp_2.val) == 0)
+                	reg_2 |= 0200;
+        	else if (exp_2.val != 0 || reg_2 == 6)
+                	reg_2 |= 0100;
 	}
-	if (exp_2.typ != S_ABS || fitb(exp_2.val) == 0)
-		mod_2 = 02;
-	else if (exp_2.val != 0 || reg_2 == 5)
-		mod_2 = 01;
 }
 
 ebranch(opc,exp)
@@ -245,7 +292,7 @@ adsize_exp(exp, relpc)
 		emit4((long)(exp.val));
 	}
 	else {
-		if (! fitw(exp.val)) {
+		if (! fitw(exp.val) && pass == PASS_3) {
 			warning("offset does not fit in 2 bytes; remove prefix");
 		}
 #ifdef RELOCATION