From 6a6c3ed1cf6e74fdf0c5fa88344dd9f7eea1011b Mon Sep 17 00:00:00 2001 From: Tobi-D7 Date: Sun, 25 Dec 2022 02:56:46 +0100 Subject: [PATCH] Fix a Big Mistake --- .gitignore | 1 - CMakeLists.txt | 4 +- example/src/main.cpp | 2 +- include/{picasso.hpp => pica.hpp} | 0 include/picasso/FileClass.h | 131 +++++++++++++++ include/picasso/maestro_opcodes.h | 57 +++++++ include/picasso/picasso.h | 256 ++++++++++++++++++++++++++++++ include/picasso/types.h | 68 ++++++++ source/picasso_assembler.cpp | 2 +- 9 files changed, 516 insertions(+), 5 deletions(-) rename include/{picasso.hpp => pica.hpp} (100%) create mode 100644 include/picasso/FileClass.h create mode 100644 include/picasso/maestro_opcodes.h create mode 100644 include/picasso/picasso.h create mode 100644 include/picasso/types.h diff --git a/.gitignore b/.gitignore index 67de2ec..4ef24a1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,5 @@ missing config.log config.status Makefile -picasso .deps/ *.bz2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dfc6d2..8a5a539 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,11 +4,11 @@ project(picasso) set(CMAKE_EXE_LINKER_FLAGS "-L${DEVKITPRO}/libctru/lib -L${DEVKITPRO}/picaGL/lib -L${DEVKITPRO}/portlibs/3ds/lib -specs=3dsx.specs -Wl,--gc-sections") -include_directories(${DEVKITPRO}/libctru/include ${DEVKITPRO}/picaGL/include ${DEVKITPRO}/portlibs/3ds/include) +include_directories(${DEVKITPRO}/libctru/include ${DEVKITPRO}/picaGL/include ${DEVKITPRO}/portlibs/3ds/include ${CMAKE_SOURCE_DIR}/include) add_definitions("-D__3DS__") enable_language(ASM) add_library(${PROJECT_NAME} STATIC source/picasso_assembler.cpp source/picasso_library.cpp) -target_include_directories(${PROJECT_NAME} PRIVATE include) \ No newline at end of file +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/include) \ No newline at end of file diff --git a/example/src/main.cpp b/example/src/main.cpp index 6b0a253..5fae605 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -1,7 +1,7 @@ #include <3ds.h> #include -#include +#include static const char *const vertShader = R"text( ; Example PICA200 vertex shader diff --git a/include/picasso.hpp b/include/pica.hpp similarity index 100% rename from include/picasso.hpp rename to include/pica.hpp diff --git a/include/picasso/FileClass.h b/include/picasso/FileClass.h new file mode 100644 index 0000000..6576fe0 --- /dev/null +++ b/include/picasso/FileClass.h @@ -0,0 +1,131 @@ +#pragma once +#include +#include "picasso/types.h" +#include +#include + +class FileClass +{ + std::stringstream f; + bool LittleEndian, own; + int filePos; + + size_t _RawRead(void* buffer, size_t size) + { + f.read((char*)buffer, size); + filePos += size; + return size; + } + + size_t _RawWrite(const void* buffer, size_t size) + { + f.write((const char*)buffer, size); + filePos += size; + return size; + } + +public: + FileClass(const char* file, const char* mode) : LittleEndian(true), own(true), filePos(0) + { + //Do nothing + } + ~FileClass() + { + //Do nothing + } + + void SetLittleEndian() { LittleEndian = true; } + void SetBigEndian() { LittleEndian = false; } + + std::stringstream* get_ptr() { return &f; } + bool openerror() { return false; } + + dword_t ReadDword() + { + dword_t value; + _RawRead(&value, sizeof(dword_t)); + return LittleEndian ? le_dword(value) : be_dword(value); + } + + void WriteDword(dword_t value) + { + value = LittleEndian ? le_dword(value) : be_dword(value); + _RawWrite(&value, sizeof(dword_t)); + } + + word_t ReadWord() + { + word_t value; + _RawRead(&value, sizeof(word_t)); + return LittleEndian ? le_word(value) : be_word(value); + } + + void WriteWord(word_t value) + { + value = LittleEndian ? le_word(value) : be_word(value); + _RawWrite(&value, sizeof(word_t)); + } + + hword_t ReadHword() + { + hword_t value; + _RawRead(&value, sizeof(hword_t)); + return LittleEndian ? le_hword(value) : be_hword(value); + } + + void WriteHword(hword_t value) + { + value = LittleEndian ? le_hword(value) : be_hword(value); + _RawWrite(&value, sizeof(hword_t)); + } + + byte_t ReadByte() + { + byte_t value; + _RawRead(&value, sizeof(byte_t)); + return value; + } + + void WriteByte(byte_t value) + { + _RawWrite(&value, sizeof(byte_t)); + } + + float ReadFloat() + { + union { word_t w; float f; } t; + t.w = ReadWord(); + return t.f; + } + + void WriteFloat(float value) + { + union { word_t w; float f; } t; + t.f = value; + WriteWord(t.w); + } + + bool ReadRaw(void* buffer, size_t size) { return _RawRead(buffer, size) == size; } + bool WriteRaw(const void* buffer, size_t size) { return _RawWrite(buffer, size) == size; } + + int Tell() { return filePos /*ftell(f)*/; } +}; + +static inline char* StringFromFile(const char* filename) +{ + FILE* f = fopen(filename, "rb"); + if (!f) return NULL; + fseek(f, 0, SEEK_END); + int size = ftell(f); + rewind(f); + char* buf = (char*)malloc(size+1); + if (!buf) + { + fclose(f); + return NULL; + } + fread(buf, 1, size, f); + buf[size] = 0; + fclose(f); + return buf; +} \ No newline at end of file diff --git a/include/picasso/maestro_opcodes.h b/include/picasso/maestro_opcodes.h new file mode 100644 index 0000000..928fb74 --- /dev/null +++ b/include/picasso/maestro_opcodes.h @@ -0,0 +1,57 @@ +#pragma once +enum +{ + MAESTRO_ADD = 0x00, + MAESTRO_DP3, + MAESTRO_DP4, + MAESTRO_DPH, + MAESTRO_DST, + MAESTRO_EX2, + MAESTRO_LG2, + MAESTRO_LITP, + MAESTRO_MUL, + MAESTRO_SGE, + MAESTRO_SLT, + MAESTRO_FLR, + MAESTRO_MAX, + MAESTRO_MIN, + MAESTRO_RCP, + MAESTRO_RSQ, + + MAESTRO_unk10, + MAESTRO_unk11, + MAESTRO_MOVA, + MAESTRO_MOV, + MAESTRO_unk14, + MAESTRO_unk15, + MAESTRO_unk16, + MAESTRO_unk17, + MAESTRO_DPHI, + MAESTRO_DSTI, + MAESTRO_SGEI, + MAESTRO_SLTI, + MAESTRO_unk1C, + MAESTRO_unk1D, + MAESTRO_unk1E, + MAESTRO_unk1F, + + MAESTRO_BREAK, + MAESTRO_NOP, + MAESTRO_END, + MAESTRO_BREAKC, + MAESTRO_CALL, + MAESTRO_CALLC, + MAESTRO_CALLU, + MAESTRO_IFU, + MAESTRO_IFC, + MAESTRO_FOR, + MAESTRO_EMIT, // Geometry shader related + MAESTRO_SETEMIT, // Geometry shader related + MAESTRO_JMPC, + MAESTRO_JMPU, + MAESTRO_CMP, // only the upper 5 bits are used for the opcode + + // Only the upper 3 bits are used for the following opcodes + MAESTRO_MADI = 0x30, + MAESTRO_MAD = 0x38, +}; \ No newline at end of file diff --git a/include/picasso/picasso.h b/include/picasso/picasso.h new file mode 100644 index 0000000..0c00a08 --- /dev/null +++ b/include/picasso/picasso.h @@ -0,0 +1,256 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#endif +#include "types.h" + +#include +#include +#include +#include +#include + +#include "picasso/FileClass.h" + +#include "picasso/maestro_opcodes.h" + +#if !defined(WIN32) && !defined(stricmp) +#define stricmp strcasecmp +#endif + +enum +{ + COMP_X = 0, + COMP_Y, + COMP_Z, + COMP_W, +}; + +#define SWIZZLE_COMP(n,v) ((v) << (6-(n)*2)) +#define OPSRC_MAKE(neg, sw) ((neg) | ((sw) << 1)) +#define OPDESC_MAKE(out, src1, src2, src3) ((out) | ((src1) << 4) | ((src2) << (4+9)) | ((src3) << (4+9*2))) +#define FMT_OPCODE(n) ((n)<<26) +#define OUTPUT_MAKE(i, reg, mask) ((i) | ((reg)<<16) | ((u64)(mask)<<32)) + +#define DEFAULT_SWIZZLE (SWIZZLE_COMP(0,COMP_X) | SWIZZLE_COMP(1,COMP_Y) | SWIZZLE_COMP(2,COMP_Z) | SWIZZLE_COMP(3,COMP_W)) +#define DEFAULT_OPSRC OPSRC_MAKE(0, DEFAULT_SWIZZLE) + +#define OPDESC_MASK_D123 OPDESC_MAKE(0xF, 0x1FF, 0x1FF, 0x1FF) +#define OPDESC_MASK_D12 OPDESC_MAKE(0xF, 0x1FF, 0x1FF, 0) +#define OPDESC_MASK_D1 OPDESC_MAKE(0xF, 0x1FF, 0, 0) +#define OPDESC_MASK_1 OPDESC_MAKE(0, 0x1FF, 0, 0) +#define OPDESC_MASK_12 OPDESC_MAKE(0, 0x1FF, 0x1FF, 0) + +enum +{ + COND_EQ = 0, + COND_NE, + COND_LT, + COND_LE, + COND_GT, + COND_GE, +}; + +//----------------------------------------------------------------------------- +// Global data +//----------------------------------------------------------------------------- + +// Output buffer +#define MAX_VSH_SIZE 512 +typedef std::vector outputBufType; +typedef outputBufType::iterator outputBufIter; +extern outputBufType g_outputBuf; + +enum +{ + SE_PROC, + SE_FOR, + SE_IF, + SE_ARRAY, +}; + +struct StackEntry +{ + int type; + size_t pos; + union + { + const char* strExtra; + size_t uExtra; + }; +}; + +// Stack used to keep track of stuff. +#define MAX_STACK 32 +extern StackEntry g_stack[MAX_STACK]; +extern int g_stackPos; + +// Operand descriptor stuff. +#define MAX_OPDESC 128 +extern int g_opdescTable[MAX_OPDESC]; +extern int g_opdeskMasks[MAX_OPDESC]; // used to keep track of used bits +extern int g_opdescCount; + +enum +{ + UTYPE_BOOL = 0, + UTYPE_IVEC, + UTYPE_FVEC, +}; + +struct Uniform +{ + std::string name; + int pos, size; + int type; + + inline bool operator <(const Uniform& rhs) const + { + return pos < rhs.pos; + } + + void init(const char* name, int pos, int size, int type) + { + this->name = name; + this->pos = pos; + this->size = size; + this->type = type; + } +}; + +// List of uniforms +#define MAX_UNIFORM 0x60 +extern Uniform g_uniformTable[MAX_UNIFORM]; +extern int g_uniformCount; + +struct DVLEData; // Forward declaration + +typedef std::pair procedure; // position, size +typedef std::pair relocation; // position, name + +typedef std::map procTableType; +typedef std::map labelTableType; +typedef std::map aliasTableType; +typedef std::vector relocTableType; +typedef std::list dvleTableType; + +typedef procTableType::iterator procTableIter; +typedef labelTableType::iterator labelTableIter; +typedef aliasTableType::iterator aliasTableIter; +typedef relocTableType::iterator relocTableIter; +typedef dvleTableType::iterator dvleTableIter; + +extern procTableType g_procTable; +extern dvleTableType g_dvleTable; +extern relocTableType g_procRelocTable; +extern int g_totalDvleCount; + +// The following are cleared before each file is processed +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); + +//----------------------------------------------------------------------------- +// Local data +//----------------------------------------------------------------------------- + +enum +{ + OUTTYPE_POS = 0, + OUTTYPE_NQUAT = 1, + OUTTYPE_CLR = 2, + OUTTYPE_TCOORD0 = 3, + OUTTYPE_TCOORD0W = 4, + OUTTYPE_TCOORD1 = 5, + OUTTYPE_TCOORD2 = 6, + OUTTYPE_VIEW = 8, + OUTTYPE_DUMMY = 9, +}; + +enum +{ + GSHTYPE_POINT = 0, + GSHTYPE_VARIABLE = 1, + GSHTYPE_FIXED = 2, +}; + +struct Constant +{ + int regId; + int type; + union + { + float fparam[4]; + u8 iparam[4]; + bool bparam; + }; +}; + +struct DVLEData +{ + // General config + std::string filename; + std::string entrypoint; + size_t entryStart, entryEnd; + bool nodvle, isGeoShader, isCompatGeoShader, isMerge; + u16 inputMask, outputMask; + u8 geoShaderType; + u8 geoShaderFixedStart; + u8 geoShaderVariableNum; + u8 geoShaderFixedNum; + + // Uniforms + Uniform uniformTable[MAX_UNIFORM]; + int uniformCount; + size_t symbolSize; + + // Constants + #define MAX_CONSTANT 0x60 + Constant constantTable[MAX_CONSTANT]; + int constantCount; + + // Outputs + #define MAX_OUTPUT 16 + u64 outputTable[MAX_OUTPUT]; + u32 outputUsedReg; + int outputCount; + + bool usesGshSpace() const { return isGeoShader && !isCompatGeoShader; } + int findFreeOutput() const + { + for (int i = 0; i < maxOutputReg(); i ++) + if (!(outputMask & BIT(i))) + return i; + return -1; + } + + int findFreeInput() const + { + for (int i = 0; i < 16; i ++) + if (!(inputMask & BIT(i))) + return i; + return -1; + } + + int maxOutputReg() const + { + return isGeoShader ? 0x07 : 0x10; + } + + DVLEData(const char* filename) : + filename(filename), entrypoint("main"), + nodvle(false), isGeoShader(false), isCompatGeoShader(false), isMerge(false), + inputMask(0), outputMask(0), geoShaderType(0), geoShaderFixedStart(0), geoShaderVariableNum(0), geoShaderFixedNum(0), + uniformCount(0), symbolSize(0), constantCount(0), outputUsedReg(0), outputCount(0) { } +}; \ No newline at end of file diff --git a/include/picasso/types.h b/include/picasso/types.h new file mode 100644 index 0000000..b4e06c1 --- /dev/null +++ b/include/picasso/types.h @@ -0,0 +1,68 @@ +#pragma once +#include + +typedef uint64_t dword_t; +typedef uint32_t word_t; +typedef uint16_t hword_t; +typedef uint8_t byte_t; +typedef int64_t dlong_t; +typedef int32_t long_t; +typedef int16_t short_t; +typedef int8_t char_t; +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +#define BIT(n) (1U << (n)) + +#ifndef __BYTE_ORDER__ +#include +#define __BYTE_ORDER__ BYTE_ORDER +#define __ORDER_LITTLE_ENDIAN__ LITTLE_ENDIAN +#define __ORDER_BIG_ENDIAN__ BIG_ENDIAN +#endif + +#ifndef __llvm__ +#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) + +static inline uint16_t __builtin_bswap16(uint16_t x) +{ + return ((x << 8) & 0xff00) | ((x >> 8) & 0x00ff); +} + +#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 7) +static inline uint32_t __builtin_bswap32(uint32_t x) +{ + return ((x << 24) & 0xff000000) | + ((x << 8) & 0x00ff0000) | + ((x >> 8) & 0x0000ff00) | + ((x >> 24) & 0x000000ff); +} + +static inline uint64_t __builtin_bswap64(uint64_t x) +{ + return (uint64_t)__builtin_bswap32(x>>32) | + ((uint64_t)__builtin_bswap32(x&0xFFFFFFFF) << 32); +} +#endif +#endif +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define be_dword(a) __builtin_bswap64(a) +#define be_word(a) __builtin_bswap32(a) +#define be_hword(a) __builtin_bswap16(a) +#define le_dword(a) (a) +#define le_word(a) (a) +#define le_hword(a) (a) +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define be_dword(a) (a) +#define be_word(a) (a) +#define be_hword(a) (a) +#define le_dword(a) __builtin_bswap64(a) +#define le_word(a) __builtin_bswap32(a) +#define le_hword(a) __builtin_bswap16(a) +#else +#error "What's the endianness of the platform you're targeting?" +#endif \ No newline at end of file diff --git a/source/picasso_assembler.cpp b/source/picasso_assembler.cpp index 250cbec..198b457 100644 --- a/source/picasso_assembler.cpp +++ b/source/picasso_assembler.cpp @@ -1,4 +1,4 @@ -#include +#include "picasso/picasso.h" //#define DEBUG #define BUF g_outputBuf