From 05d9e79095a81a99d2161236f2aaf8e2b89d2fe1 Mon Sep 17 00:00:00 2001 From: fincs Date: Wed, 20 Jul 2016 17:16:12 +0200 Subject: [PATCH] Add auto-NOP insertion to work around flow-of-control PICA errata --- source/picasso.h | 3 +++ source/picasso_assembler.cpp | 52 ++++++++++++++++++++++++++++++++++++ source/picasso_frontend.cpp | 7 +++-- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/source/picasso.h b/source/picasso.h index f50da69..581c84c 100644 --- a/source/picasso.h +++ b/source/picasso.h @@ -62,6 +62,7 @@ enum //----------------------------------------------------------------------------- // Output buffer +#define MAX_VSH_SIZE 512 typedef std::vector outputBufType; typedef outputBufType::iterator outputBufIter; extern outputBufType g_outputBuf; @@ -142,6 +143,8 @@ extern labelTableType g_labels; extern relocTableType g_labelRelocTable; extern aliasTableType g_aliases; +extern bool g_autoNop; + int AssembleString(char* str, const char* initialFilename); int RelocateProduct(void); diff --git a/source/picasso_assembler.cpp b/source/picasso_assembler.cpp index e3efce4..2759a97 100644 --- a/source/picasso_assembler.cpp +++ b/source/picasso_assembler.cpp @@ -6,6 +6,7 @@ static const char* curFile = NULL; static int curLine = -1; +static bool lastWasEnd = false; std::vector g_outputBuf; @@ -23,6 +24,8 @@ std::vector g_constArray; int g_constArraySize = -1; const char* g_constArrayName; +bool g_autoNop = true; + class UniformAlloc { int start, end, bound, tend; @@ -795,6 +798,14 @@ static inline bool isBadInputRegCombination(int a, int b, int c) return isBadInputRegCombination(a,b) || isBadInputRegCombination(b,c) || isBadInputRegCombination(c,a); } +static void insertPaddingNop() +{ + if (g_autoNop) + BUF.push_back(FMT_OPCODE(MAESTRO_NOP)); + else + fprintf(stderr, "%s:%d: warning: a padding NOP is required here\n", curFile, curLine); +} + DEF_COMMAND(format0) { ENSURE_NO_MORE_ARGS(); @@ -1245,6 +1256,21 @@ DEF_DIRECTIVE(else) if (elem.uExtra) return throwError("spurious .else\n"); + // Automatically add padding NOPs when necessary + if (lastWasEnd) + { + insertPaddingNop(); + lastWasEnd = false; + } else + { + u32 p = BUF.size(); + u32 lastOpcode = BUF[p-1] >> 26; + if (lastOpcode == MAESTRO_JMPC || lastOpcode == MAESTRO_JMPU + || lastOpcode == MAESTRO_CALL || lastOpcode == MAESTRO_CALLC || lastOpcode == MAESTRO_CALLU + || (p - elem.pos) < 2) + insertPaddingNop(); + } + u32 curPos = BUF.size(); elem.uExtra = curPos; u32& inst = BUF[elem.pos]; @@ -1265,6 +1291,24 @@ DEF_DIRECTIVE(end) return throwError(".end with unmatched block\n"); StackEntry& elem = g_stack[--g_stackPos]; + + // Automatically add padding NOPs when necessary + if (elem.type != SE_ARRAY && lastWasEnd) + { + insertPaddingNop(); + lastWasEnd = false; + } + else if (elem.type == SE_PROC || elem.type == SE_FOR || elem.type == SE_IF && BUF.size() > 0) + { + u32 p = BUF.size(); + u32 lastOpcode = BUF[p-1] >> 26; + if (lastOpcode == MAESTRO_JMPC || lastOpcode == MAESTRO_JMPU + || lastOpcode == MAESTRO_CALL || lastOpcode == MAESTRO_CALLC || lastOpcode == MAESTRO_CALLU + || (elem.type == SE_FOR && lastOpcode == MAESTRO_BREAKC) + || (elem.type != SE_ARRAY && (p - elem.pos) < (elem.type != SE_PROC ? 2 : 1))) + insertPaddingNop(); + } + u32 curPos = BUF.size(); u32 size = curPos - elem.pos; @@ -1287,6 +1331,7 @@ DEF_DIRECTIVE(end) u32& inst = BUF[elem.pos]; inst &= ~(0xFFF << 10); inst |= (curPos-1) << 10; + lastWasEnd = true; break; } @@ -1307,6 +1352,7 @@ DEF_DIRECTIVE(end) inst &= ~0x3FF; inst |= curPos - elem.uExtra; } + lastWasEnd = true; break; } @@ -1814,6 +1860,12 @@ int ProcessCommand(const char* cmd) table = dirTable; } else if (!g_stackPos) return throwError("instruction outside block\n"); + else + { + lastWasEnd = false; + if (!GetDvleData()->isGeoShader && g_outputBuf.size() >= MAX_VSH_SIZE) + return throwError("instruction outside vertex shader code memory (max %d instructions, currently %d)\n", MAX_VSH_SIZE, g_outputBuf.size()); + } for (int i = 0; table[i].name; i ++) if (stricmp(table[i].name, cmd) == 0) diff --git a/source/picasso_frontend.cpp b/source/picasso_frontend.cpp index d951222..2b0ff3c 100644 --- a/source/picasso_frontend.cpp +++ b/source/picasso_frontend.cpp @@ -36,6 +36,7 @@ int usage(const char* prog) "Options:\n" " -o, --out= Specifies the name of the SHBIN file to generate\n" " -h, --header= Specifies the name of the header file to generate\n" + " -n, --no-nop Disables the automatic insertion of padding NOPs\n" " -v, --version Displays version information\n" , prog); return EXIT_FAILURE; @@ -50,18 +51,20 @@ int main(int argc, char* argv[]) { "out", required_argument, NULL, 'o' }, { "header", required_argument, NULL, 'h' }, { "help", no_argument, NULL, '?' }, + { "no-nop", no_argument, NULL, 'n' }, { "version",no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; int opt, optidx = 0; - while ((opt = getopt_long(argc, argv, "o:h:?v", long_options, &optidx)) != -1) + while ((opt = getopt_long(argc, argv, "o:h:?nv", long_options, &optidx)) != -1) { switch (opt) { case 'o': shbinFile = optarg; break; case 'h': hFile = optarg; break; - case '?': usage(argv[0]); return EXIT_SUCCESS; + case '?': usage(argv[0]); return EXIT_SUCCESS; + case 'n': g_autoNop = false; break; case 'v': printf("%s - Built on %s %s\n", PACKAGE_STRING, __DATE__, __TIME__); return EXIT_SUCCESS; default: return usage(argv[0]); }