Merge pull request #131 from davidgiven/dtrg-mips
Add an mcg-based MIPS code generator.
This commit is contained in:
commit
8fd3e1f5ce
101 changed files with 5450 additions and 781 deletions
3
README
3
README
|
@ -33,6 +33,7 @@ pc86 produces bootable floppy disk images for 8086 PCs
|
|||
linux386 produces ELF executables for PC Linux systems
|
||||
linux68k produces ELF executables for m68020 Linux systems
|
||||
linuxppc produces ELF executables for PowerPC Linux systems
|
||||
linuxmips produces ELF executables for little-endian MIPS32r2 Linux systems
|
||||
cpm produces i80 CP/M .COM files
|
||||
rpi produces Raspberry Pi GPU binaries
|
||||
pdpv7 produces PDP/11 V7 Unix binaries
|
||||
|
@ -194,4 +195,4 @@ Please enjoy.
|
|||
|
||||
David Given (davidgiven on Github)
|
||||
dg@cowlark.com
|
||||
2016-11-26
|
||||
2018-09-18
|
||||
|
|
|
@ -10,9 +10,9 @@ vars.plats = {
|
|||
"linux386",
|
||||
"linux68k",
|
||||
"linuxppc",
|
||||
"linuxmips",
|
||||
"osx386",
|
||||
"osxppc",
|
||||
-- --"qemuppc",
|
||||
"pc86",
|
||||
"rpi",
|
||||
"pdpv7",
|
||||
|
@ -22,7 +22,7 @@ vars.plats_with_tests = {
|
|||
"linux68k",
|
||||
"linux386",
|
||||
"linuxppc",
|
||||
-- --"qemuppc",
|
||||
"linuxmips",
|
||||
"pc86",
|
||||
}
|
||||
|
||||
|
|
205
h/con_float
205
h/con_float
|
@ -5,7 +5,7 @@
|
|||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
/*
|
||||
#define CODE_GENERATOR for code generator
|
||||
#define CODE_EXPANDER for code expander
|
||||
|
||||
|
@ -20,9 +20,9 @@
|
|||
|
||||
Unfortunately, the IEEE standard does not define the byte-order.
|
||||
depends on the #defines
|
||||
FL_MSL_AT_LOW_ADDRESS 1 if most significant long is at low address
|
||||
FL_MSW_AT_LOW_ADDRESS 1 if most significant word is at low address
|
||||
FL_MSB_AT_LOW_ADDRESS 1 if most significant byte is at low address
|
||||
FL_MSL_AT_LOW_ADDRESS 1 if most significant long is at low address
|
||||
FL_MSW_AT_LOW_ADDRESS 1 if most significant word is at low address
|
||||
FL_MSB_AT_LOW_ADDRESS 1 if most significant byte is at low address
|
||||
*/
|
||||
#ifdef IEEEFLOAT
|
||||
#define USE_FLT
|
||||
|
@ -37,47 +37,57 @@
|
|||
#define FL_MSB_AT_LOW_ADDRESS 0
|
||||
#endif
|
||||
|
||||
#define I0 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I1 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
#define I2 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I3 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
#define I4 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I5 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
#define I6 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I7 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
#define I0 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I1 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
#define I2 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I3 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
#define I4 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I5 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
#define I6 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
|
||||
#define I7 \
|
||||
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
|
||||
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
|
||||
|
||||
#ifndef USE_FLT
|
||||
static int
|
||||
float_cst(str, sz, buf)
|
||||
char *str, *buf;
|
||||
int sz;
|
||||
static int float_cst(str, sz, buf) char *str, *buf;
|
||||
int sz;
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
char* p;
|
||||
float fl;
|
||||
double f;
|
||||
double atof();
|
||||
|
||||
if (sz!= 4 && sz!= 8) {
|
||||
if (sz != 4 && sz != 8)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
f = atof(str);
|
||||
if (sz == 4) {
|
||||
if (sz == 4)
|
||||
{
|
||||
fl = f;
|
||||
p = (char *) &fl;
|
||||
p = (char*)&fl;
|
||||
}
|
||||
else {
|
||||
p = (char *) &f;
|
||||
else
|
||||
{
|
||||
p = (char*)&f;
|
||||
}
|
||||
for (i = sz; i; i--) {
|
||||
for (i = sz; i; i--)
|
||||
{
|
||||
*buf++ = *p++;
|
||||
}
|
||||
return 0;
|
||||
|
@ -87,89 +97,105 @@ float_cst(str, sz, buf)
|
|||
#include <ctype.h>
|
||||
#include <flt_arith.h>
|
||||
|
||||
int
|
||||
float_cst(str, sz, buf)
|
||||
char *str, *buf;
|
||||
int sz;
|
||||
int float_cst(str, sz, buf) char *str, *buf;
|
||||
int sz;
|
||||
{
|
||||
int overflow = 0;
|
||||
flt_arith e;
|
||||
|
||||
if (sz!= 4 && sz!= 8) {
|
||||
if (sz != 4 && sz != 8)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
flt_str2flt(str, &e);
|
||||
#ifdef IEEEFLOAT
|
||||
if (sz == 4) {
|
||||
if (sz == 4)
|
||||
{
|
||||
#endif
|
||||
#ifdef PDPFLOAT
|
||||
e.flt_exp += 129;
|
||||
#else
|
||||
e.flt_exp += 127;
|
||||
e.flt_exp += 127;
|
||||
#endif
|
||||
if (e.flt_mantissa.flt_h_32 == 0) e.flt_exp = 0;
|
||||
if (e.flt_mantissa.flt_h_32 == 0)
|
||||
e.flt_exp = 0;
|
||||
#ifdef IEEEFLOAT
|
||||
if (e.flt_mantissa.flt_h_32 & 0x80) {
|
||||
if (e.flt_mantissa.flt_h_32 & 0x80)
|
||||
{
|
||||
/* rounding */
|
||||
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00) {
|
||||
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00)
|
||||
{
|
||||
e.flt_exp++;
|
||||
e.flt_mantissa.flt_h_32 = 0x80000000;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
e.flt_mantissa.flt_h_32 += 0x80;
|
||||
}
|
||||
}
|
||||
if (e.flt_exp >= 255) {
|
||||
if (e.flt_exp >= 255)
|
||||
{
|
||||
overflow = 1;
|
||||
e.flt_exp = 255;
|
||||
e.flt_mantissa.flt_h_32 = e.flt_mantissa.flt_l_32 = 0;
|
||||
}
|
||||
if (e.flt_exp <= 0) {
|
||||
if (e.flt_exp <= 0)
|
||||
{
|
||||
flt_b64_sft(&(e.flt_mantissa), 1);
|
||||
if (e.flt_exp < 0) {
|
||||
if (e.flt_exp < 0)
|
||||
{
|
||||
flt_b64_sft(&(e.flt_mantissa), -e.flt_exp);
|
||||
e.flt_exp = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef IEEEFLOAT
|
||||
if (sz == 4 && (e.flt_mantissa.flt_h_32 & 0x80)) {
|
||||
if (sz == 4 && (e.flt_mantissa.flt_h_32 & 0x80))
|
||||
{
|
||||
/* rounding */
|
||||
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00) {
|
||||
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00)
|
||||
{
|
||||
e.flt_exp++;
|
||||
e.flt_mantissa.flt_h_32 = 0x80000000;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
e.flt_mantissa.flt_h_32 += 0x80;
|
||||
}
|
||||
}
|
||||
if (sz == 8 && (e.flt_mantissa.flt_l_32 & 0x80)) {
|
||||
if (sz == 8 && (e.flt_mantissa.flt_l_32 & 0x80))
|
||||
{
|
||||
/* rounding */
|
||||
if ((e.flt_mantissa.flt_l_32 & 0xffffff00) == 0xffffff00) {
|
||||
if ((e.flt_mantissa.flt_l_32 & 0xffffff00) == 0xffffff00)
|
||||
{
|
||||
e.flt_mantissa.flt_l_32 = 0;
|
||||
if (e.flt_mantissa.flt_h_32 == 0xffffffff) {
|
||||
if (e.flt_mantissa.flt_h_32 == 0xffffffff)
|
||||
{
|
||||
e.flt_exp++;
|
||||
e.flt_mantissa.flt_h_32 = 0x80000000;
|
||||
}
|
||||
else e.flt_mantissa.flt_h_32++;
|
||||
else
|
||||
e.flt_mantissa.flt_h_32++;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
e.flt_mantissa.flt_l_32 += 0x80;
|
||||
}
|
||||
}
|
||||
if (e.flt_exp > 255) {
|
||||
if (e.flt_exp > 255)
|
||||
{
|
||||
overflow = 1;
|
||||
e.flt_exp = 255;
|
||||
e.flt_mantissa.flt_h_32 = e.flt_mantissa.flt_l_32 = 0xffffffff;
|
||||
}
|
||||
#endif
|
||||
buf[I0] = (e.flt_sign << 7) | (e.flt_exp >> 1);
|
||||
buf[I1] = ((e.flt_exp&1) << 7) |
|
||||
((e.flt_mantissa.flt_h_32 & 0x7fffffff) >> 24);
|
||||
buf[I1] = ((e.flt_exp & 1) << 7) | ((e.flt_mantissa.flt_h_32 & 0x7fffffff) >> 24);
|
||||
buf[I2] = e.flt_mantissa.flt_h_32 >> 16;
|
||||
buf[I3] = e.flt_mantissa.flt_h_32 >> 8;
|
||||
#ifndef IEEEFLOAT
|
||||
if (sz == 8) {
|
||||
if (sz == 8)
|
||||
{
|
||||
buf[I4] = e.flt_mantissa.flt_h_32;
|
||||
buf[I5] = e.flt_mantissa.flt_l_32 >> 24;
|
||||
buf[I6] = e.flt_mantissa.flt_l_32 >> 16;
|
||||
|
@ -181,37 +207,47 @@ float_cst(str, sz, buf)
|
|||
flt_b64_sft(&(e.flt_mantissa), -24);
|
||||
#ifdef IEEEFLOAT
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
e.flt_exp += 1023;
|
||||
if (e.flt_mantissa.flt_h_32 == 0) e.flt_exp = 0;
|
||||
if (e.flt_mantissa.flt_l_32 & 0x400) {
|
||||
if (e.flt_mantissa.flt_h_32 == 0)
|
||||
e.flt_exp = 0;
|
||||
if (e.flt_mantissa.flt_l_32 & 0x400)
|
||||
{
|
||||
/* rounding */
|
||||
if ((e.flt_mantissa.flt_l_32 & 0xfffff800) == 0xfffff800) {
|
||||
if ((e.flt_mantissa.flt_l_32 & 0xfffff800) == 0xfffff800)
|
||||
{
|
||||
e.flt_mantissa.flt_l_32 = 0;
|
||||
if (e.flt_mantissa.flt_h_32 == 0xffffffff) {
|
||||
if (e.flt_mantissa.flt_h_32 == 0xffffffff)
|
||||
{
|
||||
e.flt_exp++;
|
||||
e.flt_mantissa.flt_h_32 = 0x80000000;
|
||||
}
|
||||
else e.flt_mantissa.flt_h_32++;
|
||||
else
|
||||
e.flt_mantissa.flt_h_32++;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
e.flt_mantissa.flt_l_32 += 0x400;
|
||||
}
|
||||
}
|
||||
if (e.flt_exp >= 2047) {
|
||||
if (e.flt_exp >= 2047)
|
||||
{
|
||||
overflow = 1;
|
||||
e.flt_exp = 2047;
|
||||
e.flt_mantissa.flt_h_32 = e.flt_mantissa.flt_l_32 = 0;
|
||||
}
|
||||
if (e.flt_exp <= 0) {
|
||||
if (e.flt_exp <= 0)
|
||||
{
|
||||
flt_b64_sft(&(e.flt_mantissa), 1);
|
||||
if (e.flt_exp < 0) {
|
||||
if (e.flt_exp < 0)
|
||||
{
|
||||
flt_b64_sft(&(e.flt_mantissa), -e.flt_exp);
|
||||
e.flt_exp = 0;
|
||||
}
|
||||
}
|
||||
buf[I0] = (e.flt_sign << 7) | (e.flt_exp >> 4);
|
||||
buf[I1] = ((e.flt_exp & 017)<< 4) | ((e.flt_mantissa.flt_h_32 >> 27) & 017);
|
||||
buf[I1] = ((e.flt_exp & 017) << 4) | ((e.flt_mantissa.flt_h_32 >> 27) & 017);
|
||||
buf[I2] = e.flt_mantissa.flt_h_32 >> 19;
|
||||
buf[I3] = e.flt_mantissa.flt_h_32 >> 11;
|
||||
buf[I4] = e.flt_mantissa.flt_h_32 >> 3;
|
||||
|
@ -221,15 +257,17 @@ float_cst(str, sz, buf)
|
|||
flt_b64_sft(&(e.flt_mantissa), -53);
|
||||
}
|
||||
#endif
|
||||
#if ! FL_MSL_AT_LOW_ADDRESS
|
||||
if (sz == 4) {
|
||||
#if !FL_MSL_AT_LOW_ADDRESS
|
||||
if (sz == 4)
|
||||
{
|
||||
buf[I4] = buf[I0];
|
||||
buf[I5] = buf[I1];
|
||||
buf[I6] = buf[I2];
|
||||
buf[I7] = buf[I3];
|
||||
}
|
||||
#endif
|
||||
if (overflow) {
|
||||
if (overflow)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
|
@ -237,22 +275,25 @@ float_cst(str, sz, buf)
|
|||
#endif /* USE_FLT */
|
||||
|
||||
#ifdef CODE_GENERATOR
|
||||
con_float()
|
||||
void con_float(void)
|
||||
{
|
||||
char buf[8];
|
||||
int rval = float_cst(str, (int)argval, buf);
|
||||
int i;
|
||||
|
||||
if (rval == 1) {
|
||||
fprintf(stderr,"float constant size = %d\n",(int)argval);
|
||||
if (rval == 1)
|
||||
{
|
||||
fprintf(stderr, "float constant size = %d\n", (int)argval);
|
||||
fatal("bad fcon size");
|
||||
}
|
||||
fprintf(codefile,"!float %s sz %d\n", str, (int)argval);
|
||||
if (rval == 2) {
|
||||
fprintf(codefile, "!float %s sz %d\n", str, (int)argval);
|
||||
if (rval == 2)
|
||||
{
|
||||
fprintf(stderr, "Warning: overflow in floating point constant %s\n", str);
|
||||
}
|
||||
fprintf(codefile, ".data1 0%o", buf[0] & 0377);
|
||||
for (i = 1; i < (int)argval; i++) {
|
||||
for (i = 1; i < (int)argval; i++)
|
||||
{
|
||||
fprintf(codefile, ",0%o", buf[i] & 0377);
|
||||
}
|
||||
putc('\n', codefile);
|
||||
|
@ -260,19 +301,19 @@ con_float()
|
|||
#endif /* CODE_GENERATOR */
|
||||
|
||||
#ifdef CODE_EXPANDER
|
||||
con_float(str, argval)
|
||||
char *str;
|
||||
arith argval;
|
||||
void con_float(const char* str, arith argval)
|
||||
{
|
||||
char buf[8];
|
||||
int rval = float_cst(str, (int)argval, buf);
|
||||
int i;
|
||||
|
||||
if (rval == 1) {
|
||||
if (rval == 1)
|
||||
{
|
||||
argval = 8;
|
||||
rval = float_cst(str, 8, buf);
|
||||
}
|
||||
for (i = 0; i < (int)argval; i++) {
|
||||
for (i = 0; i < (int)argval; i++)
|
||||
{
|
||||
gen1(buf[i]);
|
||||
}
|
||||
}
|
||||
|
|
5
h/out.h
5
h/out.h
|
@ -67,7 +67,10 @@ struct outname {
|
|||
#define RELO4 3 /* 4 bytes */
|
||||
#define RELOPPC 4 /* PowerPC 26-bit address */
|
||||
#define RELOPPC_LIS 5 /* PowerPC lis */
|
||||
#define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */
|
||||
#define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */
|
||||
#define RELOMIPS 7 /* MIPS */
|
||||
#define RELO2HI 8 /* high 2 bytes of word */
|
||||
#define RELO2HISAD 9 /* high 2 bytes of word, sign adjusted */
|
||||
|
||||
#define RELPC 0x2000 /* pc relative */
|
||||
#define RELBR 0x4000 /* High order byte lowest address. */
|
||||
|
|
|
@ -199,19 +199,26 @@ int lab;
|
|||
|
||||
genreturns()
|
||||
{
|
||||
int count;
|
||||
int nr;
|
||||
|
||||
nr= genlabel();
|
||||
C_df_dnam("returns");
|
||||
C_rom_ilb((label) nr);
|
||||
C_rom_cst((arith)1);
|
||||
C_rom_cst((arith) (gosubcnt-1));
|
||||
C_rom_cst((arith) (gosubcnt-2));
|
||||
|
||||
count = 0;
|
||||
while ( gosubhead)
|
||||
{
|
||||
C_rom_ilb((label) gosubhead->emlabel);
|
||||
gosubhead= gosubhead->nextlist;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count != (gosubcnt-1))
|
||||
error("gosub count table mismatch");
|
||||
|
||||
C_df_ilb((label) nr);
|
||||
C_loc((arith) 1);
|
||||
C_cal("error");
|
||||
|
|
6
mach/mips/as/build.lua
Normal file
6
mach/mips/as/build.lua
Normal file
|
@ -0,0 +1,6 @@
|
|||
normalrule {
|
||||
name = "astables",
|
||||
outleaves = {"definitions.y", "tokens.y", "rules.y"},
|
||||
ins = {"./mktables.lua", "./instructions.dat"},
|
||||
commands = {"$(LUA) %{ins[1]} %{outs} < %{ins[2]}"}
|
||||
}
|
275
mach/mips/as/instructions.dat
Normal file
275
mach/mips/as/instructions.dat
Normal file
|
@ -0,0 +1,275 @@
|
|||
# Syntax:
|
||||
# <thing---->: a field occupying so many bits.
|
||||
# T: a field occupying one bit.
|
||||
# Undefined bits end up as 0.
|
||||
#
|
||||
# This is intended to be compatible with MIPS release 5, integer instructions
|
||||
# only. It's based on the MIPS32 Instruction Set v5.04 manual (available from
|
||||
# https://www.mips.com/products/architectures/mips32-2/).
|
||||
|
||||
# Useful pseudoops.
|
||||
|
||||
# or RD, RS, zero
|
||||
000000<RS->00000<RD->00000100101 "mov" RD=gpr ',' RS=gpr
|
||||
|
||||
# Condition code tokens; these have to be defined here because .f overlaps with
|
||||
# a format code.
|
||||
|
||||
%token .f
|
||||
%token .un
|
||||
%token .eq
|
||||
%token .ueq
|
||||
%token .olt
|
||||
%token .ult
|
||||
%token .ole
|
||||
%token .ule
|
||||
%token .sf
|
||||
%token .ngle
|
||||
%token .seq
|
||||
%token .ngl
|
||||
%token .lt
|
||||
%token .nge
|
||||
%token .le
|
||||
%token .ngt
|
||||
|
||||
# Core ALU instructions.
|
||||
|
||||
000000<RS-><RT-><RD->00000100000 "add" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
001000<RS-><RT-><IMM-----------> "addi" RT=gpr ',' RS=gpr ',' IMM=e16
|
||||
001001<RS-><RT-><IMM-----------> "addiu" RT=gpr ',' RS=gpr ',' IMM=e16
|
||||
000000<RS-><RT-><RD->00000100001 "addu" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT-><RD->00000100100 "and" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
001100<RS-><RT-><IMM-----------> "andi" RT=gpr ',' RS=gpr ',' IMM=e16
|
||||
0001000000000000<OFF-----------> "b" OFF=offset16
|
||||
0000010000010001<OFF-----------> "bal" OFF=offset16
|
||||
000100<RS-><RT-><OFF-----------> "beq" RS=gpr ',' RT=gpr ',' OFF=offset16
|
||||
010100<RS-><RT-><OFF-----------> "beql" RS=gpr ',' RT=gpr ',' OFF=offset16
|
||||
000001<RS->00001<OFF-----------> "bgez" RS=gpr ',' OFF=offset16
|
||||
000001<RS->10001<OFF-----------> "bgezal" RS=gpr ',' OFF=offset16
|
||||
000001<RS->10011<OFF-----------> "bgezall" RS=gpr ',' OFF=offset16
|
||||
000001<RS->00011<OFF-----------> "bgezl" RS=gpr ',' OFF=offset16
|
||||
000111<RS->00000<OFF-----------> "bgtz" RS=gpr ',' OFF=offset16
|
||||
010111<RS->00000<OFF-----------> "bgtzl" RS=gpr ',' OFF=offset16
|
||||
000110<RS->00000<OFF-----------> "blez" RS=gpr ',' OFF=offset16
|
||||
010110<RS->00000<OFF-----------> "blezl" RS=gpr ',' OFF=offset16
|
||||
000001<RS->00000<OFF-----------> "bltz" RS=gpr ',' OFF=offset16
|
||||
000001<RS->10000<OFF-----------> "bltzal" RS=gpr ',' OFF=offset16
|
||||
000001<RS->10010<OFF-----------> "bltzall" RS=gpr ',' OFF=offset16
|
||||
000001<RS->00010<OFF-----------> "bltzl" RS=gpr ',' OFF=offset16
|
||||
000101<RS-><RT-><OFF-----------> "bne" RS=gpr ',' RT=gpr ',' OFF=offset16
|
||||
010101<RS-><RT-><OFF-----------> "bnel" RS=gpr ',' RT=gpr ',' OFF=offset16
|
||||
101111<RS-><OP-><OFF-----------> "cache" OP=u5 ',' OFF=e16 '(' RS=gpr ')'
|
||||
011111<RS-><OP-><OFF---->0011011 "cachee" OP=u5 ',' OFF=e9 '(' RS=gpr ')'
|
||||
011100<RS-><RT-><RD->00000100001 "clo" RD=RT=gpr ',' RS=gpr
|
||||
011100<RS-><RT-><RD->00000100000 "clz" RD=RT=gpr ',' RS=gpr
|
||||
01000010000000000000000000011111 "deret"
|
||||
01000001011<RT->0110000000000000 "di" RT=gpr
|
||||
01000001011000000110000000000000 "di"
|
||||
000000<RS-><RT->0000000000011010 "div" RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT->0000000000011011 "divu" RS=gpr ',' RT=gpr
|
||||
00000000000000000000000011000000 "ehb"
|
||||
01000001011<RT->0110000000100000 "ei" RT=gpr
|
||||
01000001011000000110000000100000 "ei"
|
||||
011111<RS-><RT-><MSBLSB-->000000 "ext" RT=gpr ',' RS=gpr ',' extmsblsb
|
||||
011111<RS-><RT-><MSBLSB-->000100 "ins" RT=gpr ',' RS=gpr ',' insmsblsb
|
||||
000010<ABS---------------------> "j" ABS=abs26
|
||||
000011<ABS---------------------> "jal" ABS=abs26
|
||||
000000<RS->00000<RD->00000001001 "jalr" RD=gpr ',' RS=gpr
|
||||
000000<RS->000001111100000001001 "jalr" RS=gpr
|
||||
000000<RS->00000<RD->10000001001 "jalr.hb" RD=gpr ',' RS=gpr
|
||||
000000<RS->000001111110000001001 "jalr.hb" RS=gpr
|
||||
011101<ABS---------------------> "jalx" ABS=abs26
|
||||
000000<RS->000000000000000001000 "jr" RS=gpr
|
||||
000000<RS->000000000010000001000 "jr.hb" RS=gpr
|
||||
100000<RS-><RT-><IMM-----------> "lb" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0101100 "lbe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
100100<RS-><RT-><IMM-----------> "lbu" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0101000 "lbue" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
100001<RS-><RT-><IMM-----------> "lh" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0101101 "lhe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
100101<RS-><RT-><IMM-----------> "lhu" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0101001 "lhue" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
110000<RS-><RT-><IMM-----------> "ll" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0101110 "lle" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
00111100000<RT-><IMM-----------> "lui" RT=gpr ',' IMM=e16
|
||||
100011<RS-><RT-><IMM-----------> "lw" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0101111 "lwe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
100010<RS-><RT-><IMM-----------> "lwl" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0011001 "lwle" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
100110<RS-><RT-><IMM-----------> "lwr" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0011010 "lwre" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
011100<RS-><RT->0000000000000000 "madd" RS=gpr ',' RT=gpr
|
||||
011100<RS-><RT->0000000000000001 "maddu" RS=gpr ',' RT=gpr
|
||||
0000000000000000<RD->00000010000 "mfhi" RD=gpr
|
||||
0000000000000000<RD->00000010010 "mflo" RD=gpr
|
||||
000000<RS-><RT-><RD->00000001011 "movn" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT-><RD->00000001010 "movz" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
011100<RS-><RT->0000000000000100 "msub" RS=gpr ',' RT=gpr
|
||||
011100<RS-><RT->0000000000000101 "msubu" RS=gpr ',' RT=gpr
|
||||
000000<RS->000000000000000010001 "mthi" RS=gpr
|
||||
000000<RS->000000000000000010011 "mtlo" RS=gpr
|
||||
011100<RS-><RT-><RD->00000000010 "mul" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT->0000000000011000 "mult" RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT->0000000000000001 "multu" RS=gpr ',' RT=gpr
|
||||
00000000000000000000000000000000 "nop"
|
||||
000000<RS-><RT-><RD->00000100111 "nor" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT-><RD->00000100101 "or" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
001101<RS-><RT-><IMM-----------> "ori" RT=gpr ',' RS=gpr ',' IMM=e16
|
||||
00000000000000000000000101000000 "pause"
|
||||
110011<RS-><H--><IMM-----------> "pref" H=u5 ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><H--><IMM---->0100011 "prefe" H=u5 ',' IMM=e9 '(' RS=gpr ')'
|
||||
010011<RS-><RT-><H-->00000001111 "prefx" H=u5 ',' RT=gpr '(' RS=gpr ')'
|
||||
01111100000<RT-><RD->00000111011 "rdhwr" RT=gpr ',' RD=gpr
|
||||
01000001010<RT-><RD->00000000000 "rdpgpr" RD=gpr ',' RT=gpr
|
||||
00000000001<RT-><RD-><SA->000010 "rotr" RD=gpr ',' RT=gpr ',' SA=u5
|
||||
000000<RS-><RT-><RD->00001000110 "rotrv" RD=gpr ',' RT=gpr ',' RS=gpr
|
||||
101000<RS-><RT-><IMM-----------> "sb" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0011100 "sbe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
111000<RS-><RT-><IMM-----------> "sc" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0011110 "sce" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
011100<CODE-------------->111111 "sdbbp" CODE=u20
|
||||
01111100000<RT-><RD->10000100000 "seb" RD=gpr ',' RT=gpr
|
||||
01111100000<RT-><RD->11000100000 "seh" RD=gpr ',' RT=gpr
|
||||
101001<RS-><RT-><IMM-----------> "sh" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0011101 "she" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
00000000000<RT-><RD-><SA->000000 "sll" RD=gpr ',' RT=gpr ',' SA=u5
|
||||
000000<RS-><RT-><RD->00000000100 "sllv" RD=gpr ',' RT=gpr ',' RS=gpr
|
||||
000000<RS-><RT-><RD->00000101010 "slt" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
001010<RS-><RT-><IMM-----------> "slti" RT=gpr ',' RS=gpr ',' IMM=e16
|
||||
001011<RS-><RT-><IMM-----------> "sltiu" RT=gpr ',' RS=gpr ',' IMM=e16
|
||||
000000<RS-><RT-><RD->00000101011 "sltu" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
00000000000<RT-><RD-><SA->000011 "sra" RD=gpr ',' RT=gpr ',' SA=u5
|
||||
000000<RS-><RT-><RD->00000000111 "srav" RD=gpr ',' RT=gpr ',' RS=gpr
|
||||
00000000000<RT-><RD-><SA->000010 "srl" RD=gpr ',' RT=gpr ',' SA=u5
|
||||
000000<RS-><RT-><RD->00000000110 "srlv" RD=gpr ',' RT=gpr ',' RS=gpr
|
||||
00000000000000000000000001000000 "ssnop"
|
||||
000000<RS-><RT-><RD->00000100010 "sub" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT-><RD->00000100011 "subu" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
101011<RS-><RT-><IMM-----------> "sw" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0011111 "swe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
101010<RS-><RT-><IMM-----------> "swl" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0010001 "swle" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
101110<RS-><RT-><IMM-----------> "swr" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
011111<RS-><RT-><IMM---->0100010 "swre" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
|
||||
000001<RS->11111<IMM-----------> "synci" IMM=e16 '(' RS=gpr ')'
|
||||
000000<CODE-------------->001100 "syscall" CODE=u20
|
||||
000000<RS-><RT->0000000000110100 "teq" RS=gpr ',' RT=gpr
|
||||
000001<RS->01100<IMM-----------> "teqi" RS=gpr ',' IMM=e16
|
||||
000000<RS-><RT->0000000000110000 "tge" RS=gpr ',' RT=gpr
|
||||
000001<RS->01000<IMM-----------> "tgei" RS=gpr ',' IMM=e16
|
||||
000001<RS->01001<IMM-----------> "tgeiu" RS=gpr ',' IMM=e16
|
||||
000000<RS-><RT->0000000000110001 "tgeu" RS=gpr ',' RT=gpr
|
||||
01000010000000000000000000000011 "tlbinv"
|
||||
01000010000000000000000000000100 "tlbinvf"
|
||||
01000010000000000000000000001000 "tlbp"
|
||||
01000010000000000000000000000001 "tlbr"
|
||||
01000010000000000000000000000010 "tlbwi"
|
||||
01000010000000000000000000000110 "tlbwr"
|
||||
000000<RS-><RT->0000000000110010 "tlt" RS=gpr ',' RT=gpr
|
||||
000001<RS->01010<IMM-----------> "tlti" RS=gpr ',' IMM=e16
|
||||
000001<RS->01011<IMM-----------> "tltiu" RS=gpr ',' IMM=e16
|
||||
000000<RS-><RT->0000000000110011 "tltu" RS=gpr ',' RT=gpr
|
||||
000000<RS-><RT->0000000000110110 "tne" RS=gpr ',' RT=gpr
|
||||
000001<RS->01110<IMM-----------> "tnei" RS=gpr ',' IMM=e16
|
||||
01000010000000000000000000100000 "wait"
|
||||
01000001110<RT-><RD->00000000000 "wrpgpr" RD=gpr ',' RT=gpr
|
||||
01111100000<RT-><RD->00010100000 "wsbh" RD=gpr ',' RT=gpr
|
||||
000000<RS-><RT-><RD->00000100110 "xor" RD=gpr ',' RS=gpr ',' RT=gpr
|
||||
001110<RS-><RT-><IMM-----------> "xori" RT=gpr ',' RS=gpr ',' IMM=e16
|
||||
|
||||
# FPU instructions.
|
||||
|
||||
010001<F-->00000<FS-><FD->000101 "abs" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F--><FT-><FS-><FD->000000 "add" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
010011<RS-><FT-><FS-><FD->011110 "alnv" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr ',' RS=gpr
|
||||
010001<F--><FT-><FS-><C>0011<CO> "c" CO=fcond F=fmt C=u3 ',' FS=fpr ',' FT=fpr
|
||||
010001<F-->00000<FS-><FD->001010 "ceil" ".l" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->001110 "ceil" ".w" F=fmt FD=fpr ',' FS=fpr
|
||||
01000100010<RT-><FS->00000000000 "cfc1" RT=gpr ',' FS=fpr
|
||||
01000100110<RT-><FS->00000000000 "ctc1" RT=gpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->100001 "cvt" ".d" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->100101 "cvt" ".l" F=fmt FD=fpr ',' FS=fpr
|
||||
01000110000<FT-><FS-><FD->100110 "cvt" ".ps" ".s" FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
010001<F-->00000<FS-><FD->100000 "cvt" ".s" F=fmt FD=fpr ',' FS=fpr
|
||||
0100011011000000<FS-><FD->101000 "cvt" ".s" ".pl" FS=fpr ',' FD=fpr
|
||||
0100011011000000<FS-><FD->100000 "cvt" ".s" ".pu" FS=fpr ',' FD=fpr
|
||||
010001<F-->00000<FS-><FD->100100 "cvt" ".w" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F--><FT-><FS-><FD->000011 "div" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
010001<F-->00000<FS-><FD->001011 "floor" ".l" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->001111 "floor" ".w" F=fmt FD=fpr ',' FS=fpr
|
||||
110101<RS-><FT-><IMM-----------> "ldc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
010011<RS-><RT->00000<FD->000001 "ldxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
|
||||
010011<RS-><RT->00000<FD->000101 "luxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
|
||||
110001<RS-><FT-><IMM-----------> "lwc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
010011<RS-><RT->00000<FD->000000 "lwxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
|
||||
010011<FR-><FT-><FS-><FD->100<F> "madd" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
|
||||
01000100000<RT-><FS->00000000000 "mfc1" RT=gpr ',' FS=fpr
|
||||
01000100011<RT-><FS->00000000000 "mfhc1" RT=gpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->000110 "mov" F=fmt FD=fpr ',' FS=fpr
|
||||
000000<RS-><C>00<RD->00000000001 "movf" RD=gpr ',' RS=gpr ',' C=u3
|
||||
010001<F--><C>00<FS-><FD->010001 "movf" F=fmt FD=fpr ',' FS=fpr ',' C=u3
|
||||
010001<F--><RT-><FS-><FD->010011 "movn" F=fmt FD=fpr ',' FS=fpr ',' RT=gpr
|
||||
000000<RS-><C>01<RD->00000000001 "movt" RD=gpr ',' RS=gpr ',' C=u3
|
||||
010001<F--><C>01<FS-><FD->010001 "movt" F=fmt FD=fpr ',' FS=fpr ',' C=u3
|
||||
010001<F--><RT-><FS-><FD->010010 "movz" F=fmt FD=fpr ',' FS=fpr ',' RT=gpr
|
||||
010011<FR-><FT-><FS-><FD->101<F> "msub" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
|
||||
01000100100<RT-><FS->00000000000 "mtc1" RT=gpr ',' FS=fpr
|
||||
01000100111<RT-><FS->00000000000 "mthc1" RT=gpr ',' FS=fpr
|
||||
010001<F--><FT-><FS-><FD->000010 "mul" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
010001<F-->00000<FS-><FD->000111 "neg" F=fmt FD=fpr ',' FS=fpr
|
||||
010011<FR-><FT-><FS-><FD->110<F> "nmadd" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
|
||||
010011<FR-><FT-><FS-><FD->111<F> "nmsub" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
|
||||
01000110110<FT-><FS-><FD->101100 "pll" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
01000110110<FT-><FS-><FD->101101 "plu" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
01000110110<FT-><FS-><FD->101110 "pul" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
01000110110<FT-><FS-><FD->101111 "puu" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
010001<F-->00000<FS-><FD->010101 "recip." F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->001000 "round" ".l" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->001100 "round" ".w" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->010110 "rsqrt" F=fmt FD=fpr ',' FS=fpr
|
||||
111101<RS-><FT-><IMM-----------> "sdc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
010011<RS-><RT->00000<FD->001001 "sdxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
|
||||
010001<F-->00000<FS-><FD->000100 "sqrt" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F--><FT-><FS-><FD->000001 "sub" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
|
||||
010011<RS-><RT->00000<FD->001101 "suxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
|
||||
111001<RS-><FT-><IMM-----------> "swc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
|
||||
010011<RS-><RT->00000<FD->001000 "swxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
|
||||
010001<F-->00000<FS-><FD->001001 "trunc" ".l" F=fmt FD=fpr ',' FS=fpr
|
||||
010001<F-->00000<FS-><FD->001101 "trunc" ".w" F=fmt FD=fpr ',' FS=fpr
|
||||
|
||||
# Generic coprocessor instructions.
|
||||
|
||||
01000101000<C>00<OFF-----------> "bc1f" C=u3 ',' OFF=offset16
|
||||
0100010100000000<OFF-----------> "bc1f" OFF=offset16
|
||||
01000101000<C>10<OFF-----------> "bc1fl" C=u3 ',' OFF=offset16
|
||||
0100010100000010<OFF-----------> "bc1fl" OFF=offset16
|
||||
01000101000<C>01<OFF-----------> "bc1t" C=u3 ',' OFF=offset16
|
||||
0100010100000001<OFF-----------> "bc1t" OFF=offset16
|
||||
01000101000<C>11<OFF-----------> "bc1tl" C=u3 ',' OFF=offset16
|
||||
0100010100000011<OFF-----------> "bc1tl" OFF=offset16
|
||||
01001001000<C>00<OFF-----------> "bc2f" C=u3 ',' OFF=offset16
|
||||
0100100100000000<OFF-----------> "bc2f" OFF=offset16
|
||||
01001001000<C>10<OFF-----------> "bc2fl" C=u3 ',' OFF=offset16
|
||||
0100100100000010<OFF-----------> "bc2fl" OFF=offset16
|
||||
01001001000<C>01<OFF-----------> "bc2t" C=u3 ',' OFF=offset16
|
||||
0100100100000001<OFF-----------> "bc2t" OFF=offset16
|
||||
01001001000<C>11<OFF-----------> "bc2tl" C=u3 ',' OFF=offset16
|
||||
0100100100000011<OFF-----------> "bc2tl" OFF=offset16
|
||||
01001000010<RT-><IMM-----------> "cfc2" RT=gpr ',' IMM=u16
|
||||
01001000110<RT-><IMM-----------> "ctc2" RT=gpr ',' IMM=u16
|
||||
0100101<FUN--------------------> "cop2" FUN=u25
|
||||
110110<RS-><RT-><IMM-----------> "ldc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'
|
||||
110010<RS-><RT-><IMM-----------> "lwc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'
|
||||
01000000000<RT-><RD->00000000<S> "mfc0" RT=gpr ',' RD=u5 ',' S=u3
|
||||
01001000000<RT-><IMM-----------> "mfc2" RT=gpr ',' IMM=u16
|
||||
01000000010<RT-><RD->00000000<S> "mfhc0" RT=gpr ',' RD=u5 ',' S=u3
|
||||
01001000011<RT-><IMM-----------> "mfhc2" RT=gpr ',' IMM=u16
|
||||
01000000100<RT-><RD->00000000<S> "mtc0" RT=gpr ',' RD=u5 ',' S=u3
|
||||
01001000100<RT-><IMM-----------> "mtc2" RT=gpr ',' IMM=u16
|
||||
01000000110<RT-><RD->00000000<S> "mthc0" RT=gpr ',' RD=u5 ',' S=u3
|
||||
01001000111<RT-><IMM-----------> "mthc2" RT=gpr ',' IMM=u16
|
||||
111110<RS-><RT-><IMM-----------> "sdc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'
|
||||
111010<RS-><RT-><IMM-----------> "swc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'
|
||||
|
||||
|
||||
|
29
mach/mips/as/mach0.c
Normal file
29
mach/mips/as/mach0.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* $Source$
|
||||
* $State$
|
||||
*/
|
||||
|
||||
#define THREE_PASS /* branch and offset optimization */
|
||||
#define LISTING /* enable listing facilities */
|
||||
#define RELOCATION /* generate relocatable code */
|
||||
#define DEBUG 0
|
||||
|
||||
#undef valu_t
|
||||
#define valu_t int32_t
|
||||
|
||||
#undef ADDR_T
|
||||
#define ADDR_T uint32_t
|
||||
|
||||
#undef word_t
|
||||
#define word_t uint32_t
|
||||
|
||||
#undef ALIGNWORD
|
||||
#define ALIGNWORD 4
|
||||
|
||||
#undef ALIGNSECT
|
||||
#define ALIGNSECT 4
|
||||
|
||||
#undef VALWIDTH
|
||||
#define VALWIDTH 8
|
||||
|
||||
#define FIXUPFLAGS 0
|
3
mach/mips/as/mach1.c
Normal file
3
mach/mips/as/mach1.c
Normal file
|
@ -0,0 +1,3 @@
|
|||
/*
|
||||
* Do not #include anything here. Do it in mach/proto/as/comm0.h
|
||||
*/
|
23
mach/mips/as/mach2.c
Normal file
23
mach/mips/as/mach2.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
%token <y_word> GPR
|
||||
%token <y_word> FPR
|
||||
%token <y_word> FCOND
|
||||
|
||||
%token <y_word> OP_LI
|
||||
|
||||
%token <y_word> HI16
|
||||
%token <y_word> HA16
|
||||
%token <y_word> LO16
|
||||
|
||||
%type <y_word> gpr fpr
|
||||
%type <y_word> e16 e9
|
||||
%type <y_word> u25 u20 u16 u5 u3
|
||||
%type <y_word> abs26 offset16
|
||||
|
||||
%type <y_word> fmt fmt3
|
||||
%type <y_word> fcond
|
||||
|
||||
%type <y_word> extmsblsb insmsblsb
|
||||
%type <y_valu> extabsexp
|
||||
|
||||
#include "definitions.y"
|
||||
|
83
mach/mips/as/mach3.c
Normal file
83
mach/mips/as/mach3.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Integer registers */
|
||||
|
||||
0, GPR, 0, "r0",
|
||||
0, GPR, 0, "zero",
|
||||
0, GPR, 1, "r1",
|
||||
0, GPR, 1, "at",
|
||||
0, GPR, 2, "r2",
|
||||
0, GPR, 3, "r3",
|
||||
0, GPR, 4, "r4",
|
||||
0, GPR, 5, "r5",
|
||||
0, GPR, 6, "r6",
|
||||
0, GPR, 7, "r7",
|
||||
0, GPR, 8, "r8",
|
||||
0, GPR, 9, "r9",
|
||||
0, GPR, 10, "r10",
|
||||
0, GPR, 11, "r11",
|
||||
0, GPR, 12, "r12",
|
||||
0, GPR, 13, "r13",
|
||||
0, GPR, 14, "r14",
|
||||
0, GPR, 15, "r15",
|
||||
0, GPR, 16, "r16",
|
||||
0, GPR, 17, "r17",
|
||||
0, GPR, 18, "r18",
|
||||
0, GPR, 19, "r19",
|
||||
0, GPR, 20, "r20",
|
||||
0, GPR, 21, "r21",
|
||||
0, GPR, 22, "r22",
|
||||
0, GPR, 23, "r23",
|
||||
0, GPR, 24, "r24",
|
||||
0, GPR, 25, "r25",
|
||||
0, GPR, 26, "r26",
|
||||
0, GPR, 27, "r27",
|
||||
0, GPR, 28, "r28",
|
||||
0, GPR, 28, "gp",
|
||||
0, GPR, 29, "r29",
|
||||
0, GPR, 29, "sp",
|
||||
0, GPR, 30, "r30",
|
||||
0, GPR, 30, "fp",
|
||||
0, GPR, 31, "r31",
|
||||
0, GPR, 31, "ra",
|
||||
|
||||
/* Floating-point registers */
|
||||
|
||||
0, FPR, 0, "f0",
|
||||
0, FPR, 1, "f1",
|
||||
0, FPR, 2, "f2",
|
||||
0, FPR, 3, "f3",
|
||||
0, FPR, 4, "f4",
|
||||
0, FPR, 5, "f5",
|
||||
0, FPR, 6, "f6",
|
||||
0, FPR, 7, "f7",
|
||||
0, FPR, 8, "f8",
|
||||
0, FPR, 9, "f9",
|
||||
0, FPR, 10, "f10",
|
||||
0, FPR, 11, "f11",
|
||||
0, FPR, 12, "f12",
|
||||
0, FPR, 13, "f13",
|
||||
0, FPR, 14, "f14",
|
||||
0, FPR, 15, "f15",
|
||||
0, FPR, 16, "f16",
|
||||
0, FPR, 17, "f17",
|
||||
0, FPR, 18, "f18",
|
||||
0, FPR, 19, "f19",
|
||||
0, FPR, 20, "f20",
|
||||
0, FPR, 21, "f21",
|
||||
0, FPR, 22, "f22",
|
||||
0, FPR, 23, "f23",
|
||||
0, FPR, 24, "f24",
|
||||
0, FPR, 25, "f25",
|
||||
0, FPR, 26, "f26",
|
||||
0, FPR, 27, "f27",
|
||||
0, FPR, 28, "f28",
|
||||
0, FPR, 29, "f29",
|
||||
0, FPR, 30, "f30",
|
||||
0, FPR, 31, "f31",
|
||||
|
||||
0, OP_LI, 0, "li",
|
||||
0, HI16, 0, "hi16",
|
||||
0, HA16, 0, "ha16",
|
||||
0, LO16, 0, "lo16",
|
||||
|
||||
#include "tokens.y"
|
||||
|
184
mach/mips/as/mach4.c
Normal file
184
mach/mips/as/mach4.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
#include "rules.y"
|
||||
| OP_LI GPR ',' extabsexp
|
||||
{
|
||||
word_t reg = $2;
|
||||
uint32_t val = $4;
|
||||
|
||||
if (((int32_t)val >= -0x8000) && ((int32_t)val <= 0x7fff))
|
||||
emit4(0x24000000 | (reg<<16) | (val & 0xffff)); /* addiu reg, zero, value */
|
||||
else if (val <= 0xffff)
|
||||
emit4(0x34000000 | (reg<<16) | val); /* ori reg, zero, value */
|
||||
else
|
||||
{
|
||||
emit4(0x3c000000 | (reg<<16) | (val>>16)); /* lui reg, value */
|
||||
emit4(0x34000000 | (reg<<16) | (reg<<21) | (val & 0xffff)); /* ori reg, reg, value */
|
||||
}
|
||||
}
|
||||
|
||||
extabsexp
|
||||
: absexp
|
||||
| LO16 ASC_LPAR expr ASC_RPAR
|
||||
{
|
||||
newrelo($3.typ, RELO2 | FIXUPFLAGS);
|
||||
$$ = $3.val;
|
||||
}
|
||||
| HI16 ASC_LPAR expr ASC_RPAR
|
||||
{
|
||||
newrelo($3.typ, RELO2HI | FIXUPFLAGS);
|
||||
if ($3.val & 0xffff0000)
|
||||
fatal("relocation offset in hi16[] too big");
|
||||
$$ = $3.val;
|
||||
}
|
||||
| HA16 ASC_LPAR expr ASC_RPAR
|
||||
{
|
||||
newrelo($3.typ, RELO2HISAD | FIXUPFLAGS);
|
||||
if ($3.val & 0xffff0000)
|
||||
fatal("relocation offset in ha16[] too big");
|
||||
$$ = $3.val;
|
||||
}
|
||||
;
|
||||
|
||||
gpr: GPR
|
||||
fpr: FPR
|
||||
|
||||
fmt3
|
||||
: OP__DOT_S { $$ = 0; }
|
||||
| OP__DOT_D { $$ = 1; }
|
||||
| OP__DOT_W { $$ = 4; }
|
||||
| OP__DOT_L { $$ = 5; }
|
||||
| OP__DOT_PS { $$ = 6; }
|
||||
;
|
||||
|
||||
fmt
|
||||
: fmt3 { $$ = $1 + 16; }
|
||||
;
|
||||
|
||||
fcond
|
||||
: OP__DOT_F { $$ = 0; }
|
||||
| OP__DOT_UN { $$ = 1; }
|
||||
| OP__DOT_EQ { $$ = 2; }
|
||||
| OP__DOT_UEQ { $$ = 3; }
|
||||
| OP__DOT_OLT { $$ = 4; }
|
||||
| OP__DOT_ULT { $$ = 5; }
|
||||
| OP__DOT_OLE { $$ = 6; }
|
||||
| OP__DOT_ULE { $$ = 7; }
|
||||
| OP__DOT_SF { $$ = 8; }
|
||||
| OP__DOT_NGLE { $$ = 9; }
|
||||
| OP__DOT_SEQ { $$ = 10; }
|
||||
| OP__DOT_NGL { $$ = 11; }
|
||||
| OP__DOT_LT { $$ = 12; }
|
||||
| OP__DOT_NGE { $$ = 13; }
|
||||
| OP__DOT_LE { $$ = 14; }
|
||||
| OP__DOT_NGT { $$ = 15; }
|
||||
;
|
||||
|
||||
e16
|
||||
: extabsexp
|
||||
{
|
||||
/* Allow signed or unsigned 16-bit values. */
|
||||
if (($1 < -0x8000) || ($1 > 0xffff))
|
||||
serror("16-bit signed value out of range");
|
||||
$$ = (uint16_t) $1;
|
||||
}
|
||||
;
|
||||
|
||||
e9
|
||||
: absexp
|
||||
{
|
||||
/* Allow signed or unsigned 9-bit values. */
|
||||
if (($1 < -0x100) || ($1 > 0x1ff))
|
||||
serror("9-bit signed value out of range");
|
||||
$$ = (uint16_t) $1;
|
||||
}
|
||||
;
|
||||
|
||||
u25
|
||||
: absexp
|
||||
{
|
||||
if (($1 < 0) || ($1 > 0x1ffffff))
|
||||
serror("25-bit unsigned value out of range");
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
u20
|
||||
: absexp
|
||||
{
|
||||
if (($1 < 0) || ($1 > 0xfffff))
|
||||
serror("20-bit unsigned value out of range");
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
u16
|
||||
: extabsexp
|
||||
{
|
||||
if (($1 < 0) || ($1 > 0xffff))
|
||||
serror("16-bit unsigned value out of range");
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
u5
|
||||
: absexp
|
||||
{
|
||||
if (($1 < 0) || ($1 > 0x1f))
|
||||
serror("5-bit unsigned value out of range");
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
u3
|
||||
: absexp
|
||||
{
|
||||
if (($1 < 0) || ($1 > 0x7))
|
||||
serror("3-bit unsigned value out of range");
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
offset16
|
||||
: expr
|
||||
{
|
||||
int dist = $1.val - DOTVAL - 4;
|
||||
fit(fitx(dist, 18));
|
||||
|
||||
if (dist & 0x3)
|
||||
serror("jump targets must be 4-aligned");
|
||||
|
||||
newrelo($1.typ, RELOMIPS | RELPC | FIXUPFLAGS);
|
||||
$$ = (dist >> 2) & 0x0000ffff;
|
||||
}
|
||||
;
|
||||
|
||||
abs26
|
||||
: expr
|
||||
{
|
||||
int target = $1.val;
|
||||
fit(fitx(target, 28));
|
||||
|
||||
if (target & 0x3)
|
||||
serror("jump targets must be 4-aligned");
|
||||
|
||||
newrelo($1.typ, RELOMIPS | FIXUPFLAGS);
|
||||
$$ = (target >> 2) & 0x03ffffff;
|
||||
}
|
||||
;
|
||||
|
||||
extmsblsb
|
||||
: u5 ',' u5
|
||||
{
|
||||
int pos = $1;
|
||||
int size = $3;
|
||||
$$ = ((size-1) << 5) | pos;
|
||||
}
|
||||
;
|
||||
|
||||
insmsblsb
|
||||
: u5 ',' u5
|
||||
{
|
||||
int pos = $1;
|
||||
int size = $3;
|
||||
$$ = ((pos+size-1) << 5) | pos;
|
||||
}
|
||||
;
|
0
mach/mips/as/mach5.c
Normal file
0
mach/mips/as/mach5.c
Normal file
192
mach/mips/as/mktables.lua
Executable file
192
mach/mips/as/mktables.lua
Executable file
|
@ -0,0 +1,192 @@
|
|||
local args = {...}
|
||||
|
||||
local words = {}
|
||||
local insns = {}
|
||||
|
||||
local function addword(word)
|
||||
local w = words[word]
|
||||
if not w then
|
||||
w = word:upper()
|
||||
w = w:gsub("%.", "_DOT_")
|
||||
if not w:match("^[A-Z0-9_]*$") then
|
||||
error(word.." is not a valid token")
|
||||
end
|
||||
words[word] = w
|
||||
end
|
||||
return w
|
||||
end
|
||||
|
||||
local function parsesyntax(line)
|
||||
local syntax = {}
|
||||
for word in line:gmatch("%S+") do
|
||||
local _, _, s = word:find('^"(.*)"$')
|
||||
if s then
|
||||
syntax[#syntax+1] = {word=addword(s) }
|
||||
else
|
||||
_, _, s = word:find("^('.*')$")
|
||||
if s then
|
||||
syntax[#syntax+1] = {punct=s }
|
||||
else
|
||||
local token = {}
|
||||
for equate in word:gmatch("([^=]+)=") do
|
||||
token[#token+1] = equate
|
||||
end
|
||||
_, _, token.token = word:find("([^=]*)$")
|
||||
syntax[#syntax+1] = token
|
||||
if not token.token then
|
||||
error("can't parse "..word)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return syntax
|
||||
end
|
||||
|
||||
local function parsefields(line)
|
||||
local _, _, bits = line:find("^([^ ]+) ")
|
||||
if #bits ~= 32 then
|
||||
error("'"..bits.."' isn't 32 bits long")
|
||||
end
|
||||
|
||||
local fields = {}
|
||||
local i = 1
|
||||
while i ~= 33 do
|
||||
local c = line:sub(i, i)
|
||||
if c ~= "." then
|
||||
local f = { pos=i }
|
||||
if c:find("%w") then
|
||||
f.size = 1
|
||||
f.value = c
|
||||
elseif c == "<" then
|
||||
local _, newi, name = line:find("^<%-*(%w+)%-*>", i)
|
||||
f.size = 1 + newi - i
|
||||
f.value = name
|
||||
i = newi
|
||||
else
|
||||
error("bad field char '"..c.."' in '"..line.."'")
|
||||
end
|
||||
if f.value:find("[0-9]+") then
|
||||
f.literal = true
|
||||
f.variable = false
|
||||
else
|
||||
f.literal = false
|
||||
f.variable = true
|
||||
end
|
||||
-- Convert from PowerPC numbering to sane numbering
|
||||
f.pos = 33-(f.pos + f.size)
|
||||
fields[#fields+1] = f
|
||||
if f.value then
|
||||
fields[f.value] = f
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
local value = 0
|
||||
for _, f in ipairs(fields) do
|
||||
if f.literal then
|
||||
local s = math.pow(2, f.pos)
|
||||
value = value + f.value*s
|
||||
end
|
||||
end
|
||||
fields.value = value
|
||||
|
||||
return fields
|
||||
end
|
||||
|
||||
|
||||
local function emit(fields, code)
|
||||
local mask = 0
|
||||
local value = 0
|
||||
for _, f in ipairs(fields) do
|
||||
if f.literal then
|
||||
local s = math.pow(2, f.pos)
|
||||
local m = math.pow(2, f.size) - 1
|
||||
mask = mask + m*s
|
||||
value = value + f.value*s
|
||||
end
|
||||
end
|
||||
|
||||
print(string.format("if ((value & 0x%x) == 0x%x) {", mask, value))
|
||||
for _, f in ipairs(fields) do
|
||||
if f.variable then
|
||||
local m = math.pow(2, f.size) - 1
|
||||
print(string.format("uint32_t %s = (value >> %d) & 0x%x;", f.value, f.pos, m))
|
||||
end
|
||||
end
|
||||
|
||||
print(code)
|
||||
print("return;")
|
||||
print("}")
|
||||
end
|
||||
|
||||
while true do
|
||||
local line = io.stdin:read("*l")
|
||||
if not line then
|
||||
break
|
||||
end
|
||||
line = line:gsub("#.*$", "")
|
||||
line = line:gsub(" *$", "")
|
||||
if line:find("^%%token ") then
|
||||
addword(line:sub(8))
|
||||
elseif line ~= "" then
|
||||
local fields = parsefields(line)
|
||||
local syntax = parsesyntax(line:sub(34, #line))
|
||||
insns[#insns+1] = {
|
||||
fields=parsefields(line),
|
||||
syntax=parsesyntax(line:sub(34, #line))
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local definitionsfp = io.open(args[1], "w")
|
||||
for word, value in pairs(words) do
|
||||
definitionsfp:write("%token <y_word> OP_", tostring(value), " /* ", word, " */\n")
|
||||
end
|
||||
definitionsfp:close()
|
||||
|
||||
local tokensfp = io.open(args[2], "w")
|
||||
for word, value in pairs(words) do
|
||||
tokensfp:write("0, OP_", value, ", 0, \"", word, "\",\n")
|
||||
end
|
||||
tokensfp:close()
|
||||
|
||||
local rulesfp = io.open(args[3], "w")
|
||||
rulesfp:write("operation\n")
|
||||
for index, insn in ipairs(insns) do
|
||||
if index == 1 then
|
||||
rulesfp:write("\t:")
|
||||
else
|
||||
rulesfp:write("\t|")
|
||||
end
|
||||
for _, word in ipairs(insn.syntax) do
|
||||
if word.word then
|
||||
rulesfp:write(" OP_", word.word)
|
||||
end
|
||||
if word.punct then
|
||||
rulesfp:write(" ", word.punct)
|
||||
end
|
||||
if word.token then
|
||||
rulesfp:write(" ", word.token)
|
||||
end
|
||||
end
|
||||
rulesfp:write("\n")
|
||||
|
||||
rulesfp:write("\t{ emit4(", string.format("0x%08x", insn.fields.value))
|
||||
for wordindex, word in ipairs(insn.syntax) do
|
||||
if word.token then
|
||||
for _, alias in ipairs(word) do
|
||||
local f = insn.fields[alias]
|
||||
if not f then
|
||||
error("reference to field "..alias.." which doesn't exist")
|
||||
end
|
||||
local mask = math.pow(2, f.size) - 1
|
||||
rulesfp:write(" | (($", wordindex,
|
||||
" & ", string.format("0x%x", mask), ") << ", f.pos, ")")
|
||||
end
|
||||
end
|
||||
end
|
||||
rulesfp:write("); }\n")
|
||||
end
|
||||
rulesfp:close()
|
||||
|
47
mach/mips/libem/aar4.s
Normal file
47
mach/mips/libem/aar4.s
Normal file
|
@ -0,0 +1,47 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Get address of element of bounds-checked array.
|
||||
*
|
||||
* Stack: ( array-adr index descriptor-adr -- element-adr )
|
||||
* Sets r2 = size of element for .los4, .sts4
|
||||
* Preserves r25 (the last volatile register)
|
||||
*
|
||||
* An array descriptor is:
|
||||
*
|
||||
* +0 lower bound
|
||||
* +4 range (upper bound - lower bound); *inclusive*
|
||||
* +8 element size
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .aar4
|
||||
.aar4:
|
||||
lw r4, 0(sp) ! r4 = address of descriptor
|
||||
lw r5, 4(sp) ! r5 = index
|
||||
lw r6, 8(sp) ! r6 = address of array
|
||||
|
||||
lw r7, 0(r4) ! r7 = lower bound
|
||||
slt at, r5, r7 ! at = index < lower bound
|
||||
bne at, zero, .trap_earray
|
||||
nop
|
||||
subu r5, r5, r7 ! adjust index for non-zero lower bound
|
||||
|
||||
lw at, 4(r4) ! at = range
|
||||
slt at, at, r5 ! at = range < adjusted index
|
||||
bne at, zero, .trap_earray
|
||||
nop
|
||||
|
||||
lw r2, 8(r4) ! r2 = size of element
|
||||
mul r5, r5, r2 ! scale index by size
|
||||
addu r5, r5, r6 ! calculate address of element
|
||||
|
||||
sw r5, 8(sp) ! push address of element
|
||||
addiu sp, sp, 8
|
||||
jr ra
|
||||
nop
|
||||
|
||||
.define .trap_earray
|
||||
.trap_earray:
|
||||
li r4, 0 ! EARRAY = 0 in h/em_abs.h
|
||||
b .trp
|
30
mach/mips/libem/and.s
Normal file
30
mach/mips/libem/and.s
Normal file
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* Set intersection.
|
||||
* Stack: ( a b size -- a&b )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .and
|
||||
.and:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
addiu sp, sp, 4 ! sp points at b
|
||||
addu r5, sp, r4 ! r5 points at a
|
||||
srl r4, r4, 2 ! r4 = count of words
|
||||
|
||||
1:
|
||||
lw at, 0(r5) ! load a
|
||||
lw r6, 0(sp) ! load b
|
||||
and at, at, r6 ! combine
|
||||
sw at, 0(r5) ! write back to a
|
||||
addiu r5, r5, 4
|
||||
addiu sp, sp, 4
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
31
mach/mips/libem/bls4.s
Normal file
31
mach/mips/libem/bls4.s
Normal file
|
@ -0,0 +1,31 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Does a block move of words between non-overlapping buffers.
|
||||
* Stack: ( src dst len -- )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .bls4
|
||||
.bls4:
|
||||
lw r4, 0(sp) ! r4=len
|
||||
lw r5, 4(sp) ! r5=dst
|
||||
lw r6, 8(sp) ! r6=src
|
||||
addiu sp, sp, 12
|
||||
|
||||
srl r4, r4, 2 ! convert len to words
|
||||
1:
|
||||
beq r4, zero, 2f
|
||||
nop
|
||||
|
||||
lw at, 0(r6)
|
||||
sw at, 0(r5)
|
||||
addiu r6, r6, 4
|
||||
addiu r5, r5, 4
|
||||
addiu r4, r4, -1
|
||||
b 1b
|
||||
nop
|
||||
|
||||
2:
|
||||
jr ra
|
||||
nop
|
17
mach/mips/libem/build.lua
Normal file
17
mach/mips/libem/build.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
for _, plat in ipairs(vars.plats) do
|
||||
acklibrary {
|
||||
name = "headers_"..plat,
|
||||
}
|
||||
|
||||
acklibrary {
|
||||
name = "lib_"..plat,
|
||||
srcs = {
|
||||
"./*.s", -- dus4.s
|
||||
},
|
||||
vars = { plat = plat },
|
||||
deps = {
|
||||
"h+emheaders",
|
||||
"+headers_"..plat,
|
||||
}
|
||||
}
|
||||
end
|
36
mach/mips/libem/c_ud_i.s
Normal file
36
mach/mips/libem/c_ud_i.s
Normal file
|
@ -0,0 +1,36 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
.sect .text
|
||||
.define .c_ud_i
|
||||
.c_ud_i:
|
||||
/* Input: f0
|
||||
* Output: r2
|
||||
* Only at and f30/f31 may be used.
|
||||
*/
|
||||
|
||||
lui at, ha16[.fd_80000000]
|
||||
ldc1 f30, lo16[.fd_80000000] (at)
|
||||
c.le.d 0, f30, f0
|
||||
bc1t toobig
|
||||
nop
|
||||
|
||||
trunc.w.d f0, f0
|
||||
mfc1 r2, f0
|
||||
jr ra
|
||||
nop
|
||||
|
||||
toobig:
|
||||
sub.d f0, f0, f30
|
||||
trunc.w.d f0, f0
|
||||
mfc1 r2, f0
|
||||
lui at, 0x8000 ! load 0x80000000
|
||||
addu r2, r2, at
|
||||
jr ra
|
||||
nop
|
||||
|
||||
.sect .rom
|
||||
.define .fd_80000000
|
||||
.fd_80000000:
|
||||
.dataf8 2147483648.0
|
||||
|
38
mach/mips/libem/c_uf_i.s
Normal file
38
mach/mips/libem/c_uf_i.s
Normal file
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
.define .c_uf_i
|
||||
.c_uf_i:
|
||||
/* Input: f0
|
||||
* Output: r2
|
||||
* Only at and f30/f31 may be used.
|
||||
*/
|
||||
|
||||
lui at, ha16[.ff_80000000]
|
||||
lwc1 f30, lo16[.ff_80000000] (at)
|
||||
c.le.s 0, f30, f0
|
||||
bc1t toobig
|
||||
nop
|
||||
|
||||
trunc.w.s f0, f0
|
||||
mfc1 r2, f0
|
||||
jr ra
|
||||
nop
|
||||
|
||||
toobig:
|
||||
sub.s f0, f0, f30
|
||||
trunc.w.s f0, f0
|
||||
mfc1 r2, f0
|
||||
lui at, 0x8000 ! load 0x80000000
|
||||
addu r2, r2, at
|
||||
jr ra
|
||||
nop
|
||||
|
||||
.sect .rom
|
||||
.ff_80000000:
|
||||
.dataf4 2147483648.0
|
||||
|
25
mach/mips/libem/c_ui_d.s
Normal file
25
mach/mips/libem/c_ui_d.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
.sect .text
|
||||
.define .c_ui_d
|
||||
.c_ui_d:
|
||||
/* Input: r2
|
||||
* Output: f0
|
||||
* Only at and f30/f31 may be used.
|
||||
*/
|
||||
mtc1 r2, f0
|
||||
cvt.d.w f0, f0
|
||||
bgez r2, nonnegative
|
||||
nop
|
||||
|
||||
lui at, ha16[.fd_100000000]
|
||||
ldc1 f30, lo16[.fd_100000000] (at)
|
||||
add.d f0, f0, f30
|
||||
nonnegative:
|
||||
jr ra
|
||||
nop
|
||||
|
||||
.sect .rom
|
||||
.fd_100000000:
|
||||
.dataf8 4294967296.0
|
26
mach/mips/libem/c_ui_f.s
Normal file
26
mach/mips/libem/c_ui_f.s
Normal file
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
.sect .text
|
||||
.define .c_ui_f
|
||||
.c_ui_f:
|
||||
/* Input: r2
|
||||
* Output: f0
|
||||
* Only at and f30/f31 may be used.
|
||||
*/
|
||||
mtc1 r2, f0
|
||||
cvt.s.w f0, f0
|
||||
bgez r2, nonnegative
|
||||
nop
|
||||
|
||||
lui at, ha16[.fs_100000000]
|
||||
ldc1 f30, lo16[.fs_100000000] (at)
|
||||
add.d f0, f0, f30
|
||||
nonnegative:
|
||||
jr ra
|
||||
nop
|
||||
|
||||
/* 4294967296 as a float. */
|
||||
.sect .rom
|
||||
.fs_100000000:
|
||||
.dataf4 4294967296.0
|
35
mach/mips/libem/cms.s
Normal file
35
mach/mips/libem/cms.s
Normal file
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* Set comparison Returns 0 if the sets were equal.
|
||||
* Stack: ( a b size -- a!=b )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .cms
|
||||
.cms:
|
||||
lw r4, 0(sp) ! r4 = size; sp points at b-word
|
||||
addu r5, sp, r4 ! r5 points at a-word
|
||||
addu r6, r5, r4 ! r6 is final sp-word
|
||||
srl r4, r4, 2 ! r4 = count of words
|
||||
li r8, 1 ! result
|
||||
|
||||
1:
|
||||
lw at, 4(r5) ! load a
|
||||
lw r7, 4(sp) ! load b
|
||||
bne at, r7, exit ! branch if not equal
|
||||
nop
|
||||
addiu r5, r5, 4
|
||||
addiu sp, sp, 4
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
li r8, 0 ! Update result.
|
||||
exit:
|
||||
mov sp, r6
|
||||
sw r8, 0(sp)
|
||||
jr ra
|
||||
nop
|
||||
|
28
mach/mips/libem/com.s
Normal file
28
mach/mips/libem/com.s
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* Set complement.
|
||||
* Stack: ( a size -- ~a )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .com
|
||||
.com:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
addiu sp, sp, 4
|
||||
mov r5, sp ! r5 points to set
|
||||
srl r4, r4, 2 ! r4 = word count
|
||||
|
||||
1:
|
||||
lw at, 0(r5)
|
||||
nor at, zero, at
|
||||
sw at, 0(r5)
|
||||
addiu r5, r5, 4
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
39
mach/mips/libem/compareul.s
Normal file
39
mach/mips/libem/compareul.s
Normal file
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* 64-big unsigned tristate comparison.
|
||||
* Inputs:
|
||||
* r2r3: left
|
||||
* r4r5: right
|
||||
* Outputs;
|
||||
* r2: result
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .compareul
|
||||
.compareul:
|
||||
/* Compare high words. */
|
||||
|
||||
sltu at, r3, r5 ! if r3<r5, then 1
|
||||
subu at, zero, at ! if r3<r5, then -1
|
||||
bne at, zero, exit
|
||||
nop
|
||||
|
||||
sltu at, r5, r3 ! if r3>r5, then 1
|
||||
bne at, zero, exit
|
||||
nop
|
||||
|
||||
/* High words are equal --- compare low words. */
|
||||
|
||||
sltu at, r2, r4 ! if r2<r4, then 1
|
||||
subu at, zero, at ! if r2<r4, then -1
|
||||
bne at, zero, exit
|
||||
nop
|
||||
|
||||
sltu at, r4, r2 ! if r2>r4, then 1
|
||||
exit:
|
||||
mov r2, at
|
||||
jr ra
|
||||
nop
|
||||
|
42
mach/mips/libem/csa.s
Normal file
42
mach/mips/libem/csa.s
Normal file
|
@ -0,0 +1,42 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* This is not a subroutine, but just a
|
||||
* piece of code that computes the jump-
|
||||
* address and jumps to it.
|
||||
* traps if resulting address is zero
|
||||
*
|
||||
* Stack: ( value tableaddr -- )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .csa
|
||||
.csa:
|
||||
lw r4, 0(sp) /* r4 = table */
|
||||
lw r5, 4(sp) /* r5 = value */
|
||||
addiu sp, sp, 8
|
||||
|
||||
lw r6, 0(r4) /* r6 = default target */
|
||||
lw r7, 4(r4) /* r7 = lower bound */
|
||||
subu r5, r5, r7 /* adjust value */
|
||||
bltz r5, 1f /* jump to default if out of range */
|
||||
nop
|
||||
|
||||
lw r7, 8(r4) /* fetch range */
|
||||
subu r7, r7, r5 /* compute difference within range */
|
||||
bltz r7, 1f /* jump to default if out of range */
|
||||
nop
|
||||
|
||||
addiu r4, r4, 12 /* skip header */
|
||||
sll r5, r5, 2 /* value = value<<2 */
|
||||
addu r4, r4, r5 /* find address of target */
|
||||
lw r6, 0(r4) /* r6 = new target */
|
||||
|
||||
1:
|
||||
beq r6, zero, 2f /* trap if null */
|
||||
nop
|
||||
jr r6 /* otherwise jump */
|
||||
nop
|
||||
2:
|
||||
j .trap_ecase
|
||||
nop
|
47
mach/mips/libem/csb.s
Normal file
47
mach/mips/libem/csb.s
Normal file
|
@ -0,0 +1,47 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* this is not a subroutine, but just a
|
||||
* piece of code that computes the jump-
|
||||
* address and jumps to it.
|
||||
* traps if resulting address is zero
|
||||
*
|
||||
* Stack: ( value tableaddr -- )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .csb
|
||||
.csb:
|
||||
lw r4, 0(sp) ! r4 = address of table
|
||||
lw r5, 4(sp) ! r5 = value
|
||||
addiu sp, sp, 8
|
||||
|
||||
lw r6, 0(r4) ! r6 = default target
|
||||
lw r7, 4(r4) ! r7 = table count
|
||||
|
||||
2:
|
||||
addiu r7, r7, -1 ! decrement count
|
||||
bltz r7, 1f ! exit loop if out
|
||||
nop
|
||||
|
||||
lw r8, 8(r4) ! candidate value
|
||||
beq r8, r5, 3f ! branch if equal
|
||||
nop
|
||||
|
||||
addiu r4, r4, 8 ! next entry
|
||||
b 2b
|
||||
nop
|
||||
|
||||
3:
|
||||
/* We found an item in the table. */
|
||||
lw r6, 12(r4) ! load jump target
|
||||
/* fall through */
|
||||
1:
|
||||
beq r6, zero, 4f /* trap if null */
|
||||
nop
|
||||
jr r6 /* otherwise jump */
|
||||
nop
|
||||
4:
|
||||
j .trap_ecase
|
||||
nop
|
||||
|
28
mach/mips/libem/dus4.s
Normal file
28
mach/mips/libem/dus4.s
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Duplicates some words on top of stack.
|
||||
* Stack: ( a size -- a a )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .dus4
|
||||
.dus4:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
addiu sp, sp, 4 ! sp = pointer to a
|
||||
mov r5, sp ! r5 = pointer to a
|
||||
subu sp, sp, r4 ! sp = pointer to newa
|
||||
mov r6, sp ! r6 = pointer to b
|
||||
|
||||
srl r4, r4, 2 ! r4 = number of words
|
||||
1:
|
||||
lw at, 0(r5)
|
||||
sw at, 0(r6)
|
||||
addiu r5, r5, 4
|
||||
addiu r6, r6, 4
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
31
mach/mips/libem/exg.s
Normal file
31
mach/mips/libem/exg.s
Normal file
|
@ -0,0 +1,31 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Exchange top two values on stack.
|
||||
* Stack: ( a b size -- b a )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .exg
|
||||
.exg:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
srl r5, r4, 2 ! r5 = number of words
|
||||
addiu sp, sp, 4 ! adjust stack for input/output parameter size
|
||||
|
||||
mov r6, sp ! r6 = pointer to b
|
||||
addu r7, r6, r4 ! r7 = pointer to a
|
||||
|
||||
! Loop to swap each pair of words.
|
||||
1:
|
||||
lw r8, 0(r6)
|
||||
lw r9, 0(r7)
|
||||
sw r9, 0(r6)
|
||||
sw r8, 0(r7)
|
||||
addiu r6, r6, 4
|
||||
addiu r7, r7, 4
|
||||
addiu r5, r5, -1
|
||||
bne r5, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
56
mach/mips/libem/fef8.s
Normal file
56
mach/mips/libem/fef8.s
Normal file
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Split a double-precision float into fraction and exponent, like
|
||||
* frexp(3) in C, http://en.cppreference.com/w/c/numeric/math/frexp
|
||||
*
|
||||
* Stack: ( double -- fraction exponent )
|
||||
*/
|
||||
|
||||
#define DBL_EXPBITS 11
|
||||
#define DBL_FRACHBITS 20
|
||||
#define DBL_FRACLBITS 32
|
||||
#define DBL_FRACBITS 52
|
||||
#define DBL_EXP_INFNAN 2047
|
||||
|
||||
#define DBL_EXP_BIAS 1023
|
||||
|
||||
.sect .text
|
||||
.define .fef8
|
||||
.fef8:
|
||||
lw r4, 0(sp) ! r4 = low word (bits 0..31)
|
||||
lw r5, 4(sp) ! r5 = high word (bits 32..63)
|
||||
|
||||
! IEEE double = sign * 1.fraction * 2**(exponent - 1023)
|
||||
! sign exponent fraction
|
||||
! 31 30..19 18..0, 31..0
|
||||
!
|
||||
! IEEE exponent = 1022 in [0.5, 1) or (-1, -0.5].
|
||||
|
||||
ext r7, r5, DBL_FRACHBITS, DBL_EXPBITS ! r7 = IEEE exponent
|
||||
beq r7, zero, zeroexp ! this number is zero or denormalised, treat specially
|
||||
nop
|
||||
|
||||
li at, DBL_EXP_INFNAN
|
||||
beq r7, at, return ! just return if infinity or NaN
|
||||
nop
|
||||
|
||||
addiu r7, r7, -[DBL_EXP_BIAS-1] ! undo exponent bias
|
||||
li at, DBL_EXP_BIAS-1
|
||||
ins r5, at, DBL_FRACHBITS, DBL_EXPBITS ! replace exponent
|
||||
return:
|
||||
addiu sp, sp, -4 ! returning one more quad than we got
|
||||
sw r5, 8(sp)
|
||||
sw r6, 4(sp)
|
||||
sw r7, 0(sp)
|
||||
jr ra
|
||||
nop
|
||||
|
||||
/* We received a denormalised number or zero. */
|
||||
zeroexp:
|
||||
/* TODO: we just assume that the number is zero here. */
|
||||
mov r5, zero
|
||||
mov r6, zero
|
||||
mov r7, zero
|
||||
b return
|
||||
nop
|
69
mach/mips/libem/fif8.s
Normal file
69
mach/mips/libem/fif8.s
Normal file
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Multiplies two double-precision floats, then splits the product into
|
||||
* fraction and integer, both as floats, like modf(3) in C,
|
||||
* http://en.cppreference.com/w/c/numeric/math/modf
|
||||
*
|
||||
* Stack: ( a b -- fraction integer )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .fif8
|
||||
.fif8:
|
||||
ldc1 f0, 8(sp) ! f0 = a
|
||||
ldc1 f2, 0(sp) ! f2 = b
|
||||
mul.d f0, f0, f2 ! f0 = a * b
|
||||
abs.d f2, f0 ! f2 = abs(f0)
|
||||
|
||||
lui at, ha16[max_power_of_two]
|
||||
ldc1 f4, lo16[max_power_of_two] (at) ! f4 = max power of two
|
||||
|
||||
mov.d f6, f2 ! we're going to assemble the integer part in f6
|
||||
c.lt.d 0, f4, f2 ! if absolute value too big, it must be integral
|
||||
bc1t 0, return
|
||||
nop
|
||||
|
||||
! Crudely strip off the fractional part.
|
||||
|
||||
add.d f6, f2, f4 ! f6 = absolute value + max power of two
|
||||
sub.d f6, f6, f4 ! f6 -= max_power_of_two
|
||||
|
||||
! The above might round, so correct that.
|
||||
|
||||
lui at, ha16[one]
|
||||
ldc1 f8, lo16[one] (at) ! f8 = 1.0
|
||||
1:
|
||||
c.le.d 0, f6, f2 ! if result <= absolute value, stop
|
||||
bc1t 0, 2f
|
||||
nop
|
||||
|
||||
sub.d f6, f6, f8 ! result -= 1.0
|
||||
b 1b
|
||||
nop
|
||||
2:
|
||||
|
||||
! Correct the sign of the result.
|
||||
|
||||
mtc1 zero, f8
|
||||
mthc1 zero, f8 ! f8 = 0.0
|
||||
c.lt.d 0, f0, f8 ! if original value was negative
|
||||
bc1f 0, 1f
|
||||
nop
|
||||
neg.d f6, f6 ! negate the result
|
||||
1:
|
||||
|
||||
return:
|
||||
sdc1 f6, 0(sp) ! store integer part
|
||||
sub.d f6, f0, f6 ! calculate fractional part
|
||||
sdc1 f6, 8(sp) ! store fractional part
|
||||
jr ra
|
||||
nop
|
||||
|
||||
! doubles >= MAXPOWTWO are already integers
|
||||
.sect .rom
|
||||
max_power_of_two:
|
||||
.dataf8 4.503599627370496000E+15
|
||||
|
||||
one:
|
||||
.dataf8 1.0
|
32
mach/mips/libem/inn.s
Normal file
32
mach/mips/libem/inn.s
Normal file
|
@ -0,0 +1,32 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Tests a bit in a bitset on the stack.
|
||||
*
|
||||
* Stack: ( bitset bitnum setsize -- bool )
|
||||
*
|
||||
* Some back ends push false if bitnum is too large. We don't because
|
||||
* the compilers tend to pass a small enough bitnum.
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .inn
|
||||
.inn:
|
||||
lw r4, 0(sp) ! r4 = size of set (bytes)
|
||||
lw r5, 4(sp) ! r5 = bit number
|
||||
addiu sp, sp, 4 ! sp now points to word below bitset
|
||||
|
||||
andi r6, r5, ~31 ! r6 = bit offset of base of word in set
|
||||
srl r6, r6, 3 ! r6 = byte offset of base of word in set
|
||||
addu r6, sp, r6 ! r6 = address of word in set
|
||||
lw r6, 4(r6) ! r6 = word (remember stack offset)
|
||||
|
||||
andi r7, r5, 31 ! r7 = bit number within word
|
||||
srlv r6, r6, r7 ! r7 = candidate bit now at bit 0
|
||||
andi r6, r6, 1 ! r7 = bool
|
||||
|
||||
addu sp, sp, r4 ! retract over bitfield (remember stack offset)
|
||||
sw r6, 0(sp) ! store result
|
||||
|
||||
jr ra
|
||||
nop
|
30
mach/mips/libem/ior.s
Normal file
30
mach/mips/libem/ior.s
Normal file
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* Set union.
|
||||
* Stack: ( a b size -- a|b )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .ior
|
||||
.ior:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
addiu sp, sp, 4 ! sp points at b
|
||||
addu r5, sp, r4 ! r5 points at a
|
||||
srl r4, r4, 2 ! r4 = count of words
|
||||
|
||||
1:
|
||||
lw at, 0(r5) ! load a
|
||||
lw r6, 0(sp) ! load b
|
||||
or at, at, r6 ! combine
|
||||
sw at, 0(r5) ! write back to a
|
||||
addiu r5, r5, 4
|
||||
addiu sp, sp, 4
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
23
mach/mips/libem/lar4.s
Normal file
23
mach/mips/libem/lar4.s
Normal file
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Load from bounds-checked array.
|
||||
*
|
||||
* Stack: ( array-adr index descriptor-adr -- element )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .lar4
|
||||
.lar4:
|
||||
mov r25, ra
|
||||
|
||||
jal .aar4
|
||||
nop
|
||||
|
||||
/* pass r2 = size from .aar4 to .los4 */
|
||||
|
||||
jal .los4
|
||||
nop
|
||||
|
||||
jr r25
|
||||
nop
|
55
mach/mips/libem/los4.s
Normal file
55
mach/mips/libem/los4.s
Normal file
|
@ -0,0 +1,55 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Loads a variable-sized block onto the stack.
|
||||
*
|
||||
* On entry: r2 = size
|
||||
* Stack: ( address -- block )
|
||||
* Preserves r25 for .lar4 and .sar4
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .los4
|
||||
.los4:
|
||||
lw r4, 0(sp) ! r4 = address of source block
|
||||
|
||||
! Sizes 1 and 2 are handled specially.
|
||||
|
||||
li at, 1
|
||||
beq r2, at, byte_sized
|
||||
nop
|
||||
|
||||
li at, 2
|
||||
beq r2, at, word_sized
|
||||
nop
|
||||
|
||||
! Else the size must be a multiple of 4.
|
||||
|
||||
srl r5, r2, 2 ! r5 = number of words
|
||||
addiu sp, sp, 4 ! retract over address
|
||||
subu sp, sp, r2 ! allocate space for destination block
|
||||
mov r6, sp ! r6 = start of destination block
|
||||
|
||||
1:
|
||||
lw at, 0(r4)
|
||||
sw at, 0(r6)
|
||||
addiu r4, r4, 4
|
||||
addiu r6, r6, 4
|
||||
addiu r5, r5, -1
|
||||
bne r5, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
||||
byte_sized:
|
||||
lbu at, 0(r4)
|
||||
sw at, 0(sp)
|
||||
jr ra
|
||||
nop
|
||||
|
||||
word_sized:
|
||||
lhu at, 0(r4)
|
||||
sw at, 0(sp)
|
||||
jr ra
|
||||
nop
|
35
mach/mips/libem/rck.s
Normal file
35
mach/mips/libem/rck.s
Normal file
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Bounds check. Traps if the value is out of range.
|
||||
* Stack: ( value descriptor -- value )
|
||||
*
|
||||
* This ".rck" only works with 4-byte integers. The name is ".rck" and
|
||||
* not ".rck4" because many back ends only do rck with the word size.
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .rck
|
||||
.rck:
|
||||
lw r4, 0(sp) ! r4 = pointer to descriptor
|
||||
addiu sp, sp, 4 ! leave value on stack
|
||||
lw r5, 0(sp) ! r5 = value
|
||||
|
||||
lw at, 0(r4) ! at = lower bound
|
||||
slt at, r5, at ! at = r5 < at
|
||||
bne at, zero, .trap_erange
|
||||
nop
|
||||
|
||||
lw at, 4(r4) ! at = upper bound
|
||||
slt at, at, r5 ! at = at < r5
|
||||
bne at, zero, .trap_erange
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
||||
.define .trap_erange
|
||||
.trap_erange:
|
||||
li r4, 1
|
||||
j .trp
|
||||
nop
|
24
mach/mips/libem/sar4.s
Normal file
24
mach/mips/libem/sar4.s
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Store to bounds-checked array.
|
||||
*
|
||||
* Stack: ( element array-adr index descriptor-adr -- )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .sar4
|
||||
.sar4:
|
||||
mov r25, ra
|
||||
|
||||
jal .aar4
|
||||
nop
|
||||
|
||||
/* pass r2 = size from .aar4 to .sts4 */
|
||||
|
||||
jal .sts4
|
||||
nop
|
||||
|
||||
jr r25
|
||||
nop
|
||||
|
39
mach/mips/libem/set.s
Normal file
39
mach/mips/libem/set.s
Normal file
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* Create singleton set.
|
||||
* Stack: ( bitnumber size -- set )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .set
|
||||
.set:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
lw r5, 4(sp) ! r5 = bit number
|
||||
addiu sp, sp, 8
|
||||
srl r4, r4, 2 ! r4 = word count
|
||||
|
||||
! Create an empty set by pushing zeros.
|
||||
|
||||
1:
|
||||
addiu sp, sp, -4
|
||||
sw zero, 0(sp)
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
! sp now points at the set.
|
||||
|
||||
andi r6, r5, ~31 ! r6 = bit offset of base of word in set
|
||||
srl r6,r6, 3 ! r6 = byte offset of word in set
|
||||
addu r6, sp, r6 ! r6 = address of word in set
|
||||
|
||||
andi r7, r5, 31 ! r7 = bit number within word
|
||||
li r8, 1
|
||||
sllv r8, r8, r7 ! r8 = word with 1 set
|
||||
sw r8, 0(r6) ! write to set
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
57
mach/mips/libem/sts4.s
Normal file
57
mach/mips/libem/sts4.s
Normal file
|
@ -0,0 +1,57 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/* Stores a variable-sized block from the stack.
|
||||
*
|
||||
* On entry: r2 = size
|
||||
* Stack: ( block address -- )
|
||||
* Preserves r25 for .lar4 and .sar4
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .sts4
|
||||
.sts4:
|
||||
lw r4, 0(sp) ! r4 = address
|
||||
addiu sp, sp, 4 ! sp = pointer to block
|
||||
|
||||
! Sizes 1 and 2 are handled specially.
|
||||
|
||||
li at, 1
|
||||
beq r2, at, byte_sized
|
||||
nop
|
||||
|
||||
li at, 2
|
||||
beq r2, at, word_sized
|
||||
nop
|
||||
|
||||
! Else the size must be a multiple of 4.
|
||||
|
||||
srl r5, r2, 2 ! r5 = number of words
|
||||
|
||||
! Copy.
|
||||
|
||||
1:
|
||||
lw at, 0(sp)
|
||||
sw at, 0(r4)
|
||||
addiu sp, sp, 4
|
||||
addiu r4, r4, 4
|
||||
addiu r5, r5, -1
|
||||
bne r5, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
||||
byte_sized:
|
||||
lw at, 0(sp)
|
||||
sb at, 0(r4)
|
||||
addiu sp, sp, 4
|
||||
jr ra
|
||||
nop
|
||||
|
||||
word_sized:
|
||||
lw at, 0(sp)
|
||||
sh at, 0(r4)
|
||||
addiu sp, sp, 4
|
||||
jr ra
|
||||
nop
|
65
mach/mips/libem/trp.s
Normal file
65
mach/mips/libem/trp.s
Normal file
|
@ -0,0 +1,65 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
|
||||
.sect .text
|
||||
.define .trap_ecase
|
||||
.trap_ecase:
|
||||
li r4, 20 ! ECASE = 20 in h/em_abs.h
|
||||
! FALLTHROUGH to .trp
|
||||
|
||||
! Raises an EM trap.
|
||||
! Expects r4 = trap number.
|
||||
|
||||
.define .trp
|
||||
.trp:
|
||||
andi at, r4, 0xfff0
|
||||
bne at, zero, 1f ! traps > 15 can't be ignored
|
||||
nop
|
||||
|
||||
lui at, ha16[.ignmask]
|
||||
lw r5, lo16[.ignmask] (at) ! load ignore mask
|
||||
srlv r5, r5, r4
|
||||
andi r5, r5, 1
|
||||
bne r5, zero, return ! return if ignoring trap
|
||||
nop
|
||||
1:
|
||||
|
||||
lui at, ha16[.trppc]
|
||||
lw r5, lo16[.trppc] (at) ! r5 = user trap routine
|
||||
sw zero, lo16[.trppc] (at) ! reset the trap routine for next time
|
||||
beq r5, zero, abend ! abort if no user trap routine
|
||||
nop
|
||||
|
||||
addiu sp, sp, -8
|
||||
sw r4, 0(sp) ! push trap number
|
||||
sw ra, 4(sp) ! and link register
|
||||
jalr r5 ! call trap routine
|
||||
nop
|
||||
|
||||
lw ra, 4(sp) ! ...and return
|
||||
addiu sp, sp, 8
|
||||
return:
|
||||
jr ra
|
||||
nop
|
||||
|
||||
! No trap handler; write error message and exit.
|
||||
abend:
|
||||
addiu sp, sp, -12
|
||||
li at, 2
|
||||
sw at, 0(sp)
|
||||
lui at, hi16[message]
|
||||
ori at, at, lo16[message]
|
||||
sw at, 4(sp)
|
||||
li at, 6
|
||||
sw at, 8(sp)
|
||||
jal _write ! write(2, message, 6)
|
||||
nop
|
||||
|
||||
li at, 1
|
||||
sw at, 0(sp)
|
||||
j __exit ! _exit(1)
|
||||
|
||||
.sect .rom
|
||||
message:
|
||||
.ascii "TRAP!\n"
|
30
mach/mips/libem/xor.s
Normal file
30
mach/mips/libem/xor.s
Normal file
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* Set xor..
|
||||
* Stack: ( a b size -- a^b )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .xor
|
||||
.xor:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
addiu sp, sp, 4 ! sp points at b
|
||||
addu r5, sp, r4 ! r5 points at a
|
||||
srl r4, r4, 2 ! r4 = count of words
|
||||
|
||||
1:
|
||||
lw at, 0(r5) ! load a
|
||||
lw r6, 0(sp) ! load b
|
||||
xor at, at, r6 ! combine
|
||||
sw at, 0(r5) ! write back to a
|
||||
addiu r5, r5, 4
|
||||
addiu sp, sp, 4
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
25
mach/mips/libem/zer.s
Normal file
25
mach/mips/libem/zer.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
|
||||
/*
|
||||
* Create empty set.
|
||||
* Stack: ( size -- set )
|
||||
*/
|
||||
|
||||
.sect .text
|
||||
.define .zer
|
||||
.zer:
|
||||
lw r4, 0(sp) ! r4 = size
|
||||
addiu sp, sp, 4
|
||||
srl r4, r4, 2 ! r4 = word count
|
||||
|
||||
1:
|
||||
addiu sp, sp, -4
|
||||
sw zero, 0(sp)
|
||||
addiu r4, r4, -1
|
||||
bne r4, zero, 1b
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
|
8
mach/mips/libend/build.lua
Normal file
8
mach/mips/libend/build.lua
Normal file
|
@ -0,0 +1,8 @@
|
|||
for _, plat in ipairs(vars.plats) do
|
||||
acklibrary {
|
||||
name = "lib_"..plat,
|
||||
srcs = { "./*.s" },
|
||||
vars = { plat = plat },
|
||||
}
|
||||
end
|
||||
|
9
mach/mips/libend/edata.s
Normal file
9
mach/mips/libend/edata.s
Normal file
|
@ -0,0 +1,9 @@
|
|||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
.define _edata
|
||||
.sect .data
|
||||
.align 4
|
||||
.sect .data
|
||||
_edata:
|
24
mach/mips/libend/em_end.s
Normal file
24
mach/mips/libend/em_end.s
Normal file
|
@ -0,0 +1,24 @@
|
|||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
.sect .end ! only for declaration of _end, __end and endbss.
|
||||
.define endtext, endrom, enddata, endbss, __end
|
||||
|
||||
.sect .text
|
||||
.align 4
|
||||
endtext:
|
||||
.sect .rom
|
||||
.align 4
|
||||
endrom:
|
||||
.sect .data
|
||||
.align 4
|
||||
enddata:
|
||||
.sect .end
|
||||
.align 4
|
||||
__end:
|
||||
endbss:
|
7
mach/mips/libend/end.s
Normal file
7
mach/mips/libend/end.s
Normal file
|
@ -0,0 +1,7 @@
|
|||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
.define _end
|
||||
.sect .end ! only for declaration of _end, __end and endbss.
|
||||
_end:
|
9
mach/mips/libend/etext.s
Normal file
9
mach/mips/libend/etext.s
Normal file
|
@ -0,0 +1,9 @@
|
|||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
.define _etext
|
||||
.sect .text
|
||||
.align 4
|
||||
.sect .text
|
||||
_etext:
|
310
mach/mips/mcg/platform.c
Normal file
310
mach/mips/mcg/platform.c
Normal file
|
@ -0,0 +1,310 @@
|
|||
#include "mcg.h"
|
||||
|
||||
/* mcg stack frames are laid out as:
|
||||
*
|
||||
* | ...params...
|
||||
* | --------------- <- ab
|
||||
* | old FR
|
||||
* | old FP
|
||||
* | --------------- <- fp (a.k.a. lb)
|
||||
* | locals
|
||||
* | ---------------
|
||||
* | spills
|
||||
* | --------------- <- sb
|
||||
* | saved regs
|
||||
* | --------------- <- sp, rb
|
||||
* V ...user area...
|
||||
*
|
||||
* st indexes up; lb indexes down.
|
||||
*
|
||||
* Note that [fp] == old_fp and ab == fp + 8.
|
||||
*/
|
||||
|
||||
static ARRAYOF(struct hreg) saved_regs;
|
||||
|
||||
void platform_calculate_offsets(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
saved_regs.count = 0;
|
||||
for (i=0; i<current_proc->usedregs.count; i++)
|
||||
{
|
||||
struct hreg* hreg = current_proc->usedregs.item[i];
|
||||
|
||||
if (!(hreg->attrs & burm_volatile_ATTR) &&
|
||||
((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR)))
|
||||
{
|
||||
hreg->offset = current_proc->saved_size;
|
||||
current_proc->saved_size += 8;
|
||||
array_append(&saved_regs, hreg);
|
||||
}
|
||||
}
|
||||
for (i=0; i<current_proc->usedregs.count; i++)
|
||||
{
|
||||
struct hreg* hreg = current_proc->usedregs.item[i];
|
||||
|
||||
if (!(hreg->attrs & burm_volatile_ATTR) &&
|
||||
((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR)))
|
||||
{
|
||||
hreg->offset = current_proc->saved_size;
|
||||
current_proc->saved_size += 4;
|
||||
array_append(&saved_regs, hreg);
|
||||
}
|
||||
}
|
||||
|
||||
current_proc->fp_to_ab = 8;
|
||||
current_proc->fp_to_lb = 0;
|
||||
current_proc->fp_to_sb = -(current_proc->locals_size + current_proc->spills_size);
|
||||
current_proc->fp_to_rb = current_proc->fp_to_sb - current_proc->saved_size;
|
||||
}
|
||||
|
||||
struct hop* platform_prologue(void)
|
||||
{
|
||||
int i;
|
||||
int spoffset = current_proc->saved_size + current_proc->spills_size +
|
||||
current_proc->locals_size;
|
||||
struct hop* hop = new_hop(current_proc->entry, NULL);
|
||||
|
||||
hop_add_insel(hop, "! locals_size = %d", current_proc->locals_size);
|
||||
hop_add_insel(hop, "! spills_size = %d", current_proc->spills_size);
|
||||
hop_add_insel(hop, "! saved_size = %d", current_proc->saved_size);
|
||||
hop_add_insel(hop, "! params @ fp+%d", current_proc->fp_to_ab);
|
||||
hop_add_insel(hop, "! lr @ fp+4");
|
||||
hop_add_insel(hop, "! fp @ fp+0");
|
||||
hop_add_insel(hop, "! locals @ fp-%d to fp+0",
|
||||
current_proc->locals_size);
|
||||
hop_add_insel(hop, "! spills @ fp-%d to fp-%d",
|
||||
-current_proc->fp_to_sb, current_proc->locals_size);
|
||||
for (i=saved_regs.count-1; i>=0; i--)
|
||||
{
|
||||
struct hreg* hreg = saved_regs.item[i];
|
||||
hop_add_insel(hop, "! %s @ fp-%d",
|
||||
hreg->id, -(current_proc->fp_to_rb + hreg->offset));
|
||||
}
|
||||
|
||||
hop_add_insel(hop, "addiu sp, sp, %d", -(spoffset + 8));
|
||||
hop_add_insel(hop, "sw fp, %d(sp)", spoffset + 0);
|
||||
hop_add_insel(hop, "sw ra, %d(sp)", spoffset + 4);
|
||||
hop_add_insel(hop, "addiu fp, sp, %d", spoffset);
|
||||
|
||||
/* Saved reg offsets are negative. */
|
||||
for (i=0; i<saved_regs.count; i++)
|
||||
{
|
||||
struct hreg* hreg = saved_regs.item[i];
|
||||
if (hreg->attrs & burm_int_ATTR)
|
||||
hop_add_insel(hop, "sw %H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset);
|
||||
else if (hreg->attrs & burm_long_ATTR)
|
||||
{
|
||||
hop_add_insel(hop, "sw %0H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset + 0);
|
||||
hop_add_insel(hop, "sw %1H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset + 4);
|
||||
}
|
||||
else if (hreg->attrs & burm_float_ATTR)
|
||||
hop_add_insel(hop, "swc1 %H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset);
|
||||
else if (hreg->attrs & burm_double_ATTR)
|
||||
hop_add_insel(hop, "sdc1 %H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset);
|
||||
else
|
||||
fatal("unsavable non-volatile register %s", hreg->id);
|
||||
}
|
||||
return hop;
|
||||
}
|
||||
|
||||
struct hop* platform_epilogue(void)
|
||||
{
|
||||
struct hop* hop = new_hop(current_proc->exit, NULL);
|
||||
int i;
|
||||
|
||||
for (i=0; i<saved_regs.count; i++)
|
||||
{
|
||||
struct hreg* hreg = saved_regs.item[i];
|
||||
if (hreg->attrs & burm_int_ATTR)
|
||||
hop_add_insel(hop, "lw %H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset);
|
||||
else if (hreg->attrs & burm_long_ATTR)
|
||||
{
|
||||
hop_add_insel(hop, "lw %0H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset + 0);
|
||||
hop_add_insel(hop, "lw %1H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset + 4);
|
||||
}
|
||||
else if (hreg->attrs & burm_float_ATTR)
|
||||
hop_add_insel(hop, "lwc1 %H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset);
|
||||
else if (hreg->attrs & burm_double_ATTR)
|
||||
hop_add_insel(hop, "ldc1 %H, %d(fp)",
|
||||
hreg, current_proc->fp_to_rb + hreg->offset);
|
||||
else
|
||||
fatal("unloadable non-volatile register %s", hreg->id);
|
||||
}
|
||||
|
||||
hop_add_insel(hop, "lw ra, 4(fp)");
|
||||
hop_add_insel(hop, "lw at, 0(fp)"); /* load old fp */
|
||||
hop_add_insel(hop, "addiu sp, fp, %d", current_proc->fp_to_ab);
|
||||
hop_add_insel(hop, "mov fp, at");
|
||||
hop_add_insel(hop, "jr ra");
|
||||
hop_add_insel(hop, "nop");
|
||||
|
||||
return hop;
|
||||
}
|
||||
|
||||
struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest)
|
||||
{
|
||||
struct hop* hop = new_hop(bb, NULL);
|
||||
|
||||
if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS))
|
||||
fatal("hreg move of %%%d from %s to %s with mismatched types", vreg->id, src->id, dest->id);
|
||||
else
|
||||
{
|
||||
uint32_t type = src->attrs & TYPE_ATTRS;
|
||||
tracef('R', "R: non-converting move from %s to %s of type 0x%x\n", src->id, dest->id, type);
|
||||
|
||||
if (!src->is_stacked && dest->is_stacked)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "sw %H, %S(fp) ! %H", src, dest, dest);
|
||||
break;
|
||||
|
||||
case burm_long_ATTR:
|
||||
hop_add_insel(hop, "sw %0H, 0+%S(fp) ! %H", src, dest, dest);
|
||||
hop_add_insel(hop, "sw %1H, 4+%S(fp) ! %H", src, dest, dest);
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "swc1 %H, %S(fp) ! %H", src, dest, dest);
|
||||
break;
|
||||
|
||||
case burm_double_ATTR:
|
||||
hop_add_insel(hop, "sdc1 %H, %S(fp) ! %H", src, dest, dest);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto nomove;
|
||||
}
|
||||
}
|
||||
else if (src->is_stacked && !dest->is_stacked)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "lw %H, %S(fp) ! %H", dest, src, src);
|
||||
break;
|
||||
|
||||
case burm_long_ATTR:
|
||||
/* Can't load straight into dest because it might overlap with src. */
|
||||
hop_add_insel(hop, "lw at, 0+%S(fp) ! %H", dest, src, src);
|
||||
hop_add_insel(hop, "lw %1H, 4+%S(fp) ! %H", dest, src, src);
|
||||
hop_add_insel(hop, "mov %0H, at", dest);
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "lwc1 %H, %S(fp) ! %H", dest, src, src);
|
||||
break;
|
||||
|
||||
case burm_double_ATTR:
|
||||
hop_add_insel(hop, "ldc1 %H, %S(fp) ! %H", dest, src, src);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto nomove;
|
||||
}
|
||||
}
|
||||
else if (!src->is_stacked && !dest->is_stacked)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "mov %H, %H", dest, src);
|
||||
break;
|
||||
|
||||
case burm_long_ATTR:
|
||||
hop_add_insel(hop, "mov %0H, %0H", dest, src);
|
||||
hop_add_insel(hop, "mov %1H, %1H", dest, src);
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "mov.s %H, %H", dest, src);
|
||||
break;
|
||||
|
||||
case burm_double_ATTR:
|
||||
hop_add_insel(hop, "mov.d %H, %H", dest, src);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto nomove;
|
||||
}
|
||||
}
|
||||
else if (src->is_stacked && dest->is_stacked)
|
||||
fatal("tried to move stacked object %%%d of type 0x%x from %s to %s", vreg->id, type, src->id, dest->id);
|
||||
else
|
||||
goto nomove;
|
||||
}
|
||||
|
||||
return hop;
|
||||
|
||||
nomove:
|
||||
fatal("cannot move %s to %s", src->id, dest->id);
|
||||
}
|
||||
|
||||
struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest)
|
||||
{
|
||||
struct hop* hop = new_hop(bb, NULL);
|
||||
|
||||
tracef('R', "R: swap of %s to %s\n", src->id, dest->id);
|
||||
assert(!src->is_stacked);
|
||||
assert(!dest->is_stacked);
|
||||
assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS));
|
||||
|
||||
switch (src->attrs & TYPE_ATTRS)
|
||||
{
|
||||
case burm_int_ATTR:
|
||||
hop_add_insel(hop, "mov at, %H", src);
|
||||
hop_add_insel(hop, "mov %H, %H", src, dest);
|
||||
hop_add_insel(hop, "mov %H, at", dest);
|
||||
break;
|
||||
|
||||
case burm_long_ATTR:
|
||||
hop_add_insel(hop, "mov at, %0H", src);
|
||||
hop_add_insel(hop, "mov %0H, %0H", src, dest);
|
||||
hop_add_insel(hop, "mov %0H, at", dest);
|
||||
|
||||
hop_add_insel(hop, "mov at, %1H", src);
|
||||
hop_add_insel(hop, "mov %1H, %1H", src, dest);
|
||||
hop_add_insel(hop, "mov %1H, at", dest);
|
||||
break;
|
||||
|
||||
case burm_float_ATTR:
|
||||
hop_add_insel(hop, "mov.s f30, %H", src);
|
||||
hop_add_insel(hop, "mov.s %H, %H", src, dest);
|
||||
hop_add_insel(hop, "mov.s %H, f30", dest);
|
||||
break;
|
||||
|
||||
case burm_double_ATTR:
|
||||
hop_add_insel(hop, "mov.d f30, %H", src);
|
||||
hop_add_insel(hop, "mov.d %H, %H", src, dest);
|
||||
hop_add_insel(hop, "mov.d %H, f30", dest);
|
||||
break;
|
||||
}
|
||||
|
||||
return hop;
|
||||
}
|
||||
|
||||
const char* platform_label(const char* label)
|
||||
{
|
||||
/* Labels starting with . are internal, not exported, and don't need mangling. */
|
||||
|
||||
if (label[0] == '.')
|
||||
return label;
|
||||
|
||||
/* Otherwise, mangle. */
|
||||
|
||||
return aprintf("_%s", label);
|
||||
}
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
992
mach/mips/mcg/table
Normal file
992
mach/mips/mcg/table
Normal file
|
@ -0,0 +1,992 @@
|
|||
REGISTERS
|
||||
|
||||
/* Registers are allocated top down. The odd order below is to make sure
|
||||
* that cheap registers get allocated first.
|
||||
*
|
||||
* Attributes may have at most one of: int, float, long, double. These
|
||||
* indicate that the register is used to store a value of that type. If
|
||||
* your register can store more than one type, create an alias. Registers
|
||||
* with none of these cannot be copied by the code generator (and so cannot
|
||||
* be moved from register to register or spilt).
|
||||
*/
|
||||
|
||||
r4 int volatile;
|
||||
r5 int volatile;
|
||||
r6 int volatile;
|
||||
r7 int volatile;
|
||||
r8 int volatile;
|
||||
r9 int volatile;
|
||||
r10 int volatile;
|
||||
r11 int volatile;
|
||||
r12 int volatile;
|
||||
r13 int volatile;
|
||||
r14 int volatile;
|
||||
r15 int volatile;
|
||||
r24 int volatile;
|
||||
r25 int volatile;
|
||||
r2 int volatile iret;
|
||||
r3 int volatile;
|
||||
|
||||
r17 named("r16") int;
|
||||
r18 named("r18") int;
|
||||
r19 named("r19") int;
|
||||
r20 named("r20") int;
|
||||
r21 named("r21") int;
|
||||
r22 named("r22") int;
|
||||
r23 named("r23") int;
|
||||
|
||||
r4r5 named("r4", "r5") aliases(r4, r5) long volatilei lret1;
|
||||
r6r7 named("r6", "r7") aliases(r6, r7) long volatile;
|
||||
r8r9 named("r8", "r9") aliases(r8, r9) long volatile;
|
||||
r10r11 named("r10", "r11") aliases(r10, r11) long volatile;
|
||||
r12r13 named("r12", "r13") aliases(r12, r13) long volatile;
|
||||
r14r15 named("r14", "r15") aliases(r14, r15) long volatile;
|
||||
r24r25 named("r24", "r25") aliases(r24, r25) long volatile;
|
||||
r2r3 named("r2", "r3") aliases(r2, r3) long volatile lret;
|
||||
|
||||
r17r18 named("r17", "r18") aliases(r17, r18) long;
|
||||
r19r20 named("r19", "r20") aliases(r19, r20) long;
|
||||
r21r22 named("r21", "r22") aliases(r21, r22) long;
|
||||
|
||||
f0 float volatile fret;
|
||||
f1 float volatile;
|
||||
f2 float volatile;
|
||||
f3 float volatile;
|
||||
f4 float volatile;
|
||||
f5 float volatile;
|
||||
f6 float volatile;
|
||||
f7 float volatile;
|
||||
f8 float volatile;
|
||||
f9 float volatile;
|
||||
f10 float volatile;
|
||||
f11 float volatile;
|
||||
f12 float volatile;
|
||||
f13 float volatile;
|
||||
f14 float volatile;
|
||||
f15 float volatile;
|
||||
f16 float volatile;
|
||||
f17 float volatile;
|
||||
f18 float volatile;
|
||||
f19 float volatile;
|
||||
|
||||
f20 float;
|
||||
f21 float;
|
||||
f22 float;
|
||||
f23 float;
|
||||
f24 float;
|
||||
f25 float;
|
||||
f26 float;
|
||||
f27 float;
|
||||
f28 float;
|
||||
f29 float;
|
||||
/* f30 and f31 is used by the compiler as a temporary. */
|
||||
|
||||
d0 named("f0") aliases(f0, f1) double volatile dret;
|
||||
d2 named("f2") aliases(f2, f3) double volatile;
|
||||
d4 named("f4") aliases(f4, f5) double volatile;
|
||||
d6 named("f6") aliases(f6, f7) double volatile;
|
||||
d8 named("f8") aliases(f8, f9) double volatile;
|
||||
d10 named("f10") aliases(f10, f11) double volatile;
|
||||
d12 named("f12") aliases(f12, f13) double volatile;
|
||||
d14 named("f14") aliases(f14, f15) double volatile;
|
||||
d16 named("f16") aliases(f16, f17) double volatile;
|
||||
d18 named("f18") aliases(f18, f19) double volatile;
|
||||
|
||||
d20 named("f20") aliases(f20, f21) double;
|
||||
d22 named("f22") aliases(f22, f23) double;
|
||||
d24 named("f24") aliases(f24, f25) double;
|
||||
d26 named("f26") aliases(f26, f27) double;
|
||||
d28 named("f28") aliases(f28, f29) double;
|
||||
|
||||
|
||||
|
||||
DECLARATIONS
|
||||
|
||||
ubyteX; /* bottom 8 bits valid, the rest undefined */
|
||||
ubyte0; /* bottom 8 bits valid, the rest 0 */
|
||||
ushortX; /* bottom 16 bits valid, the rest undefined */
|
||||
ushort0; /* bottom 16 bits valid, the rest 0 */
|
||||
|
||||
address fragment;
|
||||
|
||||
|
||||
|
||||
PATTERNS
|
||||
|
||||
/* Special */
|
||||
|
||||
PAIR(BLOCK.I, BLOCK.I);
|
||||
|
||||
|
||||
|
||||
/* Miscellaneous special things */
|
||||
|
||||
PUSH.I(in:(int)reg)
|
||||
emit "addiu sp, sp, -4"
|
||||
emit "sw %in, 0(sp)"
|
||||
cost 8;
|
||||
|
||||
PUSH.L(in:(long)reg)
|
||||
emit "addiu sp, sp, -8"
|
||||
emit "sw %in.0, 0(sp)"
|
||||
emit "sw %in.1, 4(sp)"
|
||||
cost 12;
|
||||
|
||||
PUSH.F(in:(float)reg)
|
||||
emit "addiu sp, sp, -4"
|
||||
emit "swc1 %in, 0(sp)"
|
||||
cost 8;
|
||||
|
||||
PUSH.D(in:(double)reg)
|
||||
emit "addiu sp, sp, -8"
|
||||
emit "sdc1 %in, 0(sp)"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = POP.I
|
||||
emit "lw %out, 0(sp)"
|
||||
emit "addiu sp, sp, 4"
|
||||
cost 8;
|
||||
|
||||
out:(long)reg = POP.L
|
||||
emit "lw %out.0, 4(sp)"
|
||||
emit "lw %out.1, 0(sp)"
|
||||
emit "addiu sp, sp, 8"
|
||||
cost 12;
|
||||
|
||||
out:(float)reg = POP.F
|
||||
emit "lwc1 %out, 0(sp)"
|
||||
emit "addiu sp, sp, 4"
|
||||
cost 8;
|
||||
|
||||
out:(double)reg = POP.D
|
||||
emit "ldc1 %out, 0(sp)"
|
||||
emit "addiu sp, sp, 8"
|
||||
cost 8;
|
||||
|
||||
SETRET.I(in:(iret)reg)
|
||||
emit "! setret.i"
|
||||
cost 1;
|
||||
|
||||
SETRET.L(in:(lret)reg)
|
||||
emit "! setret.l"
|
||||
cost 1;
|
||||
|
||||
SETRET.F(in:(fret)reg)
|
||||
emit "! setret.f"
|
||||
cost 1;
|
||||
|
||||
SETRET.D(in:(dret)reg)
|
||||
emit "! setret.d"
|
||||
cost 1;
|
||||
|
||||
STACKADJUST.I(delta:CONST.I)
|
||||
when signed_constant(%delta, 16)
|
||||
emit "addiu sp, sp, $delta"
|
||||
cost 4;
|
||||
|
||||
STACKADJUST.I(in:(int)reg)
|
||||
emit "addu sp, sp, %in"
|
||||
cost 4;
|
||||
|
||||
STACKADJUST.I(NEG.I(in:(int)reg))
|
||||
emit "subu sp, sp, %in"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = GETFP.I
|
||||
emit "mov %out, fp"
|
||||
cost 4;
|
||||
|
||||
SETFP.I(in:(int)reg)
|
||||
emit "mov fp, %in"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = CHAINFP.I(in:(int)reg)
|
||||
emit "lw %out, 0(%in)"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = FPTOAB.I(GETFP.I)
|
||||
emit "addiu %out, fp, 8"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = FPTOAB.I(in:(int)reg)
|
||||
emit "addiu %out, %in, 8"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = FPTOLB.I(in:(int)reg)
|
||||
with %out == %in
|
||||
cost 1;
|
||||
|
||||
out:(int)reg = GETSP.I
|
||||
emit "mov %out, sp"
|
||||
cost 4;
|
||||
|
||||
SETSP.I(in:(int)reg)
|
||||
emit "mov sp, %in"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = ANY.I
|
||||
cost 1;
|
||||
|
||||
out:(long)reg = ANY.L
|
||||
cost 1;
|
||||
|
||||
|
||||
|
||||
/* Memory operations */
|
||||
|
||||
/* Stores */
|
||||
|
||||
STORE.L(addr:address, value:(long)reg)
|
||||
emit "sw %value.0, 0+%addr"
|
||||
emit "sw %value.1, 4+%addr"
|
||||
cost 8;
|
||||
|
||||
STORE.I(addr:address, value:(int)reg)
|
||||
emit "sw %value, %addr"
|
||||
cost 4;
|
||||
|
||||
STORE.I(label:LABEL.I, value:(int)reg)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "sw %value, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
STOREH.I(addr:address, value:(int)ushortX)
|
||||
emit "sh %value, %addr"
|
||||
cost 4;
|
||||
|
||||
STOREH.I(label:LABEL.I, value:(int)reg)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "sh %value, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
STOREB.I(addr:address, value:(int)ubyteX)
|
||||
emit "sb %value, %addr"
|
||||
cost 4;
|
||||
|
||||
STOREB.I(label:LABEL.I, value:(int)reg)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "sb %value, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
STORE.F(addr:address, value:(float)reg)
|
||||
emit "swc1 %value, %addr"
|
||||
cost 4;
|
||||
|
||||
STORE.F(label:LABEL.I, value:(int)reg)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "swc1 %value, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
STORE.D(addr:address, value:(double)reg)
|
||||
emit "sdc1 %value, %addr"
|
||||
cost 4;
|
||||
|
||||
STORE.D(label:LABEL.I, value:(int)reg)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "sdc1 %value, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
/* Loads */
|
||||
|
||||
out:(int)reg = LOAD.I(addr:address)
|
||||
emit "lw %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = LOAD.I(label:LABEL.I)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "lw %out, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
/* We can't just load directly because %out.0 and %addr might share
|
||||
* a register, resulting in %addr being corrupted before %out.1 is
|
||||
* loaded. */
|
||||
out:(long)reg = LOAD.L(addr:address)
|
||||
emit "lw at, 0+%addr"
|
||||
emit "lw %out.1, 4+%addr"
|
||||
emit "mov %out.0, at"
|
||||
cost 12;
|
||||
|
||||
out:(int)ushort0 = LOADH.I(addr:address)
|
||||
emit "lhu %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = EXTENDH.I(LOADH.I(addr:address))
|
||||
emit "lh %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(int)ushort0 = LOADH.I(label:LABEL.I)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "lhu %out, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = EXTENDH.I(LOADH.I(label:LABEL.I))
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "lh %out, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
out:(int)ubyte0 = LOADB.I(addr:address)
|
||||
emit "lbu %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = EXTENDB.I(LOADB.I(addr:address))
|
||||
emit "lb %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(int)ubyte0 = LOADB.I(label:LABEL.I)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "lbu %out, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = EXTENDB.I(LOADB.I(label:LABEL.I))
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "lb %out, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
out:(float)reg = LOAD.F(addr:address)
|
||||
emit "lwc1 %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = LOAD.F(label:LABEL.I)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "lwc1 %out, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
out:(double)reg = LOAD.D(addr:address)
|
||||
emit "ldc1 %out, %addr"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = LOAD.D(label:LABEL.I)
|
||||
emit "lui at, ha16[$label]"
|
||||
emit "ldc1 %out, lo16[$label] (at)"
|
||||
cost 8;
|
||||
|
||||
/* ubyte intrinsics */
|
||||
|
||||
out:(int)ubyteX = in:(int)ubyte0
|
||||
with %out == %in
|
||||
emit "! ubyte0 -> ubyteX"
|
||||
cost 1;
|
||||
|
||||
out:(int)ubyte0 = in:(int)ubyteX
|
||||
emit "andiu %out, %in, 0xff ! ubyteX -> ubyte0"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = in:(int)ubyte0
|
||||
with %out == %in
|
||||
emit "! ubyte0 -> reg"
|
||||
cost 4;
|
||||
|
||||
out:(int)ubyteX = in:(int)reg
|
||||
with %out == %in
|
||||
emit "! reg -> ubyteX"
|
||||
cost 1;
|
||||
|
||||
/* ushort intrinsics */
|
||||
|
||||
out:(int)ushortX = in:(int)ushort0
|
||||
with %out == %in
|
||||
emit "! ushort0 -> ushortX"
|
||||
cost 1;
|
||||
|
||||
out:(int)ushort0 = in:(int)ushortX
|
||||
emit "andiu %out, %in, 0xffff ! ushortX -> ushort0"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = in:(int)ushort0
|
||||
with %out == %in
|
||||
emit "! ushort0 -> reg"
|
||||
cost 4;
|
||||
|
||||
out:(int)ushortX = in:(int)reg
|
||||
with %out == %in
|
||||
emit "! reg -> ushortX"
|
||||
cost 1;
|
||||
|
||||
|
||||
|
||||
/* Extensions and conversions */
|
||||
|
||||
out:(int)reg = EXTENDB.I(in:(int)reg)
|
||||
emit "seb %out, %in"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = EXTENDH.I(in:(int)reg)
|
||||
emit "seh %out, %in"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = FROMSI.I(in:(int)reg)
|
||||
with %out == %in
|
||||
emit "! FROMSI.I(int) -> int"
|
||||
cost 1;
|
||||
|
||||
out:(int)reg = FROMUI.I(in:(int)reg)
|
||||
with %out == %in
|
||||
emit "! FROMUI.I(int) -> int"
|
||||
cost 1;
|
||||
|
||||
out:(long)reg = FROMSI.L(in:(int)reg)
|
||||
emit "mov %out.0, %in"
|
||||
emit "sra %out.1, %in, 31"
|
||||
cost 8;
|
||||
|
||||
out:(long)reg = FROMUI.L(in:(int)reg)
|
||||
emit "mr %out.0, %in"
|
||||
emit "li %out.1, 0"
|
||||
cost 8;
|
||||
|
||||
out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg)
|
||||
with preserved(%in1), preserved(%in2)
|
||||
emit "mov %out.0, %in1"
|
||||
emit "mov %out.1, %in2"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = FROML0.I(in:(long)reg)
|
||||
emit "mov %out, %in.0"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = FROML1.I(in:(long)reg)
|
||||
emit "mov %out, %in.1"
|
||||
cost 4;
|
||||
|
||||
|
||||
|
||||
/* Locals */
|
||||
|
||||
out:(int)reg = in:LOCAL.I
|
||||
emit "addiu %out, fp, $in"
|
||||
cost 4;
|
||||
|
||||
address = in:LOCAL.I
|
||||
emit "$in(fp)";
|
||||
|
||||
|
||||
|
||||
/* Memory addressing modes */
|
||||
|
||||
address = ADD.I(addr:(int)reg, offset:CONST.I)
|
||||
when signed_constant(%offset, 16)
|
||||
emit "$offset(%addr)";
|
||||
|
||||
address = addr:(int)reg
|
||||
emit "0(%addr)";
|
||||
|
||||
|
||||
|
||||
/* Branches */
|
||||
|
||||
JUMP(addr:BLOCK.I)
|
||||
emit "b $addr"
|
||||
emit "nop"
|
||||
cost 8;
|
||||
|
||||
FARJUMP(addr:LABEL.I)
|
||||
with corrupted(volatile)
|
||||
emit "j $addr"
|
||||
emit "nop"
|
||||
cost 8;
|
||||
|
||||
JUMP(dest:(int)reg)
|
||||
emit "jr %dest"
|
||||
emit "nop"
|
||||
cost 8;
|
||||
|
||||
CJUMPEQ(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
emit "beq %left, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
CJUMPLT(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
emit "bltz %left, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
CJUMPLE(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
emit "blez %left, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
#define CALLLABEL(insn) \
|
||||
insn (dest:LABEL.I) \
|
||||
with corrupted(volatile) \
|
||||
emit "jal $dest" \
|
||||
emit "nop" \
|
||||
cost 8;
|
||||
|
||||
CALLLABEL(CALL)
|
||||
out:(iret)reg = CALLLABEL(CALL.I)
|
||||
out:(lret)reg = CALLLABEL(CALL.L)
|
||||
|
||||
#define CALLINDIRECT(insn) \
|
||||
insn (dest:(int)reg) \
|
||||
with corrupted(volatile) \
|
||||
emit "jalr %dest" \
|
||||
emit "nop" \
|
||||
cost 8;
|
||||
|
||||
CALLINDIRECT(CALL)
|
||||
out:(iret)reg = CALLINDIRECT(CALL.I)
|
||||
out:(lret)reg = CALLINDIRECT(CALL.L)
|
||||
|
||||
JUMP(dest:LABEL.I)
|
||||
emit "b $dest"
|
||||
emit "nop"
|
||||
cost 8;
|
||||
|
||||
|
||||
|
||||
/* Conditional branches */
|
||||
|
||||
/* Normally COMPARE returns a condition code (in a flags register) which the CJUMP
|
||||
* instructions can then operate on. But MIPS doesn't have a flags register, and
|
||||
* requires you to know what condition you're testing for when you do the comparison.
|
||||
* mcg doesn't like this much and we have to list every combination individually.
|
||||
*/
|
||||
|
||||
/* Signed integer comparisons against zero */
|
||||
|
||||
CJUMPEQ(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when specific_constant(%zero, 0)
|
||||
emit "beq %left, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
CJUMPLT(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when specific_constant(%zero, 0)
|
||||
emit "bltz %left, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
CJUMPLE(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when specific_constant(%zero, 0)
|
||||
emit "blez %left, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
/* Signed integer comparisons against a constant */
|
||||
|
||||
CJUMPEQ(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
emit "li at, $value"
|
||||
emit "beq %left, at, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
CJUMPLT(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when signed_constant(%value, 16)
|
||||
emit "slti at, %left, $value"
|
||||
emit "bne at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
CJUMPLE(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when constant_within_inclusive_range(%value, -0x8000, 0x7ffe)
|
||||
emit "slti at, %left, 1+$value"
|
||||
emit "bne at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
/* Signed integer comparisons against a register */
|
||||
|
||||
CJUMPEQ(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
emit "beq %left, %right, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
CJUMPLT(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
emit "slt at, %left, %right"
|
||||
emit "bne at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
CJUMPLE(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
emit "slt at, %right, %left"
|
||||
emit "beq at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
/* Unsigned integer comparisons against a constant */
|
||||
|
||||
CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when signed_constant(%right, 16)
|
||||
when specific_constant(%alwayszero, 0)
|
||||
emit "sltiu at, %left, $right"
|
||||
emit "bne at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when constant_within_inclusive_range(%right, -0x8000, 0x7ffe)
|
||||
when specific_constant(%alwayszero, 0)
|
||||
emit "sltiu at, %left, 1+$right"
|
||||
emit "bne at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 20;
|
||||
|
||||
/* Unsigned integer comparisons against registers */
|
||||
|
||||
CJUMPEQ(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when specific_constant(%alwayszero, 0)
|
||||
emit "beq %left, %right, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when specific_constant(%alwayszero, 0)
|
||||
emit "sltu at, %left, %right"
|
||||
emit "bne at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
|
||||
when specific_constant(%alwayszero, 0)
|
||||
emit "sltu at, %right, %left"
|
||||
emit "beq at, zero, $true"
|
||||
emit "nop"
|
||||
emit "b $false"
|
||||
emit "nop"
|
||||
cost 16;
|
||||
|
||||
|
||||
|
||||
|
||||
/* Comparisons */
|
||||
|
||||
/* The COMPARE nodes return tristate integer values; -1, 0 or 1. */
|
||||
|
||||
out:(int)reg = COMPARESI.I(left:(int)reg, right:(int)reg)
|
||||
with preserved(%left), preserved(%right)
|
||||
emit "slt at, %left, %right"
|
||||
emit "bne at, zero, 1f"
|
||||
emit "li %out, -1" /* delay slot */
|
||||
emit "slt %out, %right, %left"
|
||||
emit "1:"
|
||||
cost 20;
|
||||
|
||||
out:(int)reg = COMPAREUI.I(left:(int)reg, right:(int)reg)
|
||||
with preserved(%left), preserved(%right)
|
||||
emit "sltu at, %left, %right"
|
||||
emit "bne at, zero, 1f"
|
||||
emit "li %out, -1" /* delay slot */
|
||||
emit "sltu %out, %right, %left"
|
||||
emit "1:"
|
||||
cost 20;
|
||||
|
||||
out:(iret)reg = COMPAREUL.I(left:(lret)reg, right:(lret1)reg)
|
||||
emit "jal .compareul"
|
||||
emit "nop"
|
||||
cost 30;
|
||||
|
||||
out:(int)reg = COMPAREF.I(left:(float)reg, right:(float)reg)
|
||||
with preserved(%left), preserved(%right)
|
||||
emit "c.lt.s 0, %left, %right"
|
||||
emit "li %out, -1"
|
||||
emit "bc1t 0, 1f"
|
||||
emit "nop"
|
||||
emit "c.lt.s 0, %right, %left"
|
||||
emit "li %out, 1"
|
||||
emit "movf %out, zero, 0"
|
||||
emit "1:"
|
||||
cost 28;
|
||||
|
||||
out:(int)reg = COMPARED.I(left:(double)reg, right:(double)reg)
|
||||
with preserved(%left), preserved(%right)
|
||||
emit "c.lt.d 0, %left, %right"
|
||||
emit "li %out, -1"
|
||||
emit "bc1t 0, 1f"
|
||||
emit "nop"
|
||||
emit "c.lt.d 0, %right, %left"
|
||||
emit "li %out, 1"
|
||||
emit "movf %out, zero, 0"
|
||||
emit "1:"
|
||||
cost 28;
|
||||
|
||||
/* Booleans */
|
||||
|
||||
/* If 0 then 1, else 0 */
|
||||
out:(int)reg = IFEQ.I(in:(int)reg)
|
||||
emit "sltiu %out, %in, 1"
|
||||
cost 4;
|
||||
|
||||
/* If -1 then 1, else 0 */
|
||||
out:(int)reg = IFLT.I(in:(int)reg)
|
||||
emit "srl %out, %in, 31"
|
||||
cost 4;
|
||||
|
||||
/* If 1 or 0 then 1, else 0 */
|
||||
out:(int)reg = IFLE.I(in:(int)reg)
|
||||
emit "slti %out, %in, 1"
|
||||
cost 4;
|
||||
|
||||
|
||||
|
||||
/* Conversions */
|
||||
|
||||
#if 0
|
||||
out:(int)reg = CIU44(in:(int)reg)
|
||||
with %out == %in
|
||||
emit "! ciu44"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = CUI44(in:(int)reg)
|
||||
with %out == %in
|
||||
emit "! cui44"
|
||||
cost 4;
|
||||
#endif
|
||||
|
||||
/* ALU operations */
|
||||
|
||||
/* reg + reg */
|
||||
#define ALUR(name, instr) \
|
||||
out:(int)reg = name(left:(int)reg, right:(int)reg) \
|
||||
emit instr " %out, %left, %right" \
|
||||
cost 4; \
|
||||
|
||||
/* reg + const */
|
||||
#define ALUC(name, instr) \
|
||||
out:(int)reg = name(left:(int)reg, right:CONST.I) \
|
||||
when signed_constant(%right, 16) \
|
||||
emit instr " %out, %left, $right" \
|
||||
cost 4; \
|
||||
|
||||
/* const + reg */
|
||||
#define ALUC_reversed(name, instr) \
|
||||
out:(int)reg = name(left:CONST.I, right:(int)reg) \
|
||||
when signed_constant(%left, 16) \
|
||||
emit instr " %out, %right, $left" \
|
||||
cost 4; \
|
||||
|
||||
/* reg + const AND const + reg */
|
||||
#define ALUCC(name, instr) \
|
||||
ALUC(name, instr) \
|
||||
ALUC_reversed(name, instr)
|
||||
|
||||
ALUR(ADD.I, "addu")
|
||||
ALUCC(ADD.I, "addiu")
|
||||
|
||||
out:(int)reg = SUB.I(left:(int)reg, right:(int)reg)
|
||||
emit "subu %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = SUB.I(left:(int)reg, right:CONST.I)
|
||||
emit "addiu %out, %left, -[$right]"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = DIV.I(left:(int)reg, right:(int)reg)
|
||||
emit "div %left, %right"
|
||||
emit "mflo %out"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = DIVU.I(left:(int)reg, right:(int)reg)
|
||||
emit "divu %left, %right"
|
||||
emit "mflo %out"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = MOD.I(left:(int)reg, right:(int)reg)
|
||||
emit "div %left, %right"
|
||||
emit "mfhi %out"
|
||||
cost 8;
|
||||
|
||||
out:(int)reg = MODU.I(left:(int)reg, right:(int)reg)
|
||||
emit "divu %left, %right"
|
||||
emit "mfhi %out"
|
||||
cost 8;
|
||||
|
||||
ALUR(MUL.I, "mul")
|
||||
|
||||
ALUR(ASL.I, "sllv")
|
||||
ALUC(ASL.I, "sll")
|
||||
ALUR(ASR.I, "srav")
|
||||
ALUC(ASR.I, "sra")
|
||||
|
||||
ALUR(LSL.I, "sllv")
|
||||
ALUC(LSL.I, "sll")
|
||||
ALUR(LSR.I, "srlv")
|
||||
ALUC(LSR.I, "srl")
|
||||
|
||||
out:(int)reg = NEG.I(left:(int)reg)
|
||||
emit "subu %out, zero, %left"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = NOT.I(in:(int)reg)
|
||||
emit "nor %out, %in, %in"
|
||||
cost 4;
|
||||
|
||||
ALUR(AND.I, "and")
|
||||
ALUCC(AND.I, "andi")
|
||||
|
||||
ALUR(OR.I, "or")
|
||||
ALUCC(OR.I, "ori")
|
||||
|
||||
ALUR(EOR.I, "xor")
|
||||
ALUCC(EOR.I, "xori")
|
||||
|
||||
out:(int)reg = value:LABEL.I
|
||||
emit "lui %out, hi16[$value]"
|
||||
emit "ori %out, %out, lo16[$value]"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = value:BLOCK.I
|
||||
emit "lui %out, hi16[$value]"
|
||||
emit "ori %out, %out, lo16[$value]"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = value:CONST.I
|
||||
emit "li %out, $value"
|
||||
cost 4;
|
||||
|
||||
|
||||
|
||||
/* FPU operations */
|
||||
|
||||
/* Doubles */
|
||||
|
||||
out:(double)reg = ADDF.D(left:(double)reg, right:(double)reg)
|
||||
emit "add.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = SUBF.D(left:(double)reg, right:(double)reg)
|
||||
emit "sub.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = MULF.D(left:(double)reg, right:(double)reg)
|
||||
emit "mul.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = DIVF.D(left:(double)reg, right:(double)reg)
|
||||
emit "div.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = NEGF.D(left:(double)reg)
|
||||
emit "neg.d %out, %left"
|
||||
cost 4;
|
||||
|
||||
out:(double)reg = FROMSI.D(in:(int)reg)
|
||||
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
|
||||
emit "cvt.d.w %out, %out"
|
||||
cost 4;
|
||||
|
||||
out:(dret)reg = FROMUI.D(in:(iret)reg)
|
||||
emit "jal .c_ui_d"
|
||||
emit "nop"
|
||||
cost 30;
|
||||
|
||||
out:(int)reg = FROMSD.I(in:(double)reg)
|
||||
emit "trunc.w.d f30, %in"
|
||||
emit "mfc1 %out, f30"
|
||||
cost 8;
|
||||
|
||||
out:(lret)reg = FROMSD.L(in:(dret)reg)
|
||||
emit "jal .c_sd_l"
|
||||
emit "nop"
|
||||
cost 30;
|
||||
|
||||
out:(iret)reg = FROMUD.I(in:(dret)reg)
|
||||
with corrupted(dret)
|
||||
emit "jal .c_ud_i"
|
||||
emit "nop"
|
||||
cost 30;
|
||||
|
||||
out:(double)reg = COPYL.D(in:(long)reg)
|
||||
emit "mtc1 %in.0, %out" /* mtc1 has reversed parameters */
|
||||
emit "mthc1 %in.1, %out" /* mtc1 has reversed parameters */
|
||||
cost 8;
|
||||
|
||||
out:(long)reg = COPYD.L(in:(double)reg)
|
||||
emit "mfc1 %out.0, %in"
|
||||
emit "mfhc1 %out.1, %in"
|
||||
cost 8;
|
||||
|
||||
/* Floats */
|
||||
|
||||
out:(float)reg = ADDF.F(left:(float)reg, right:(float)reg)
|
||||
emit "add.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = SUBF.F(left:(float)reg, right:(float)reg)
|
||||
emit "sub.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = MULF.F(left:(float)reg, right:(float)reg)
|
||||
emit "mul.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = DIVF.F(left:(float)reg, right:(float)reg)
|
||||
emit "div.d %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = NEGF.F(left:(float)reg)
|
||||
emit "neg.s %out, %left"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = FROMSI.F(in:(int)reg)
|
||||
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
|
||||
emit "cvt.s.w %out, %out"
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = FROMSF.I(in:(float)reg)
|
||||
emit "trunc.w.s f30, %in"
|
||||
emit "mfc1 %out, f30"
|
||||
cost 8;
|
||||
|
||||
out:(lret)reg = FROMSF.L(in:(fret)reg)
|
||||
emit "jal .c_sf_l"
|
||||
emit "nop"
|
||||
cost 30;
|
||||
|
||||
out:(fret)reg = FROMUI.F(in:(iret)reg)
|
||||
emit "jal .c_ui_f"
|
||||
emit "nop"
|
||||
cost 30;
|
||||
|
||||
out:(iret)reg = FROMUF.I(in:(fret)reg)
|
||||
with corrupted(fret)
|
||||
emit "jal .c_uf_i"
|
||||
emit "nop"
|
||||
cost 30;
|
||||
|
||||
out:(float)reg = COPYI.F(in:(int)reg)
|
||||
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
|
||||
cost 4;
|
||||
|
||||
out:(int)reg = COPYF.I(in:(float)reg)
|
||||
emit "mfc1 %out, %in"
|
||||
cost 4;
|
||||
|
||||
out:(float)reg = value:CONST.F
|
||||
when specific_constant(%value, 0)
|
||||
emit "mtc1 zero, %out" /* mtc1 has reversed parameters */
|
||||
cost 4;
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
47
mach/mips/top/table
Normal file
47
mach/mips/top/table
Normal file
|
@ -0,0 +1,47 @@
|
|||
|
||||
/* MIPS table for ACK target optimizer */
|
||||
|
||||
MAXOP 5;
|
||||
LABEL_STARTER '.';
|
||||
|
||||
%%;
|
||||
|
||||
X, Y, Z { TRUE };
|
||||
R { TRUE };
|
||||
|
||||
%%;
|
||||
|
||||
/* Whitespace is significant here! */
|
||||
|
||||
addiu R, R, X : addiu R, R, Y { plus(X, Y, Z) } -> addiu R, R, Z ;
|
||||
|
||||
addiu X, X, 0 -> ;
|
||||
|
||||
b X : nop : labdef X -> labdef X ;
|
||||
|
||||
%%;
|
||||
|
||||
/* Does it fit a signed 16-bit integer? */
|
||||
static int fits16(long l) {
|
||||
return l >= -32768 && l <= 32767;
|
||||
}
|
||||
|
||||
/* Tries sum = a + b with signed 16-bit integers. */
|
||||
int plus(const char *a, const char *b, const char *sum)
|
||||
{
|
||||
long la, lb, lsum;
|
||||
char *end;
|
||||
|
||||
la = strtol(a, &end, 10);
|
||||
if (*a == '\0' || *end != '\0' || !fits16(la))
|
||||
return 0;
|
||||
lb = strtol(b, &end, 10);
|
||||
if (*b == '\0' || *end != '\0' || !fits16(lb))
|
||||
return 0;
|
||||
|
||||
lsum = la + lb;
|
||||
if (!fits16(lsum))
|
||||
return 0;
|
||||
snprintf(sum, 7, "%ld", lsum);
|
||||
return 1;
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
#define WORDS_REVERSED
|
||||
#define LISTING
|
||||
#define RELOCATION
|
||||
#define PDPFLOAT
|
||||
#undef ISALPHA
|
||||
#define ISALPHA(c) (isalpha(c) || c == '_' || c == '.' || c == '~')
|
||||
#undef ISALNUM
|
||||
|
|
|
@ -128,7 +128,7 @@ struct hop* platform_epilogue(void)
|
|||
return hop;
|
||||
}
|
||||
|
||||
struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest)
|
||||
struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest)
|
||||
{
|
||||
struct hop* hop = new_hop(bb, NULL);
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ include("first/yacc.lua")
|
|||
|
||||
definerule("build_as",
|
||||
{
|
||||
arch = { type="string" }
|
||||
arch = { type="string" },
|
||||
deps = { type="targets", default={} },
|
||||
},
|
||||
function(e)
|
||||
-- Remember this is executed from the caller's directory; local
|
||||
|
@ -25,6 +26,7 @@ definerule("build_as",
|
|||
"mach/proto/as/comm1.h",
|
||||
"h+emheaders",
|
||||
archlib,
|
||||
e.deps,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -42,8 +44,10 @@ definerule("build_as",
|
|||
deps = {
|
||||
"h+emheaders",
|
||||
"modules/src/object+lib",
|
||||
"modules/src/flt_arith+lib",
|
||||
archlib,
|
||||
yaccfiles
|
||||
yaccfiles,
|
||||
e.deps
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -22,6 +22,7 @@ _include <string.h>
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* ========== ON/OFF options (use #define in mach0.c) ========== */
|
||||
|
|
|
@ -153,6 +153,7 @@ void emit1(int);
|
|||
void emit2(int);
|
||||
void emit4(long);
|
||||
void emitx(valu_t, int);
|
||||
void emitf(int size, int negative);
|
||||
void emitstr(int);
|
||||
void ffreopen(char *, FILE *);
|
||||
FILE *ffcreat(char *);
|
||||
|
|
|
@ -43,9 +43,11 @@ static item_t *last_it, *o_it;
|
|||
%token NUMBER2
|
||||
%token NUMBER3
|
||||
%token <y_valu> NUMBER
|
||||
%token NUMBERF
|
||||
%token DOT
|
||||
%token EXTERN
|
||||
%token <y_word> DATA
|
||||
%token <y_word> DATAF
|
||||
%token <y_word> ASCII
|
||||
%token SECTION
|
||||
%token COMMON
|
||||
|
@ -58,14 +60,6 @@ static item_t *last_it, *o_it;
|
|||
%token <y_word> LINE
|
||||
%token FILe
|
||||
%token <y_word> LIST
|
||||
%token OP_EQ
|
||||
%token OP_NE
|
||||
%token OP_LE
|
||||
%token OP_GE
|
||||
%token OP_LL
|
||||
%token OP_RR
|
||||
%token OP_OO
|
||||
%token OP_AA
|
||||
|
||||
%left OP_OO
|
||||
%left OP_AA
|
||||
|
@ -257,6 +251,7 @@ operation
|
|||
DOTSCT->s_zero += $2;
|
||||
}
|
||||
| DATA datalist
|
||||
| DATAF dataflist
|
||||
| ASCII STRING
|
||||
{ emitstr($1);}
|
||||
;
|
||||
|
@ -284,6 +279,23 @@ datalist
|
|||
emitx($3.val, (int)$<y_word>0);
|
||||
}
|
||||
;
|
||||
|
||||
numberf
|
||||
: NUMBERF
|
||||
{
|
||||
emitf((int)$<y_word>-1, 0);
|
||||
}
|
||||
| '-' NUMBERF
|
||||
{
|
||||
emitf((int)$<y_word>-1, 1);
|
||||
}
|
||||
;
|
||||
|
||||
dataflist
|
||||
: numberf
|
||||
| dataflist ',' numberf
|
||||
;
|
||||
|
||||
expr : error
|
||||
{ serror("expr syntax err");
|
||||
$$.val = 0; $$.typ = S_UND;
|
||||
|
|
|
@ -29,6 +29,8 @@ item_t keytab[] = {
|
|||
0, DATA, RELO1, ".data1",
|
||||
0, DATA, RELO2, ".data2",
|
||||
0, DATA, RELO4, ".data4",
|
||||
0, DATAF, 4, ".dataf4",
|
||||
0, DATAF, 8, ".dataf8",
|
||||
0, ASCII, 0, ".ascii",
|
||||
0, ASCII, 1, ".asciz",
|
||||
0, ALIGN, 0, ".align",
|
||||
|
|
|
@ -5,26 +5,28 @@
|
|||
*/
|
||||
/* @(#)comm5.c 1.1 */
|
||||
|
||||
#include "comm0.h"
|
||||
#include "comm1.h"
|
||||
#include "y.tab.h"
|
||||
#include "comm0.h"
|
||||
#include "comm1.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
static void readcode(int);
|
||||
static int induo(int);
|
||||
static int inident(int);
|
||||
static int innumber(int);
|
||||
static int instring(int);
|
||||
static int inescape(void);
|
||||
static int infbsym(const char *);
|
||||
static void readcode(int);
|
||||
static int induo(int);
|
||||
static int inident(int);
|
||||
static int innumber(int);
|
||||
static int instring(int);
|
||||
static int inescape(void);
|
||||
static int infbsym(const char*);
|
||||
|
||||
int
|
||||
yylex(void)
|
||||
static int maxstring = 0;
|
||||
|
||||
int yylex(void)
|
||||
{
|
||||
int c, c0, c1;
|
||||
|
||||
if (pass == PASS_1) {
|
||||
if (pass == PASS_1)
|
||||
{
|
||||
/* scan the input file */
|
||||
do
|
||||
c = nextchar();
|
||||
|
@ -33,126 +35,150 @@ yylex(void)
|
|||
c = inident(c);
|
||||
else if (isdigit(c))
|
||||
c = innumber(c);
|
||||
else switch (c) {
|
||||
case '=':
|
||||
case '<':
|
||||
case '>':
|
||||
case '|':
|
||||
case '&':
|
||||
c = induo(c); break;
|
||||
case ASC_SQUO:
|
||||
case ASC_DQUO:
|
||||
c = instring(c); break;
|
||||
case ASC_COMM:
|
||||
do
|
||||
c = nextchar();
|
||||
while (c != '\n' && c != '\0');
|
||||
break;
|
||||
case CTRL('A'):
|
||||
c = CODE1; readcode(1); break;
|
||||
case CTRL('B'):
|
||||
c = CODE2; readcode(2); break;
|
||||
case CTRL('C'):
|
||||
c = CODE4; readcode(4); break;
|
||||
}
|
||||
else
|
||||
switch (c)
|
||||
{
|
||||
case '=':
|
||||
case '<':
|
||||
case '>':
|
||||
case '|':
|
||||
case '&':
|
||||
c = induo(c);
|
||||
break;
|
||||
case ASC_SQUO:
|
||||
case ASC_DQUO:
|
||||
c = instring(c);
|
||||
break;
|
||||
case ASC_COMM:
|
||||
do
|
||||
c = nextchar();
|
||||
while (c != '\n' && c != '\0');
|
||||
break;
|
||||
case CTRL('A'):
|
||||
c = CODE1;
|
||||
readcode(1);
|
||||
break;
|
||||
case CTRL('B'):
|
||||
c = CODE2;
|
||||
readcode(2);
|
||||
break;
|
||||
case CTRL('C'):
|
||||
c = CODE4;
|
||||
readcode(4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* produce the intermediate token file */
|
||||
if (c <= 0)
|
||||
return(0);
|
||||
if (c < 256) {
|
||||
return (0);
|
||||
if (c < 256)
|
||||
{
|
||||
putc(c, tempfile);
|
||||
putc(0, tempfile);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
putval(c);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* read from intermediate token file */
|
||||
c0 = getc(tempfile);
|
||||
if (c0 == EOF)
|
||||
return(0);
|
||||
return (0);
|
||||
c1 = getc(tempfile);
|
||||
if (c1 == EOF)
|
||||
return(0);
|
||||
return (0);
|
||||
|
||||
c = c0 + (c1 << 8);
|
||||
if (c >= 256)
|
||||
c = getval(c);
|
||||
}
|
||||
curr_token = c;
|
||||
return(c);
|
||||
return (c);
|
||||
}
|
||||
|
||||
void
|
||||
putval(int c)
|
||||
void putval(int c)
|
||||
{
|
||||
valu_t v;
|
||||
int n = 0;
|
||||
char *p = 0;
|
||||
char* p = 0;
|
||||
|
||||
assert(c == (c & 0xffff));
|
||||
switch (c) {
|
||||
case CODE1:
|
||||
n = 1; goto putnum;
|
||||
case CODE2:
|
||||
n = 2; goto putnum;
|
||||
case CODE4:
|
||||
n = 4; goto putnum;
|
||||
case NUMBER:
|
||||
v = yylval.y_valu;
|
||||
for (n = 0; n < sizeof(v); n++) {
|
||||
if (v == 0)
|
||||
break;
|
||||
v >>= 8;
|
||||
}
|
||||
assert(n <= 4);
|
||||
c = NUMBER0 + n;
|
||||
putnum:
|
||||
putc(c, tempfile);
|
||||
putc(c >> 8, tempfile);
|
||||
v = yylval.y_valu;
|
||||
while (--n >= 0)
|
||||
putc((int) (v >> (n*8)), tempfile);
|
||||
return;
|
||||
case IDENT:
|
||||
case FBSYM:
|
||||
n = sizeof(item_t *);
|
||||
p = (char *) &yylval.y_item; break;
|
||||
switch (c)
|
||||
{
|
||||
case CODE1:
|
||||
n = 1;
|
||||
goto putnum;
|
||||
case CODE2:
|
||||
n = 2;
|
||||
goto putnum;
|
||||
case CODE4:
|
||||
n = 4;
|
||||
goto putnum;
|
||||
case NUMBER:
|
||||
v = yylval.y_valu;
|
||||
for (n = 0; n < sizeof(v); n++)
|
||||
{
|
||||
if (v == 0)
|
||||
break;
|
||||
v >>= 8;
|
||||
}
|
||||
assert(n <= 4);
|
||||
c = NUMBER0 + n;
|
||||
putnum:
|
||||
putc(c, tempfile);
|
||||
putc(c >> 8, tempfile);
|
||||
v = yylval.y_valu;
|
||||
while (--n >= 0)
|
||||
putc((int)(v >> (n * 8)), tempfile);
|
||||
return;
|
||||
case IDENT:
|
||||
case FBSYM:
|
||||
n = sizeof(item_t*);
|
||||
p = (char*)&yylval.y_item;
|
||||
break;
|
||||
#ifdef ASLD
|
||||
case MODULE:
|
||||
n = sizeof(char *);
|
||||
p = (char *) &yylval.y_strp; break;
|
||||
case MODULE:
|
||||
n = sizeof(char*);
|
||||
p = (char*)&yylval.y_strp;
|
||||
break;
|
||||
#endif
|
||||
case STRING:
|
||||
v = stringlen;
|
||||
putc(c, tempfile);
|
||||
putc(c >> 8, tempfile);
|
||||
for (n = 0; n < sizeof(v); n++) {
|
||||
if (v == 0)
|
||||
break;
|
||||
v >>= 8;
|
||||
}
|
||||
assert(n <= 4);
|
||||
putc(n, tempfile);
|
||||
v = stringlen;
|
||||
while (--n >= 0)
|
||||
putc((int) (v >> (n*8)), tempfile);
|
||||
p = stringbuf;
|
||||
n = stringlen;
|
||||
while (--n >= 0)
|
||||
putc(*p++, tempfile);
|
||||
return;
|
||||
case OP_EQ:
|
||||
case OP_NE:
|
||||
case OP_LE:
|
||||
case OP_GE:
|
||||
case OP_LL:
|
||||
case OP_RR:
|
||||
case OP_OO:
|
||||
case OP_AA:
|
||||
break;
|
||||
default:
|
||||
n = sizeof(word_t);
|
||||
p = (char *) &yylval.y_word; break;
|
||||
case STRING:
|
||||
case NUMBERF:
|
||||
v = stringlen;
|
||||
putc(c, tempfile);
|
||||
putc(c >> 8, tempfile);
|
||||
for (n = 0; n < sizeof(v); n++)
|
||||
{
|
||||
if (v == 0)
|
||||
break;
|
||||
v >>= 8;
|
||||
}
|
||||
assert(n <= 4);
|
||||
putc(n, tempfile);
|
||||
v = stringlen;
|
||||
while (--n >= 0)
|
||||
putc((int)(v >> (n * 8)), tempfile);
|
||||
p = stringbuf;
|
||||
n = stringlen;
|
||||
while (--n >= 0)
|
||||
putc(*p++, tempfile);
|
||||
return;
|
||||
case OP_EQ:
|
||||
case OP_NE:
|
||||
case OP_LE:
|
||||
case OP_GE:
|
||||
case OP_LL:
|
||||
case OP_RR:
|
||||
case OP_OO:
|
||||
case OP_AA:
|
||||
break;
|
||||
default:
|
||||
n = sizeof(word_t);
|
||||
p = (char*)&yylval.y_word;
|
||||
break;
|
||||
}
|
||||
putc(c, tempfile);
|
||||
putc(c >> 8, tempfile);
|
||||
|
@ -160,151 +186,172 @@ putval(int c)
|
|||
putc(*p++, tempfile);
|
||||
}
|
||||
|
||||
int
|
||||
getval(int c)
|
||||
int getval(int c)
|
||||
{
|
||||
int n = 0;
|
||||
valu_t v;
|
||||
char *p = 0;
|
||||
char* p = 0;
|
||||
|
||||
switch (c) {
|
||||
case CODE1:
|
||||
n = 1; goto getnum;
|
||||
case CODE2:
|
||||
n = 2; goto getnum;
|
||||
case CODE4:
|
||||
n = 4; goto getnum;
|
||||
case NUMBER0:
|
||||
c = NUMBER; goto getnum;
|
||||
case NUMBER1:
|
||||
n = 1; c = NUMBER; goto getnum;
|
||||
case NUMBER2:
|
||||
n = 2; c = NUMBER; goto getnum;
|
||||
case NUMBER3:
|
||||
n = 3; c = NUMBER; goto getnum;
|
||||
case NUMBER:
|
||||
n = 4;
|
||||
getnum:
|
||||
v = 0;
|
||||
while (--n >= 0) {
|
||||
v <<= 8;
|
||||
v |= getc(tempfile);
|
||||
}
|
||||
yylval.y_valu = v;
|
||||
return(c);
|
||||
case IDENT:
|
||||
case FBSYM:
|
||||
n = sizeof(item_t *);
|
||||
p = (char *) &yylval.y_item; break;
|
||||
switch (c)
|
||||
{
|
||||
case CODE1:
|
||||
n = 1;
|
||||
goto getnum;
|
||||
case CODE2:
|
||||
n = 2;
|
||||
goto getnum;
|
||||
case CODE4:
|
||||
n = 4;
|
||||
goto getnum;
|
||||
case NUMBER0:
|
||||
c = NUMBER;
|
||||
goto getnum;
|
||||
case NUMBER1:
|
||||
n = 1;
|
||||
c = NUMBER;
|
||||
goto getnum;
|
||||
case NUMBER2:
|
||||
n = 2;
|
||||
c = NUMBER;
|
||||
goto getnum;
|
||||
case NUMBER3:
|
||||
n = 3;
|
||||
c = NUMBER;
|
||||
goto getnum;
|
||||
case NUMBER:
|
||||
n = 4;
|
||||
getnum:
|
||||
v = 0;
|
||||
while (--n >= 0)
|
||||
{
|
||||
v <<= 8;
|
||||
v |= getc(tempfile);
|
||||
}
|
||||
yylval.y_valu = v;
|
||||
return (c);
|
||||
case IDENT:
|
||||
case FBSYM:
|
||||
n = sizeof(item_t*);
|
||||
p = (char*)&yylval.y_item;
|
||||
break;
|
||||
#ifdef ASLD
|
||||
case MODULE:
|
||||
n = sizeof(char *);
|
||||
p = (char *) &yylval.y_strp; break;
|
||||
case MODULE:
|
||||
n = sizeof(char*);
|
||||
p = (char*)&yylval.y_strp;
|
||||
break;
|
||||
#endif
|
||||
case STRING:
|
||||
getval(getc(tempfile)+NUMBER0);
|
||||
stringlen = n = yylval.y_valu;
|
||||
p = stringbuf;
|
||||
p[n] = '\0'; break;
|
||||
case OP_EQ:
|
||||
case OP_NE:
|
||||
case OP_LE:
|
||||
case OP_GE:
|
||||
case OP_LL:
|
||||
case OP_RR:
|
||||
case OP_OO:
|
||||
case OP_AA:
|
||||
break;
|
||||
default:
|
||||
n = sizeof(word_t);
|
||||
p = (char *) &yylval.y_word; break;
|
||||
case STRING:
|
||||
case NUMBERF:
|
||||
getval(getc(tempfile) + NUMBER0);
|
||||
stringlen = n = yylval.y_valu;
|
||||
p = stringbuf;
|
||||
p[n] = '\0';
|
||||
break;
|
||||
case OP_EQ:
|
||||
case OP_NE:
|
||||
case OP_LE:
|
||||
case OP_GE:
|
||||
case OP_LL:
|
||||
case OP_RR:
|
||||
case OP_OO:
|
||||
case OP_AA:
|
||||
break;
|
||||
default:
|
||||
n = sizeof(word_t);
|
||||
p = (char*)&yylval.y_word;
|
||||
break;
|
||||
}
|
||||
while (--n >= 0)
|
||||
*p++ = getc(tempfile);
|
||||
return(c);
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* ---------- lexical scan in pass 1 ---------- */
|
||||
|
||||
int
|
||||
nextchar(void)
|
||||
int nextchar(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (peekc != -1) {
|
||||
if (peekc != -1)
|
||||
{
|
||||
c = peekc;
|
||||
peekc = -1;
|
||||
return(c);
|
||||
return (c);
|
||||
}
|
||||
#ifdef ASLD
|
||||
if (archmode && --archsize < 0)
|
||||
return(0);
|
||||
return (0);
|
||||
#endif
|
||||
if ((c = getc(input)) == EOF)
|
||||
return(0);
|
||||
return (0);
|
||||
if (isascii(c) == 0)
|
||||
fatal("non-ascii character");
|
||||
#ifdef LISTING
|
||||
if (listflag & 0440)
|
||||
putc(c, listfile);
|
||||
#endif
|
||||
return(c);
|
||||
return (c);
|
||||
}
|
||||
|
||||
static void
|
||||
readcode(int n)
|
||||
static void readcode(int n)
|
||||
{
|
||||
int c;
|
||||
|
||||
yylval.y_valu = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
if (
|
||||
#ifdef ASLD
|
||||
(archmode && --archsize < 0)
|
||||
||
|
||||
(archmode && --archsize < 0) ||
|
||||
#endif
|
||||
(c = getc(input)) == EOF
|
||||
)
|
||||
(c = getc(input)) == EOF)
|
||||
fatal("unexpected EOF in compact input");
|
||||
yylval.y_valu <<= 8;
|
||||
yylval.y_valu |= c;
|
||||
} while (--n);
|
||||
}
|
||||
|
||||
static int
|
||||
induo(int c)
|
||||
static int induo(int c)
|
||||
{
|
||||
static short duo[] = {
|
||||
('='<<8) | '=', OP_EQ,
|
||||
('<'<<8) | '>', OP_NE,
|
||||
('<'<<8) | '=', OP_LE,
|
||||
('>'<<8) | '=', OP_GE,
|
||||
('<'<<8) | '<', OP_LL,
|
||||
('>'<<8) | '>', OP_RR,
|
||||
('|'<<8) | '|', OP_OO,
|
||||
('&'<<8) | '&', OP_AA,
|
||||
0 /* terminates array */
|
||||
('=' << 8) | '=',
|
||||
OP_EQ,
|
||||
('<' << 8) | '>',
|
||||
OP_NE,
|
||||
('<' << 8) | '=',
|
||||
OP_LE,
|
||||
('>' << 8) | '=',
|
||||
OP_GE,
|
||||
('<' << 8) | '<',
|
||||
OP_LL,
|
||||
('>' << 8) | '>',
|
||||
OP_RR,
|
||||
('|' << 8) | '|',
|
||||
OP_OO,
|
||||
('&' << 8) | '&',
|
||||
OP_AA,
|
||||
0 /* terminates array */
|
||||
};
|
||||
short *p;
|
||||
short* p;
|
||||
|
||||
c = (c<<8) | nextchar();
|
||||
c = (c << 8) | nextchar();
|
||||
for (p = duo; *p; p++)
|
||||
if (*p++ == c)
|
||||
return(*p++);
|
||||
return (*p++);
|
||||
peekc = c & 0377;
|
||||
return(c>>8);
|
||||
return (c >> 8);
|
||||
}
|
||||
|
||||
static char name[NAMEMAX+1];
|
||||
static char name[NAMEMAX + 1];
|
||||
|
||||
static int
|
||||
inident(int c)
|
||||
static int inident(int c)
|
||||
{
|
||||
char *p = name;
|
||||
item_t *ip;
|
||||
char* p = name;
|
||||
item_t* ip;
|
||||
int n = NAMEMAX;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
if (--n >= 0)
|
||||
*p++ = c;
|
||||
c = nextchar();
|
||||
|
@ -312,76 +359,88 @@ inident(int c)
|
|||
*p = '\0';
|
||||
peekc = c;
|
||||
ip = item_search(name);
|
||||
if (ip == 0) {
|
||||
if (ip == 0)
|
||||
{
|
||||
ip = item_alloc(S_UND);
|
||||
ip->i_name = remember(name);
|
||||
/* printf("ident %s %o\n", ip->i_name, ip); */
|
||||
unresolved++;
|
||||
item_insert(ip, H_LOCAL + (hashindex%H_SIZE));
|
||||
} else if (hashindex < H_SIZE) {
|
||||
item_insert(ip, H_LOCAL + (hashindex % H_SIZE));
|
||||
}
|
||||
else if (hashindex < H_SIZE)
|
||||
{
|
||||
assert(H_KEY == 0);
|
||||
yylval.y_word = (word_t) ip->i_valu;
|
||||
return(ip->i_type);
|
||||
yylval.y_word = (word_t)ip->i_valu;
|
||||
return (ip->i_type);
|
||||
}
|
||||
yylval.y_item = ip;
|
||||
return(IDENT);
|
||||
return (IDENT);
|
||||
}
|
||||
|
||||
#ifdef ASLD
|
||||
char *
|
||||
readident(int c)
|
||||
char* readident(int c)
|
||||
{
|
||||
int n = NAMEMAX;
|
||||
char *p = name;
|
||||
char* p = name;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
if (--n >= 0)
|
||||
*p++ = c;
|
||||
c = nextchar();
|
||||
} while (ISALNUM(c));
|
||||
*p++ = '\0';
|
||||
peekc = c;
|
||||
return(name);
|
||||
return (name);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
innumber(int c)
|
||||
static int innumber(int c)
|
||||
{
|
||||
char *p;
|
||||
char* p;
|
||||
int radix;
|
||||
static char num[20+1];
|
||||
static char num[40 + 1];
|
||||
|
||||
p = num;
|
||||
radix = 20;
|
||||
do {
|
||||
radix = 40;
|
||||
if (c == '.')
|
||||
goto floatconstant;
|
||||
do
|
||||
{
|
||||
if (--radix < 0)
|
||||
fatal("number too long");
|
||||
if (isupper(c))
|
||||
c += ('a' - 'A');
|
||||
*p++ = c;
|
||||
c = nextchar();
|
||||
if (c == '.')
|
||||
goto floatconstant;
|
||||
} while (isalnum(c));
|
||||
peekc = c;
|
||||
*p = '\0';
|
||||
c = *--p;
|
||||
p = num;
|
||||
radix = 10;
|
||||
if (*p == '0') {
|
||||
if (*p == '0')
|
||||
{
|
||||
radix = 8;
|
||||
p++;
|
||||
if (*p == 'x') {
|
||||
if (*p == 'x')
|
||||
{
|
||||
radix = 16;
|
||||
p++;
|
||||
} else if (*p == 'b') {
|
||||
}
|
||||
else if (*p == 'b')
|
||||
{
|
||||
radix = 2;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (radix != 16 && (c == 'f' || c == 'b'))
|
||||
return(infbsym(num));
|
||||
return (infbsym(num));
|
||||
yylval.y_valu = 0;
|
||||
while (c = *p++) {
|
||||
while (c = *p++)
|
||||
{
|
||||
if (c > '9')
|
||||
c -= ('a' - '9' - 1);
|
||||
c -= '0';
|
||||
|
@ -389,26 +448,50 @@ innumber(int c)
|
|||
serror("digit exceeds radix");
|
||||
yylval.y_valu = yylval.y_valu * radix + c;
|
||||
}
|
||||
return(NUMBER);
|
||||
return (NUMBER);
|
||||
|
||||
floatconstant:
|
||||
do
|
||||
{
|
||||
if (--radix < 0)
|
||||
fatal("number too long");
|
||||
*p++ = c;
|
||||
c = nextchar();
|
||||
if (isupper(c))
|
||||
c = tolower(c);
|
||||
} while (isdigit(c) || (c == '.') || (c == 'e') || (c == '+') || (c == '-'));
|
||||
peekc = c;
|
||||
|
||||
*p = '\0';
|
||||
stringlen = p - num;
|
||||
if (stringlen > maxstring)
|
||||
{
|
||||
maxstring = stringlen;
|
||||
stringbuf = realloc(stringbuf, maxstring);
|
||||
}
|
||||
strcpy(stringbuf, num);
|
||||
return NUMBERF;
|
||||
}
|
||||
|
||||
static int
|
||||
instring(int termc)
|
||||
static int instring(int termc)
|
||||
{
|
||||
char *p;
|
||||
char* p;
|
||||
int c;
|
||||
static int maxstring = 0;
|
||||
|
||||
if (! maxstring) {
|
||||
if (!maxstring)
|
||||
{
|
||||
maxstring = STRINGMAX;
|
||||
if ((stringbuf = malloc(maxstring)) == 0) {
|
||||
if ((stringbuf = malloc(maxstring)) == 0)
|
||||
{
|
||||
fatal("out of memory");
|
||||
}
|
||||
}
|
||||
p = stringbuf;
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
c = nextchar();
|
||||
if (c == '\n' || c == '\0') {
|
||||
if (c == '\n' || c == '\0')
|
||||
{
|
||||
peekc = c;
|
||||
serror("non-terminated string");
|
||||
break;
|
||||
|
@ -417,10 +500,12 @@ instring(int termc)
|
|||
break;
|
||||
if (c == '\\')
|
||||
c = inescape();
|
||||
if (p >= &stringbuf[maxstring - 1]) {
|
||||
if (p >= &stringbuf[maxstring - 1])
|
||||
{
|
||||
int cnt = p - stringbuf;
|
||||
|
||||
if ((stringbuf = realloc(stringbuf, maxstring += 256)) == 0) {
|
||||
if ((stringbuf = realloc(stringbuf, maxstring += 256)) == 0)
|
||||
{
|
||||
fatal("out of memory");
|
||||
}
|
||||
p = stringbuf + cnt;
|
||||
|
@ -429,57 +514,69 @@ instring(int termc)
|
|||
}
|
||||
stringlen = p - stringbuf;
|
||||
*p = '\0';
|
||||
return(STRING);
|
||||
return (STRING);
|
||||
}
|
||||
|
||||
static int
|
||||
inescape(void)
|
||||
static int inescape(void)
|
||||
{
|
||||
int c, j, r;
|
||||
|
||||
c = nextchar();
|
||||
if (c >= '0' && c <= '7') {
|
||||
if (c >= '0' && c <= '7')
|
||||
{
|
||||
r = c - '0';
|
||||
for (j = 0; j < 2; j++) {
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
c = nextchar();
|
||||
if (c < '0' || c > '7') {
|
||||
if (c < '0' || c > '7')
|
||||
{
|
||||
peekc = c;
|
||||
return(r);
|
||||
return (r);
|
||||
}
|
||||
r <<= 3;
|
||||
r += (c - '0');
|
||||
}
|
||||
return(r);
|
||||
return (r);
|
||||
}
|
||||
switch (c) {
|
||||
case 'b': return('\b');
|
||||
case 'f': return('\f');
|
||||
case 'n': return('\n');
|
||||
case 'r': return('\r');
|
||||
case 't': return('\t');
|
||||
case '\'': return('\'');
|
||||
case '"': return('"');
|
||||
switch (c)
|
||||
{
|
||||
case 'b':
|
||||
return ('\b');
|
||||
case 'f':
|
||||
return ('\f');
|
||||
case 'n':
|
||||
return ('\n');
|
||||
case 'r':
|
||||
return ('\r');
|
||||
case 't':
|
||||
return ('\t');
|
||||
case '\'':
|
||||
return ('\'');
|
||||
case '"':
|
||||
return ('"');
|
||||
}
|
||||
return(c);
|
||||
return (c);
|
||||
}
|
||||
|
||||
static int
|
||||
infbsym(const char *p)
|
||||
static int infbsym(const char* p)
|
||||
{
|
||||
int lab;
|
||||
item_t *ip;
|
||||
item_t* ip;
|
||||
|
||||
lab = *p++ - '0';
|
||||
if ((unsigned)lab < 10) {
|
||||
if (*p++ == 'f') {
|
||||
ip = fb_ptr[FB_FORW+lab];
|
||||
if (ip == 0) {
|
||||
if ((unsigned)lab < 10)
|
||||
{
|
||||
if (*p++ == 'f')
|
||||
{
|
||||
ip = fb_ptr[FB_FORW + lab];
|
||||
if (ip == 0)
|
||||
{
|
||||
ip = fb_alloc(lab);
|
||||
fb_ptr[FB_FORW+lab] = ip;
|
||||
fb_ptr[FB_FORW + lab] = ip;
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
ip = fb_ptr[FB_BACK+lab];
|
||||
ip = fb_ptr[FB_BACK + lab];
|
||||
if (ip != 0 && *p == 0)
|
||||
goto ok;
|
||||
}
|
||||
|
@ -487,32 +584,33 @@ infbsym(const char *p)
|
|||
ip = fb_alloc(0);
|
||||
ok:
|
||||
yylval.y_item = ip;
|
||||
return(FBSYM);
|
||||
return (FBSYM);
|
||||
}
|
||||
|
||||
int
|
||||
hash(const char *p)
|
||||
int hash(const char* p)
|
||||
{
|
||||
unsigned short h;
|
||||
int c;
|
||||
|
||||
h = 0;
|
||||
while (c = *p++) {
|
||||
while (c = *p++)
|
||||
{
|
||||
h <<= 2;
|
||||
h += c;
|
||||
}
|
||||
return(h % H_SIZE);
|
||||
return (h % H_SIZE);
|
||||
}
|
||||
|
||||
item_t *
|
||||
item_search(const char *p)
|
||||
item_t* item_search(const char* p)
|
||||
{
|
||||
int h;
|
||||
item_t *ip;
|
||||
item_t* ip;
|
||||
|
||||
for (h = hash(p); h < H_TOTAL; h += H_SIZE) {
|
||||
for (h = hash(p); h < H_TOTAL; h += H_SIZE)
|
||||
{
|
||||
ip = hashtab[h];
|
||||
while (ip != 0) {
|
||||
while (ip != 0)
|
||||
{
|
||||
if (strcmp(p, ip->i_name) == 0)
|
||||
goto done;
|
||||
ip = ip->i_next;
|
||||
|
@ -520,25 +618,24 @@ item_search(const char *p)
|
|||
}
|
||||
done:
|
||||
hashindex = h;
|
||||
return(ip);
|
||||
return (ip);
|
||||
}
|
||||
|
||||
void
|
||||
item_insert(item_t *ip, int h)
|
||||
void item_insert(item_t* ip, int h)
|
||||
{
|
||||
ip->i_next = hashtab[h];
|
||||
hashtab[h] = ip;
|
||||
}
|
||||
|
||||
item_t *
|
||||
item_alloc(int typ)
|
||||
item_t* item_alloc(int typ)
|
||||
{
|
||||
item_t *ip;
|
||||
item_t* ip;
|
||||
static int nleft = 0;
|
||||
static item_t *next;
|
||||
static item_t* next;
|
||||
|
||||
if (--nleft < 0) {
|
||||
next = (item_t *) malloc(MEMINCR);
|
||||
if (--nleft < 0)
|
||||
{
|
||||
next = (item_t*)malloc(MEMINCR);
|
||||
if (next == 0)
|
||||
fatal("out of memory");
|
||||
nleft += (MEMINCR / sizeof(item_t));
|
||||
|
@ -548,36 +645,34 @@ item_alloc(int typ)
|
|||
ip->i_type = typ;
|
||||
ip->i_name = 0;
|
||||
ip->i_valu = 0;
|
||||
return(ip);
|
||||
return (ip);
|
||||
}
|
||||
|
||||
item_t *
|
||||
fb_alloc(int lab)
|
||||
item_t* fb_alloc(int lab)
|
||||
{
|
||||
item_t *ip, *p;
|
||||
|
||||
ip = item_alloc(S_UND);
|
||||
p = fb_ptr[FB_TAIL+lab];
|
||||
p = fb_ptr[FB_TAIL + lab];
|
||||
if (p == 0)
|
||||
fb_ptr[FB_HEAD+lab] = ip;
|
||||
fb_ptr[FB_HEAD + lab] = ip;
|
||||
else
|
||||
p->i_next = ip;
|
||||
fb_ptr[FB_TAIL+lab] = ip;
|
||||
return(ip);
|
||||
fb_ptr[FB_TAIL + lab] = ip;
|
||||
return (ip);
|
||||
}
|
||||
|
||||
item_t *
|
||||
fb_shift(int lab)
|
||||
item_t* fb_shift(int lab)
|
||||
{
|
||||
item_t *ip;
|
||||
item_t* ip;
|
||||
|
||||
ip = fb_ptr[FB_FORW+lab];
|
||||
ip = fb_ptr[FB_FORW + lab];
|
||||
if (ip == 0)
|
||||
if (pass == PASS_1)
|
||||
ip = fb_alloc(lab);
|
||||
else
|
||||
ip = fb_ptr[FB_HEAD+lab];
|
||||
fb_ptr[FB_BACK+lab] = ip;
|
||||
fb_ptr[FB_FORW+lab] = ip->i_next;
|
||||
return(ip);
|
||||
ip = fb_ptr[FB_HEAD + lab];
|
||||
fb_ptr[FB_BACK + lab] = ip;
|
||||
fb_ptr[FB_FORW + lab] = ip->i_next;
|
||||
return (ip);
|
||||
}
|
||||
|
|
|
@ -8,37 +8,37 @@
|
|||
* miscellaneous
|
||||
*/
|
||||
|
||||
#include "comm0.h"
|
||||
#include "comm1.h"
|
||||
#include "y.tab.h"
|
||||
#include <stdarg.h>
|
||||
#include <object.h>
|
||||
#include "comm0.h"
|
||||
#include "comm1.h"
|
||||
#include "y.tab.h"
|
||||
#include <stdarg.h>
|
||||
#include <object.h>
|
||||
|
||||
valu_t
|
||||
load(const item_t *ip)
|
||||
valu_t load(const item_t* ip)
|
||||
{
|
||||
#ifdef ASLD
|
||||
int typ;
|
||||
|
||||
typ = ip->i_type & S_TYP;
|
||||
if ((typ -= S_MIN) < 0) /* S_UND or S_ABS */
|
||||
return(ip->i_valu);
|
||||
return(ip->i_valu + sect[typ].s_base);
|
||||
if ((typ -= S_MIN) < 0) /* S_UND or S_ABS */
|
||||
return (ip->i_valu);
|
||||
return (ip->i_valu + sect[typ].s_base);
|
||||
#else
|
||||
if ((ip->i_type & S_TYP) == S_UND || (ip->i_type & S_COM)) {
|
||||
if (pass == PASS_3) {
|
||||
if ((ip->i_type & S_TYP) == S_UND || (ip->i_type & S_COM))
|
||||
{
|
||||
if (pass == PASS_3)
|
||||
{
|
||||
if (relonami != 0)
|
||||
serror("relocation error (relonami=%d, type=%08x)", relonami, ip->i_type);
|
||||
relonami = ip->i_valu+1;
|
||||
relonami = ip->i_valu + 1;
|
||||
}
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
return(ip->i_valu);
|
||||
return (ip->i_valu);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
store(item_t *ip, valu_t val)
|
||||
int store(item_t* ip, valu_t val)
|
||||
{
|
||||
#ifdef ASLD
|
||||
int typ;
|
||||
|
@ -48,27 +48,27 @@ store(item_t *ip, valu_t val)
|
|||
val -= sect[typ].s_base;
|
||||
#else
|
||||
if ((ip->i_type & S_TYP) == S_UND)
|
||||
return(0);
|
||||
return (0);
|
||||
#endif
|
||||
assert(pass != PASS_3 || (ip->i_type & S_VAR) || ip->i_valu == val);
|
||||
ip->i_valu = val;
|
||||
return(1);
|
||||
return (1);
|
||||
}
|
||||
|
||||
char *
|
||||
remember(char *s)
|
||||
char* remember(char* s)
|
||||
{
|
||||
char *p;
|
||||
char* p;
|
||||
int n;
|
||||
static int nleft = 0;
|
||||
static char *next;
|
||||
static char* next;
|
||||
|
||||
p = s;
|
||||
n = 0;
|
||||
do
|
||||
n++;
|
||||
while (*p++);
|
||||
if ((nleft -= n) < 0) {
|
||||
if ((nleft -= n) < 0)
|
||||
{
|
||||
next = malloc(MEMINCR);
|
||||
if (next == 0)
|
||||
fatal("out of memory");
|
||||
|
@ -80,84 +80,86 @@ remember(char *s)
|
|||
;
|
||||
s = next;
|
||||
next = p;
|
||||
return(s);
|
||||
return (s);
|
||||
}
|
||||
|
||||
int
|
||||
combine(int typ1, int typ2, int op)
|
||||
int combine(int typ1, int typ2, int op)
|
||||
{
|
||||
switch (op) {
|
||||
case '+':
|
||||
if (typ1 == S_ABS)
|
||||
return(typ2);
|
||||
if (typ2 == S_ABS)
|
||||
return(typ1);
|
||||
break;
|
||||
case '-':
|
||||
if (typ2 == S_ABS)
|
||||
return(typ1);
|
||||
if ((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND)
|
||||
return(S_ABS|S_VAR);
|
||||
break;
|
||||
case '>':
|
||||
if (typ1 == S_ABS && typ2 == S_ABS)
|
||||
return(S_ABS);
|
||||
if (
|
||||
((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND)
|
||||
|| (typ1 == S_ABS)
|
||||
|| (typ2 == S_ABS)
|
||||
)
|
||||
return(S_ABS|S_VAR);
|
||||
break;
|
||||
default:
|
||||
if (typ1 == S_ABS && typ2 == S_ABS)
|
||||
return(S_ABS);
|
||||
break;
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
if (typ1 == S_ABS)
|
||||
return (typ2);
|
||||
if (typ2 == S_ABS)
|
||||
return (typ1);
|
||||
break;
|
||||
case '-':
|
||||
if (typ2 == S_ABS)
|
||||
return (typ1);
|
||||
if ((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND)
|
||||
return (S_ABS | S_VAR);
|
||||
break;
|
||||
case '>':
|
||||
if (typ1 == S_ABS && typ2 == S_ABS)
|
||||
return (S_ABS);
|
||||
if (((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND) || (typ1 == S_ABS)
|
||||
|| (typ2 == S_ABS))
|
||||
return (S_ABS | S_VAR);
|
||||
break;
|
||||
default:
|
||||
if (typ1 == S_ABS && typ2 == S_ABS)
|
||||
return (S_ABS);
|
||||
break;
|
||||
}
|
||||
if (pass != PASS_1)
|
||||
serror("illegal operator");
|
||||
return(S_UND);
|
||||
return (S_UND);
|
||||
}
|
||||
|
||||
#ifdef LISTING
|
||||
int
|
||||
printx(int ndig, valu_t val)
|
||||
int printx(int ndig, valu_t val)
|
||||
{
|
||||
static char buf[8];
|
||||
char *p;
|
||||
char* p;
|
||||
int c, n;
|
||||
|
||||
p = buf; n = ndig;
|
||||
do {
|
||||
*p++ = (int) val & 017;
|
||||
p = buf;
|
||||
n = ndig;
|
||||
do
|
||||
{
|
||||
*p++ = (int)val & 017;
|
||||
val >>= 4;
|
||||
} while (--n);
|
||||
do {
|
||||
do
|
||||
{
|
||||
c = "0123456789ABCDEF"[*--p];
|
||||
putchar(c);
|
||||
} while (p > buf);
|
||||
return(ndig);
|
||||
return (ndig);
|
||||
}
|
||||
|
||||
void
|
||||
listline(int textline)
|
||||
void listline(int textline)
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((listflag & 4) && (c = getc(listfile)) != '\n' && textline) {
|
||||
if ((listflag & 4) && (c = getc(listfile)) != '\n' && textline)
|
||||
{
|
||||
if (listcolm >= 24)
|
||||
printf(" \\\n\t\t\t");
|
||||
else
|
||||
do {
|
||||
do
|
||||
{
|
||||
putchar('\t');
|
||||
listcolm += 8;
|
||||
} while (listcolm < 24);
|
||||
do {
|
||||
do
|
||||
{
|
||||
assert(c != EOF);
|
||||
putchar(c);
|
||||
} while ((c = getc(listfile)) != '\n');
|
||||
}
|
||||
if (listflag & 7) {
|
||||
if (listflag & 7)
|
||||
{
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
}
|
||||
|
@ -170,35 +172,40 @@ listline(int textline)
|
|||
/* ---------- code optimization ---------- */
|
||||
|
||||
#ifdef THREE_PASS
|
||||
#define PBITTABSZ 128
|
||||
static char *pbittab[PBITTABSZ];
|
||||
#define PBITTABSZ 128
|
||||
static char* pbittab[PBITTABSZ];
|
||||
|
||||
int
|
||||
small(int fitsmall, int gain)
|
||||
int small(int fitsmall, int gain)
|
||||
{
|
||||
int bit;
|
||||
char *p;
|
||||
char* p;
|
||||
|
||||
if (DOTSCT == NULL)
|
||||
nosect();
|
||||
if (bflag)
|
||||
return(0);
|
||||
if (nbits == BITCHUNK) {
|
||||
return (0);
|
||||
if (nbits == BITCHUNK)
|
||||
{
|
||||
bitindex++;
|
||||
nbits = 0;
|
||||
if (bitindex == PBITTABSZ) {
|
||||
if (bitindex == PBITTABSZ)
|
||||
{
|
||||
static int w_given;
|
||||
if (pass == PASS_1 && ! w_given) {
|
||||
if (pass == PASS_1 && !w_given)
|
||||
{
|
||||
w_given = 1;
|
||||
warning("bit table overflow");
|
||||
}
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
if (pbittab[bitindex] == 0 && pass == PASS_1) {
|
||||
if ((pbittab[bitindex] = calloc(MEMINCR, 1)) == 0) {
|
||||
if (pbittab[bitindex] == 0 && pass == PASS_1)
|
||||
{
|
||||
if ((pbittab[bitindex] = calloc(MEMINCR, 1)) == 0)
|
||||
{
|
||||
static int w2_given;
|
||||
|
||||
if (!w2_given) {
|
||||
if (!w2_given)
|
||||
{
|
||||
w2_given = 1;
|
||||
warning("out of space for bit table");
|
||||
}
|
||||
|
@ -207,21 +214,23 @@ small(int fitsmall, int gain)
|
|||
if (pbittab[bitindex] == 0)
|
||||
return (0);
|
||||
}
|
||||
bit = 1 << (nbits&7);
|
||||
p = pbittab[bitindex]+(nbits>>3);
|
||||
bit = 1 << (nbits & 7);
|
||||
p = pbittab[bitindex] + (nbits >> 3);
|
||||
nbits++;
|
||||
switch (pass) {
|
||||
case PASS_1:
|
||||
return(0);
|
||||
case PASS_2:
|
||||
if (fitsmall) {
|
||||
DOTGAIN += gain;
|
||||
*p |= bit;
|
||||
}
|
||||
return(fitsmall);
|
||||
case PASS_3:
|
||||
assert(fitsmall || (*p & bit) == 0);
|
||||
return(*p & bit);
|
||||
switch (pass)
|
||||
{
|
||||
case PASS_1:
|
||||
return (0);
|
||||
case PASS_2:
|
||||
if (fitsmall)
|
||||
{
|
||||
DOTGAIN += gain;
|
||||
*p |= bit;
|
||||
}
|
||||
return (fitsmall);
|
||||
case PASS_3:
|
||||
assert(fitsmall || (*p & bit) == 0);
|
||||
return (*p & bit);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
@ -229,13 +238,14 @@ small(int fitsmall, int gain)
|
|||
|
||||
/* ---------- output ---------- */
|
||||
|
||||
void
|
||||
emit1(int arg)
|
||||
void emit1(int arg)
|
||||
{
|
||||
static int olddottyp = -1;
|
||||
#ifdef LISTING
|
||||
if (listeoln) {
|
||||
if (listflag & 1) {
|
||||
if (listeoln)
|
||||
{
|
||||
if (listflag & 1)
|
||||
{
|
||||
listcolm += printx(VALWIDTH, (valu_t)DOTVAL);
|
||||
listcolm++;
|
||||
putchar(' ');
|
||||
|
@ -243,81 +253,90 @@ emit1(int arg)
|
|||
listeoln = 0;
|
||||
}
|
||||
if (listflag & 2)
|
||||
listcolm += printx(2, (valu_t) arg);
|
||||
listcolm += printx(2, (valu_t)arg);
|
||||
#endif
|
||||
switch (pass) {
|
||||
case PASS_1:
|
||||
if (DOTSCT == NULL)
|
||||
nosect();
|
||||
/* no break */
|
||||
case PASS_2:
|
||||
DOTSCT->s_zero = 0;
|
||||
break;
|
||||
case PASS_3:
|
||||
if (DOTTYP != olddottyp) {
|
||||
wr_outsect(DOTTYP-S_MIN);
|
||||
olddottyp = DOTTYP;
|
||||
}
|
||||
while (DOTSCT->s_zero) {
|
||||
wr_putc(0);
|
||||
DOTSCT->s_zero--;
|
||||
}
|
||||
wr_putc(arg);
|
||||
break;
|
||||
switch (pass)
|
||||
{
|
||||
case PASS_1:
|
||||
if (DOTSCT == NULL)
|
||||
nosect();
|
||||
/* no break */
|
||||
case PASS_2:
|
||||
DOTSCT->s_zero = 0;
|
||||
break;
|
||||
case PASS_3:
|
||||
if (DOTTYP != olddottyp)
|
||||
{
|
||||
wr_outsect(DOTTYP - S_MIN);
|
||||
olddottyp = DOTTYP;
|
||||
}
|
||||
while (DOTSCT->s_zero)
|
||||
{
|
||||
wr_putc(0);
|
||||
DOTSCT->s_zero--;
|
||||
}
|
||||
wr_putc(arg);
|
||||
break;
|
||||
}
|
||||
DOTVAL++;
|
||||
}
|
||||
|
||||
void
|
||||
emit2(int arg)
|
||||
void emit2(int arg)
|
||||
{
|
||||
#ifdef BYTES_REVERSED
|
||||
emit1((arg>>8)); emit1(arg);
|
||||
emit1((arg >> 8));
|
||||
emit1(arg);
|
||||
#else
|
||||
emit1(arg); emit1((arg>>8));
|
||||
emit1(arg);
|
||||
emit1((arg >> 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
emit4(long arg)
|
||||
void emit4(long arg)
|
||||
{
|
||||
#ifdef WORDS_REVERSED
|
||||
emit2((int)(arg>>16)); emit2((int)(arg));
|
||||
emit2((int)(arg >> 16));
|
||||
emit2((int)(arg));
|
||||
#else
|
||||
emit2((int)(arg)); emit2((int)(arg>>16));
|
||||
emit2((int)(arg));
|
||||
emit2((int)(arg >> 16));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
emitx(valu_t val, int n)
|
||||
void emitx(valu_t val, int n)
|
||||
{
|
||||
switch (n) {
|
||||
case RELO1:
|
||||
emit1((int)val); break;
|
||||
case RELO2:
|
||||
switch (n)
|
||||
{
|
||||
case RELO1:
|
||||
emit1((int)val);
|
||||
break;
|
||||
case RELO2:
|
||||
#ifdef BYTES_REVERSED
|
||||
emit1(((int)val>>8)); emit1((int)val);
|
||||
emit1(((int)val >> 8));
|
||||
emit1((int)val);
|
||||
#else
|
||||
emit1((int)val); emit1(((int)val>>8));
|
||||
emit1((int)val);
|
||||
emit1(((int)val >> 8));
|
||||
#endif
|
||||
break;
|
||||
case RELO4:
|
||||
break;
|
||||
case RELO4:
|
||||
#ifdef WORDS_REVERSED
|
||||
emit2((int)(val>>16)); emit2((int)(val));
|
||||
emit2((int)(val >> 16));
|
||||
emit2((int)(val));
|
||||
#else
|
||||
emit2((int)(val)); emit2((int)(val>>16));
|
||||
emit2((int)(val));
|
||||
emit2((int)(val >> 16));
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
emitstr(int zero)
|
||||
void emitstr(int zero)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
char* p;
|
||||
|
||||
p = stringbuf;
|
||||
i = stringlen;
|
||||
|
@ -327,57 +346,92 @@ emitstr(int zero)
|
|||
emit1(0);
|
||||
}
|
||||
|
||||
#define CODE_EXPANDER
|
||||
|
||||
#if !defined IEEEFLOAT && !defined PDPFLOAT
|
||||
#define IEEEFLOAT
|
||||
#endif
|
||||
|
||||
#if defined WORDS_REVERSED
|
||||
#define FL_MSL_AT_LOW_ADDRESS 1
|
||||
#define FL_MSW_AT_LOW_ADDRESS 1
|
||||
#else
|
||||
#define FL_MSL_AT_LOW_ADDRESS 0
|
||||
#define FL_MSW_AT_LOW_ADDRESS 0
|
||||
#endif
|
||||
|
||||
#if defined BYTES_REVERSED
|
||||
#define FL_MSB_AT_LOW_ADDRESS 1
|
||||
#else
|
||||
#define FL_MSB_AT_LOW_ADDRESS 0
|
||||
#endif
|
||||
|
||||
#define gen1 emit1
|
||||
#include <con_float>
|
||||
|
||||
void emitf(int size, int negative)
|
||||
{
|
||||
char buffer[40];
|
||||
|
||||
if (stringlen > sizeof(buffer)-1)
|
||||
fatal("floating point constant too long");
|
||||
|
||||
if (negative)
|
||||
{
|
||||
buffer[0] = '-';
|
||||
strcpy(buffer+1, stringbuf);
|
||||
con_float(buffer, size);
|
||||
}
|
||||
else
|
||||
con_float(stringbuf, size);
|
||||
}
|
||||
|
||||
/* ---------- Error checked file I/O ---------- */
|
||||
|
||||
void
|
||||
ffreopen(char *s, FILE *f)
|
||||
void ffreopen(char* s, FILE* f)
|
||||
{
|
||||
if (freopen(s, "r", f) == NULL)
|
||||
fatal("can't reopen %s", s);
|
||||
}
|
||||
|
||||
FILE *
|
||||
ffcreat(char *s)
|
||||
FILE* ffcreat(char* s)
|
||||
{
|
||||
FILE *f;
|
||||
FILE* f;
|
||||
|
||||
if ((f = fopen(s, "w")) == NULL)
|
||||
fatal("can't create %s", s);
|
||||
return(f);
|
||||
return (f);
|
||||
}
|
||||
|
||||
#ifndef TMPDIR
|
||||
#define TMPDIR "/tmp"
|
||||
#endif
|
||||
char *tmp_dir = TMPDIR;
|
||||
char* tmp_dir = TMPDIR;
|
||||
|
||||
FILE *
|
||||
fftemp(char *path, char *tail)
|
||||
FILE* fftemp(char* path, char* tail)
|
||||
{
|
||||
char *dir;
|
||||
char* dir;
|
||||
|
||||
if ((dir = getenv("TMPDIR")) == NULL)
|
||||
dir = tmp_dir;
|
||||
sprintf(path, "%s/%s", dir, tail);
|
||||
close(mkstemp(path));
|
||||
return(ffcreat(path));
|
||||
return (ffcreat(path));
|
||||
}
|
||||
|
||||
/* ---------- Error handling ---------- */
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
yyerror(const char *message)
|
||||
{} /* we will do our own error printing */
|
||||
void yyerror(const char* message)
|
||||
{
|
||||
} /* we will do our own error printing */
|
||||
|
||||
void
|
||||
nosect(void)
|
||||
void nosect(void)
|
||||
{
|
||||
fatal("no sections");
|
||||
}
|
||||
|
||||
void
|
||||
wr_fatal(void)
|
||||
void wr_fatal(void)
|
||||
{
|
||||
fatal("write error");
|
||||
}
|
||||
|
@ -432,8 +486,7 @@ void warning(const char* s, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
nofit(void)
|
||||
void nofit(void)
|
||||
{
|
||||
if (pass == PASS_3)
|
||||
warning("too big");
|
||||
|
|
|
@ -85,6 +85,7 @@ int regallowed=0;
|
|||
extern char em_flag[];
|
||||
extern short em_ptyp[];
|
||||
extern double atof();
|
||||
extern void con_float(void);
|
||||
|
||||
/* Own version of atol that continues computing on overflow.
|
||||
We don't know that about the ANSI C one.
|
||||
|
|
|
@ -35,7 +35,6 @@ definerule("build_mcg",
|
|||
"modules/src/data+lib",
|
||||
"modules/src/em_code+lib_k",
|
||||
"modules/src/em_data+lib",
|
||||
"modules/src/flt_arith+lib",
|
||||
"modules/src/idf+lib",
|
||||
"modules/src/object+lib",
|
||||
"modules/src/read_em+lib_kv",
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
#include "mcg.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define IEEEFLOAT
|
||||
#define FL_MSL_AT_LOW_ADDRESS 1
|
||||
#define FL_MSW_AT_LOW_ADDRESS 1
|
||||
#define FL_MSB_AT_LOW_ADDRESS 1
|
||||
|
||||
#include "con_float"
|
||||
|
||||
static struct symbol* pending;
|
||||
|
||||
void data_label(const char* label)
|
||||
|
@ -66,7 +59,7 @@ void data_int(arith data, size_t size, bool is_ro)
|
|||
{
|
||||
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
|
||||
assert((size == 1) || (size == 2) || (size == 4) || (size == 8));
|
||||
fprintf(outputfile, "\t.data%d ", size);
|
||||
fprintf(outputfile, "\t.data%ld ", size);
|
||||
writehex(data, size);
|
||||
fprintf(outputfile, "\n");
|
||||
}
|
||||
|
@ -80,19 +73,7 @@ void data_float(const char* data, size_t size, bool is_ro)
|
|||
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
|
||||
assert((size == 4) || (size == 8));
|
||||
|
||||
i = float_cst(data, size, (char*) buffer);
|
||||
if ((i != 0) && (i != 2)) /* 2 == overflow */
|
||||
fatal("cannot parse floating point constant %s sz %d", data, size);
|
||||
|
||||
fprintf(outputfile, "\t!float %s sz %d\n", data, size);
|
||||
fprintf(outputfile, "\t.data1 ");
|
||||
writehex(buffer[0], 1);
|
||||
for (i=1; i<size; i++)
|
||||
{
|
||||
fprintf(outputfile, ", ");
|
||||
writehex(buffer[i], 1);
|
||||
}
|
||||
fprintf(outputfile, "\n");
|
||||
fprintf(outputfile, "\t.dataf%ld %s\n", size, data);
|
||||
}
|
||||
|
||||
static bool istext(c)
|
||||
|
@ -149,7 +130,7 @@ void data_block(const uint8_t* data, size_t size, bool is_ro)
|
|||
void data_offset(const char* label, arith offset, bool is_ro)
|
||||
{
|
||||
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
|
||||
fprintf(outputfile, "\t.data%d %s+%lld\n",
|
||||
fprintf(outputfile, "\t.data%d %s+%ld\n",
|
||||
EM_pointersize, platform_label(label), offset);
|
||||
}
|
||||
|
||||
|
@ -159,7 +140,7 @@ void data_bss(arith size, int init)
|
|||
fatal("non-zero-initialised bss not supported");
|
||||
|
||||
emit_header(SECTION_BSS);
|
||||
fprintf(outputfile, "\t.space %lld\n", size);
|
||||
fprintf(outputfile, "\t.space %ld\n", size);
|
||||
}
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "flt_arith.h"
|
||||
#include "em_arith.h"
|
||||
#include "em_label.h"
|
||||
#include "em.h"
|
||||
|
@ -123,7 +122,7 @@ extern void pass_wire_up_return_values(void);
|
|||
extern void platform_calculate_offsets(void);
|
||||
extern struct hop* platform_prologue(void);
|
||||
extern struct hop* platform_epilogue(void);
|
||||
extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest);
|
||||
extern struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest);
|
||||
extern struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest);
|
||||
extern const char* platform_label(const char* label);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ extern void burm_panic_cannot_match(NODEPTR_TYPE node);
|
|||
extern bool burm_predicate_signed_constant(struct burm_node* node, arith size);
|
||||
extern bool burm_predicate_unsigned_constant(struct burm_node* node, arith size);
|
||||
extern bool burm_predicate_specific_constant(struct burm_node* node, arith value);
|
||||
extern bool burm_predicate_constant_within_inclusive_range(struct burm_node* node, arith min, arith max);
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
||||
|
|
|
@ -181,6 +181,36 @@ static void queue_ilabel(arith label)
|
|||
change_basicblock(bb_get(ilabel_to_str(label)));
|
||||
}
|
||||
|
||||
/* This is really hacky; to handle basic block flow
|
||||
* descriptor blocks, we need to be able to identify
|
||||
* them, read them and parse them. So we create
|
||||
* can exit to. So we create fake bb objects for each
|
||||
* block, purely to track this, and copy ints and labels
|
||||
* into them.
|
||||
*/
|
||||
|
||||
static void data_block_int(arith value)
|
||||
{
|
||||
if (data_bb)
|
||||
{
|
||||
struct em* em = new_insn(op_loc);
|
||||
em->paramtype = PARAM_IVALUE;
|
||||
em->u.ivalue = value;
|
||||
array_append(&data_bb->ems, em);
|
||||
}
|
||||
}
|
||||
|
||||
static void data_block_label(const char* label)
|
||||
{
|
||||
if (data_bb)
|
||||
{
|
||||
struct em* em = new_insn(op_bra);
|
||||
em->paramtype = PARAM_BVALUE;
|
||||
em->u.bvalue.left = bb_get(label);
|
||||
array_append(&data_bb->ems, em);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_pseu(void)
|
||||
{
|
||||
switch (em.em_opcode)
|
||||
|
@ -227,6 +257,7 @@ static void parse_pseu(void)
|
|||
{
|
||||
arith val = atol(em.em_string);
|
||||
data_int(val, em.em_size, ro);
|
||||
data_block_int(val);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -237,12 +268,16 @@ static void parse_pseu(void)
|
|||
}
|
||||
|
||||
case str_ptyp:
|
||||
data_block(strdup(em.em_string), em.em_size, ro);
|
||||
data_block((const uint8_t*) strdup(em.em_string), em.em_size, ro);
|
||||
break;
|
||||
|
||||
case cst_ptyp:
|
||||
data_int(em.em_cst, EM_wordsize, ro);
|
||||
{
|
||||
arith value = em.em_cst;
|
||||
data_int(value, EM_wordsize, ro);
|
||||
data_block_int(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case nof_ptyp:
|
||||
data_offset(dlabel_to_str(em.em_dlb), em.em_off, ro);
|
||||
|
@ -256,22 +291,8 @@ static void parse_pseu(void)
|
|||
case ilb_ptyp:
|
||||
{
|
||||
const char* label = ilabel_to_str(em.em_ilb);
|
||||
|
||||
/* This is really hacky; to handle basic block flow
|
||||
* descriptor blocks, we need to track which bbs a descriptor
|
||||
* can exit to. So we create fake bb objects for each
|
||||
* block, purely to track this.
|
||||
*/
|
||||
|
||||
if (data_bb)
|
||||
{
|
||||
struct em* em = new_insn(op_bra);
|
||||
em->paramtype = PARAM_BVALUE;
|
||||
em->u.bvalue.left = bb_get(label);
|
||||
array_append(&data_bb->ems, em);
|
||||
}
|
||||
|
||||
data_offset(label, 0, ro);
|
||||
data_block_label(label);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -384,9 +405,12 @@ static void create_data_label(const char* label)
|
|||
data_label(label);
|
||||
if (current_proc)
|
||||
{
|
||||
/* Create the fake bb used to track values inside this data block
|
||||
* (as it's a chance it's a jump table which we'll need to process
|
||||
* later).
|
||||
*/
|
||||
data_bb = bb_get(label);
|
||||
data_bb->is_fake = true;
|
||||
array_append(¤t_proc->blocks, data_bb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ static void make_phimap(void)
|
|||
for (i=0; i<cfg.preorder.count; i++)
|
||||
{
|
||||
struct basicblock* bb = cfg.preorder.item[i];
|
||||
|
||||
|
||||
/* Registers imported through a phi can come from multiple locations. */
|
||||
for (j=0; j<bb->phis.count; j++)
|
||||
{
|
||||
struct vreg* vreg = bb->phis.item[j].left;
|
||||
|
@ -36,8 +37,10 @@ static void recursively_associate_group(struct phicongruence* c, struct vreg* vr
|
|||
struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg);
|
||||
if (c->type == 0)
|
||||
c->type = vreg->type;
|
||||
|
||||
assert(c->type == vreg->type);
|
||||
|
||||
if (c->type != vreg->type)
|
||||
fatal("tried to add register %%%d of type 0x%x to a phi congruence group of type 0x%x",
|
||||
vreg->id, vreg->type, c->type);
|
||||
|
||||
array_appendu(&c->definitions, vreg->defined);
|
||||
}
|
||||
|
|
|
@ -386,16 +386,28 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s
|
|||
for (i=0; i<hregs.count; i++)
|
||||
{
|
||||
hreg = hregs.item[i];
|
||||
if ((hreg->attrs & srctype) &&
|
||||
if (!hreg->is_stacked && (hreg->attrs & srctype) &&
|
||||
allocatable_through(hreg, vreg))
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
/* No more registers --- allocate a stack slot. */
|
||||
/* No more registers --- allocate a stack slot. Ensure that we use the same stack
|
||||
* slot for this vreg throughout the function. */
|
||||
|
||||
hreg = new_stacked_hreg(srctype);
|
||||
hreg = vreg->evicted;
|
||||
if (!hreg)
|
||||
{
|
||||
if (vreg->congruence)
|
||||
hreg = vreg->evicted = vreg->congruence->evicted;
|
||||
if (!hreg)
|
||||
{
|
||||
hreg = vreg->evicted = new_stacked_hreg(srctype);
|
||||
if (vreg->congruence)
|
||||
vreg->congruence->evicted = hreg;
|
||||
}
|
||||
}
|
||||
array_append(&hregs, hreg);
|
||||
|
||||
found:
|
||||
|
@ -480,7 +492,7 @@ static void assign_hregs_to_vregs(void)
|
|||
{
|
||||
tracef('R', "R: import hreg %s for input %%%d from %s\n",
|
||||
hreg->id, vreg->id, prevbb->name);
|
||||
assert(!pmap_findleft(old, hreg));
|
||||
assert(!register_used(old, hreg));
|
||||
pmap_put(old, hreg, vreg);
|
||||
goto nextvreg;
|
||||
}
|
||||
|
@ -506,7 +518,7 @@ static void assign_hregs_to_vregs(void)
|
|||
|
||||
struct hreg* hreg = pmap_findright(
|
||||
phi->prev->regsout, phi->ir->result);
|
||||
if (hreg && !pmap_findleft(old, hreg))
|
||||
if (hreg && !register_used(old, hreg))
|
||||
{
|
||||
tracef('R', "R: import hreg %s for %%%d, imported from %s %%%d\n",
|
||||
hreg->id, vreg->id,
|
||||
|
@ -617,7 +629,8 @@ static int insert_moves(struct basicblock* bb, int index,
|
|||
{
|
||||
/* Copy. */
|
||||
|
||||
hop = platform_move(bb, src, dest);
|
||||
struct vreg* vreg = pmap_findleft(srcregs, src);
|
||||
hop = platform_move(bb, vreg, src, dest);
|
||||
pmap_remove(&copies, src, dest);
|
||||
}
|
||||
else
|
||||
|
@ -710,13 +723,17 @@ static void insert_phi_copies(void)
|
|||
|
||||
for (k=0; k<bb->regsin.count; k++)
|
||||
{
|
||||
struct hreg*hreg = bb->regsin.item[k].left;
|
||||
struct hreg* hreg = bb->regsin.item[k].left;
|
||||
struct vreg* vreg = bb->regsin.item[k].right;
|
||||
struct hreg* src = pmap_findright(prevbb->regsout, vreg);
|
||||
if (!pmap_findleft(&bb->phis, vreg))
|
||||
{
|
||||
tracef('R', "R: input map %%%d (%s) -> (%s)\n",
|
||||
vreg->id, src->id, hreg->id);
|
||||
if ((src->id != hreg->id) && src->is_stacked && hreg->is_stacked)
|
||||
fatal("vreg %%%d is stacked in %s on entry to %s, but is passed in in %s from %s",
|
||||
vreg->id, hreg->id, bb->name,
|
||||
src->id, prevbb->name);
|
||||
|
||||
pmap_add(&destregs, hreg, vreg);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,14 @@ bool burm_predicate_specific_constant(struct burm_node* node, arith val)
|
|||
return ir->u.ivalue == val;
|
||||
}
|
||||
|
||||
bool burm_predicate_constant_within_inclusive_range(struct burm_node* node, arith min, arith max)
|
||||
{
|
||||
struct ir* ir = node->ir;
|
||||
assert(ir->opcode == IR_CONST);
|
||||
|
||||
return (ir->u.ivalue >= min) && (ir->u.ivalue <= max);
|
||||
}
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,18 @@ static void print_blocks(char k)
|
|||
}
|
||||
}
|
||||
|
||||
static void print_vreg(char k, register_assignment_t* assignments, struct vreg* vreg)
|
||||
{
|
||||
struct hreg* hreg;
|
||||
tracef(k, "%%%d", vreg->id);
|
||||
if (assignments)
|
||||
{
|
||||
hreg = pmap_findright(assignments, vreg);
|
||||
if (hreg)
|
||||
tracef(k, "(%s)", hreg->id);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_hops(char k)
|
||||
{
|
||||
int i;
|
||||
|
@ -73,7 +85,10 @@ static void print_hops(char k)
|
|||
{
|
||||
tracef(k, "%c: INS:", k);
|
||||
for (j=0; j<bb->liveins.count; j++)
|
||||
tracef(k, " %%%d", bb->liveins.item[j]->id);
|
||||
{
|
||||
tracef(k, " ");
|
||||
print_vreg(k, &bb->regsin, bb->liveins.item[j]);
|
||||
}
|
||||
tracef(k, "\n");
|
||||
}
|
||||
|
||||
|
@ -81,7 +96,10 @@ static void print_hops(char k)
|
|||
{
|
||||
tracef(k, "%c: OUTS:", k);
|
||||
for (j=0; j<bb->liveouts.count; j++)
|
||||
tracef(k, " %%%d", bb->liveouts.item[j]->id);
|
||||
{
|
||||
tracef(k, " ");
|
||||
print_vreg(k, bb->regsout, bb->liveouts.item[j]);
|
||||
}
|
||||
tracef(k, "\n");
|
||||
}
|
||||
|
||||
|
@ -93,10 +111,10 @@ static void print_hops(char k)
|
|||
struct vreg* vreg = bb->phis.item[j].left;
|
||||
struct phi* phi = bb->phis.item[j].right;
|
||||
|
||||
tracef(k, " %%%d(via %s)=>%%%d",
|
||||
tracef(k, " %%%d(via %s)=>",
|
||||
phi->ir->result->id,
|
||||
phi->prev->name,
|
||||
vreg->id);
|
||||
phi->prev->name);
|
||||
print_vreg(k, &bb->regsin, vreg);
|
||||
}
|
||||
tracef(k, "\n");
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ struct phicongruence
|
|||
ARRAYOF(struct vreg) vregs;
|
||||
ARRAYOF(struct hop) definitions;
|
||||
uint32_t type;
|
||||
struct hreg* evicted; /* stack slot to evict to */
|
||||
};
|
||||
|
||||
struct hreg
|
||||
|
@ -28,6 +29,7 @@ struct vreg
|
|||
struct phicongruence* congruence;
|
||||
struct hop* defined;
|
||||
ARRAYOF(struct hop) used;
|
||||
struct hreg* evicted; /* stack slot to evict to */
|
||||
};
|
||||
|
||||
typedef PMAPOF(struct hreg, struct vreg) register_assignment_t;
|
||||
|
|
|
@ -5,10 +5,20 @@ static struct basicblock* current_bb;
|
|||
static int stackptr;
|
||||
static struct ir* stack[64];
|
||||
|
||||
struct jumptable
|
||||
{
|
||||
struct basicblock* defaulttarget;
|
||||
IMAPOF(struct basicblock) targets;
|
||||
};
|
||||
|
||||
static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode);
|
||||
static struct ir* appendir(struct ir* ir);
|
||||
static void insn_ivalue(int opcode, arith value);
|
||||
|
||||
static void parse_csa(struct basicblock* data_bb, struct jumptable* table);
|
||||
static void parse_csb(struct basicblock* data_bb, struct jumptable* table);
|
||||
static void emit_jumptable(struct ir* targetvalue, struct jumptable* table);
|
||||
|
||||
static void reset_stack(void)
|
||||
{
|
||||
stackptr = 0;
|
||||
|
@ -85,6 +95,8 @@ static struct ir* pop(int size)
|
|||
}
|
||||
else if ((size == EM_wordsize) && (ir->size == (EM_wordsize*2)))
|
||||
{
|
||||
appendir(ir);
|
||||
|
||||
/* Tried to read an int, but we got a long. */
|
||||
push(
|
||||
new_ir1(
|
||||
|
@ -553,6 +565,7 @@ static void insn_simple(int opcode)
|
|||
{
|
||||
struct ir* label = new_labelir(".trppc");
|
||||
struct ir* value = pop(EM_pointersize);
|
||||
appendir(label); /* because we need to use label twice */
|
||||
push(
|
||||
load(
|
||||
EM_pointersize,
|
||||
|
@ -717,6 +730,10 @@ static void rotate(int opcode, int size, int irop, int irop_reverse)
|
|||
struct ir* left = pop(size);
|
||||
struct ir* bits = new_wordir(8 * size);
|
||||
|
||||
/* Fix left and right so we can refer to them multiple times. */
|
||||
appendir(right);
|
||||
appendir(left);
|
||||
|
||||
/* a rol b -> (a << b) | (a >> (32 - b)) */
|
||||
push(
|
||||
new_ir2(
|
||||
|
@ -732,27 +749,6 @@ static void rotate(int opcode, int size, int irop, int irop_reverse)
|
|||
}
|
||||
}
|
||||
|
||||
static struct ir* extract_block_refs(struct basicblock* bb)
|
||||
{
|
||||
struct ir* outir = NULL;
|
||||
int i;
|
||||
|
||||
for (i=0; i<bb->ems.count; i++)
|
||||
{
|
||||
struct em* em = bb->ems.item[i];
|
||||
assert(em->opcode == op_bra);
|
||||
assert(em->paramtype == PARAM_BVALUE);
|
||||
|
||||
outir = new_ir2(
|
||||
IR_PAIR, 0,
|
||||
new_bbir(em->u.bvalue.left),
|
||||
outir
|
||||
);
|
||||
}
|
||||
|
||||
return outir;
|
||||
}
|
||||
|
||||
static void change_by(struct ir* address, int amount)
|
||||
{
|
||||
appendir(
|
||||
|
@ -1332,25 +1328,34 @@ static void insn_ivalue(int opcode, arith value)
|
|||
}
|
||||
|
||||
case op_csa:
|
||||
case op_csb:
|
||||
{
|
||||
const char* helper = aprintf(".%s",
|
||||
(opcode == op_csa) ? "csa" : "csb");
|
||||
struct ir* descriptor = pop(EM_pointersize);
|
||||
struct ir* targetvalue = appendir(pop(EM_pointersize));
|
||||
struct jumptable jumptable = {};
|
||||
int i;
|
||||
|
||||
if (descriptor->opcode != IR_LABEL)
|
||||
fatal("csa/csb are only supported if they refer "
|
||||
fatal("csa is only supported if it refers "
|
||||
"directly to a descriptor block");
|
||||
|
||||
push(descriptor);
|
||||
materialise_stack();
|
||||
appendir(
|
||||
new_ir2(
|
||||
IR_FARJUMP, 0,
|
||||
new_labelir(helper),
|
||||
extract_block_refs(bb_get(descriptor->u.lvalue))
|
||||
)
|
||||
);
|
||||
parse_csa(bb_get(descriptor->u.lvalue), &jumptable);
|
||||
emit_jumptable(targetvalue, &jumptable);
|
||||
break;
|
||||
}
|
||||
|
||||
case op_csb:
|
||||
{
|
||||
struct ir* descriptor = pop(EM_pointersize);
|
||||
struct ir* targetvalue = appendir(pop(EM_pointersize));
|
||||
struct jumptable jumptable = {};
|
||||
int i;
|
||||
|
||||
if (descriptor->opcode != IR_LABEL)
|
||||
fatal("csb is only supported if it refers "
|
||||
"directly to a descriptor block");
|
||||
|
||||
parse_csb(bb_get(descriptor->u.lvalue), &jumptable);
|
||||
emit_jumptable(targetvalue, &jumptable);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1755,4 +1760,133 @@ void tb_procedure(void)
|
|||
generate_tree(current_proc->blocks.item[i]);
|
||||
}
|
||||
|
||||
static void parse_csa(struct basicblock* data_bb, struct jumptable* table)
|
||||
{
|
||||
struct em* em;
|
||||
int lowerbound;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
assert(data_bb->ems.count >= 3);
|
||||
|
||||
/* Default target */
|
||||
|
||||
em = data_bb->ems.item[0];
|
||||
assert(em->opcode == op_bra);
|
||||
assert(em->paramtype == PARAM_BVALUE);
|
||||
table->defaulttarget = em->u.bvalue.left;
|
||||
|
||||
/* Lower bound */
|
||||
|
||||
em = data_bb->ems.item[1];
|
||||
assert(em->opcode == op_loc);
|
||||
assert(em->paramtype == PARAM_IVALUE);
|
||||
lowerbound = em->u.ivalue;
|
||||
|
||||
/* Count */
|
||||
|
||||
em = data_bb->ems.item[2];
|
||||
assert(em->opcode == op_loc);
|
||||
assert(em->paramtype == PARAM_IVALUE);
|
||||
count = em->u.ivalue + 1; /* value in descriptor is inclusive */
|
||||
assert(data_bb->ems.count >= (count + 3));
|
||||
|
||||
/* Now, each target in turn. */
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
struct basicblock* target;
|
||||
|
||||
em = data_bb->ems.item[3 + i];
|
||||
assert(em->opcode == op_bra);
|
||||
assert(em->paramtype == PARAM_BVALUE);
|
||||
target = em->u.bvalue.left;
|
||||
|
||||
imap_put(&table->targets, lowerbound+i, target);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_csb(struct basicblock* data_bb, struct jumptable* table)
|
||||
{
|
||||
struct em* em;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
assert(data_bb->ems.count >= 2);
|
||||
|
||||
/* Default target */
|
||||
|
||||
em = data_bb->ems.item[0];
|
||||
assert(em->opcode == op_bra);
|
||||
assert(em->paramtype == PARAM_BVALUE);
|
||||
table->defaulttarget = em->u.bvalue.left;
|
||||
|
||||
/* Number of targets */
|
||||
|
||||
em = data_bb->ems.item[1];
|
||||
assert(em->opcode == op_loc);
|
||||
assert(em->paramtype == PARAM_IVALUE);
|
||||
count = em->u.ivalue;
|
||||
assert(data_bb->ems.count >= (count*2 + 2));
|
||||
|
||||
/* Now, each target in turn. */
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
int value;
|
||||
struct basicblock* target;
|
||||
|
||||
em = data_bb->ems.item[2 + i*2];
|
||||
assert(em->opcode == op_loc);
|
||||
assert(em->paramtype == PARAM_IVALUE);
|
||||
value = em->u.ivalue;
|
||||
|
||||
em = data_bb->ems.item[3 + i*2];
|
||||
assert(em->opcode == op_bra);
|
||||
assert(em->paramtype == PARAM_BVALUE);
|
||||
target = em->u.bvalue.left;
|
||||
|
||||
imap_put(&table->targets, value, target);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_jumptable(struct ir* targetvalue, struct jumptable* jumptable)
|
||||
{
|
||||
int i;
|
||||
|
||||
materialise_stack();
|
||||
for (i=0; i<jumptable->targets.count; i++)
|
||||
{
|
||||
int value = jumptable->targets.item[i].left;
|
||||
struct basicblock* target = jumptable->targets.item[i].right;
|
||||
struct basicblock* nextblock = bb_get(NULL);
|
||||
|
||||
array_append(¤t_proc->blocks, nextblock);
|
||||
appendir(
|
||||
new_ir2(
|
||||
IR_CJUMPEQ, 0,
|
||||
new_ir2(
|
||||
IR_COMPARESI, EM_wordsize,
|
||||
targetvalue,
|
||||
new_wordir(value)
|
||||
),
|
||||
new_ir2(
|
||||
IR_PAIR, 0,
|
||||
new_bbir(target),
|
||||
new_bbir(nextblock)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
current_bb = nextblock;
|
||||
}
|
||||
|
||||
appendir(
|
||||
new_ir1(
|
||||
IR_JUMP, 0,
|
||||
new_bbir(jumptable->defaulttarget)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
|
@ -83,7 +83,7 @@ extern short em_ptyp[];
|
|||
/* machine dependent */
|
||||
void con_part(int, word);
|
||||
void con_mult(word);
|
||||
int con_float(void); /* actually returns void, but need K&R C compatibility */
|
||||
void con_float(void); /* actually returns void, but need K&R C compatibility */
|
||||
void prolog(full nlocals);
|
||||
void mes(word);
|
||||
|
||||
|
|
|
@ -206,6 +206,16 @@ This is not followed by automatic alignment.
|
|||
.Pu ".data4 \fIexpression [, expression]*\fP"
|
||||
Initialize a sequence of longs (4-byte values).
|
||||
This is not followed by automatic alignment.
|
||||
.Pu ".dataf4 \fIliteralfloat [, literalfloat]*\fP"
|
||||
Initialize a sequence of floats (4-byte values).
|
||||
The values must be literal floating point constants containing
|
||||
a dot character.
|
||||
This is not followed by automatic alignment.
|
||||
.Pu ".dataf8 \fIliteralfloat [, literalfloat]*\fP"
|
||||
Initialize a sequence of doubles (8-byte values).
|
||||
The values must be literal floating point constants containing
|
||||
a dot character.
|
||||
This is not followed by automatic alignment.
|
||||
.Pu ".ascii \fIstring\fP"
|
||||
Initialize a sequence of bytes with the value of the bytes in
|
||||
the string.
|
||||
|
|
37
plat/linuxmips/README
Normal file
37
plat/linuxmips/README
Normal file
|
@ -0,0 +1,37 @@
|
|||
The linuxmips platform
|
||||
======================
|
||||
|
||||
linuxmips is a little-endian MIPS32r2 BSP that produces Linux MIPS executables.
|
||||
|
||||
This port only implements a very limited number of system calls; basically,
|
||||
just enough to make the demo apps run. Adding more is easy, but there are some
|
||||
subtleties that require more thought. The port should be considered only in
|
||||
proof-of-concept stage right now.
|
||||
|
||||
Important note: you *can't* link access ELF shared libraries from these
|
||||
executables. In other words, you have to all your work from inside ACK.
|
||||
|
||||
IEEE floating point is available, but requires an FPU.
|
||||
|
||||
The executables are generated with aelfslod and are extremely simple; there's
|
||||
one rwx ELF section which contains all the application's code and data. This
|
||||
is not optimal, but it does work. Symbols are provided.
|
||||
|
||||
|
||||
Bugs
|
||||
====
|
||||
|
||||
isatty() is a stub and always returns 0.
|
||||
|
||||
|
||||
Example command line
|
||||
====================
|
||||
|
||||
ack -mlinuxmips -O -o linuxmips.exe examples/paranoia.c
|
||||
|
||||
The file linuxmips.exe can then be run on a MIPS32r2 Linux machine (or on an
|
||||
emulation thereof).
|
||||
|
||||
|
||||
David Given
|
||||
dg@cowlark.com
|
58
plat/linuxmips/boot.s
Normal file
58
plat/linuxmips/boot.s
Normal file
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
.define .entry
|
||||
.entry:
|
||||
! This code is placed at the beginning of the ELF executable and is the
|
||||
! first thing that runs.
|
||||
!
|
||||
! On entry, the stack looks like this:
|
||||
!
|
||||
! sp+... NULL
|
||||
! sp+8+(4*argc) env (X quads)
|
||||
! sp+4+(4*argc) NULL
|
||||
! sp+4 argv (argc quads)
|
||||
! sp argc
|
||||
!
|
||||
! The ACK actually expects:
|
||||
!
|
||||
! sp+8 argc
|
||||
! sp+4 ptr to argv
|
||||
! sp ptr to env
|
||||
|
||||
lw r4, 0(sp) ! r4 = argc
|
||||
addiu r5, sp, 4 ! r5 = argv
|
||||
sll r6, r4, 2 ! r6 = argc*4
|
||||
addu r6, r6, r5 ! r6 = null after last arg
|
||||
addiu r6, r6, 4 ! r6 = env
|
||||
|
||||
addiu sp, sp, -3 * 4
|
||||
sw r4, 0(sp) ! argc
|
||||
sw r5, 4(sp) ! argv
|
||||
sw r6, 8(sp) ! envp
|
||||
|
||||
j __m_a_i_n
|
||||
nop
|
||||
|
||||
! Define symbols at the beginning of our various segments, so that we can find
|
||||
! them. (Except .text, which has already been done.)
|
||||
|
||||
.sect .data; begdata:
|
||||
.sect .rom; begrom:
|
||||
.sect .bss; begbss:
|
||||
|
||||
! Some magic data. All EM systems need these.
|
||||
|
||||
.define _errno
|
||||
.comm _errno, 4 ! Posix errno storage
|
||||
|
||||
.define .trppc, .ignmask
|
||||
.comm .trppc, 4 ! ptr to user trap handler
|
||||
.comm .ignmask, 4 ! user trap ignore mask
|
25
plat/linuxmips/build-pkg.lua
Normal file
25
plat/linuxmips/build-pkg.lua
Normal file
|
@ -0,0 +1,25 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
ackfile {
|
||||
name = "boot",
|
||||
srcs = { "./boot.s" },
|
||||
vars = { plat = "linuxmips" }
|
||||
}
|
||||
|
||||
build_plat_libs {
|
||||
name = "libs",
|
||||
arch = "mips",
|
||||
plat = "linuxmips",
|
||||
}
|
||||
|
||||
installable {
|
||||
name = "pkg",
|
||||
map = {
|
||||
"+tools",
|
||||
"+libs",
|
||||
"./include+pkg",
|
||||
["$(PLATIND)/linuxmips/boot.o"] = "+boot",
|
||||
["$(PLATIND)/linuxmips/libsys.a"] = "./libsys+lib",
|
||||
}
|
||||
}
|
||||
|
29
plat/linuxmips/build-tools.lua
Normal file
29
plat/linuxmips/build-tools.lua
Normal file
|
@ -0,0 +1,29 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
build_as {
|
||||
name = "as",
|
||||
arch = "mips",
|
||||
deps = { "mach/mips/as+astables" }
|
||||
}
|
||||
|
||||
build_mcg {
|
||||
name = "mcg",
|
||||
arch = "mips",
|
||||
}
|
||||
|
||||
build_top {
|
||||
name = "top",
|
||||
arch = "mips",
|
||||
}
|
||||
|
||||
return installable {
|
||||
name = "tools",
|
||||
map = {
|
||||
["$(PLATDEP)/linuxmips/as"] = "+as",
|
||||
["$(PLATDEP)/linuxmips/mcg"] = "+mcg",
|
||||
["$(PLATDEP)/linuxmips/top"] = "+top",
|
||||
["$(PLATIND)/descr/linuxmips"] = "./descr",
|
||||
"util/amisc+aelflod-pkg",
|
||||
"util/opt+pkg",
|
||||
}
|
||||
}
|
87
plat/linuxmips/descr
Normal file
87
plat/linuxmips/descr
Normal file
|
@ -0,0 +1,87 @@
|
|||
# plat/linuxppc/descr
|
||||
|
||||
var w=4
|
||||
var wa=4
|
||||
var p={w}
|
||||
var pa={w}
|
||||
var s=2
|
||||
var sa={s}
|
||||
var l={w}
|
||||
var la={w}
|
||||
var f={w}
|
||||
var fa={w}
|
||||
var d=8
|
||||
var da={d}
|
||||
var x=8
|
||||
var xa={x}
|
||||
var ARCH=mips
|
||||
var PLATFORM=linuxmips
|
||||
var PLATFORMDIR={EM}/share/ack/{PLATFORM}
|
||||
var CPP_F=-D__unix
|
||||
var ALIGN=-a0:8 -a1:8 -a2:8 -a3:8 -b0:0x00400058
|
||||
var MACHOPT_F=-m2
|
||||
#var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr
|
||||
|
||||
# Override the setting in fe so that files compiled for linuxppc can see
|
||||
# the platform-specific headers.
|
||||
|
||||
var C_INCLUDES=-I{EM}/share/ack/linux/include -I{EM}/share/ack/include/ansi
|
||||
|
||||
name be
|
||||
from .m.g
|
||||
to .s
|
||||
program {EM}/lib/ack/{PLATFORM}/mcg
|
||||
mapflag -gdb GF=-gdb
|
||||
args {GF?} <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name asopt
|
||||
from .s
|
||||
to .so
|
||||
program {EM}/lib/ack/{PLATFORM}/top
|
||||
args
|
||||
optimizer
|
||||
stdin
|
||||
stdout
|
||||
end
|
||||
name as
|
||||
from .s.so
|
||||
to .o
|
||||
program {EM}/lib/ack/{PLATFORM}/as
|
||||
args - -o > <
|
||||
prep cond
|
||||
end
|
||||
name led
|
||||
from .o.a
|
||||
to .out
|
||||
program {EM}/lib/ack/em_led
|
||||
mapflag -l* LNAME={PLATFORMDIR}/lib*
|
||||
mapflag -fp FLOATS={EM}/{LIB}fp
|
||||
args {ALIGN} {SEPID?} \
|
||||
({RTS}:.b=-u _i_main) \
|
||||
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
|
||||
({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
|
||||
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
|
||||
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
|
||||
({RTS}:.p={PLATFORMDIR}/pascal.o) \
|
||||
-o > < \
|
||||
(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
|
||||
(.b:{TAIL}={PLATFORMDIR}/libb.a) \
|
||||
(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
|
||||
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
|
||||
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
|
||||
(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
|
||||
{FLOATS?} \
|
||||
(.e:{TAIL}={PLATFORMDIR}/libem.a \
|
||||
{PLATFORMDIR}/libsys.a \
|
||||
{PLATFORMDIR}/libend.a)
|
||||
linker
|
||||
end
|
||||
name cv
|
||||
from .out
|
||||
to .exe
|
||||
program {EM}/bin/aelflod
|
||||
args -m8 -l -f0x70001000 < >
|
||||
outfile linuxmips.exe
|
||||
end
|
4
plat/linuxmips/include/build.lua
Normal file
4
plat/linuxmips/include/build.lua
Normal file
|
@ -0,0 +1,4 @@
|
|||
installable {
|
||||
name = "pkg",
|
||||
map = { "plat/linux/include+pkg" }
|
||||
}
|
34
plat/linuxmips/libsys/_syscall.s
Normal file
34
plat/linuxmips/libsys/_syscall.s
Normal file
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
#define EINVAL 22
|
||||
|
||||
! Perform a Linux system call.
|
||||
|
||||
.define __syscall
|
||||
__syscall:
|
||||
lw r2, 0(sp) ! syscall number
|
||||
addiu r2, r2, 4000 ! MIPS uses non-standard numbers
|
||||
lw r4, 4(sp)
|
||||
lw r5, 8(sp)
|
||||
lw r6, 12(sp)
|
||||
syscall 0
|
||||
|
||||
beq r7, zero, exit ! branch on success
|
||||
nop
|
||||
|
||||
/* The result (in r2) is the errno. */
|
||||
lui at, ha16[_errno]
|
||||
sw r2, lo16[_errno] (at)
|
||||
li r2, -1
|
||||
exit:
|
||||
jr ra
|
||||
nop
|
||||
|
33
plat/linuxmips/libsys/build.lua
Normal file
33
plat/linuxmips/libsys/build.lua
Normal file
|
@ -0,0 +1,33 @@
|
|||
acklibrary {
|
||||
name = "lib",
|
||||
srcs = {
|
||||
"./_syscall.s",
|
||||
"plat/linux/libsys/_exit.c",
|
||||
"plat/linux/libsys/_hol0.s",
|
||||
"plat/linux/libsys/close.c",
|
||||
"plat/linux/libsys/creat.c",
|
||||
"plat/linux/libsys/execve.c",
|
||||
"plat/linux/libsys/getpid.c",
|
||||
"plat/linux/libsys/gettimeofday.c",
|
||||
"plat/linux/libsys/ioctl.c",
|
||||
"plat/linux/libsys/isatty.c",
|
||||
"plat/linux/libsys/kill.c",
|
||||
"plat/linux/libsys/lseek.c",
|
||||
"plat/linux/libsys/open.c",
|
||||
"plat/linux/libsys/read.c",
|
||||
"plat/linux/libsys/sbrk.c",
|
||||
"plat/linux/libsys/signal.c",
|
||||
"plat/linux/libsys/sigprocmask.c",
|
||||
"plat/linux/libsys/unlink.c",
|
||||
"plat/linux/libsys/write.c",
|
||||
},
|
||||
deps = {
|
||||
"plat/linux/libsys/*.h",
|
||||
"lang/cem/libcc.ansi/headers+headers",
|
||||
"plat/linuxmips/include+pkg",
|
||||
},
|
||||
vars = {
|
||||
plat = "linuxmips"
|
||||
}
|
||||
}
|
||||
|
8
plat/linuxmips/tests/build.lua
Normal file
8
plat/linuxmips/tests/build.lua
Normal file
|
@ -0,0 +1,8 @@
|
|||
include("tests/plat/build.lua")
|
||||
|
||||
plat_testsuite {
|
||||
name = "tests",
|
||||
plat = "linuxmips",
|
||||
method = "qemu-mipsel",
|
||||
-- skipsets = {"m2"},
|
||||
}
|
75
tests/plat/core/aar_e.e
Normal file
75
tests/plat/core/aar_e.e
Normal file
|
@ -0,0 +1,75 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
/*
|
||||
* Does basic testing of aar. Unfortunately, aar throws ERANGE on
|
||||
* error, which we can't catch (or at least, the platforms I've looked at
|
||||
* don't allow it to be caught, those platforms which actually throw it on
|
||||
* error). So we just test the non-throwing cases, not the negative ones.
|
||||
*/
|
||||
|
||||
array
|
||||
bss 3*EM_WSIZE, 0, 0
|
||||
|
||||
descriptor
|
||||
con -1 ; lower bound
|
||||
con 2 ; range, *inclusive*
|
||||
con EM_WSIZE ; size of element
|
||||
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* Access element -1 */
|
||||
|
||||
lae array
|
||||
loc -1
|
||||
lae descriptor
|
||||
aar EM_WSIZE
|
||||
|
||||
lae array
|
||||
cmu EM_WSIZE
|
||||
zeq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
1
|
||||
|
||||
/* Access element 0 */
|
||||
|
||||
lae array
|
||||
loc 0
|
||||
lae descriptor
|
||||
aar EM_WSIZE
|
||||
|
||||
lae array
|
||||
adp EM_WSIZE
|
||||
cmu EM_WSIZE
|
||||
zeq *2
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
2
|
||||
|
||||
/* Access element 1 */
|
||||
|
||||
lae array
|
||||
loc 1
|
||||
lae descriptor
|
||||
aar EM_WSIZE
|
||||
|
||||
lae array
|
||||
adp EM_WSIZE*2
|
||||
cmu EM_WSIZE
|
||||
zeq *3
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
3
|
||||
|
||||
cal $finished
|
||||
end
|
||||
|
54
tests/plat/core/and_e.e
Normal file
54
tests/plat/core/and_e.e
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* And word-sized set */
|
||||
|
||||
four
|
||||
rom EM_WSIZE
|
||||
|
||||
loc 32769
|
||||
loc 1
|
||||
loe four /* to defeat constant folding */
|
||||
and
|
||||
loc 1
|
||||
cmu EM_WSIZE
|
||||
zeq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
1
|
||||
|
||||
/* And triple-word-sized set */
|
||||
|
||||
four_by_three
|
||||
rom EM_WSIZE*3
|
||||
|
||||
loc 32769
|
||||
loc 32770
|
||||
loc 32772
|
||||
loc 1
|
||||
loc 2
|
||||
loc 4
|
||||
loe four_by_three
|
||||
and
|
||||
loc 4
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 2
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 1
|
||||
cmu EM_WSIZE
|
||||
zeq *3
|
||||
2
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
3
|
||||
|
||||
cal $finished
|
||||
end
|
75
tests/plat/core/cms_e.e
Normal file
75
tests/plat/core/cms_e.e
Normal file
|
@ -0,0 +1,75 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* Compare equal word sets. */
|
||||
|
||||
word
|
||||
rom EM_WSIZE
|
||||
|
||||
loc 1
|
||||
loc 1
|
||||
loe word /* to defeat constant folding */
|
||||
cms
|
||||
zeq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
1
|
||||
|
||||
/* Compare non-equal word sets. */
|
||||
|
||||
loc 1
|
||||
loc 2
|
||||
loe word /* to defeat constant folding */
|
||||
cms
|
||||
zne *2
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
2
|
||||
|
||||
/* Compare equal triple-word sets. */
|
||||
|
||||
loc 1
|
||||
loc 2
|
||||
loc 3
|
||||
loc 1
|
||||
loc 2
|
||||
loc 3
|
||||
loe word /* to defeat constant folding */
|
||||
loc 3
|
||||
mli EM_WSIZE
|
||||
cms
|
||||
zeq *3
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
3
|
||||
|
||||
/* Compare non-equal triple-word sets. */
|
||||
|
||||
loc 1
|
||||
loc 2
|
||||
loc 3
|
||||
loc 1
|
||||
loc 2
|
||||
loc 4
|
||||
loe word /* to defeat constant folding */
|
||||
loc 3
|
||||
mli EM_WSIZE
|
||||
cms
|
||||
zne *4
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
4
|
||||
|
||||
cal $finished
|
||||
end
|
54
tests/plat/core/ior_e.e
Normal file
54
tests/plat/core/ior_e.e
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* Or word-sized set */
|
||||
|
||||
four
|
||||
rom EM_WSIZE
|
||||
|
||||
loc 0
|
||||
loc 1
|
||||
loe four /* to defeat constant folding */
|
||||
ior
|
||||
loc 1
|
||||
cmu EM_WSIZE
|
||||
zeq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
1
|
||||
|
||||
/* Or triple-word-sized set */
|
||||
|
||||
four_by_three
|
||||
rom EM_WSIZE*3
|
||||
|
||||
loc 16
|
||||
loc 32
|
||||
loc 64
|
||||
loc 1
|
||||
loc 2
|
||||
loc 3
|
||||
loe four_by_three
|
||||
ior
|
||||
loc 67
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 34
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 17
|
||||
cmu EM_WSIZE
|
||||
zeq *3
|
||||
2
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
3
|
||||
|
||||
cal $finished
|
||||
end
|
73
tests/plat/core/lar_e.e
Normal file
73
tests/plat/core/lar_e.e
Normal file
|
@ -0,0 +1,73 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
/*
|
||||
* Does basic testing of lar. Unfortunately, lar throws ERANGE on
|
||||
* error, which we can't catch (or at least, the platforms I've looked at
|
||||
* don't allow it to be caught, those platforms which actually throw it on
|
||||
* error). So we just test the non-throwing cases, not the negative ones.
|
||||
*/
|
||||
|
||||
#define ARRAY_SIZE 3*EM_WSIZE
|
||||
|
||||
array
|
||||
con 1
|
||||
con 2
|
||||
con 3
|
||||
|
||||
descriptor
|
||||
con -1 ; lower bound
|
||||
con 2 ; range, *inclusive*
|
||||
con EM_WSIZE ; size of element
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* Read element -1 */
|
||||
|
||||
lae array
|
||||
loc -1
|
||||
lae descriptor
|
||||
lar EM_WSIZE
|
||||
|
||||
loc 1
|
||||
beq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
1
|
||||
|
||||
/* Read element 0 */
|
||||
|
||||
lae array
|
||||
loc 0
|
||||
lae descriptor
|
||||
lar EM_WSIZE
|
||||
|
||||
loc 2
|
||||
beq *2
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
2
|
||||
|
||||
/* Read element 1 */
|
||||
|
||||
lae array
|
||||
loc 1
|
||||
lae descriptor
|
||||
lar EM_WSIZE
|
||||
|
||||
loc 3
|
||||
beq *3
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
3
|
||||
|
||||
cal $finished
|
||||
end
|
||||
|
125
tests/plat/core/sar_e.e
Normal file
125
tests/plat/core/sar_e.e
Normal file
|
@ -0,0 +1,125 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
/*
|
||||
* Does basic testing of sar. Unfortunately, sar throws ERANGE on
|
||||
* error, which we can't catch (or at least, the platforms I've looked at
|
||||
* don't allow it to be caught, those platforms which actually throw it on
|
||||
* error). So we just test the non-throwing cases, not the negative ones.
|
||||
*/
|
||||
|
||||
#define ARRAY_SIZE 3*EM_WSIZE
|
||||
|
||||
array
|
||||
bss ARRAY_SIZE, 0, 0
|
||||
|
||||
descriptor
|
||||
con -1 ; lower bound
|
||||
con 2 ; range, *inclusive*
|
||||
con EM_WSIZE ; size of element
|
||||
|
||||
element0
|
||||
con 1
|
||||
con 0
|
||||
con 0
|
||||
|
||||
element1
|
||||
con 0
|
||||
con 1
|
||||
con 0
|
||||
|
||||
element2
|
||||
con 0
|
||||
con 0
|
||||
con 1
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* Write element -1 */
|
||||
|
||||
cal $clear_array
|
||||
loc 1
|
||||
lae array
|
||||
loc -1
|
||||
lae descriptor
|
||||
sar EM_WSIZE
|
||||
|
||||
lae array
|
||||
loi ARRAY_SIZE
|
||||
lae element0
|
||||
loi ARRAY_SIZE
|
||||
loc ARRAY_SIZE
|
||||
cms
|
||||
zeq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
1
|
||||
|
||||
/* Write element 0 */
|
||||
|
||||
cal $clear_array
|
||||
loc 1
|
||||
lae array
|
||||
loc 0
|
||||
lae descriptor
|
||||
sar EM_WSIZE
|
||||
|
||||
lae array
|
||||
loi ARRAY_SIZE
|
||||
lae element1
|
||||
loi ARRAY_SIZE
|
||||
loc ARRAY_SIZE
|
||||
cms
|
||||
zeq *2
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
2
|
||||
|
||||
/* Write element 1 */
|
||||
|
||||
cal $clear_array
|
||||
loc 1
|
||||
lae array
|
||||
loc 1
|
||||
lae descriptor
|
||||
sar EM_WSIZE
|
||||
|
||||
lae array
|
||||
loi ARRAY_SIZE
|
||||
lae element2
|
||||
loi ARRAY_SIZE
|
||||
loc ARRAY_SIZE
|
||||
cms
|
||||
zeq *3
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
ass EM_WSIZE
|
||||
3
|
||||
|
||||
cal $finished
|
||||
end
|
||||
|
||||
exp $clear_array
|
||||
pro $clear_array, 0
|
||||
|
||||
loc 0
|
||||
lae array + EM_WSIZE*0
|
||||
sti EM_WSIZE
|
||||
|
||||
loc 0
|
||||
lae array + EM_WSIZE*1
|
||||
sti EM_WSIZE
|
||||
|
||||
loc 0
|
||||
lae array + EM_WSIZE*2
|
||||
sti EM_WSIZE
|
||||
|
||||
ret 0
|
||||
end
|
||||
|
50
tests/plat/core/set_e.e
Normal file
50
tests/plat/core/set_e.e
Normal file
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* Create word-sized singleton set. */
|
||||
|
||||
word
|
||||
rom EM_WSIZE
|
||||
|
||||
loc 1
|
||||
loe word /* to defeat constant folding */
|
||||
set
|
||||
|
||||
loc 2
|
||||
cmu EM_WSIZE
|
||||
zeq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
1
|
||||
|
||||
/* Create triple-word-sized set with low bit */
|
||||
|
||||
loc EM_WSIZE*8 + 1
|
||||
loe word /* to defeat constant folding */
|
||||
loc 3
|
||||
mli EM_WSIZE
|
||||
set
|
||||
|
||||
|
||||
loc 0
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 2
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 0
|
||||
cmu EM_WSIZE
|
||||
zeq *3
|
||||
2
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
3
|
||||
|
||||
cal $finished
|
||||
end
|
54
tests/plat/core/xor_e.e
Normal file
54
tests/plat/core/xor_e.e
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
mes 2, EM_WSIZE, EM_PSIZE
|
||||
|
||||
exp $_m_a_i_n
|
||||
pro $_m_a_i_n, 0
|
||||
|
||||
/* Xor word-sized set */
|
||||
|
||||
four
|
||||
rom EM_WSIZE
|
||||
|
||||
loc 32769
|
||||
loc 1
|
||||
loe four /* to defeat constant folding */
|
||||
xor
|
||||
loc 32768
|
||||
cmu EM_WSIZE
|
||||
zeq *1
|
||||
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
1
|
||||
|
||||
/* Xor triple-word-sized set */
|
||||
|
||||
four_by_three
|
||||
rom EM_WSIZE*3
|
||||
|
||||
loc 32769
|
||||
loc 32770
|
||||
loc 32772
|
||||
loc 1
|
||||
loc 2
|
||||
loc 4
|
||||
loe four_by_three
|
||||
xor
|
||||
loc 32768
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 32768
|
||||
cmu EM_WSIZE
|
||||
zne *2
|
||||
loc 32768
|
||||
cmu EM_WSIZE
|
||||
zeq *3
|
||||
2
|
||||
loc __LINE__
|
||||
cal $fail
|
||||
asp 4
|
||||
3
|
||||
|
||||
cal $finished
|
||||
end
|
|
@ -6,7 +6,9 @@ double one = 1.0;
|
|||
double zero = 0.0;
|
||||
double minusone = -1.0;
|
||||
double big = (double)INT_MAX;
|
||||
double minusbig = (double)INT_MIN;
|
||||
/* We don't test INT_MIN because some platforms *cough*mips*cough* don't handle
|
||||
* it correctly, and we don't want to fail them. */
|
||||
double minusbig = (double)(INT_MIN+1);
|
||||
|
||||
/* Bypasses the CRT, so there's no stdio. */
|
||||
void _m_a_i_n(void)
|
||||
|
@ -15,7 +17,7 @@ void _m_a_i_n(void)
|
|||
ASSERT((int)one == 1);
|
||||
ASSERT((int)minusone == -1);
|
||||
ASSERT((int)big == INT_MAX);
|
||||
ASSERT((int)minusbig == INT_MIN);
|
||||
ASSERT((int)minusbig == (INT_MIN+1));
|
||||
|
||||
finished();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ void finished(void)
|
|||
_exit(0);
|
||||
}
|
||||
|
||||
void writehex(uint32_t code)
|
||||
void writehex(unsigned int code)
|
||||
{
|
||||
char buf[8];
|
||||
char* p = &buf[sizeof(buf)];
|
||||
|
@ -24,7 +24,7 @@ void writehex(uint32_t code)
|
|||
write(1, p, buf + sizeof(buf) - p);
|
||||
}
|
||||
|
||||
void fail(uint32_t code)
|
||||
void fail(unsigned int code)
|
||||
{
|
||||
static const char fail_msg[] = "@@FAIL 0x";
|
||||
static const char nl_msg[] = "\n";
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include <stdint.h>
|
||||
|
||||
extern void finished(void);
|
||||
extern void writehex(uint32_t code);
|
||||
extern void fail(uint32_t code);
|
||||
extern void writehex(unsigned int code);
|
||||
extern void fail(unsigned int code);
|
||||
|
||||
#define ASSERT(condition) \
|
||||
do { if (!(condition)) fail(__LINE__); } while(0)
|
||||
|
|
|
@ -35,6 +35,10 @@ The default value is \fI3\fP for Intel 386 (i386).
|
|||
Other values are \fI4\fP for Motorola 68000 (m68k)
|
||||
and \fI20\fP for PowerPC.
|
||||
.TP
|
||||
.BI \-f number
|
||||
Set the processor flags in the ELF header to \fInumber\fP.
|
||||
The default value is 0.
|
||||
.TP
|
||||
.B \-v
|
||||
Be verbose.
|
||||
.PP
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
int bigendian = 0;
|
||||
int elfabi = 3; /* abi = Linux */
|
||||
int elfmachine = 3; /* machine = EM_386 */
|
||||
uint32_t elfflags = 0; /* elf processor flags */
|
||||
|
||||
/* Header and section table of an ack object file. */
|
||||
|
||||
|
@ -643,7 +644,7 @@ int main(int argc, char* argv[])
|
|||
switch (argv[1][1])
|
||||
{
|
||||
case 'a':
|
||||
elfabi = atoi(&argv[1][2]);
|
||||
elfabi = strtoul(&argv[1][2], NULL, 0);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
|
@ -660,7 +661,11 @@ int main(int argc, char* argv[])
|
|||
break;
|
||||
|
||||
case 'm':
|
||||
elfmachine = atoi(&argv[1][2]);
|
||||
elfmachine = strtoul(&argv[1][2], NULL, 0);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
elfflags = strtoul(&argv[1][2], NULL, 0);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
|
@ -808,7 +813,7 @@ int main(int argc, char* argv[])
|
|||
emit32(outsect[TEXT].os_base); /* entry point */
|
||||
emit32(ELF_HEADER_SIZE); /* program header offset */
|
||||
emit32(sh_offset); /* section header offset */
|
||||
emit32(0); /* flags */
|
||||
emit32(elfflags); /* flags */
|
||||
emit16(ELF_HEADER_SIZE); /* elf header size */
|
||||
emit16(PROGRAM_HEADER_SIZE); /* program header entry size */
|
||||
emit16(1); /* number of program header entries */
|
||||
|
|
|
@ -134,6 +134,12 @@ showrelo()
|
|||
case RELO2:
|
||||
printf("\t2 bytes\n");
|
||||
break;
|
||||
case RELO2HI:
|
||||
printf("\ttop 2 bytes of result\n");
|
||||
break;
|
||||
case RELO2HISAD:
|
||||
printf("\ttop 2 bytes of result, sign adjusted\n");
|
||||
break;
|
||||
case RELO4:
|
||||
printf("\t4 bytes\n");
|
||||
break;
|
||||
|
@ -146,6 +152,9 @@ showrelo()
|
|||
case RELOVC4:
|
||||
printf("\tVideoCore IV address in 32-bit instruction\n");
|
||||
break;
|
||||
case RELOMIPS:
|
||||
printf("\tMIPS b or j instruction\n");
|
||||
break;
|
||||
default:
|
||||
printf("\tunknown relocation type %d\n", relrec.or_type & RELSZ);
|
||||
break;
|
||||
|
|
|
@ -579,7 +579,7 @@ addbase(name)
|
|||
return;
|
||||
|
||||
name->on_valu += outsect[sectindex].os_base;
|
||||
debug( "%s: type 0x%x, value %ld\n",
|
||||
debug( "%s: type 0x%x, value 0x%lx\n",
|
||||
address((name->on_type & S_EXT) ? ALLOGCHR : ALLOLCHR,
|
||||
(ind_t)name->on_foff
|
||||
),
|
||||
|
|
|
@ -18,7 +18,7 @@ static char rcsid[] = "$Id$";
|
|||
#include "orig.h"
|
||||
#include "sym.h"
|
||||
|
||||
#define UBYTE(x) ((x) & BYTEMASK)
|
||||
#define UBYTE(x) ((x)&BYTEMASK)
|
||||
|
||||
static uint16_t read2(char* addr, int type)
|
||||
{
|
||||
|
@ -34,10 +34,13 @@ static uint32_t read4(char* addr, int type)
|
|||
{
|
||||
unsigned short word0, word1;
|
||||
|
||||
if (type & RELBR) {
|
||||
if (type & RELBR)
|
||||
{
|
||||
word0 = (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
|
||||
word1 = (UBYTE(addr[2]) << WIDTH) + UBYTE(addr[3]);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
word0 = (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
|
||||
word1 = (UBYTE(addr[3]) << WIDTH) + UBYTE(addr[2]);
|
||||
}
|
||||
|
@ -61,9 +64,9 @@ static uint32_t get_vc4_valu(char* addr)
|
|||
* st<w> rd, $+o: [1110 0111 ww 1 d:5] [11111 o:27]
|
||||
*/
|
||||
|
||||
int32_t value = read4(addr+2, 0);
|
||||
int32_t value = read4(addr + 2, 0);
|
||||
value &= 0x07ffffff;
|
||||
value = value<<5>>5;
|
||||
value = value << 5 >> 5;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -75,7 +78,7 @@ static uint32_t get_vc4_valu(char* addr)
|
|||
|
||||
uint32_t value = read4(addr, RELWR);
|
||||
value &= 0x007fffff;
|
||||
value = value<<9>>9;
|
||||
value = value << 9 >> 9;
|
||||
value *= 2;
|
||||
return value;
|
||||
}
|
||||
|
@ -90,18 +93,18 @@ static uint32_t get_vc4_valu(char* addr)
|
|||
int32_t value = read4(addr, RELWR);
|
||||
int32_t lov = value & 0x007fffff;
|
||||
int32_t hiv = value & 0x0f000000;
|
||||
value = lov | (hiv>>1);
|
||||
value = value<<5>>5;
|
||||
value = lov | (hiv >> 1);
|
||||
value = value << 5 >> 5;
|
||||
value *= 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
if ((opcode & 0xffe0) == 0xe500)
|
||||
{
|
||||
/* lea: [1110 0101 000 d:5] [o:32] */
|
||||
/* lea: [1110 0101 000 d:5] [o:32] */
|
||||
|
||||
return read4(addr+2, 0);
|
||||
}
|
||||
return read4(addr + 2, 0);
|
||||
}
|
||||
|
||||
assert(0 && "unrecognised VC4 instruction");
|
||||
}
|
||||
|
@ -137,22 +140,20 @@ static bool is_powerpc_memory_op(uint32_t opcode)
|
|||
|
||||
static uint32_t get_powerpc_valu(char* addr, uint16_t type)
|
||||
{
|
||||
uint32_t opcode1 = read4(addr+0, type);
|
||||
uint32_t opcode2 = read4(addr+4, type);
|
||||
uint32_t opcode1 = read4(addr + 0, type);
|
||||
uint32_t opcode2 = read4(addr + 4, type);
|
||||
|
||||
if ((opcode1 & 0xfc000000) == 0x48000000)
|
||||
{
|
||||
/* branch instruction */
|
||||
return opcode1 & 0x03fffffd;
|
||||
}
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
|
||||
((opcode2 & 0xfc000000) == 0x60000000))
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && ((opcode2 & 0xfc000000) == 0x60000000))
|
||||
{
|
||||
/* addis / ori instruction pair */
|
||||
return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff);
|
||||
}
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
|
||||
is_powerpc_memory_op(opcode2))
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && is_powerpc_memory_op(opcode2))
|
||||
{
|
||||
/* addis / memoryop instruction pair */
|
||||
uint16_t hi = opcode1 & 0xffff;
|
||||
|
@ -166,12 +167,13 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type)
|
|||
return ((hi << 16) | lo);
|
||||
}
|
||||
|
||||
fatal("Don't know how to read from PowerPC fixup on instructions 0x%08lx+0x%08lx",
|
||||
(unsigned long)opcode1, (unsigned long)opcode2);
|
||||
fatal(
|
||||
"Don't know how to read from PowerPC fixup on instructions 0x%08lx+0x%08lx",
|
||||
(unsigned long)opcode1, (unsigned long)opcode2);
|
||||
}
|
||||
|
||||
/* RELOPPC_LIS stores a signed 26-bit offset in the low bits. */
|
||||
static uint32_t get_lis_valu(char *addr, uint16_t type)
|
||||
static uint32_t get_lis_valu(char* addr, uint16_t type)
|
||||
{
|
||||
uint32_t valu = read4(addr, type) & 0x03ffffff;
|
||||
if (valu & 0x02000000)
|
||||
|
@ -179,39 +181,71 @@ static uint32_t get_lis_valu(char *addr, uint16_t type)
|
|||
return valu;
|
||||
}
|
||||
|
||||
/* RELOMIPS is used for j and b instructions only. */
|
||||
static uint32_t get_mips_valu(char* addr)
|
||||
{
|
||||
uint32_t value = read4(addr, 0);
|
||||
switch (value >> 26)
|
||||
{
|
||||
case 2: /* j */
|
||||
case 3: /* jal */
|
||||
case 29: /* jalx */
|
||||
/* Unsigned 26-bit payload. */
|
||||
value = value & ((1 << 26) - 1);
|
||||
break;
|
||||
|
||||
default: /* assume everything else is a b, there are lots */
|
||||
/* Signed 16-bit payload. */
|
||||
value = ((int32_t)value << 16) >> 16;
|
||||
break;
|
||||
}
|
||||
|
||||
/* The value has two implicit zero bits on the bottom. */
|
||||
value <<= 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bits in type indicate how many bytes the value occupies and what
|
||||
* significance should be attributed to each byte.
|
||||
*/
|
||||
static uint32_t getvalu(char* addr, uint16_t type)
|
||||
{
|
||||
switch (type & RELSZ) {
|
||||
case RELO1:
|
||||
return UBYTE(addr[0]);
|
||||
case RELO2:
|
||||
return read2(addr, type);
|
||||
case RELO4:
|
||||
return read4(addr, type);
|
||||
case RELOPPC:
|
||||
return get_powerpc_valu(addr, type);
|
||||
case RELOPPC_LIS:
|
||||
return get_lis_valu(addr, type);
|
||||
case RELOVC4:
|
||||
return get_vc4_valu(addr);
|
||||
default:
|
||||
fatal("bad relocation type %x", type & RELSZ);
|
||||
switch (type & RELSZ)
|
||||
{
|
||||
case RELO1:
|
||||
return UBYTE(addr[0]);
|
||||
case RELO2:
|
||||
case RELO2HI:
|
||||
case RELO2HISAD:
|
||||
return read2(addr, type);
|
||||
case RELO4:
|
||||
return read4(addr, type);
|
||||
case RELOPPC:
|
||||
return get_powerpc_valu(addr, type);
|
||||
case RELOPPC_LIS:
|
||||
return get_lis_valu(addr, type);
|
||||
case RELOVC4:
|
||||
return get_vc4_valu(addr);
|
||||
case RELOMIPS:
|
||||
return get_mips_valu(addr);
|
||||
default:
|
||||
fatal("can't read relocation type %x", type & RELSZ);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void write2(uint16_t valu, char* addr, int type)
|
||||
{
|
||||
unsigned short word0, word1;
|
||||
unsigned short word0, word1;
|
||||
|
||||
if (type & RELBR) {
|
||||
if (type & RELBR)
|
||||
{
|
||||
addr[0] = valu >> WIDTH;
|
||||
addr[1] = valu;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
addr[0] = valu;
|
||||
addr[1] = valu >> WIDTH;
|
||||
}
|
||||
|
@ -219,21 +253,27 @@ static void write2(uint16_t valu, char* addr, int type)
|
|||
|
||||
static void write4(uint32_t valu, char* addr, int type)
|
||||
{
|
||||
unsigned short word0, word1;
|
||||
unsigned short word0, word1;
|
||||
|
||||
if (type & RELWR) {
|
||||
if (type & RELWR)
|
||||
{
|
||||
word0 = valu >> (2 * WIDTH);
|
||||
word1 = valu;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
word0 = valu;
|
||||
word1 = valu >> (2 * WIDTH);
|
||||
}
|
||||
if (type & RELBR) {
|
||||
if (type & RELBR)
|
||||
{
|
||||
addr[0] = word0 >> WIDTH;
|
||||
addr[1] = word0;
|
||||
addr[2] = word1 >> WIDTH;
|
||||
addr[3] = word1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
addr[0] = word0;
|
||||
addr[1] = word0 >> WIDTH;
|
||||
addr[2] = word1;
|
||||
|
@ -255,10 +295,10 @@ static void put_vc4_valu(char* addr, uint32_t value)
|
|||
* st<w> rd, o, (pc): [1110 0111 ww 1 d:5] [11111 o:27]
|
||||
*/
|
||||
|
||||
uint32_t v = read4(addr+2, 0);
|
||||
uint32_t v = read4(addr + 2, 0);
|
||||
v &= 0xf8000000;
|
||||
v |= value & 0x07ffffff;
|
||||
write4(v, addr+2, 0);
|
||||
write4(v, addr + 2, 0);
|
||||
}
|
||||
else if ((opcode & 0xf080) == 0x9000)
|
||||
{
|
||||
|
@ -268,7 +308,7 @@ static void put_vc4_valu(char* addr, uint32_t value)
|
|||
|
||||
uint32_t v = read4(addr, RELWR);
|
||||
v &= 0xff800000;
|
||||
v |= (value/2) & 0x007fffff;
|
||||
v |= (value / 2) & 0x007fffff;
|
||||
write4(v, addr, RELWR);
|
||||
}
|
||||
else if ((opcode & 0xf080) == 0x9080)
|
||||
|
@ -279,19 +319,19 @@ static void put_vc4_valu(char* addr, uint32_t value)
|
|||
*/
|
||||
|
||||
uint32_t v = read4(addr, RELWR);
|
||||
uint32_t lovalue = (value/2) & 0x007fffff;
|
||||
uint32_t hivalue = (value/2) & 0x07800000;
|
||||
uint32_t lovalue = (value / 2) & 0x007fffff;
|
||||
uint32_t hivalue = (value / 2) & 0x07800000;
|
||||
v &= 0xf0800000;
|
||||
v |= lovalue | (hivalue<<1);
|
||||
v |= lovalue | (hivalue << 1);
|
||||
write4(v, addr, RELWR);
|
||||
}
|
||||
else if ((opcode & 0xffe0) == 0xe500)
|
||||
{
|
||||
/* lea: [1110 0101 000 d:5] [o:32] */
|
||||
/* lea: [1110 0101 000 d:5] [o:32] */
|
||||
|
||||
write4(value, addr+2, 0);
|
||||
}
|
||||
else
|
||||
write4(value, addr + 2, 0);
|
||||
}
|
||||
else
|
||||
assert(0 && "unrecognised VC4 instruction");
|
||||
}
|
||||
|
||||
|
@ -302,8 +342,8 @@ static void put_vc4_valu(char* addr, uint32_t value)
|
|||
|
||||
static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
|
||||
{
|
||||
uint32_t opcode1 = read4(addr+0, type);
|
||||
uint32_t opcode2 = read4(addr+4, type);
|
||||
uint32_t opcode1 = read4(addr + 0, type);
|
||||
uint32_t opcode2 = read4(addr + 4, type);
|
||||
|
||||
if ((opcode1 & 0xfc000000) == 0x48000000)
|
||||
{
|
||||
|
@ -312,18 +352,16 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
|
|||
i |= value & 0x03fffffd;
|
||||
write4(i, addr, type);
|
||||
}
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
|
||||
((opcode2 & 0xfc000000) == 0x60000000))
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && ((opcode2 & 0xfc000000) == 0x60000000))
|
||||
{
|
||||
/* addis / ori instruction pair */
|
||||
uint16_t hi = value >> 16;
|
||||
uint16_t lo = value & 0xffff;
|
||||
|
||||
write4((opcode1 & 0xffff0000) | hi, addr+0, type);
|
||||
write4((opcode2 & 0xffff0000) | lo, addr+4, type);
|
||||
write4((opcode1 & 0xffff0000) | hi, addr + 0, type);
|
||||
write4((opcode2 & 0xffff0000) | lo, addr + 4, type);
|
||||
}
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
|
||||
is_powerpc_memory_op(opcode2))
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && is_powerpc_memory_op(opcode2))
|
||||
{
|
||||
/* addis / memoryop instruction pair */
|
||||
uint16_t hi = value >> 16;
|
||||
|
@ -334,13 +372,14 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
|
|||
if (lo > 0x7fff)
|
||||
hi++;
|
||||
|
||||
write4((opcode1 & 0xffff0000) | hi, addr+0, type);
|
||||
write4((opcode2 & 0xffff0000) | lo, addr+4, type);
|
||||
write4((opcode1 & 0xffff0000) | hi, addr + 0, type);
|
||||
write4((opcode2 & 0xffff0000) | lo, addr + 4, type);
|
||||
}
|
||||
|
||||
else
|
||||
fatal("Don't know how to write a PowerPC fixup to instructions 0x%08lx+0x%08lx",
|
||||
(unsigned long)opcode1, (unsigned long)opcode2);
|
||||
fatal(
|
||||
"Don't know how to write a PowerPC fixup to instructions 0x%08lx+0x%08lx",
|
||||
(unsigned long)opcode1, (unsigned long)opcode2);
|
||||
}
|
||||
|
||||
/* Writes a PowerPC lis instruction. */
|
||||
|
@ -369,6 +408,36 @@ static void put_lis_valu(char* addr, uint32_t value, uint16_t type)
|
|||
write4(opcode, addr, type);
|
||||
}
|
||||
|
||||
/* RELOMIPS is used for j and b instructions only. */
|
||||
static void put_mips_valu(char* addr, uint32_t value)
|
||||
{
|
||||
uint32_t opcode = read4(addr, 0);
|
||||
|
||||
/* The two bottom zero bits are implicit. */
|
||||
if (value & 3)
|
||||
fatal("invalid MIPS relocation value 0x%x", value);
|
||||
value >>= 2;
|
||||
|
||||
switch (opcode >> 26)
|
||||
{
|
||||
case 2: /* j */
|
||||
case 3: /* jal */
|
||||
case 29: /* jalx */
|
||||
/* Unsigned 26-bit payload. */
|
||||
value = value & ((1 << 26) - 1);
|
||||
opcode = opcode & ~((1 << 26) - 1);
|
||||
break;
|
||||
|
||||
default: /* assume everything else is a b, there are lots */
|
||||
/* Signed 16-bit payload. */
|
||||
value = value & ((1 << 16) - 1);
|
||||
opcode = opcode & ~((1 << 16) - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
write4(opcode | value, addr, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The bits in type indicate how many bytes the value occupies and what
|
||||
* significance should be attributed to each byte.
|
||||
|
@ -377,32 +446,42 @@ static void put_lis_valu(char* addr, uint32_t value, uint16_t type)
|
|||
static putvalu(uint32_t valu, char* addr, uint16_t type)
|
||||
{
|
||||
|
||||
switch (type & RELSZ) {
|
||||
case RELO1:
|
||||
addr[0] = valu;
|
||||
break;
|
||||
case RELO2:
|
||||
write2(valu, addr, type);
|
||||
break;
|
||||
case RELO4:
|
||||
write4(valu, addr, type);
|
||||
break;
|
||||
case RELOPPC:
|
||||
put_powerpc_valu(addr, valu, type);
|
||||
break;
|
||||
case RELOPPC_LIS:
|
||||
put_lis_valu(addr, valu, type);
|
||||
break;
|
||||
case RELOVC4:
|
||||
put_vc4_valu(addr, valu);
|
||||
break;
|
||||
default:
|
||||
fatal("bad relocation type %x", type & RELSZ);
|
||||
switch (type & RELSZ)
|
||||
{
|
||||
case RELO1:
|
||||
addr[0] = valu;
|
||||
break;
|
||||
case RELO2:
|
||||
write2(valu, addr, type);
|
||||
break;
|
||||
case RELO2HI:
|
||||
write2(valu >> 16, addr, type);
|
||||
break;
|
||||
case RELO2HISAD:
|
||||
write2((valu >> 16) + !!(valu & 0x8000), addr, type);
|
||||
break;
|
||||
case RELO4:
|
||||
write4(valu, addr, type);
|
||||
break;
|
||||
case RELOPPC:
|
||||
put_powerpc_valu(addr, valu, type);
|
||||
break;
|
||||
case RELOPPC_LIS:
|
||||
put_lis_valu(addr, valu, type);
|
||||
break;
|
||||
case RELOVC4:
|
||||
put_vc4_valu(addr, valu);
|
||||
break;
|
||||
case RELOMIPS:
|
||||
put_mips_valu(addr, valu);
|
||||
break;
|
||||
default:
|
||||
fatal("can't write relocation type %x", type & RELSZ);
|
||||
}
|
||||
}
|
||||
|
||||
extern struct outsect outsect[];
|
||||
extern struct orig relorig[];
|
||||
extern struct outsect outsect[];
|
||||
extern struct orig relorig[];
|
||||
|
||||
/*
|
||||
* There are two cases: `local' is an undefined external or common name,
|
||||
|
@ -416,42 +495,47 @@ extern struct orig relorig[];
|
|||
* Second case: we must update the value by the change
|
||||
* in position of the section of local.
|
||||
*/
|
||||
static unsigned
|
||||
addrelo(relo, names, valu_out)
|
||||
struct outrelo *relo;
|
||||
struct outname *names;
|
||||
long *valu_out; /* Out variable. */
|
||||
static unsigned addrelo(relo, names, valu_out) struct outrelo* relo;
|
||||
struct outname* names;
|
||||
long* valu_out; /* Out variable. */
|
||||
{
|
||||
register struct outname *local = &names[relo->or_nami];
|
||||
register unsigned short index = NLocals;
|
||||
register long valu = *valu_out;
|
||||
register struct outname* local = &names[relo->or_nami];
|
||||
register unsigned short index = NLocals;
|
||||
register long valu = *valu_out;
|
||||
|
||||
if ((local->on_type & S_SCT)) {
|
||||
register int sectindex = (local->on_type & S_TYP) - S_MIN;
|
||||
if ((local->on_type & S_SCT))
|
||||
{
|
||||
register int sectindex = (local->on_type & S_TYP) - S_MIN;
|
||||
|
||||
valu += relorig[sectindex].org_size;
|
||||
valu += outsect[sectindex].os_base;
|
||||
index += NGlobals + sectindex;
|
||||
} else {
|
||||
register struct outname *name;
|
||||
extern int hash();
|
||||
extern struct outname *searchname();
|
||||
extern unsigned indexof();
|
||||
extern struct outhead outhead;
|
||||
}
|
||||
else
|
||||
{
|
||||
register struct outname* name;
|
||||
extern int hash();
|
||||
extern struct outname* searchname();
|
||||
extern unsigned indexof();
|
||||
extern struct outhead outhead;
|
||||
|
||||
name = searchname(local->on_mptr, hash(local->on_mptr));
|
||||
if (name == (struct outname *)0)
|
||||
if (name == (struct outname*)0)
|
||||
fatal("name %s not found in pass 2", local->on_mptr);
|
||||
if (ISCOMMON(name) || ISUNDEFINED(name)) {
|
||||
debug("can't relocate from %s\n",local->on_mptr,0,0,0);
|
||||
if (ISCOMMON(name) || ISUNDEFINED(name))
|
||||
{
|
||||
debug("can't relocate from %s\n", local->on_mptr, 0, 0, 0);
|
||||
index += indexof(name);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
valu += name->on_valu;
|
||||
if ((name->on_type & S_TYP) == S_ABS) {
|
||||
if ((name->on_type & S_TYP) == S_ABS)
|
||||
{
|
||||
index += NGlobals + outhead.oh_nsect;
|
||||
}
|
||||
else index += NGlobals +
|
||||
(name->on_type & S_TYP) - S_MIN;
|
||||
else
|
||||
index += NGlobals + (name->on_type & S_TYP) - S_MIN;
|
||||
}
|
||||
}
|
||||
*valu_out = valu;
|
||||
|
@ -463,21 +547,23 @@ addrelo(relo, names, valu_out)
|
|||
* which the header is pointed to by `head'. Relocation is relative to the
|
||||
* names in `names'; `relo' tells how to relocate.
|
||||
*/
|
||||
relocate(head, emit, names, relo, off)
|
||||
struct outhead *head;
|
||||
char *emit;
|
||||
struct outname names[];
|
||||
struct outrelo *relo;
|
||||
long off;
|
||||
relocate(head, emit, names, relo, off) struct outhead* head;
|
||||
char* emit;
|
||||
struct outname names[];
|
||||
struct outrelo* relo;
|
||||
long off;
|
||||
{
|
||||
long valu;
|
||||
int sectindex = relo->or_sect - S_MIN;
|
||||
extern struct outhead outhead;
|
||||
long valu;
|
||||
int sectindex = relo->or_sect - S_MIN;
|
||||
extern struct outhead outhead;
|
||||
uint32_t realaddress = outsect[sectindex].os_base + relo->or_addr
|
||||
+ relorig[sectindex].org_size;
|
||||
|
||||
/*
|
||||
* Pick up previous value at location to be relocated.
|
||||
*/
|
||||
valu = getvalu(emit + (relo->or_addr - off), relo->or_type);
|
||||
debug("read relocation from 0x%08x type 0x%x value 0x%08x symbol %d\n", realaddress, relo->or_type, valu, relo->or_nami);
|
||||
|
||||
/*
|
||||
* Or_nami is an index in the name table of the considered module.
|
||||
|
@ -486,10 +572,13 @@ relocate(head, emit, names, relo, off)
|
|||
* - a section name
|
||||
* - the first name outside! the name table (argh)
|
||||
*/
|
||||
if (relo->or_nami < head->oh_nname) {
|
||||
if (relo->or_nami < head->oh_nname)
|
||||
{
|
||||
/* First two cases. */
|
||||
relo->or_nami = addrelo(relo, names, &valu);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Third case: it is absolute. The relocation of absolute
|
||||
* names is always 0. We only need to change the index.
|
||||
|
@ -504,11 +593,12 @@ relocate(head, emit, names, relo, off)
|
|||
* now we subtract the origin of the referencING section.
|
||||
*/
|
||||
if (relo->or_type & RELPC)
|
||||
valu -= relorig[sectindex].org_size+outsect[sectindex].os_base;
|
||||
valu -= relorig[sectindex].org_size + outsect[sectindex].os_base;
|
||||
|
||||
/*
|
||||
* Now put the value back.
|
||||
*/
|
||||
debug("written fixed up relocation to 0x%08x type 0x%x value 0x%08x\n", realaddress, relo->or_type, valu, 0);
|
||||
putvalu(valu, emit + (relo->or_addr - off), relo->or_type);
|
||||
|
||||
/*
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
#include "smap.h"
|
||||
#include "mcgg.h"
|
||||
|
||||
static char rcsid[] = "$Id$";
|
||||
#define REGATTR_INT 0
|
||||
#define REGATTR_LONG 1
|
||||
#define REGATTR_FLOAT 2
|
||||
#define REGATTR_DOUBLE 3
|
||||
|
||||
int maxcost = SHRT_MAX / 2;
|
||||
|
||||
|
@ -162,6 +165,18 @@ int main(int argc, char* argv[])
|
|||
rule(®, tree(&NOPL, tree(®, NULL, NULL), NULL))->cost = 1;
|
||||
rule(®, tree(&NOPD, tree(®, NULL, NULL), NULL))->cost = 1;
|
||||
rule(NULL, tree(&RET, NULL, NULL))->cost = 1;
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
struct regattr* attr = makeregattr("int");
|
||||
assert(attr->number == REGATTR_INT);
|
||||
attr = makeregattr("long");
|
||||
assert(attr->number == REGATTR_LONG);
|
||||
attr = makeregattr("float");
|
||||
assert(attr->number == REGATTR_FLOAT);
|
||||
attr = makeregattr("double");
|
||||
assert(attr->number == REGATTR_DOUBLE);
|
||||
}
|
||||
|
||||
yyin = infp;
|
||||
|
@ -612,7 +627,8 @@ static void emitregisterattrs(void)
|
|||
assert(rc->number == i);
|
||||
|
||||
print("%1\"%s\",\n", rc->name);
|
||||
printh("#define %P%s_ATTR (1U<<%d)\n", rc->name, rc->number);
|
||||
if (rc->number > REGATTR_DOUBLE)
|
||||
printh("#define %P%s_ATTR (1U<<%d)\n", rc->name, rc->number);
|
||||
}
|
||||
print("};\n\n");
|
||||
printh("\n");
|
||||
|
@ -655,7 +671,10 @@ static void emitregisters(void)
|
|||
for (i=0; i<registers.count; i++)
|
||||
{
|
||||
struct reg* r = registers.item[i].right;
|
||||
uint32_t type = r->attrs & TYPE_ATTRS;
|
||||
assert(r->number == i);
|
||||
if (type & (type-1))
|
||||
yyerror("register %s has more than one type attribute set", r->name);
|
||||
|
||||
print("%1{ \"%s\", 0x%x, %Pregister_names_%d_%s, %Pregister_aliases_%d_%s },\n",
|
||||
r->name, r->attrs, i, r->name, i, r->name);
|
||||
|
|
|
@ -17,6 +17,11 @@ struct ir_data
|
|||
|
||||
extern const struct ir_data ir_data[];
|
||||
|
||||
#define burm_int_ATTR (1U<<0)
|
||||
#define burm_long_ATTR (1U<<1)
|
||||
#define burm_float_ATTR (1U<<2)
|
||||
#define burm_double_ATTR (1U<<3)
|
||||
|
||||
#define TYPE_ATTRS \
|
||||
(burm_int_ATTR | burm_long_ATTR | burm_float_ATTR | burm_double_ATTR)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue