Skip to contentSkip to conversation

b43-asm: Add 3 new virtual instructions.

PATCH New francesco.gringoli at ing.unibs.it 3 participants 6 messages Nov 12, 2011

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 b43-asm: Add 3 new virtual instructions.

Hi Michael,

I added three new (virtual) instructions to make the code more readable. These are "human-friendly" versions of orx, jzx and jnzx, e.g., one can use "orxh" like

	orxh	(r1 << 8) & 0x0100, r2 & ~0x0100, r2

instead of

	orx	0, 8, r1, r2, r2

or better write

#define NEED_ACK 0x10

#define	NEED_BEACON	0x20
	orxh	NEED_ACK, r1 & ~(NEED_ACK|NEED_BEACON), r2

instead of

	orx	1, 4, 0x1, r1, r2

Similarly:

	jzxh	(r12 << 16 | r13) & 0x1F000, label

instead of

	jzx	4, 12, r13, r12, label

Examples added to test.asm and README.

Regards,
-Francesco

-------------=--------------
The following changes are made to b43-tools

1) b43-asm assembles new virtual instructions orxh, jzxh, jnzxh

assembler/main.c +114 -0
Index: b43-tools/assembler/main.c
===================================================================
@@ -503,6 +503,106 @@
 	do_assemble_insn(ctx, insn, opcode);
 }
 
+static unsigned int merge_ext_into_opcode_human(struct assembler_context *ctx,
+						unsigned int opbase,
+						struct instruction *insn)
+{
+	struct operlist *ol;
+	unsigned int opcode;
+
+	unsigned long masks[256];
+	unsigned long m, s, j = 0;
+	unsigned long imm, shift, mask, mask2;
+	for(m = 0; m < 16; m++) {
+		mask = (1 << (m+1)) - 1;
+		for(s = 0; s < 16; s++) {
+			mask2 = (mask << s) | (mask >> (16 - s));
+			mask2 = mask2 & 0xFFFF;
+			masks[j] = mask2;
+			j++;
+		}
+	}
+
+	opcode = opbase;
+	ol = insn->operands;
+
+	for(j = 0; j < 256; j++)
+		if(masks[j] == ((~ol->oper[5]->u.raw) & 0xFFFF))
+			break;
+	if(j == 256)
+		asm_error(ctx, "can't build valid mask");
+	m = j / 16; s = j % 16;
+	mask = (1 << (m + 1)) - 1;
+	mask = (mask << s) | (mask >> (16 - s));
+	if(mask != ((~ol->oper[5]->u.raw) & 0xFFFF))
+		asm_error(ctx, "can't match mask");
+
+	if(ol->oper[4]->u.raw != 0)
+		asm_error(ctx, "can't use shift here");
+
+	shift = ol->oper[1]->u.raw;
+	mask = ol->oper[2]->u.raw;
+
+	if(ol->oper[0]->type == OPER_IMM) {
+		imm = ((ol->oper[0]->u.imm->imm << shift) & mask) & 0xFFFF;
+		ol->oper[0]->u.imm->imm = imm;
+		imm = ((imm >> s) | (imm << (16-s))) & 0xFFFF;
+		if(imm & ~0x3FF ||
+		   ol->oper[0]->u.imm->imm != (((imm << s) | (imm >> (16-s))) & 0xFFFF))
+			asm_error(ctx, "immediate value can't be encoded");
+		ol->oper[0]->u.imm->imm = imm;
+	} else {
+		if(shift > 15)
+			asm_error(ctx, "invalid shift");
+		if(mask != ((~ol->oper[5]->u.raw) & 0xFFFF))
+			asm_error(ctx, "unmatched masks");
+	}
+
+	opcode |= (m << 4);
+	opcode |= s;
+
+	ol->oper[1] = ol->oper[3];
+	ol->oper[2] = ol->oper[6];
+
+	return opcode;
+}
+
+static unsigned int merge_ext_into_opcode_human2(struct assembler_context *ctx,
+						 unsigned int opbase,
+						 struct instruction *insn)
+{
+	struct operlist *ol;
+	unsigned long masks[256];
+	unsigned long m, s, j = 0;
+	unsigned long mask;
+	unsigned int opcode = opbase;
+	for(m = 0; m < 16; m++) {
+		mask = (1 << (m+1)) - 1;
+		for(s = 0; s < 16; s++) {
+			masks[j] = (mask << s) & 0xFFFFFFFF;
+			j++;
+		}
+	}
+
+	ol = insn->operands;
+
+	for(j = 0; j < 256; j++)
+		if(ol->oper[2]->u.imm->imm == masks[j])
+			break;
+	if(j == 256)
+		asm_error(ctx, "can't build valid mask");
+	m = j / 16; s = j % 16;
+	mask = (1 << (m + 1)) - 1;
+	mask = (mask << s) & 0xFFFFFFFF;
+	if(mask != ol->oper[2]->u.imm->imm)
+		asm_error(ctx, "can't match mask");
+	opcode |= (m << 4);
+	opcode |= s;
+
+	ol->oper[2] = ol->oper[3];
+	return opcode;
+}
+
 static unsigned int merge_ext_into_opcode(struct assembler_context *ctx,
 					  unsigned int opbase,
 					  struct instruction *insn)
@@ -799,6 +899,10 @@
 		opcode = merge_ext_into_opcode(ctx, 0x300, insn);
 		do_assemble_insn(ctx, insn, opcode);
 		break;
+	case OP_ORXH:
+		opcode = merge_ext_into_opcode_human(ctx, 0x300, insn);
+		do_assemble_insn(ctx, insn, opcode);
+		break;
 	case OP_MOV:
 		emulate_mov_insn(ctx, insn);
 		return;
@@ -879,11 +983,21 @@
 		out = do_assemble_insn(ctx, insn, opcode);
 		out->is_jump_insn = 1;
 		break;
+	case OP_JZXH:
+		opcode = merge_ext_into_opcode_human2(ctx, 0x400, insn);
+		out = do_assemble_insn(ctx, insn, opcode);
+		out->is_jump_insn = 1;
+		break;
 	case OP_JNZX:
 		opcode = merge_ext_into_opcode(ctx, 0x500, insn);
 		out = do_assemble_insn(ctx, insn, opcode);
 		out->is_jump_insn = 1;
 		break;
+	case OP_JNZXH:
+		opcode = merge_ext_into_opcode_human2(ctx, 0x500, insn);
+		out = do_assemble_insn(ctx, insn, opcode);
+		out->is_jump_insn = 1;
+		break;
 	case OP_JEXT:
 		opcode = merge_external_jmp_into_opcode(ctx, 0x700, insn);
 		out = do_assemble_insn(ctx, insn, opcode);
assembler/main.h +7 -1
Index: b43-tools/assembler/main.h
===================================================================
@@ -96,8 +96,14 @@
 	} u;
 };
 
+struct operand_shift_mask {
+	struct operand *op;
+	unsigned int mask;
+	unsigned int shift;
+};
+
 struct operlist {
-	struct operand *oper[5];
+	struct operand *oper[7];
 };
 
 struct instruction {
assembler/parser.y +236 -1

285 lines not on this page · raw message

assembler/scanner.l +3 -0
Index: b43-tools/assembler/scanner.l
===================================================================
@@ -105,6 +105,7 @@
 rr			{ update_lineinfo(); return OP_RR; }
 nand			{ update_lineinfo(); return OP_NAND; }
 orx			{ update_lineinfo(); return OP_ORX; }
+orxh			{ update_lineinfo(); return OP_ORXH; }
 mov			{ update_lineinfo(); return OP_MOV; }
 
 jmp			{ update_lineinfo(); return OP_JMP; }
@@ -127,7 +128,9 @@
 jdp			{ update_lineinfo(); return OP_JDP; }
 jdnz			{ update_lineinfo(); return OP_JDNZ; }
 jzx			{ update_lineinfo(); return OP_JZX; }
+jzxh			{ update_lineinfo(); return OP_JZXH; }
 jnzx			{ update_lineinfo(); return OP_JNZX; }
+jnzxh			{ update_lineinfo(); return OP_JNZXH; }
 jext			{ update_lineinfo(); return OP_JEXT; }
 jnext			{ update_lineinfo(); return OP_JNEXT; }
 
assembler/test.asm +12 -0
Index: b43-tools/assembler/test.asm
===================================================================
@@ -72,6 +72,11 @@
 
 	orx	7,8,r0,r1,r2	/* eXtended OR */
 
+	orxh	0x10, r1 & ~0x30, r2	/* r2 = 0x10 | (r1 & ~0x30) */
+	orxh	0, r1 & ~0xFFF0, r2	/* r2 = r1 & ~0xFFF0 */
+	orxh	r1 & 0x7FFF, 0 & ~0x7FFF, r2		/* r2 = r1 & 0x7FFF */
+	orxh	(r1 << 8) & 0x0100, r2 & ~0x0100, r2	/* r2 = (r1 << 8) & 0x0100 | r2 & ~0x0100 */
+
 	/* Copy instruction. This is a virtual instruction
 	 * translated to more lowlevel stuff like OR. */
 	mov	r0,r2		/* copy data */
@@ -100,6 +105,13 @@
 	jzx	7,8,r0,r1,label	/* Jump if zero after shift and mask */
 	jnzx	7,8,r0,r1,label	/* Jump if nonzero after shift and mask */
 
+	jzxh	r12 & 0x18, label  /* jump if result is zero */
+	jzxh	(r12 << 16) & 0x001FFFC0, label    /* jump if result is zero */
+	jzxh	(r12 << 16 | r13) & 0x1F000, label /* jump if result is zero */
+	jnzxh	r12 & 0x18, label  /* jump if result is non zero */
+	jnzxh	(r12 << 16) & 0x001FFFC0, label    /* jump if result is non zero */
+	jnzxh	(r12 << 16 | r13) & 0x1F000, label /* jump if result is non zero */
+
 	/* jump on external conditions */
 	jext	ECOND_MAC_ON,label  /* jump if external condition is TRUE */
 	jnext	ECOND_MAC_ON,label  /* jump if external condition is FALSE */
assembler/README +3 -0
@@ -43,7 +43,9 @@
 ret       | lrX,lrY    | Store PC, ret from func         | lrX=PC; PC=lrY
 rets      |            | ret from function               | stack->PC
 jzx       | M,S,A,B,l  | Jump if zero after shift + mask |
+jzxh      | A,l        | Human readable alias for jzx    | See detailed docs
 jnzx      | M,S,A,B,l  | Jump if nonzero after shift+msk |
+jnzxh     | A,l        | Human readable alias for jnzx   | See detailed docs
 jext      | E,A,B,l    | Jump if External Condition true | if(E) PC=l
 jnext     | E,A,B,l    | Jump if External Condition false| if(!E) PC=l
 
@@ -66,6 +68,7 @@
 rr        | A,B,rD     | Rotate right                    | rD=rrot(A, B bits)
 nand      | A,B,rD     | Clear bits (notmask+and)        | rD=A&(~B)
 orx       | M,S,A,B,rD | OR with shift and select        | See detailed docs
+orxh      | A,B,rD     | Human readable alias for orx    | See detailed docs
 
 Other instructions:
 nap       | none       | Sleep until event               | See detailed docs
#1 lore raw

PATCH 1/1 b43-asm: Add 3 new virtual instructions.

Quoted 1 line · On Sat, 12 Nov 2011 18:31:21 +0100 francesco.gringoli at ing.unibs.it wrote:
	orxh	(r1 << 8) & 0x0100, r2 & ~0x0100, r2

This is not really going to fly. If you want this highlevel stuff, you should port a C compiler to the architecture.
This is assembly. It doesn't know about reg<<imm or similar stuff.

Signature · 1 line
Greetings, Michael.
#2 lore raw

PATCH 1/1 b43-asm: Add 3 new virtual instructions.

Quoted 8 lines · Michael B?sch
Quoted 1 line · On Sat, 12 Nov 2011 18:31:21 +0100 francesco.gringoli at ing.unibs.it wrote:
	orxh	(r1 << 8) & 0x0100, r2 & ~0x0100, r2

This is not really going to fly. If you want this highlevel stuff, you should port a C compiler to the architecture.
This is assembly. It doesn't know about reg<<imm or similar stuff.

Yes, you are right and, in fact, the patched assembler will just accept only what the cpu may execute, I does not pretend to be a C compiler. It's just another way for assembling "or with shift and select" (or jzx), and this way really enhances the readability of the assembly code. Give it a try :-).

If I'm not wrong, it's like "mov 0x1234, r1": such instruction doesn't exist but the assembler accepts it and converts to "orx 7, 8, 0x12, 0x34, r1". So why not adding more assembly options so that the code can be easily understood? Consider these lines

	orx		0, 5, 0x001, SPR_BRC, SPR_BRC
	orx		0, 3, 0x000, SPR_BRC, SPR_BRC
	orx		1, 0, GP_REG1, SPR_TXE0_PHY_CTL, SPR_TXE0_PHY_CTL;

and compare them to

#define FRAME_BURST 0x0020
#define CONTENTION_PARAM_MODIFIED 0x0008
#define FRAME_ENCODING 0x0003
orxh FRAME_BURST, SPR_BRC & ~FRAME_BURST, SPR_BRC
orxh 0x0000, SPR_BRC & ~CONTENTION_PARAM_MODIFIED, SPR_BRC
orxh r1 & FRAME_ENCODING, SPR_TXE0_PHY_CTL & ~ FRAME_ENCODING, SPR_TXE0_PHY_CTL

Regards,
-Francesco

Quoted 3 lines
Signature · 2 lines
-- 
Greetings, Michael.
#3 lore raw

PATCH 1/1 b43-asm: Add 3 new virtual instructions.

Quoted 5 lines · On Sat, 12 Nov 2011 20:03:36 +0100 francesco.gringoli at ing.unibs.it wrote:
Quoted 3 lines · Michael B?sch

On Sat, 12 Nov 2011 18:31:21 +0100
francesco.gringoli at ing.unibs.it wrote:

Quoted 8 lines
Quoted 5 lines
Quoted 1 line
	orxh	(r1 << 8) & 0x0100, r2 & ~0x0100, r2

This is not really going to fly. If you want this highlevel stuff, you should port a C compiler to the architecture.
This is assembly. It doesn't know about reg<<imm or similar stuff.

Yes, you are right and, in fact, the patched assembler will just accept only what the cpu may execute, I does not pretend to be a C compiler. It's just another way for assembling "or with shift and select" (or jzx), and this way really enhances the readability of the assembly code. Give it a try :-).

If I'm not wrong, it's like "mov 0x1234, r1"

No.
It crosses the line where it does (pseudo)operations (like shift, and, or, etc..) on non-const (non-immediate) stuff.

Just do a preprocessor or something like that, that translates your pseudo-insns to real insns. Alternatively port a small C compiler.

I also don't think that this is easier to read for people familiar to the CPU. And you have to be familiar to the CPU when writing code for it.

I won't merge this. No way.

The "/* duplicate some complex_imm rules to avoid parentheses" part also is not really merge-able as-is. yacc knows about operator precedence. If you want operator precedence (to get rid of parenthesis), just use this yacc feature to implement this.

Signature · 1 line
Greetings, Michael.
#4 lore raw

PATCH 1/1 b43-asm: Add 3 new virtual instructions.

Quoted 21 lines · Michael B?sch
Quoted 5 lines · On Sat, 12 Nov 2011 20:03:36 +0100 francesco.gringoli at ing.unibs.it wrote:
Quoted 3 lines · Michael B?sch

On Sat, 12 Nov 2011 18:31:21 +0100
francesco.gringoli at ing.unibs.it wrote:

Quoted 8 lines
Quoted 5 lines
Quoted 1 line
	orxh	(r1 << 8) & 0x0100, r2 & ~0x0100, r2

This is not really going to fly. If you want this highlevel stuff, you should port a C compiler to the architecture.
This is assembly. It doesn't know about reg<<imm or similar stuff.

Yes, you are right and, in fact, the patched assembler will just accept only what the cpu may execute, I does not pretend to be a C compiler. It's just another way for assembling "or with shift and select" (or jzx), and this way really enhances the readability of the assembly code. Give it a try :-).

If I'm not wrong, it's like "mov 0x1234, r1"

No.
It crosses the line where it does (pseudo)operations (like shift, and, or, etc..) on non-const (non-immediate) stuff.

Quoted 5 lines

Just do a preprocessor or something like that, that translates your pseudo-insns to real insns. Alternatively port a small C compiler.

I also don't think that this is easier to read for people familiar to the CPU. And you have to be familiar to the CPU when writing code for it.

I initially started with a pre-processor but I soon realized that those three instructions were the only one whose readability could have been improved by the preprocessor itself.

Quoted 1 line

I won't merge this. No way.

Ok, anyway I urge to share with other researchers a new version of the standard ucode and for the moment I don't have more time to spend on the "preprocessor". I'm sorry but the new ucode source will require the patched assembler. As soon as I have finished some work on the N-PHY firmware I will come back to the preprocessor.

Quoted 3 lines

The "/* duplicate some complex_imm rules to avoid parentheses" part also is not really merge-able as-is. yacc knows about operator precedence. If you want operator precedence (to get rid of parenthesis), just use this yacc feature to implement this.

Yes, I did it this way because "[reg|mem] << imm" is not assembly (as you say :-) ) and the assembler strictly checks that such syntax is used only with "orxh".

Regards,
-Francesco

Quoted 3 lines
Signature · 2 lines
-- 
Greetings, Michael.
#5 lore raw

PATCH 1/1 b43-asm: Add 3 new virtual instructions.

Quoted 30 lines · On Sat, Nov 12, 2011 at 9:12 PM, <[email protected]> wrote:
Quoted 21 lines · Michael B?sch
Quoted 5 lines · On Sat, 12 Nov 2011 20:03:36 +0100 francesco.gringoli at ing.unibs.it wrote:
Quoted 3 lines · Michael B?sch

On Sat, 12 Nov 2011 18:31:21 +0100
francesco.gringoli at ing.unibs.it wrote:

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

? ?orxh ? ?(r1 << 8) & 0x0100, r2 & ~0x0100, r2

This is not really going to fly. If you want this highlevel stuff, you should port a C compiler to the architecture.
This is assembly. It doesn't know about reg<<imm or similar stuff.

Yes, you are right and, in fact, the patched assembler will just accept only what the cpu may execute, I does not pretend to be a C compiler. It's just another way for assembling "or with shift and select" (or jzx), and this way really enhances the readability of the assembly code. Give it a try :-).

If I'm not wrong, it's like "mov 0x1234, r1"

No.
It crosses the line where it does (pseudo)operations (like shift, and, or, etc..) on non-const (non-immediate) stuff.

Quoted 5 lines

Just do a preprocessor or something like that, that translates your pseudo-insns to real insns. Alternatively port a small C compiler.

I also don't think that this is easier to read for people familiar to the CPU. And you have to be familiar to the CPU when writing code for it.

I initially started with a pre-processor but I soon realized that those three instructions were the only one whose readability could have been improved by the preprocessor itself.

Quoted 7 lines
Quoted 1 line

I won't merge this. No way.

Ok, anyway I urge to share with other researchers ?a new version of the standard ucode and for the moment I don't have more time to spend on the "preprocessor". I'm sorry but the new ucode source will require the patched assembler. As soon as I have finished some work on the N-PHY firmware I will come back to the preprocessor.

Quoted 3 lines

The "/* duplicate some complex_imm rules to avoid parentheses" part also is not really merge-able as-is. yacc knows about operator precedence. If you want operator precedence (to get rid of parenthesis), just use this yacc feature to implement this.

Yes, I did it this way because "[reg|mem] << imm" is not assembly (as you say :-) ) and the assembler strictly checks that such syntax is used only with "orxh".

Well, in x86, we have "mov eax, es:[bx+di]". A lot more readable than, say, "mov eax, es, bx, di".

Quoted 14 lines

Regards,
-Francesco

Quoted 3 lines

--
Greetings, Michael.

_______________________________________________
b43-dev mailing list
b43-dev at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/b43-dev

Signature · 1 line
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)