Add most vanilla memory load/store instructions.

--HG--
branch : dtrg-videocore
This commit is contained in:
David Given 2013-05-19 00:56:56 +01:00
parent 26877d3c4f
commit fc2833d456
7 changed files with 205 additions and 106 deletions

View file

@ -19,6 +19,8 @@
#undef word_t
#define word_t long
typedef unsigned long quad;
#undef ALIGNWORD
#define ALIGNWORD 4

View file

@ -9,19 +9,21 @@
#define ALWAYS 14
extern void alu_instr_reg(unsigned opcode, unsigned cc, unsigned rd,
unsigned ra, unsigned rb);
extern void alu_instr_reg(quad opcode, quad cc, quad rd,
quad ra, quad rb);
extern void alu_instr_lit(unsigned opcode, unsigned cc, unsigned rd,
unsigned ra, unsigned value);
extern void alu_instr_lit(quad opcode, quad cc, quad rd,
quad ra, quad value);
extern void misc_instr_reg(unsigned opcode, unsigned cc, unsigned rd,
unsigned ra, unsigned rb);
extern void misc_instr_reg(quad opcode, quad cc, quad rd,
quad ra, quad rb);
extern void misc_instr_lit(unsigned opcode, unsigned cc, unsigned rd,
unsigned ra, unsigned value);
extern void misc_instr_lit(quad opcode, quad cc, quad rd,
quad ra, quad value);
extern void branch_instr(unsigned bl, unsigned cc, struct expr_t* expr);
extern void branch_instr(quad bl, quad cc, struct expr_t* expr);
extern void stack_instr(unsigned opcode, unsigned loreg, unsigned hireg,
unsigned extrareg);
extern void stack_instr(quad opcode, quad loreg, quad hireg,
quad extrareg);
extern void mem_instr(quad opcode, quad cc, quad rd, long offset, quad rs);

View file

@ -19,8 +19,4 @@
%token <y_word> OP_MISCL
%token <y_word> OP_STACK
/* Other token types */
/* %type <y_word> c */
%type <y_word> e16 u8 u7 u6 u5 u4 u2 u1
/* %type <y_word> nb ds bda bdl lia lil */

View file

@ -33,13 +33,13 @@
0, GPR, 22, "r22",
0, GPR, 23, "r23",
0, GPR, 24, "r24",
0, GPR, 24, "fp",
0, GPR, 25, "r25",
0, GPR, 25, "sp",
0, GPR, 26, "r26",
0, GPR, 26, "lr",
0, GPR, 27, "r27",
0, GPR, 27, "fp",
0, GPR, 28, "r28",
0, GPR, 29, "r29",
0, GPR, 30, "r30",
@ -134,3 +134,13 @@
0, OP_STACK, B16(00000010,00000000), "push",
0, OP_STACK, B16(00000010,10000000), "pop",
0, OP_MEM, B8(00000000), "ld",
0, OP_MEM, B8(00000001), "st",
0, OP_MEM, B8(00000010), "ldh",
0, OP_MEM, B8(00000011), "sth",
0, OP_MEM, B8(00000100), "ldb",
0, OP_MEM, B8(00000101), "stb",
0, OP_MEM, B8(00000110), "ldhs",
0, OP_MEM, B8(00000111), "sths",

View file

@ -41,78 +41,16 @@ operation
| OP_STACK GPR ',' GPR { stack_instr($1, $2, $2, $4); }
| OP_STACK GPR '-' GPR { stack_instr($1, $2, $4, -1); }
| OP_STACK GPR '-' GPR ',' GPR { stack_instr($1, $2, $4, $6); }
;
e16
: expr
{
DOTVAL += 2;
newrelo($1.typ, RELO2 | FIXUPFLAGS);
DOTVAL -= 2;
$$ = $1.val & 0xFFFF;
}
;
u8
: absexp
{
if (($1 < 0) || ($1 > 0xFF))
serror("8-bit unsigned value out of range");
$$ = $1;
}
;
u7
: absexp
{
if (($1 < 0) || ($1 > 0x7F))
serror("7-bit unsigned value out of range");
$$ = $1;
}
;
u6
: absexp
{
if (($1 < 0) || ($1 > 0x3F))
serror("6-bit unsigned value out of range");
$$ = $1;
}
;
u5
: absexp
{
if (($1 < 0) || ($1 > 0x1F))
serror("5-bit unsigned value out of range");
$$ = $1;
}
;
u4
: absexp
{
if (($1 < 0) || ($1 > 0xF))
serror("4-bit unsigned value out of range");
$$ = $1;
}
;
u1
: absexp
{
if (($1 < 0) || ($1 > 1))
serror("1-bit unsigned value out of range");
$$ = $1;
}
;
u2
: absexp
{
if (($1 < 0) || ($1 > 0x3))
serror("2-bit unsigned value out of range");
$$ = $1;
}
| OP_MEM GPR ',' '(' GPR ')' { mem_instr($1, ALWAYS, $2, 0, $5); }
| OP_MEM CC GPR ',' '(' GPR ')' { mem_instr($1, $2, $3, 0, $6); }
| OP_MEM GPR ',' absexp '(' GPR ')' { mem_instr($1, ALWAYS, $2, $4, $6); }
| OP_MEM CC GPR ',' absexp '(' GPR ')' { mem_instr($1, $2, $3, $5, $7); }
| OP_MEM GPR ',' '(' GPR ',' GPR ')'
| OP_MEM CC GPR ',' '(' GPR ',' GPR ')'
| OP_MEM GPR ',' '(' GPR ')' '+' '+'
| OP_MEM CC GPR ',' '(' GPR ')' '+' '+'
;

View file

@ -5,10 +5,11 @@
* See the file 'Copying' in the root of the distribution for the full text.
*/
#define maskx(v, x) (v & ((1<<(x))-1))
/* Assemble an ALU instruction where rb is a register. */
void alu_instr_reg(unsigned op, unsigned cc,
unsigned rd, unsigned ra, unsigned rb)
void alu_instr_reg(quad op, quad cc, quad rd, quad ra, quad rb)
{
/* Can we use short form? */
@ -26,8 +27,7 @@ void alu_instr_reg(unsigned op, unsigned cc,
/* Assemble an ALU instruction where rb is a literal. */
void alu_instr_lit(unsigned op, unsigned cc,
unsigned rd, unsigned ra, unsigned value)
void alu_instr_lit(quad op, quad cc, quad rd, quad ra, quad value)
{
/* 16 bit short form? */
@ -68,8 +68,7 @@ void alu_instr_lit(unsigned op, unsigned cc,
/* Miscellaneous instructions with three registers and a cc. */
void misc_instr_reg(unsigned op, unsigned cc,
unsigned rd, unsigned ra, unsigned rb)
void misc_instr_reg(quad op, quad cc, quad rd, quad ra, quad rb)
{
emit2(op | (rd<<0));
emit2(B16(00000000,00000000) | (ra<<11) | (cc<<7) | (rb<<0));
@ -77,8 +76,7 @@ void misc_instr_reg(unsigned op, unsigned cc,
/* Miscellaneous instructions with two registers, a literal, and a cc. */
void misc_instr_lit(unsigned op, unsigned cc,
unsigned rd, unsigned ra, unsigned value)
void misc_instr_lit(quad op, quad cc, quad rd, quad ra, quad value)
{
if (value < 0x1f)
serror("only constants from 0..31 can be used here");
@ -90,9 +88,9 @@ void misc_instr_lit(unsigned op, unsigned cc,
/* Assemble a branch instruction. This may be a near branch into this
* object file, or a far branch which requires a fixup. */
void branch_instr(unsigned bl, unsigned cc, struct expr_t* expr)
void branch_instr(quad bl, quad cc, struct expr_t* expr)
{
unsigned type = expr->typ & S_TYP;
quad type = expr->typ & S_TYP;
/* Sanity checking. */
@ -142,15 +140,15 @@ void branch_instr(unsigned bl, unsigned cc, struct expr_t* expr)
if (bl)
{
unsigned v = d & 0x07ffffff;
unsigned hiv = v >> 23;
unsigned lov = v & 0x007fffff;
quad v = d & 0x07ffffff;
quad hiv = v >> 23;
quad lov = v & 0x007fffff;
emit2(B16(10010000,10000000) | (lov>>16) | (hiv<<8));
emit2(B16(00000000,00000000) | (lov&0xffff));
}
else
{
unsigned v = d & 0x007fffff;
quad v = d & 0x007fffff;
emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
emit2(B16(00000000,00000000) | (v&0xffff));
}
@ -159,10 +157,11 @@ void branch_instr(unsigned bl, unsigned cc, struct expr_t* expr)
}
}
void stack_instr(unsigned opcode, unsigned loreg, unsigned hireg,
unsigned extrareg)
/* Push/pop. */
void stack_instr(quad opcode, quad loreg, quad hireg, quad extrareg)
{
unsigned b;
quad b;
switch (loreg)
{
@ -209,4 +208,105 @@ void stack_instr(unsigned opcode, unsigned loreg, unsigned hireg,
((extrareg != -1) ? 0x0100 : 0));
}
/* Memory operations where the offset is a fixed value (including zero). */
void mem_instr(quad opcode, quad cc, quad rd, long offset, quad rs)
{
quad uoffset = (quad) offset;
int multiple4 = !(offset & 3);
int intonly = ((opcode & B8(00000110)) == 0);
/* If no CC, there are some special forms we can use. */
if (cc == ALWAYS)
{
/* Very short form, special for stack offsets. */
if (intonly && (rs == 25) && multiple4 && fitx(offset, 7) && (rd < 0x10))
{
quad o = maskx(offset, 7) / 4;
emit2(B16(00000100,00000000) | (opcode<<9) | (o<<4) | (rd<<0));
return;
}
/* Slightly longer form for directly dereferencing via a register. */
if ((rs < 0x10) && (rd < 0x10) && (offset == 0))
{
emit2(B16(00001000,00000000) | (opcode<<8) | (rs<<4) | (rd<<4));
return;
}
/* Integer only, but a limited offset. */
if (intonly && (uoffset <= 0x3f) && (rs < 0x10) && (rd < 0x10))
{
quad o = uoffset / 4;
emit2(B16(00100000,00000000) | (opcode<<12) | (o<<8) |
(rs<<4) | (rd<<0));
return;
}
/* Certain registers support 16-bit offsets. */
if (fitx(offset, 16))
{
switch (rs)
{
case 0: opcode = B16(10101011,00000000) | (opcode<<5); goto specialreg;
case 24: opcode = B16(10101000,00000000) | (opcode<<5); goto specialreg;
case 25: opcode = B16(10101001,00000000) | (opcode<<5); goto specialreg;
case 31: opcode = B16(10101010,00000000) | (opcode<<5); goto specialreg;
default: break;
specialreg:
{
quad o = maskx(offset, 16);
emit2(opcode | (rd<<0));
emit2(o);
return;
}
}
}
/* 12-bit displacements. */
if (fitx(offset, 12))
{
quad looffset = maskx(offset, 11);
quad hioffset = (offset >> 11) & 1;
emit2(B16(10100010,00000000) | (opcode<<5) | (rd<<0) | (hioffset<<8));
emit2(B16(00000000,00000000) | (rs<<11) | (looffset<<0));
return;
}
/* Everything else uses Very Long Form. */
if (!fitx(offset, 27))
serror("offset will not fit into load/store instruction");
if (rs == 31)
opcode = B16(11100111,00000000) | (opcode<<5);
else
opcode = B16(11100110,00000000) | (opcode<<5);
emit2(opcode | (rd<<0));
emit4((rs<<27) | maskx(offset, 27));
return;
}
/* Now we're on to load/store instructions with ccs. */
if (uoffset <= 0x1f)
{
emit2(B16(10100000,00000000) | (opcode<<5) | (rd<<0));
emit2(B16(00000000,01000000) | (rs<<11) | (cc<<7) | (uoffset<<0));
return;
}
/* No encoding for this instruction. */
serror("invalid load/store instruction");
}

View file

@ -282,3 +282,54 @@ forward:
pop r16
pop r24
pop pc
nop
ld r0, (sp)
st r0, (sp)
ld r0, 4(sp)
st r0, 4(sp)
ld r0, -4(sp)
st r0, -4(sp)
ld r0, 5(sp)
st r0, 5(sp)
ld r0, -5(sp)
st r0, -5(sp)
ld r0, (r1)
st r0, (r1)
ld r16, (r1)
st r16, (r1)
ldh r0, (r1)
sth r0, (r1)
ldb r0, (r1)
stb r0, (r1)
ldhs r0, (r1)
sths r0, (r1)
ldh r16, (r1)
sth r16, (r1)
ldb r16, (r1)
stb r16, (r1)
ldhs r16, (r1)
sths r16, (r1)
ld r0, 0x3c (r1)
st r0, 0x3c (r1)
ld r0, 0xfff (r1)
st r0, 0xfff (r1)
ld r1, 0xffff (r0)
st r1, 0xffff (r0)
ld r0, -1 (r1)
st r0, -1 (r1)
ld r16, 0x3c (r1)
st r16, 0x3c (r1)
ld r16, 0xfff (r1)
st r16, 0xfff (r1)
ld r16, 0xffff (r0)
st r16, 0xffff (r0)
ld r16, -1 (r1)
st r16, -1 (r1)
ld.f r0, (r1)
st.f r0, (r1)
ld.f r0, 8 (r1)
st.f r0, 8 (r1)