e576bb | 2002-10-11 | Martin Nilsson | | |
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | | || $Id: sparc.c,v 1.21 2002/11/07 16:58:49 grubba Exp $
|
e576bb | 2002-10-11 | Martin Nilsson | | */
|
1b10db | 2002-10-08 | Martin Nilsson | |
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | |
|
fc3100 | 2001-07-24 | Henrik Grubbström (Grubba) | | #include "operators.h"
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | |
#define SPARC_REG_G0 0
#define SPARC_REG_G1 1
#define SPARC_REG_G2 2
#define SPARC_REG_G3 3
#define SPARC_REG_G4 4
#define SPARC_REG_G5 5
#define SPARC_REG_G6 6
#define SPARC_REG_G7 7
#define SPARC_REG_O0 8
#define SPARC_REG_O1 9
#define SPARC_REG_O2 10
#define SPARC_REG_O3 11
#define SPARC_REG_O4 12
#define SPARC_REG_O5 13
#define SPARC_REG_O6 14 /* SP */
#define SPARC_REG_O7 15
#define SPARC_REG_L0 16
#define SPARC_REG_L1 17
#define SPARC_REG_L2 18
#define SPARC_REG_L3 19
#define SPARC_REG_L4 20
#define SPARC_REG_L5 21
#define SPARC_REG_L6 22
#define SPARC_REG_L7 23
#define SPARC_REG_I0 24
#define SPARC_REG_I1 25
#define SPARC_REG_I2 26
#define SPARC_REG_I3 27
#define SPARC_REG_I4 28
#define SPARC_REG_I5 29
#define SPARC_REG_I6 30 /* FP */
#define SPARC_REG_I7 31 /* PC */
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | * ALU operations.
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | */
#define SPARC_OP3_AND 0x01
#define SPARC_OP3_ANDcc 0x11
#define SPARC_OP3_ANDN 0x05
#define SPARC_OP3_ANDNcc 0x15
#define SPARC_OP3_OR 0x02
#define SPARC_OP3_ORcc 0x12
#define SPARC_OP3_ORN 0x06
#define SPARC_OP3_ORNcc 0x16
#define SPARC_OP3_XOR 0x03
#define SPARC_OP3_XORcc 0x13
#define SPARC_OP3_XNOR 0x07
#define SPARC_OP3_XNORcc 0x17
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | #define SPARC_OP3_ADD 0x00
#define SPARC_OP3_ADDcc 0x10
#define SPARC_OP3_ADDC 0x08
#define SPARC_OP3_ADDCcc 0x18
|
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | | #define SPARC_OP3_SUB 0x04
#define SPARC_OP3_SUBcc 0x14
#define SPARC_OP3_SUBC 0x0c
#define SPARC_OP3_SUBCcc 0x1c
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | | #define SPARC_OP3_SLL 0x25
#define SPARC_OP3_SRL 0x26
#define SPARC_OP3_SRA 0x27
#define SPARC_OP3_RD 0x28
|
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | | #define SPARC_OP3_SAVE 0x3c
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | |
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | | #define SPARC_RD_REG_CCR 0x02
#define SPARC_RD_REG_PC 0x05
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | #define SPARC_ALU_OP(OP3, D, S1, S2, I) \
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | add_to_program(0x80000000|((D)<<25)|((OP3)<<19)|((S1)<<14)|((I)<<13)| \
|
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | | ((S2)&0x1fff))
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | |
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | #define SPARC_OR(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_OR, D, S1, S2, I)
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | |
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | #define SPARC_SRA(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_SRA, D, S1, S2, I)
#define SPARC_ADD(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_ADD, D, S1, S2, I)
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | |
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | | #define SPARC_RD(D, RDREG) SPARC_ALU_OP(SPARC_OP3_RD, D, RDREG, 0, 0)
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | #define SPARC_SETHI(D, VAL) \
add_to_program(0x01000000|((D)<<25)|(((VAL)>>10)&0x3fffff))
#define SET_REG(REG, X) do { \
INT32 val_ = X; \
INT32 reg_ = REG; \
if ((-4096 <= val_) && (val_ <= 4095)) { \
/* or %g0, val_, reg */ \
|
40f462 | 2002-11-05 | Henrik Grubbström (Grubba) | | SPARC_OR(reg_, SPARC_REG_G0, val_, 1); \
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | } else { \
/* sethi %hi(val_), reg */ \
SPARC_SETHI(reg_, val_); \
if (val_ & 0x3ff) { \
/* or reg, %lo(val_), reg */ \
|
8d0cf1 | 2002-11-05 | Henrik Grubbström (Grubba) | | SPARC_OR(reg_, reg_, val_ & 0x3ff, 1); \
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | } \
if (val_ < 0) { \
/* Sign extend. */ \
/* sra reg, %g0, reg */ \
SPARC_SRA(reg_, reg_, SPARC_REG_G0, 0); \
} \
} \
} while(0)
|
f1d1eb | 2001-07-20 | Henrik Grubbström (Grubba) | | #define ADD_CALL(X, DELAY_OK) do { \
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | INT32 delta_; \
struct program *p_ = Pike_compiler->new_program; \
INT32 off_ = p_->num_program; \
|
f1d1eb | 2001-07-20 | Henrik Grubbström (Grubba) | | /* noop */ \
INT32 delay_ = 0x01000000; \
\
if (DELAY_OK) { \
/* Move the previous opcode to the delay-slot. */ \
delay_ = p_->program[--off_]; \
} else { \
add_to_program(0); /* Placeholder... */ \
} \
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | /* call X */ \
delta_ = ((PIKE_OPCODE_T *)(X)) - (p_->program + off_); \
p_->program[off_] = 0x40000000 | (delta_ & 0x3fffffff); \
add_to_relocations(off_); \
|
f1d1eb | 2001-07-20 | Henrik Grubbström (Grubba) | | add_to_program(delay_); \
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | | sparc_last_pc = off_; /* Value in %o7. */ \
sparc_codegen_state |= SPARC_CODEGEN_PC_IS_SET; \
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | } while(0)
#define SPARC_REG_PIKE_FP SPARC_REG_L0
#define SPARC_REG_SP SPARC_REG_O6
#define SPARC_REG_PC SPARC_REG_O7
unsigned INT32 sparc_codegen_state = 0;
int sparc_last_pc = 0;
#define LOAD_PIKE_FP() do { \
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | | if (1 || !(sparc_codegen_state & SPARC_CODEGEN_FP_IS_SET)) { \
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | SET_REG(SPARC_REG_PIKE_FP, \
((INT32)(&Pike_interpreter.frame_pointer))); \
/* lduw [ %i0 ], %i0 */ \
add_to_program(0xc0000000|(SPARC_REG_PIKE_FP<<25)| \
(SPARC_REG_PIKE_FP<<14)); \
sparc_codegen_state |= SPARC_CODEGEN_FP_IS_SET; \
} \
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | } while(0)
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | |
void sparc_ins_entry(void)
{
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | add_to_program(0x81e02000|(SPARC_REG_SP<<25)|
(SPARC_REG_SP<<14)|((-112)&0x1fff));
|
b3618b | 2002-11-06 | Henrik Grubbström (Grubba) | | FLUSH_CODE_GENERATOR_STATE();
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | }
|
8d0cf1 | 2002-11-05 | Henrik Grubbström (Grubba) | |
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | void sparc_update_pc(void)
{
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | |
SPARC_RD(SPARC_REG_I0, SPARC_RD_REG_PC);
|
0dc1b7 | 2002-11-06 | Henrik Grubbström (Grubba) | | LOAD_PIKE_FP();
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | |
add_to_program(0xc0202000|(SPARC_REG_I0<<25)|(SPARC_REG_PIKE_FP<<14)|
|
4f4332 | 2002-11-05 | Henrik Grubbström (Grubba) | | OFFSETOF(pike_frame, pc));
}
|
f1d1eb | 2001-07-20 | Henrik Grubbström (Grubba) | | static void low_ins_f_byte(unsigned int b, int delay_ok)
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | {
|
11ed4b | 2001-07-24 | Henrik Grubbström (Grubba) | | void *addr;
|
fc3100 | 2001-07-24 | Henrik Grubbström (Grubba) | |
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | #ifdef PIKE_DEBUG
if(store_linenumbers && b<F_MAX_OPCODE)
ADD_COMPILED(b);
#endif /* PIKE_DEBUG */
b-=F_OFFSET;
#ifdef PIKE_DEBUG
if(b>255)
Pike_error("Instruction too big %d\n",b);
#endif
|
11ed4b | 2001-07-24 | Henrik Grubbström (Grubba) | | addr = instrs[b].address;
|
9a928d | 2002-05-10 | Martin Stjernholm | | #ifdef PIKE_DEBUG
if (d_flag < 3)
#endif
|
fc3100 | 2001-07-24 | Henrik Grubbström (Grubba) | |
switch(b)
{
case F_MAKE_ITERATOR - F_OFFSET:
{
extern void f_Iterator(INT32);
SET_REG(SPARC_REG_O0, 1);
delay_ok = 1;
addr = (void *)f_Iterator;
}
break;
case F_ADD - F_OFFSET:
SET_REG(SPARC_REG_O0, 2);
delay_ok = 1;
addr = (void *)f_add;
break;
}
|
9a928d | 2002-05-10 | Martin Stjernholm | |
|
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | | {
static int last_prog_id=-1;
static size_t last_num_linenumbers=(size_t)~0;
if(last_prog_id != Pike_compiler->new_program->id ||
last_num_linenumbers != Pike_compiler->new_program->num_linenumbers)
{
last_prog_id=Pike_compiler->new_program->id;
last_num_linenumbers = Pike_compiler->new_program->num_linenumbers;
LOAD_PIKE_FP();
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | | |
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | | * This works since the new %o7 is available immediately.
* (Sparc Architecture Manual V9 p149.)
*/
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | |
add_to_program(0xc0202000|(SPARC_REG_O7<<25)|(SPARC_REG_PIKE_FP<<14)|
|
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | | OFFSETOF(pike_frame, pc));
|
327cdd | 2002-11-07 | Henrik Grubbström (Grubba) | |
|
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | | delay_ok = 1;
}
}
|
11ed4b | 2001-07-24 | Henrik Grubbström (Grubba) | | ADD_CALL(addr, delay_ok);
|
f1d1eb | 2001-07-20 | Henrik Grubbström (Grubba) | | }
void ins_f_byte(unsigned int opcode)
{
low_ins_f_byte(opcode, 0);
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | }
void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b)
{
|
7df348 | 2001-07-21 | Henrik Grubbström (Grubba) | | SET_REG(SPARC_REG_O0, b);
|
f1d1eb | 2001-07-20 | Henrik Grubbström (Grubba) | | low_ins_f_byte(a, 1);
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | return;
}
void ins_f_byte_with_2_args(unsigned int a,
unsigned INT32 c,
unsigned INT32 b)
{
|
7df348 | 2001-07-21 | Henrik Grubbström (Grubba) | | SET_REG(SPARC_REG_O0, c);
SET_REG(SPARC_REG_O1, b);
|
f1d1eb | 2001-07-20 | Henrik Grubbström (Grubba) | | low_ins_f_byte(a, 1);
|
dd6bca | 2001-07-20 | Henrik Grubbström (Grubba) | | return;
}
|
697e0a | 2001-07-20 | Henrik Grubbström (Grubba) | |
#define addstr(s, l) low_my_binary_strcat((s), (l), buf)
#define adddata2(s,l) addstr((char *)(s),(l) * sizeof((s)[0]));
void sparc_encode_program(struct program *p, struct dynamic_buffer_s *buf)
{
size_t prev = 0, rel;
for (rel = 0; rel < p->num_relocations; rel++) {
size_t off = p->relocations[rel];
INT32 opcode;
#ifdef PIKE_DEBUG
if (off < prev) {
|
5aad93 | 2002-08-15 | Marcus Comstedt | | Pike_fatal("Relocations in bad order!\n");
|
697e0a | 2001-07-20 | Henrik Grubbström (Grubba) | | }
#endif /* PIKE_DEBUG */
adddata2(p->program + prev, off - prev);
#ifdef PIKE_DEBUG
if ((p->program[off] & 0xc0000000) != 0x40000000) {
|
5aad93 | 2002-08-15 | Marcus Comstedt | | Pike_fatal("Bad relocation!\n");
|
697e0a | 2001-07-20 | Henrik Grubbström (Grubba) | | }
#endif /* PIKE_DEBUG */
opcode = 0x40000000 |
((p->program[off] + (((INT32)(p->program)>>2))) & 0x3fffffff);
adddata2(&opcode, 1);
prev = off+1;
}
adddata2(p->program + prev, p->num_program - prev);
}
void sparc_decode_program(struct program *p)
{
PIKE_OPCODE_T *prog = p->program;
INT32 delta = ((INT32)p->program)>>2;
size_t rel = p->num_relocations;
while (rel--) {
#ifdef PIKE_DEBUG
if ((prog[p->relocations[rel]] & 0xc0000000) != 0x40000000) {
Pike_error("Bad relocation: %d, off:%d, opcode: 0x%08x\n",
rel, p->relocations[rel],
prog[p->relocations[rel]]);
}
#endif /* PIKE_DEBUG */
prog[p->relocations[rel]] = 0x40000000 |
(((prog[p->relocations[rel]] & 0x3fffffff) - delta) &
0x3fffffff);
}
}
|
9d2e2d | 2001-07-21 | Henrik Grubbström (Grubba) | |
const unsigned INT32 sparc_flush_instruction_cache[] = {
0x80a02000|(SPARC_REG_O1<<14)|1,
0x81d80000|(SPARC_REG_O0<<14)|(SPARC_REG_O1),
0x36800000|((-1)&0x3fffff),
0x80a02000|(SPARC_REG_O1<<25)|(SPARC_REG_O1<<14)|8,
0x81c02000|(SPARC_REG_O7<<14)|8,
0x80100000|(SPARC_REG_O0<<25),
};
|
f5e862 | 2002-11-07 | Henrik Grubbström (Grubba) | |
static void sparc_disass_reg(int reg_no)
{
fprintf(stderr, "%%%c%1x", "goli"[(reg_no>>3)&3], reg_no & 7);
}
void sparc_disassemble_code(void *addr, size_t bytes)
{
unsigned INT32 *code = addr;
size_t len = (bytes+3)>>2;
while(len--) {
unsigned INT32 opcode = *code;
fprintf(stderr, "%p %08x ", code, opcode);
switch(opcode & 0xc0000000) {
case 0x00000000:
{
int op2 = (opcode >> 22) & 0x7;
switch(op2) {
case 4:
fprintf(stderr, "sethi %%hi(0x%08x), ", opcode << 10);
break;
}
sparc_disass_reg(opcode>>25);
fprintf(stderr, "\n");
}
break;
case 0x40000000:
fprintf(stderr, "call 0x%p\n", ((char *)code) + (opcode << 2));
break;
case 0x80000000:
{
int op3 = (opcode >> 19) & 0x3f;
char buf[16];
char *mnemonic = NULL;
if (!(op3 & 0x20)) {
switch(op3 & 0xf) {
case SPARC_OP3_ADD: mnemonic = "add"; break;
case SPARC_OP3_AND: mnemonic = "and"; break;
case SPARC_OP3_OR: mnemonic = "or"; break;
case SPARC_OP3_XOR: mnemonic = "xor"; break;
case SPARC_OP3_SUB: mnemonic = "sub"; break;
case SPARC_OP3_ANDN: mnemonic = "andn"; break;
case SPARC_OP3_ORN: mnemonic = "orn"; break;
case SPARC_OP3_XNOR: mnemonic = "xnor"; break;
case SPARC_OP3_ADDC: mnemonic = "addc"; break;
case SPARC_OP3_SUBC: mnemonic = "subc"; break;
default:
sprintf(buf, "op3(0x%02x)", op3 & 0xf);
mnemonic = buf;
break;
}
if (op3 & 0x10) {
fprintf(stderr, "%scc ", mnemonic);
} else {
fprintf(stderr, "%s ", mnemonic);
}
} else {
switch(op3) {
case SPARC_OP3_SLL: mnemonic = "sll"; break;
case SPARC_OP3_SRL: mnemonic = "srl"; break;
case SPARC_OP3_SRA: mnemonic = "sra"; break;
case SPARC_OP3_SAVE: mnemonic = "save"; break;
default:
sprintf(buf, "op3(0x%02x)", op3);
mnemonic = buf;
break;
}
fprintf(stderr, "%s ", mnemonic);
}
sparc_disass_reg(opcode>>14);
fprintf(stderr, ", ");
if (opcode & 0x00002000) {
fprintf(stderr, "0x%04x, ", opcode & 0x1fff);
} else {
sparc_disass_reg(opcode);
fprintf(stderr, ", ");
}
sparc_disass_reg(opcode >> 25);
fprintf(stderr, "\n");
}
break;
case 0xc0000000:
{
int op3 = (opcode >> 19) & 0x3f;
char buf[16];
char *mnemonic = NULL;
switch(op3) {
case 0x00: mnemonic="lduw"; break;
case 0x01: mnemonic="ldub"; break;
case 0x02: mnemonic="lduh"; break;
case 0x03: mnemonic="ldd"; break;
case 0x04: mnemonic="stw"; break;
case 0x05: mnemonic="stb"; break;
case 0x06: mnemonic="sth"; break;
case 0x07: mnemonic="std"; break;
case 0x08: mnemonic="ldsw"; break;
case 0x09: mnemonic="ldsb"; break;
case 0x0a: mnemonic="ldsh"; break;
case 0x0b: mnemonic="ldx"; break;
case 0x0e: mnemonic="stx"; break;
default:
sprintf(buf, "op3(0x%02x)", op3);
mnemonic = buf;
break;
}
if (op3 & 0x04) {
fprintf(stderr, "%s ", mnemonic);
sparc_disass_reg(opcode >> 25);
fprintf(stderr, ", [");
sparc_disass_reg(opcode >> 14);
if (opcode & 0x00002000) {
fprintf(stderr, ", 0x%04x", opcode & 0x1fff);
} else {
fprintf(stderr, ", ");
sparc_disass_reg(opcode);
}
fprintf(stderr, "]\n");
} else {
fprintf(stderr, "%s [", mnemonic);
sparc_disass_reg(opcode >> 14);
if (opcode & 0x00002000) {
fprintf(stderr, ", 0x%04x", opcode & 0x1fff);
} else {
fprintf(stderr, ", ");
sparc_disass_reg(opcode);
}
fprintf(stderr, "], ");
sparc_disass_reg(opcode >> 25);
fprintf(stderr, "\n");
}
}
break;
}
code++;
}
}
|