Commit 7fd69f57 authored by Michael Büsch's avatar Michael Büsch

Partial support for the new v15 architecture.

Signed-off-by: Michael Büsch's avatarMichael Buesch <mb@bu3sch.de>
parent 3691c9a3
...@@ -64,7 +64,9 @@ struct code_output { ...@@ -64,7 +64,9 @@ struct code_output {
}; };
struct assembler_context { struct assembler_context {
int arch; /* The architecture version (802.11 core revision) */
unsigned int arch;
struct label *start_label; struct label *start_label;
/* Tracking stuff */ /* Tracking stuff */
...@@ -119,6 +121,10 @@ static void eval_directives(struct assembler_context *ctx) ...@@ -119,6 +121,10 @@ static void eval_directives(struct assembler_context *ctx)
if (have_arch) if (have_arch)
asm_error(ctx, "Multiple %%arch definitions"); asm_error(ctx, "Multiple %%arch definitions");
ctx->arch = ad->u.arch; ctx->arch = ad->u.arch;
if (ctx->arch != 5 && ctx->arch != 15) {
asm_error(ctx, "Architecture version %u unsupported",
ctx->arch);
}
have_arch = 1; have_arch = 1;
break; break;
case ADIR_START: case ADIR_START:
...@@ -135,13 +141,11 @@ static void eval_directives(struct assembler_context *ctx) ...@@ -135,13 +141,11 @@ static void eval_directives(struct assembler_context *ctx)
if (!have_arch) if (!have_arch)
asm_error(ctx, "No %%arch defined"); asm_error(ctx, "No %%arch defined");
if (ctx->arch != NEWWORLD)
asm_error(ctx, "TODO: Only NEWWORLD arch supported, yet");
if (!have_start_label) if (!have_start_label)
asm_info(ctx, "Using start address 0"); asm_info(ctx, "Using start address 0");
} }
static int is_possible_imm(unsigned int imm) static bool is_possible_imm(unsigned int imm)
{ {
unsigned int mask; unsigned int mask;
...@@ -160,29 +164,48 @@ static int is_possible_imm(unsigned int imm) ...@@ -160,29 +164,48 @@ static int is_possible_imm(unsigned int imm)
return 1; return 1;
} }
static int is_valid_imm(unsigned int imm) static bool is_valid_imm(struct assembler_context *ctx,
unsigned int imm)
{ {
unsigned int mask; unsigned int mask;
unsigned int immediate_size;
/* This function checks if the immediate value is representable /* This function checks if the immediate value is representable
* as a native immediate operand. * as a native immediate operand.
* *
* The value itself is 10bit long, signed. * For v5 architecture the immediate can be 10bit long.
* We also honor sign-extension, so we allow values * For v15 architecture the immediate can be 11bit long.
* of 0xFFFF, for example. *
* The value is sign-extended, so we allow values
* of 0xFFFA, for example.
*/ */
if (!is_possible_imm(imm)) if (!is_possible_imm(imm))
return 0; return 0;
imm &= 0xFFFF; imm &= 0xFFFF;
/* assert sign extension */ if (ctx->arch == 5) {
mask = 0xFC00; immediate_size = 10; /* 10bit */
if (imm & (1 << 9)) { } else if (ctx->arch == 15) {
/* sign-extended */ immediate_size = 11; /* 11bit */
} else {
asm_error(ctx, "Unknown immediate size for arch %u",
ctx->arch);
}
/* First create a mask with all possible bits for
* an immediate value unset. */
mask = (~0 << immediate_size) & 0xFFFF;
/* Is the sign bit of the immediate set? */
if (imm & (1 << (immediate_size - 1))) {
/* Yes, so all bits above that must also
* be set, otherwise we can't represent this
* value in an operand. */
if ((imm & mask) != mask) if ((imm & mask) != mask)
return 0; return 0;
} else { } else {
/* All bits above the immediate's size must
* be unset. */
if (imm & mask) if (imm & mask)
return 0; return 0;
} }
...@@ -190,33 +213,33 @@ static int is_valid_imm(unsigned int imm) ...@@ -190,33 +213,33 @@ static int is_valid_imm(unsigned int imm)
return 1; return 1;
} }
static int is_contiguous_bitmask(unsigned int mask) /* This checks if the value is nonzero and a power of two. */
static bool is_power_of_two(unsigned int value)
{ {
int bit; return (value && ((value & (value - 1)) == 0));
int only_zero_now = 0; }
/* This checks if the mask is contiguous.
* A contiguous mask is:
* 0b0001111110000
* A non-contiguous mask is:
* 0b0001101110000
*/
bit = ffs(mask); /* This checks if all bits set in the mask are contiguous.
if (!bit) * Zero is also considered a contiguous mask. */
return 1; static bool is_contiguous_bitmask(unsigned int mask)
if (bit > 16) {
return 1; unsigned int low_zeros_mask;
bit--; bool is_contiguous;
for ( ; bit < 16; bit++) {
if (mask & (1 << bit)) {
if (only_zero_now)
return 0;
} else
only_zero_now = 1;
}
return 1; if (mask == 0)
return 1;
/* Turn the lowest zeros of the mask into a bitmask.
* Example: 0b00011000 -> 0b00000111 */
low_zeros_mask = (mask - 1) & ~mask;
/* Adding the low_zeros_mask to the original mask
* basically is a bitwise OR operation.
* If the original mask was contiguous, we end up with a
* contiguous bitmask from bit 0 to the highest bit
* set in the original mask. Adding 1 will result in a single
* bit set, which is a power of two. */
is_contiguous = is_power_of_two(mask + low_zeros_mask + 1);
return is_contiguous;
} }
static unsigned int generate_imm_operand(struct assembler_context *ctx, static unsigned int generate_imm_operand(struct assembler_context *ctx,
...@@ -224,21 +247,25 @@ static unsigned int generate_imm_operand(struct assembler_context *ctx, ...@@ -224,21 +247,25 @@ static unsigned int generate_imm_operand(struct assembler_context *ctx,
{ {
unsigned int val, tmp; unsigned int val, tmp;
unsigned int mask; unsigned int mask;
int too_long = 0;
/* format: 0b11ii iiii iiii */ /* format: 0b11ii iiii iiii */
val = 0xC00; val = 0xC00;
if (ctx->arch == 15)
val <<= 1;
tmp = imm->imm; tmp = imm->imm;
if (!is_valid_imm(tmp)) { if (!is_valid_imm(ctx, tmp)) {
asm_warn(ctx, "IMMEDIATE 0x%X (%d) too long " asm_warn(ctx, "IMMEDIATE 0x%X (%d) too long "
"(> 9 bits + sign). Did you intend to " "(> 9 bits + sign). Did you intend to "
"use implicit sign extension?", "use implicit sign extension?",
tmp, (int)tmp); tmp, (int)tmp);
} }
tmp &= 0x3FF; if (ctx->arch == 15)
tmp &= 0x7FF;
else
tmp &= 0x3FF;
val |= tmp; val |= tmp;
return val; return val;
...@@ -253,13 +280,17 @@ static unsigned int generate_reg_operand(struct assembler_context *ctx, ...@@ -253,13 +280,17 @@ static unsigned int generate_reg_operand(struct assembler_context *ctx,
case GPR: case GPR:
/* format: 0b1011 11rr rrrr */ /* format: 0b1011 11rr rrrr */
val |= 0xBC0; val |= 0xBC0;
if (reg->nr & ~0x3F) if (ctx->arch == 15)
val <<= 1;
if (reg->nr & ~0x3F) //FIXME 128 regs for v15 arch possible?
asm_error(ctx, "GPR-nr too big"); asm_error(ctx, "GPR-nr too big");
val |= reg->nr; val |= reg->nr;
break; break;
case SPR: case SPR:
/* format: 0b100. .... .... */ /* format: 0b100. .... .... */
val |= 0x800; val |= 0x800;
if (ctx->arch == 15) //FIXME is this ok?
val <<= 1;
if (reg->nr & ~0x1FF) if (reg->nr & ~0x1FF)
asm_error(ctx, "SPR-nr too big"); asm_error(ctx, "SPR-nr too big");
val |= reg->nr; val |= reg->nr;
...@@ -267,6 +298,8 @@ static unsigned int generate_reg_operand(struct assembler_context *ctx, ...@@ -267,6 +298,8 @@ static unsigned int generate_reg_operand(struct assembler_context *ctx,
case OFFR: case OFFR:
/* format: 0b1000 0110 0rrr */ /* format: 0b1000 0110 0rrr */
val |= 0x860; val |= 0x860;
if (ctx->arch == 15) //FIXME is this ok?
val <<= 1;
if (reg->nr & ~0x7) if (reg->nr & ~0x7)
asm_error(ctx, "OFFR-nr too big"); asm_error(ctx, "OFFR-nr too big");
val |= reg->nr; val |= reg->nr;
...@@ -287,7 +320,7 @@ static unsigned int generate_mem_operand(struct assembler_context *ctx, ...@@ -287,7 +320,7 @@ static unsigned int generate_mem_operand(struct assembler_context *ctx,
case MEM_DIRECT: case MEM_DIRECT:
/* format: 0b0mmm mmmm mmmm */ /* format: 0b0mmm mmmm mmmm */
off = mem->offset; off = mem->offset;
if (off & ~0x7FF) { if (off & ~0x7FF) { //FIXME 4096 words for v15 arch possible?
asm_warn(ctx, "DIRECT memoffset 0x%X too long (> 11 bits)", off); asm_warn(ctx, "DIRECT memoffset 0x%X too long (> 11 bits)", off);
off &= 0x7FF; off &= 0x7FF;
} }
...@@ -298,6 +331,7 @@ static unsigned int generate_mem_operand(struct assembler_context *ctx, ...@@ -298,6 +331,7 @@ static unsigned int generate_mem_operand(struct assembler_context *ctx,
off = mem->offset; off = mem->offset;
reg = mem->offr_nr; reg = mem->offr_nr;
val |= 0xA00; val |= 0xA00;
//FIXME what about v15 arch?
if (off & ~0x3F) { if (off & ~0x3F) {
asm_warn(ctx, "INDIRECT memoffset 0x%X too long (> 6 bits)", off); asm_warn(ctx, "INDIRECT memoffset 0x%X too long (> 6 bits)", off);
off &= 0x3F; off &= 0x3F;
...@@ -481,7 +515,7 @@ static void emulate_mov_insn(struct assembler_context *ctx, ...@@ -481,7 +515,7 @@ static void emulate_mov_insn(struct assembler_context *ctx,
tmp = in->u.imm->imm; tmp = in->u.imm->imm;
if (!is_possible_imm(tmp)) if (!is_possible_imm(tmp))
asm_error(ctx, "MOV operand 0x%X > 16bit", tmp); asm_error(ctx, "MOV operand 0x%X > 16bit", tmp);
if (!is_valid_imm(tmp)) { if (!is_valid_imm(ctx, tmp)) {
/* Immediate too big for plain OR */ /* Immediate too big for plain OR */
em_insn.op = OP_ORX; em_insn.op = OP_ORX;
...@@ -563,7 +597,7 @@ static void emulate_jand_insn(struct assembler_context *ctx, ...@@ -563,7 +597,7 @@ static void emulate_jand_insn(struct assembler_context *ctx,
* Check if it's representable by a normal JAND insn. * Check if it's representable by a normal JAND insn.
*/ */
tmp = imm_oper->u.imm->imm; tmp = imm_oper->u.imm->imm;
if (!is_valid_imm(tmp)) { if (!is_valid_imm(ctx, tmp)) {
/* Nope, this must be emulated by JZX/JNZX */ /* Nope, this must be emulated by JZX/JNZX */
if (!is_contiguous_bitmask(tmp)) { if (!is_contiguous_bitmask(tmp)) {
asm_error(ctx, "Long bitmask 0x%X is not contiguous", asm_error(ctx, "Long bitmask 0x%X is not contiguous",
...@@ -987,26 +1021,39 @@ static void emit_code(struct assembler_context *ctx) ...@@ -987,26 +1021,39 @@ static void emit_code(struct assembler_context *ctx)
} }
code = 0; code = 0;
/* Instruction binary format is: xxyy yzzz 0000 oooX if (ctx->arch == 5) {
* Big-Endian, X is the most significant part of Xxx. /* Instruction binary format is: xxyyyzzz0000oooX
*/ * byte-0-^ byte-7-^
code |= (c->opcode << 4); * ooo is the opcode
* Xxx is the first operand
code |= (((uint64_t)c->operands[0].u.operand & 0xF00) >> 8); * yyy is the second operand
code |= (((uint64_t)c->operands[0].u.operand & 0x0FF) << 56); * zzz is the third operand
*/
code |= ((uint64_t)c->operands[1].u.operand << 44); code |= ((uint64_t)c->operands[2].u.operand);
code |= ((uint64_t)c->operands[1].u.operand) << 12;
code |= ((uint64_t)c->operands[2].u.operand << 32); code |= ((uint64_t)c->operands[0].u.operand) << 24;
code |= ((uint64_t)c->opcode) << 36;
outbuf[7] = (code & 0x00000000000000FFULL); code = ((code & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) |
outbuf[6] = (code & 0x000000000000FF00ULL) >> 8; ((code & (uint64_t)0x00000000FFFFFFFFULL) << 32);
outbuf[5] = (code & 0x0000000000FF0000ULL) >> 16; } else if (ctx->arch == 15) {
outbuf[4] = (code & 0x00000000FF000000ULL) >> 24; code |= ((uint64_t)c->operands[2].u.operand);
outbuf[3] = (code & 0x000000FF00000000ULL) >> 32; code |= ((uint64_t)c->operands[1].u.operand) << 13;
outbuf[2] = (code & 0x0000FF0000000000ULL) >> 40; code |= ((uint64_t)c->operands[0].u.operand) << 26;
outbuf[1] = (code & 0x00FF000000000000ULL) >> 48; code |= ((uint64_t)c->opcode) << 39;
outbuf[0] = (code & 0xFF00000000000000ULL) >> 56; code = ((code & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) |
((code & (uint64_t)0x00000000FFFFFFFFULL) << 32);
} else {
asm_error(ctx, "No emit format for arch %u",
ctx->arch);
}
outbuf[0] = (code & (uint64_t)0xFF00000000000000ULL) >> 56;
outbuf[1] = (code & (uint64_t)0x00FF000000000000ULL) >> 48;
outbuf[2] = (code & (uint64_t)0x0000FF0000000000ULL) >> 40;
outbuf[3] = (code & (uint64_t)0x000000FF00000000ULL) >> 32;
outbuf[4] = (code & (uint64_t)0x00000000FF000000ULL) >> 24;
outbuf[5] = (code & (uint64_t)0x0000000000FF0000ULL) >> 16;
outbuf[6] = (code & (uint64_t)0x000000000000FF00ULL) >> 8;
outbuf[7] = (code & (uint64_t)0x00000000000000FFULL) >> 0;
if (fwrite(&outbuf, ARRAY_SIZE(outbuf), 1, fd) != 1) { if (fwrite(&outbuf, ARRAY_SIZE(outbuf), 1, fd) != 1) {
fprintf(stderr, "Could not write microcode outfile\n"); fprintf(stderr, "Could not write microcode outfile\n");
......
...@@ -112,10 +112,7 @@ struct asmdir { ...@@ -112,10 +112,7 @@ struct asmdir {
ADIR_START, ADIR_START,
} type; } type;
union { union {
enum { unsigned int arch;
OLDWORLD,
NEWWORLD,
} arch;
struct label *start; struct label *start;
} u; } u;
}; };
......
...@@ -487,8 +487,11 @@ statement : asmdir { ...@@ -487,8 +487,11 @@ statement : asmdir {
; ;
/* ASM directives */ /* ASM directives */
asmdir : asmarch { asmdir : ASM_ARCH hexnum_decnum {
$$ = $1; struct asmdir *ad = xmalloc(sizeof(struct asmdir));
ad->type = ADIR_ARCH;
ad->u.arch = (unsigned int)(unsigned long)$2;
$$ = ad;
} }
| ASM_START identifier { | ASM_START identifier {
struct asmdir *ad = xmalloc(sizeof(struct asmdir)); struct asmdir *ad = xmalloc(sizeof(struct asmdir));
...@@ -501,20 +504,6 @@ asmdir : asmarch { ...@@ -501,20 +504,6 @@ asmdir : asmarch {
} }
; ;
asmarch : ASM_ARCH ARCH_NEWWORLD {
struct asmdir *ad = xmalloc(sizeof(struct asmdir));
ad->type = ADIR_ARCH;
ad->u.arch = NEWWORLD;
$$ = ad;
}
| ASM_ARCH ARCH_OLDWORLD {
struct asmdir *ad = xmalloc(sizeof(struct asmdir));
ad->type = ADIR_ARCH;
ad->u.arch = OLDWORLD;
$$ = ad;
}
;
label : LABEL { label : LABEL {
struct label *label = xmalloc(sizeof(struct label)); struct label *label = xmalloc(sizeof(struct label));
char *l; char *l;
......
...@@ -143,9 +143,6 @@ shm32 { update_lineinfo(); return IVAL_SHM32; } ...@@ -143,9 +143,6 @@ shm32 { update_lineinfo(); return IVAL_SHM32; }
0x[0-9a-fA-F]+ { update_lineinfo(); return HEXNUM; } 0x[0-9a-fA-F]+ { update_lineinfo(); return HEXNUM; }
-?[0-9]+ { update_lineinfo(); return DECNUM; } -?[0-9]+ { update_lineinfo(); return DECNUM; }
bcm43xx_newworld { update_lineinfo(); return ARCH_NEWWORLD; }
bcm43xx_oldworld { update_lineinfo(); return ARCH_OLDWORLD; }
{IDENTIFIER}: { update_lineinfo(); return LABEL; } {IDENTIFIER}: { update_lineinfo(); return LABEL; }
{IDENTIFIER} { update_lineinfo(); return IDENT; } {IDENTIFIER} { update_lineinfo(); return IDENT; }
......
...@@ -18,7 +18,10 @@ ...@@ -18,7 +18,10 @@
; ;
%arch bcm43xx_newworld ; or bcm43xx-oldworld ; The target architecture. Supported versions are 5 and 15
%arch 5
; Program entry point
%start testlabel %start testlabel
#define PSM_BRC spr848 #define PSM_BRC spr848
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment