fixes, improvements, __interrupt
Fixes/workarounds: - octal escape sequence is to be terminated no later than after three octal digits: "\1011" is now parsed equivalently to "A1" - workaround truncation of immediate operands to 16 bits in MIPS instructions addi[u], subi[u], slti[u], andi, ori, xori in RetroBSD's as (disabled since as is being fixed). Improvements: - warn on string literal truncation when initializing array of char - generate trap/break-less form of MIPS div[u] New: - experimental support for __interrupt functions (x86/huge only)
This commit is contained in:
@@ -37,6 +37,11 @@ either expressed or implied, of the FreeBSD Project.
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Works around bugs in RetroBSD's as instruction reordering
|
||||
#define REORDER_WORKAROUND
|
||||
// Works around bugs in RetroBSD's as immediate operand truncation to 16 bits
|
||||
//#define INSTR_IMM_WORKAROUND
|
||||
|
||||
int UseGp = 0;
|
||||
|
||||
void GenInit(void)
|
||||
@@ -47,7 +52,7 @@ void GenInit(void)
|
||||
CodeHeader = "\t.text";
|
||||
DataHeader = "\t.data";
|
||||
UseLeadingUnderscores = 0;
|
||||
#ifndef NO_REORDER_WORKAROUND
|
||||
#ifdef REORDER_WORKAROUND
|
||||
FileHeader = "\t.set\tnoreorder";
|
||||
#else
|
||||
FileHeader = "\t.set\treorder";
|
||||
@@ -65,8 +70,10 @@ int GenInitParams(int argc, char** argv, int* idx)
|
||||
}
|
||||
else if (!strcmp(argv[*idx], "-v"))
|
||||
{
|
||||
// RetroBSD's cc may supply this parameter. Just need to consume it.
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -294,7 +301,7 @@ void GenPrintInstr(int instr, int val)
|
||||
#define MipsOpLabelGpOption 0x83
|
||||
#define MipsOpIndLocal MipsOpIndRegFp
|
||||
|
||||
#ifndef NO_REORDER_WORKAROUND
|
||||
#ifdef REORDER_WORKAROUND
|
||||
void GenNop(void)
|
||||
{
|
||||
puts2("\tnop");
|
||||
@@ -363,7 +370,7 @@ void GenPrintInstr1Operand(int instr, int instrval, int operand, int operandval)
|
||||
GenPrintOperand(operand, operandval);
|
||||
GenPrintNewLine();
|
||||
|
||||
#ifndef NO_REORDER_WORKAROUND
|
||||
#ifdef REORDER_WORKAROUND
|
||||
if (instr == MipsInstrJ || instr == MipsInstrJAL)
|
||||
GenNop();
|
||||
#endif
|
||||
@@ -387,10 +394,61 @@ void GenPrintInstr3Operands(int instr, int instrval,
|
||||
int operand2, int operand2val,
|
||||
int operand3, int operand3val)
|
||||
{
|
||||
#ifdef INSTR_IMM_WORKAROUND
|
||||
int useAt = 0;
|
||||
#endif
|
||||
|
||||
if (operand3 == MipsOpConst && operand3val == 0 &&
|
||||
(instr == MipsInstrAddU || instr == MipsInstrSubU))
|
||||
return;
|
||||
|
||||
#ifdef INSTR_IMM_WORKAROUND
|
||||
if (operand3 == MipsOpConst)
|
||||
{
|
||||
unsigned imm = truncUint(operand3val);
|
||||
|
||||
switch (instr)
|
||||
{
|
||||
// signed imm16:
|
||||
// addi[u], subi[u], slti[u]
|
||||
case MipsInstrAddU:
|
||||
case MipsInstrSLT:
|
||||
case MipsInstrSLTU:
|
||||
if (imm > 0x7FFF && imm < 0xFFFF8000) // if not (-0x8000 <= imm <= 0x7FFF)
|
||||
useAt = 1;
|
||||
break;
|
||||
case MipsInstrSubU:
|
||||
// subi[u] will be transformed into addi[u] and the immediate will be negated,
|
||||
// hence the immediate range is shifted by 1
|
||||
if (imm > 0x8000 && imm < 0xFFFF8001) // if not (-0x7FFF <= imm <= 0x8000)
|
||||
useAt = 1;
|
||||
break;
|
||||
|
||||
// unsigned imm16:
|
||||
// andi, ori, xori
|
||||
case MipsInstrAnd:
|
||||
case MipsInstrOr:
|
||||
case MipsInstrXor:
|
||||
if (imm > 0xFFFF)
|
||||
useAt = 1;
|
||||
break;
|
||||
|
||||
// also: various trap instructions
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (useAt)
|
||||
{
|
||||
puts2("\t.set\tnoat");
|
||||
GenPrintInstr2Operands(MipsInstrLI, 0,
|
||||
MipsOpRegAt, 0,
|
||||
MipsOpConst, operand3val);
|
||||
operand3 = MipsOpRegAt;
|
||||
}
|
||||
#endif
|
||||
|
||||
GenPrintInstr(instr, instrval);
|
||||
GenPrintOperand(operand1, operand1val);
|
||||
GenPrintOperandSeparator();
|
||||
@@ -399,7 +457,14 @@ void GenPrintInstr3Operands(int instr, int instrval,
|
||||
GenPrintOperand(operand3, operand3val);
|
||||
GenPrintNewLine();
|
||||
|
||||
#ifndef NO_REORDER_WORKAROUND
|
||||
#ifdef INSTR_IMM_WORKAROUND
|
||||
if (useAt)
|
||||
{
|
||||
puts2("\t.set\tat");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef REORDER_WORKAROUND
|
||||
if (instr == MipsInstrBEQ || instr == MipsInstrBNE)
|
||||
GenNop();
|
||||
#endif
|
||||
@@ -1133,11 +1198,13 @@ void GenExpr0(void)
|
||||
{
|
||||
int reg = GenPopReg(MipsOpRegT0);
|
||||
if (tok == '/' || tok == '%')
|
||||
GenPrintInstr2Operands(MipsInstrDiv, 0,
|
||||
GenPrintInstr3Operands(MipsInstrDiv, 0,
|
||||
MipsOpRegZero, 0,
|
||||
reg, 0,
|
||||
MipsOpRegV0, 0);
|
||||
else
|
||||
GenPrintInstr2Operands(MipsInstrDivU, 0,
|
||||
GenPrintInstr3Operands(MipsInstrDivU, 0,
|
||||
MipsOpRegZero, 0,
|
||||
reg, 0,
|
||||
MipsOpRegV0, 0);
|
||||
if (tok == '%' || tok == tokUMod)
|
||||
@@ -1240,11 +1307,13 @@ void GenExpr0(void)
|
||||
|
||||
GenReadIndirect(MipsOpRegT1, reg, v);
|
||||
if (tok == tokAssignDiv || tok == tokAssignMod)
|
||||
GenPrintInstr2Operands(MipsInstrDiv, 0,
|
||||
GenPrintInstr3Operands(MipsInstrDiv, 0,
|
||||
MipsOpRegZero, 0,
|
||||
MipsOpRegT1, 0,
|
||||
MipsOpRegV0, 0);
|
||||
else
|
||||
GenPrintInstr2Operands(MipsInstrDivU, 0,
|
||||
GenPrintInstr3Operands(MipsInstrDivU, 0,
|
||||
MipsOpRegZero, 0,
|
||||
MipsOpRegT1, 0,
|
||||
MipsOpRegV0, 0);
|
||||
if (tok == tokAssignMod || tok == tokAssignUMod)
|
||||
@@ -1604,11 +1673,11 @@ void GenFin(void)
|
||||
"\taddiu\t$3, $3, 1");
|
||||
printf2("\tbne\t$4, $0, "); GenPrintNumLabel(lbl);
|
||||
puts2("");
|
||||
#ifndef NO_REORDER_WORKAROUND
|
||||
#ifdef REORDER_WORKAROUND
|
||||
GenNop();
|
||||
#endif
|
||||
puts2("\tj\t$31");
|
||||
#ifndef NO_REORDER_WORKAROUND
|
||||
#ifdef REORDER_WORKAROUND
|
||||
GenNop();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -803,6 +803,79 @@ void GenFxnEpilog(void)
|
||||
GenPrintInstrNoOperand(X86InstrRet);
|
||||
}
|
||||
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
/*
|
||||
struct INTREGS
|
||||
{
|
||||
unsigned short gs, fs, es, ds;
|
||||
unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
unsigned short ss, ip, cs, flags;
|
||||
};
|
||||
void __interrupt isr(struct INTREGS** ppRegs)
|
||||
{
|
||||
// **ppRegs (input/output values of registers) can be modified to
|
||||
// handle software interrupts requested via the int instruction and
|
||||
// communicate data via registers
|
||||
|
||||
// *ppRegs (directly related to the stack pointer) can be modified to
|
||||
// return to a different location & implement preemptive scheduling,
|
||||
// e.g. save *ppRegs of the interrupted task somewhere, update *ppRegs
|
||||
// with a value from another interrupted task.
|
||||
}
|
||||
*/
|
||||
void GenIsrProlog(void)
|
||||
{
|
||||
// The CPU has already done these:
|
||||
// push flags
|
||||
// push cs
|
||||
// push ip
|
||||
|
||||
puts2("\tpush\tss");
|
||||
puts2("\tpushad");
|
||||
puts2("\tpush\tds\n"
|
||||
"\tpush\tes\n"
|
||||
"\tpush\tfs\n"
|
||||
"\tpush\tgs");
|
||||
|
||||
// The context has been saved
|
||||
|
||||
puts2("\txor\teax, eax\n\tmov\tax, ss"); // mov r32, sreg leaves top 16 bits undefined on pre-Pentium CPUs
|
||||
puts2("\txor\tebx, ebx\n\tmov\tbx, sp"); // top 16 bits of esp can contain garbage as well
|
||||
puts2("\tshl\teax, 4\n\tadd\teax, ebx");
|
||||
puts2("\tpush\teax"); // pointer to the structure with register values
|
||||
puts2("\tsub\teax, 4\n\tpush\teax"); // pointer to the pointer to the structure with register values
|
||||
|
||||
puts2("\tpush\teax"); // fake return address allowing to use the existing bp-relative addressing of locals and params
|
||||
|
||||
puts2("\tpush\tebp\n"
|
||||
"\tmov\tebp, esp");
|
||||
}
|
||||
|
||||
void GenIsrEpilog(void)
|
||||
{
|
||||
puts2("\tdb\t0x66\n\tleave");
|
||||
|
||||
puts2("\tpop\teax"); // fake return address
|
||||
|
||||
puts2("\tpop\teax"); // pointer to the pointer to the structure with register values
|
||||
puts2("\tpop\tebx"); // pointer to the structure with register values
|
||||
puts2("\tror\tebx, 4\n\tmov\tds, bx\n\tshr\tebx, 28"); // ds:bx = pointer to the structure with register values
|
||||
puts2("\tmov\tax, [bx+4*10]\n\tmov\tbx, [bx+4*5]\n\tsub\tbx, 4*10"); // ax:bx = proper pointer (with original segment) to the struct...
|
||||
puts2("\tmov\tss, ax\n\tmov\tsp, bx"); // restore ss:sp that we had after push gs
|
||||
|
||||
// The context is now going to be restored
|
||||
|
||||
puts2("\tpop\tgs\n"
|
||||
"\tpop\tfs\n"
|
||||
"\tpop\tes\n"
|
||||
"\tpop\tds");
|
||||
puts2("\tpopad");
|
||||
puts2("\tpop\tss");
|
||||
|
||||
puts2("\tiret");
|
||||
}
|
||||
#endif
|
||||
|
||||
void GenReadIdent(int opSz, int label)
|
||||
{
|
||||
GenPrintInstr2Operands(X86InstrMov, 0,
|
||||
|
||||
@@ -302,6 +302,7 @@ int vfprintf(FILE*, char*, void*);
|
||||
#define tokTag 0x91
|
||||
#define tokMemberIdent 0x92
|
||||
#define tokEnumPtr 0x93
|
||||
#define tokIntr 0x94
|
||||
|
||||
#define FormatFlat 0
|
||||
#define FormatSegmented 1
|
||||
@@ -368,6 +369,8 @@ void GenJumpIfNotEqual(int val, int Label);
|
||||
|
||||
void GenFxnProlog(void);
|
||||
void GenFxnEpilog(void);
|
||||
void GenIsrProlog(void);
|
||||
void GenIsrEpilog(void);
|
||||
|
||||
void GenLocalAlloc(int Size);
|
||||
|
||||
@@ -614,8 +617,10 @@ unsigned truncUint(unsigned n)
|
||||
// Truncate n to SizeOfWord * 8 bits
|
||||
if (SizeOfWord == 2)
|
||||
n &= ~(~0u << 8 << 8);
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
else if (SizeOfWord == 4)
|
||||
n &= ~(~0u << 8 << 12 << 12);
|
||||
#endif
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -628,11 +633,13 @@ int truncInt(int n)
|
||||
un &= ~(~0u << 8 << 8);
|
||||
un |= (((un >> 8 >> 7) & 1) * ~0u) << 8 << 8;
|
||||
}
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
else if (SizeOfWord == 4)
|
||||
{
|
||||
un &= ~(~0u << 8 << 12 << 12);
|
||||
un |= (((un >> 8 >> 12 >> 11) & 1) * ~0u) << 8 << 12 << 12;
|
||||
}
|
||||
#endif
|
||||
return uint2int(un);
|
||||
}
|
||||
|
||||
@@ -902,7 +909,8 @@ char* rws[] =
|
||||
"static", "switch", "unsigned", "void", "while", "asm", "auto",
|
||||
"const", "double", "enum", "float", "goto", "inline", "long",
|
||||
"register", "restrict", "short", "struct", "typedef", "union",
|
||||
"volatile", "_Bool", "_Complex", "_Imaginary"
|
||||
"volatile", "_Bool", "_Complex", "_Imaginary",
|
||||
"__interrupt"
|
||||
};
|
||||
|
||||
unsigned char rwtk[] =
|
||||
@@ -912,7 +920,8 @@ unsigned char rwtk[] =
|
||||
tokStatic, tokSwitch, tokUnsigned, tokVoid, tokWhile, tok_Asm, tokAuto,
|
||||
tokConst, tokDouble, tokEnum, tokFloat, tokGoto, tokInline, tokLong,
|
||||
tokRegister, tokRestrict, tokShort, tokStruct, tokTypedef, tokUnion,
|
||||
tokVolatile, tok_Bool, tok_Complex, tok_Imagin
|
||||
tokVolatile, tok_Bool, tok_Complex, tok_Imagin,
|
||||
tokIntr
|
||||
};
|
||||
|
||||
int GetTokenByWord(char* word)
|
||||
@@ -1368,11 +1377,10 @@ void GetString(char terminator, int SkipNewLines)
|
||||
c = (c * 8) & 0xFF;
|
||||
c += *p - '0';
|
||||
ShiftCharN(1);
|
||||
cnt++;
|
||||
// octal escape sequence is terminated after three octal digits
|
||||
if (++cnt == 3)
|
||||
break;
|
||||
}
|
||||
if (!cnt)
|
||||
//error("Unsupported or invalid character/string constant\n");
|
||||
errorChrStr();
|
||||
c -= (c >= 0x80 && CHAR_MIN) * 0x100;
|
||||
ch = c;
|
||||
}
|
||||
@@ -1530,11 +1538,13 @@ int GetNumber(void)
|
||||
}
|
||||
|
||||
// Ensure the constant fits into 16(32) bits
|
||||
if ((SizeOfWord == 2 && n >> 8 >> 8) || // equiv. to SizeOfWord == 2 && n > 0xFFFF
|
||||
if (
|
||||
(SizeOfWord == 2 && n >> 8 >> 8) // equiv. to SizeOfWord == 2 && n > 0xFFFF
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
(SizeOfWord == 2 && lSuffix) || // long (which must have at least 32 bits) isn't supported in 16-bit models
|
||||
|| (SizeOfWord == 2 && lSuffix) // long (which must have at least 32 bits) isn't supported in 16-bit models
|
||||
|| (SizeOfWord == 4 && n >> 8 >> 12 >> 12) // equiv. to SizeOfWord == 4 && n > 0xFFFFFFFF
|
||||
#endif
|
||||
(SizeOfWord == 4 && n >> 8 >> 12 >> 12)) // equiv. to SizeOfWord == 4 && n > 0xFFFFFFFF
|
||||
)
|
||||
error("Constant too big for %d-bit type\n", SizeOfWord * 8);
|
||||
|
||||
TokenValueInt = uint2int(n);
|
||||
@@ -1542,8 +1552,13 @@ int GetNumber(void)
|
||||
// Unsuffixed (with 'u') integer constants (octal, decimal, hex)
|
||||
// fitting into 15(31) out of 16(32) bits are signed ints
|
||||
if (!uSuffix &&
|
||||
((SizeOfWord == 2 && !(n >> 8 >> 7)) || // equiv. to SizeOfWord == 2 && n <= 0x7FFF
|
||||
(SizeOfWord == 4 && !(n >> 8 >> 12 >> 11)))) // equiv. to SizeOfWord == 4 && n <= 0x7FFFFFFF
|
||||
(
|
||||
(SizeOfWord == 2 && !(n >> 15)) // equiv. to SizeOfWord == 2 && n <= 0x7FFF
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
|| (SizeOfWord == 4 && !(n >> 8 >> 12 >> 11)) // equiv. to SizeOfWord == 4 && n <= 0x7FFFFFFF
|
||||
#endif
|
||||
)
|
||||
)
|
||||
return tokNumInt;
|
||||
|
||||
// Unlike octal and hex constants, decimal constants are always
|
||||
@@ -5600,6 +5615,11 @@ int ParseDerived(int tok)
|
||||
{
|
||||
int stars = 0;
|
||||
int params = 0;
|
||||
#ifndef MIPS
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
int isInterrupt = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (tok == '*')
|
||||
{
|
||||
@@ -5607,6 +5627,19 @@ int ParseDerived(int tok)
|
||||
tok = GetToken();
|
||||
}
|
||||
|
||||
#ifndef MIPS
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (tok == tokIntr)
|
||||
{
|
||||
// __interrupt is supported in the huge mode(l) only
|
||||
if (OutputFormat != FormatSegHuge)
|
||||
errorDecl();
|
||||
isInterrupt = 1;
|
||||
tok = GetToken();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (tok == '(')
|
||||
{
|
||||
tok = GetToken();
|
||||
@@ -5642,7 +5675,15 @@ int ParseDerived(int tok)
|
||||
tok = GetToken();
|
||||
else
|
||||
PushSyntax2(tokIdent, AddIdent("<something>"));
|
||||
#ifndef MIPS
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (isInterrupt)
|
||||
PushSyntax2('(', 1);
|
||||
else // fallthrough
|
||||
#endif
|
||||
#endif
|
||||
PushSyntax('(');
|
||||
|
||||
ParseLevel++;
|
||||
ParamLevel++;
|
||||
ParseFxnParams(tok);
|
||||
@@ -5897,6 +5938,9 @@ int InitArray(int synPtr, int tok)
|
||||
int undoIdents = IdentTableLen;
|
||||
int slen = StringTableLen;
|
||||
|
||||
if (elementsRequired * ((unsigned)TokenStringLen > elementsRequired))
|
||||
warning("String literal truncated\n");
|
||||
|
||||
tok = ParseExpr(tok, &gotUnary, &synPtr2, &constExpr, &exprVal, ',', 0);
|
||||
|
||||
if (!gotUnary ||
|
||||
@@ -6576,7 +6620,16 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
|
||||
GenLabel(IdentTable + SyntaxStack[lastSyntaxPtr][1], Static);
|
||||
CurFxnEpilogLabel = LabelCnt++;
|
||||
|
||||
#ifndef MIPS
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (SyntaxStack[lastSyntaxPtr + 1][1] & 1)
|
||||
GenIsrProlog();
|
||||
else // fallthrough
|
||||
#endif
|
||||
#endif
|
||||
GenFxnProlog();
|
||||
|
||||
GenJumpUncond(locAllocLabel + 1);
|
||||
GenNumLabel(locAllocLabel);
|
||||
|
||||
@@ -6623,7 +6676,16 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
}
|
||||
|
||||
GenNumLabel(CurFxnEpilogLabel);
|
||||
|
||||
#ifndef MIPS
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (SyntaxStack[lastSyntaxPtr + 1][1] & 1)
|
||||
GenIsrEpilog();
|
||||
else // fallthrough
|
||||
#endif
|
||||
#endif
|
||||
GenFxnEpilog();
|
||||
|
||||
GenNumLabel(locAllocLabel + 1);
|
||||
if (CurFxnMinLocalOfs)
|
||||
GenLocalAlloc(-CurFxnMinLocalOfs);
|
||||
|
||||
Reference in New Issue
Block a user