From c6e95b938281e73ae9999786964f12405db49186 Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Tue, 4 Feb 2020 20:27:51 +0100 Subject: [PATCH] added floating point constants generator --- Makefile | 21 ++-- src/generate_constants.cc | 222 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 src/generate_constants.cc diff --git a/Makefile b/Makefile index d3f98316..ca6fc45f 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ SRC_TOOLS = $(wildcard src/tools/*.c,src/tools/*.cc) # Generated files -GEN_BASIC = build/,generated/packed_messages.s +GEN_BASIC = build/,generated/packed_messages.s build/,generated/float_constants.s GEN_KERNAL = # List of build directories @@ -70,13 +70,14 @@ DEP_KERNAL = $(SRC_KERNAL) $(SRCDIR_KERNAL) $(GEN_KERNAL) # List of tools -TOOL_COLLECT_DATA = build/tools/collect_data -TOOL_COMPRESS_TEXT = build/tools/compress_text -TOOL_PNGPREPARE = build/tools/pngprepare -TOOL_BUILD_SEGMENT = build/tools/build_segment -TOOL_RELEASE = build/tools/release -TOOL_SIMILARITY = build/tools/similarity -TOOL_ASSEMBLER = assembler/KickAss.jar +TOOL_COLLECT_DATA = build/tools/collect_data +TOOL_COMPRESS_TEXT = build/tools/compress_text +TOOL_GENERATE_CONSTANTS = build/tools/generate_constants +TOOL_PNGPREPARE = build/tools/pngprepare +TOOL_BUILD_SEGMENT = build/tools/build_segment +TOOL_RELEASE = build/tools/release +TOOL_SIMILARITY = build/tools/similarity +TOOL_ASSEMBLER = assembler/KickAss.jar TOOLS_LIST = $(pathsubst src/tools/%,build/tools/%,$(basename $(SRC_TOOLS))) @@ -212,6 +213,10 @@ build/,generated/packed_messages.s: $(TOOL_COMPRESS_TEXT) @mkdir -p build/,generated $(TOOL_COMPRESS_TEXT) > build/,generated/packed_messages.s +build/,generated/float_constants.s: $(TOOL_GENERATE_CONSTANTS) + @mkdir -p build/,generated + $(TOOL_GENERATE_CONSTANTS) -o build/,generated/float_constants.s + .PRECIOUS: build/target_%/OUTB_X.BIN build/target_%/BASIC_combined.vs build/target_%/OUTB_X.BIN build/target_%/BASIC_combined.vs: @mkdir -p build/target_$* diff --git a/src/generate_constants.cc b/src/generate_constants.cc new file mode 100644 index 00000000..e0f12044 --- /dev/null +++ b/src/generate_constants.cc @@ -0,0 +1,222 @@ +// +// Utility to generate various floating points constants +// in a Commodore-specific variable format +// + +#include "common.h" + +#include + +#include +#include +#include +#include +#include + +// +// Basic types definition +// + +typedef struct ConstEntry +{ + ConstEntry(const std::string &constName, double constValue) : + constName(constName), + constValue(constValue), + outString(".error \"not generated\"") + { + }; + + const std::string constName; + const double constValue; + + std::string outString; + +} ConstEntry; + +// +// Constants to output +// + +std::vector GLOBAL_constants = +{ + ConstEntry( "PI", M_PI ), + ConstEntry( "HALF", 0.5 ), + ConstEntry( "1", 1.0 ), + ConstEntry( "10", 10.0 ), +}; + +// +// Command line settings +// + +std::string CMD_outFile = "out.s"; + +// +// Common helper functions +// + +void printUsage() +{ + std::cout << "\n" << + "usage: generate_constants [-o ]" << "\n\n"; +} + +void printBanner() +{ + printBannerLineTop(); + std::cout << "// Generating floating point constants" << "\n"; + printBannerLineBottom(); +} + +// +// Top-level functions +// + +void parseCommandLine(int argc, char **argv) +{ + int opt; + + // Retrieve command line options + + while ((opt = getopt(argc, argv, "o:")) != -1) + { + switch(opt) + { + case 'o': CMD_outFile = optarg; break; + default: printUsage(); ERROR(); + } + } +} + +// +// Constants generation +// + +std::string toAssemblerString(const std::string &constName, double constValue) +{ + uint8_t outFloat[5] = { 0 }; + + // Retrieve mantissa nad exponent + + int exponent = -0x80; + double mantissa = frexp(std::abs(constValue), &exponent); + + // Add a bias to exponent + + exponent += 0x80; + + // Check if output format can contain such a number + + if (exponent > 0xFF) + { + ERROR(std::string("const '") + constName + "' abs value too large"); + } + else if (exponent <= 0) + { + ERROR(std::string("const '") + constName + "' abs value too small"); + } + + // Set output constant exponent + + outFloat[0] = exponent; + + // Set output constant mantissa + + for (uint8_t idxByte = 1; idxByte <= 4; idxByte++) + { + for (uint8_t idxBit = 0; idxBit <= 7; idxBit++) + { + outFloat[idxByte] = outFloat[idxByte] << 1; + if (mantissa >= 0.5) + { + outFloat[idxByte]++; + mantissa -= 0.5; + } + + mantissa *= 2; + } + } + + if (outFloat[1] < 0x80) ERROR(std::string("const '") + constName + "' not normalized"); + + // Set output constant sign + + if (constValue >= 0.0) + { + outFloat[1] = outFloat[1] & 0x7F; + } + + // Return the output constant as string for assembler + + char buf[256] = { 0 }; + snprintf(buf, sizeof(buf), "$%02X, $%02X, $%02X, $%02X, $%02X // %22.10f", + outFloat[0], + outFloat[1], + outFloat[2], + outFloat[3], + outFloat[4], + constValue); + + std::string outDef = std::string("\n.macro putConst_") + constName + "()\n{\n\t.byte " + buf + "\n}\n"; + + return outDef; +} + + +void writeConstants() +{ + // Convert constants to assembler strings + + for (auto &entry : GLOBAL_constants) + { + entry.outString = toAssemblerString(entry.constName, entry.constValue); + } + + // Remove old file + + unlink(CMD_outFile.c_str()); + + // Open output file for writing + + std::ofstream outFile(CMD_outFile, std::fstream::out | std::fstream::trunc); + if (!outFile.good()) ERROR(std::string("can't open oputput file '") + CMD_outFile + "'"); + + // Write header + + outFile << "//\n// Generated file - do not edit\n//\n\n"; + + // Write constants + + for (auto &entry : GLOBAL_constants) + { + outFile << entry.outString; + } + + if (!outFile.good()) + { + outFile.close(); + unlink(CMD_outFile.c_str()); + ERROR(std::string("can't write oputput file '") + CMD_outFile + "'"); + } + + // Close the file + + outFile.close(); + + std::cout << std::string("Constants written to: ") + CMD_outFile + "\n\n"; +} + + +// +// Main function +// + +int main(int argc, char **argv) +{ + parseCommandLine(argc, argv); + + printBanner(); + writeConstants(); + + return 0; +}