From 107598bb02a8f927c4ee9215e187364c47a15146 Mon Sep 17 00:00:00 2001 From: Shawn Quick Date: Mon, 6 Feb 2023 22:27:19 -0800 Subject: [PATCH] working on parameters and options --- .gitignore | 2 - .vscode/launch.json | 1 + CMakeLists.txt | 7 +- Makefile | 7 +- asm.cpp | 153 +++++++++++------ asm.h | 43 ++--- cider.h | 2 +- config.h | 2 +- opcodes.cpp | 3 +- parms.json | 10 +- psuedo.cpp | 406 +++++++++++++++++++++++--------------------- qasm.cpp | 88 +++++----- qasm.h | 6 +- qoptions.cpp | 3 + qoptions.h | 229 ++++++++++++++++++++++++- test.link | 10 ++ test.s | 59 +++++++ util.cpp | 32 +++- util.h | 20 ++- 19 files changed, 740 insertions(+), 343 deletions(-) create mode 100644 test.link create mode 100644 test.s diff --git a/.gitignore b/.gitignore index a3d5d9d..ca50d53 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,6 @@ *.a *.so Finder.Data -test.s -disk_commands.txt .vscode/browse* .vscode/book* diff --git a/.vscode/launch.json b/.vscode/launch.json index 230606d..0dc37ee 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,6 +8,7 @@ // Resolved by CMake Tools: "program": "${command:cmake.launchTargetPath}", "args": [ + " -d -d -d", "${workspaceFolder}/test.s" ], "stopAtEntry": false, diff --git a/CMakeLists.txt b/CMakeLists.txt index 60c37f2..e00f945 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0) -set(CIDER "1") +#set(CIDER "1") #set (CMAKE_C_COMPILER /usr/bin/clang) #set (CMAKE_CXX_COMPILER /usr/bin/clang++) @@ -45,6 +45,8 @@ set(SOURCE ${PROJECT_ROOT}/psuedo.cpp ${PROJECT_ROOT}/qoptions.cpp ${PROJECT_ROOT}/cider.cpp + ${PROJECT_ROOT}/util.cpp + ) #find_package(OpenSSL REQUIRED) @@ -67,7 +69,6 @@ include_directories(BEFORE set (CIDERLIBS "" ) if ( ${CIDER} ) add_definitions(-DCIDERPRESS) -add_definitions(-DAPPVERSION=${APPVERSION}) include_directories(AFTER ${PROJECT_ROOT}/diskimg) add_subdirectory(${PROJECT_ROOT}/libhfs) @@ -81,6 +82,8 @@ find_library(NUFX_LIB libnufx_static.a ${PROJECT_ROOT}/build ) set (CIDERLIBS diskimg_static hfs_static nufx_static ${ZLIB_LIBRARIES}) endif ( ${CIDER} ) +add_definitions(-DAPPVERSION=${APPVERSION}) + add_subdirectory(${PROJECT_ROOT}/libpal) add_executable( ${PROJECT_NAME} ${SOURCE}) diff --git a/Makefile b/Makefile index d8eca69..af25d0d 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,12 @@ debug: -mkdir -p ./build -cd ./build && cmake -DCMAKE_BUILD_TYPE=DEBUG .. && $(MAKE) $S +cider: + -rm -rf ./build + -mkdir -p ./build + -cd ./build && cmake -DCIDER=1 -DCMAKE_BUILD_TYPE=DEBUG .. && $(MAKE) $S + + distclean: clean -rm -rf ./qasmout -rm -rf ./m32out @@ -38,7 +44,6 @@ distclean: clean clean: -rm -rf ./build *.2mg test.bin - depend: -cd ./build && $(MAKE) depend diff --git a/asm.cpp b/asm.cpp index 79347c9..d2adc05 100644 --- a/asm.cpp +++ b/asm.cpp @@ -11,12 +11,12 @@ #define CLASS MerlinLine -CLASS::CLASS() +CLASS::CLASS(ConfigOptions &opt) //: options(opt) { clear(); } -CLASS::CLASS(std::string line) +CLASS::CLASS(std::string line, ConfigOptions &opt) //: options(opt) { clear(); set(line); @@ -28,13 +28,11 @@ void CLASS::setError(uint32_t ecode) errorcode = ecode; } + void CLASS::print(uint32_t lineno) { uint32_t l, i, savpcol, pcol; bool commentprinted = false; - static bool checked = false; - static bool nc1 = false; - bool nc = false; uint8_t commentcol = tabs[2]; uint32_t b = 4; // how many bytes show on the first line @@ -66,27 +64,17 @@ void CLASS::print(uint32_t lineno) flags &= (~FLAG_NOLINEPRINT); } - if (flags & FLAG_NOLINEPRINT) + bool np=(flags & FLAG_NOLINEPRINT); + if (options->isQuiet()) + np=true; + if (options->isList()) + np=false; + + if (np) { return; } - if (!checked) - { - nc1 = getBool("option.nocolor", false); - checked = true; - } - else - { - nc = nc1; - } - - //if ((!isatty(STDOUT_FILENO)) || (merlinerrors)) - if ((!isatty(STDOUT_FILENO)) || (0)) - { - nc = true; - } - - if (!nc) + if (options->useColor()) { if (errorcode > 0) { @@ -156,7 +144,9 @@ void CLASS::print(uint32_t lineno) if (isDebug() > 1) { - pcol += printf("%02X ", addressmode & 0xFF); + //pcol += printf("%02X ", addressmode & 0xFF); + pcol += printf(" %s ", addrtext.c_str()); + } savpcol = pcol; // this is how many bytes are in the side margin @@ -250,7 +240,7 @@ void CLASS::print(uint32_t lineno) } //printf("\n"); - if ((!nc) && (errorcode > 0)) + if ((options->useColor()) && (errorcode > 0)) { SetColor(CL_NORMAL | BG_NORMAL); } @@ -522,7 +512,8 @@ void CLASS::set(std::string line) if (x > 1) { // M32 syntax allows a colon after lable, and it is not part of the lable - if ((syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) + //if ((syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) + if (options->isMerlin32()) { while ((x > 1) && (lable[x - 1] == ':')) { @@ -539,11 +530,11 @@ void CLASS::set(std::string line) #undef CLASS #define CLASS TFileProcessor -CLASS::CLASS() +CLASS::CLASS(ConfigOptions &opt) : options(opt) { int x; errorct = 0; - syntax=SYNTAX_QASM; + //syntax=SYNTAX_QASM; win_columns = -1; win_rows = -1; @@ -562,9 +553,9 @@ CLASS::~CLASS() { } -void CLASS::setSyntax(uint32_t syn) +void CLASS::setProduct(string product) { - syntax=syn; + options.setProduct(product); } void CLASS::errorOut(uint16_t code) @@ -581,7 +572,7 @@ void CLASS::init(void) starttime = GetTickCount(); initialdir = Poco::Path::current(); filecount = 0; - syntax = SYNTAX_QASM; + //syntax = SYNTAX_QASM; //std::string tabstr = getConfig("reformat.tabs", "8,16,32"); std::string tabstr = getConfig("reformat.tabs", "12,24,40,70"); @@ -620,7 +611,10 @@ void CLASS::complete(void) //cout << "Processing Time: " << n - starttime << "ms" << endl; uint64_t x = n - starttime; uint32_t x1 = x & 0xFFFFFFFF; - printf("Elapsed time: %u ms\n", x1); + if ((!getBool("option.quiet",false)) && (isDebug()>0)) + { + printf("Elapsed time: %u ms\n", x1); + } } } @@ -926,11 +920,13 @@ int CLASS::processfile(std::string p, std::string &newfilename) return (res); } +#if 1 #undef CLASS #define CLASS TMerlinConverter -CLASS::CLASS() : TFileProcessor() +CLASS::CLASS(ConfigOptions &opt) : TFileProcessor(opt) { format_flags=CONVERT_TEST; + //options=new ConfigOptions(); } CLASS::~CLASS() { @@ -946,7 +942,7 @@ int CLASS::doline(int lineno, std::string line) { UNUSED(lineno); - MerlinLine l(line); + MerlinLine l(line, options); lines.push_back(l); return 0; } @@ -969,7 +965,8 @@ void CLASS::process(void) for (uint32_t lineno = 0; lineno < ct; lineno++) { - MerlinLine &line = lines.at(lineno); + MerlinLine line = lines.at(lineno); + //printf("line: |%s|\n",line.wholetext.c_str()); orval=0x00; if (flags&CONVERT_HIGH) { @@ -1001,7 +998,14 @@ void CLASS::process(void) t = tabs[2]; if (flags&CONVERT_COMPRESS) { - len += sprintf(&buff[len+tlen]," "); + if (flags&CONVERT_TABS) + { + len += sprintf(&buff[len+tlen],"\t\t\t\t"); + } + else + { + len += sprintf(&buff[len+tlen]," "); + } } else { @@ -1022,7 +1026,14 @@ void CLASS::process(void) { if (flags&CONVERT_COMPRESS) { - len += sprintf(&buff[len+tlen]," "); + if (flags&CONVERT_TABS) + { + len += sprintf(&buff[len+tlen],"\t\t\t"); + } + else + { + len += sprintf(&buff[len+tlen]," "); + } } else { @@ -1039,7 +1050,14 @@ void CLASS::process(void) { if (flags&CONVERT_COMPRESS) { - len += sprintf(&buff[len+tlen]," "); + if (flags&CONVERT_TABS) + { + len += sprintf(&buff[len+tlen],"\t\t\t"); + } + else + { + len += sprintf(&buff[len+tlen]," "); + } } else { @@ -1056,7 +1074,14 @@ void CLASS::process(void) { if (flags&CONVERT_COMPRESS) { - len += sprintf(&buff[len+tlen]," "); + if (flags&CONVERT_TABS) + { + len += sprintf(&buff[len+tlen],"\t\t\t"); + } + else + { + len += sprintf(&buff[len+tlen]," "); + } } else { @@ -1125,8 +1150,11 @@ void CLASS::process(void) buff[idx++]=c|orval; } } + buff[idx]=0; + fprintf(stdout,"%s",buff); +#if 0 FILE *f=NULL; - //string outfile= + f=fopen("./aout.s","w+"); if (f!=NULL) { @@ -1138,18 +1166,20 @@ void CLASS::process(void) { printf("file error\n"); } +#endif } } void CLASS::complete(void) { } +#endif #undef CLASS #define CLASS T65816Asm -CLASS::CLASS() : TFileProcessor() +CLASS::CLASS(ConfigOptions &opt) : TFileProcessor(opt) { lines.clear(); psuedoops = new TPsuedoOp(); @@ -1588,7 +1618,8 @@ int CLASS::callOpCode(std::string op, MerlinLine &line) //line.expr_value = (line.expr_value >> 16) & 0xFFFF; break; case '|': - if (syntax == SYNTAX_MERLIN) + //if (syntax == SYNTAX_MERLIN) + if (options.isMerlin()) { line.setError(errBadLabel); line.expr_value = 0; @@ -1790,6 +1821,7 @@ void CLASS::initpass(void) savepath = getConfig("option.objfile", ""); + //printf("savepath: %s\n",savepath.c_str()); lastcarry = false; relocatable = false; @@ -1847,7 +1879,10 @@ void CLASS::complete(void) std::string currentdir = Poco::Path::current(); savepath = processFilename(savepath, currentdir, 0); - printf("saving to file: %s\n", savepath.c_str()); + if (!options.isQuiet()) + { + printf("saving to file: %s\n", savepath.c_str()); + } std::ofstream f(savepath); @@ -1878,8 +1913,10 @@ void CLASS::complete(void) printf("\nErrors in assembly. Output not SAVED.\n\n"); } } - - printf("\n\nEnd qASM assembly, %d bytes, %u errors, %lu lines, %lu symbols.\n", PC.totalbytes, errorct, lines.size(), symbols.size()); + if ((!options.isQuiet()) || (options.isList())) + { + printf("\n\nEnd qASM assembly, %d bytes, %u errors, %lu lines, %lu symbols.\n", PC.totalbytes, errorct, lines.size(), symbols.size()); + } TFileProcessor::complete(); @@ -1909,10 +1946,17 @@ int CLASS::evaluate(MerlinLine &line, std::string expr, int64_t &value) { if (isDebug() > 2) { - int c = SetColor(CL_RED); + int c; + if (options.useColor()) + { + c = SetColor(CL_RED); + } uint32_t rr = result & 0xFFFFFFFF; printf("eval Error=%d %08X |%s|\n", res, rr, eval.badsymbol.c_str()); - SetColor(c); + if (options.useColor()) + { + SetColor(c); + } } } if (res == 0) @@ -2015,7 +2059,8 @@ int CLASS::getAddrMode(MerlinLine & line) // symbol is defined later, we will generate different // bytes on the next pass - if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) + if (options.isMerlin32()) + //if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) { if (Poco::toUpper(oper) == "A") // check the whole operand, not just the expression { @@ -2281,7 +2326,7 @@ void CLASS::process(void) int x;; char c; char buff[256]; - MerlinLine errLine; + MerlinLine errLine(options); std::string op, realop, operand, ls; pass = 0; @@ -2351,7 +2396,7 @@ void CLASS::process(void) line.linemx = mx; line.bytect = 0; line.showmx = showmx; - line.syntax = syntax; + //line.syntax = syntax; line.merlinerrors = merlinerrors; if ((line.lable != "") && (op != "mac")) @@ -2476,7 +2521,7 @@ void CLASS::process(void) for (uint32_t lc = expand_macro.start; lc < expand_macro.end; lc++) { //printf("pushing %s\n", lines[lc].wholetext.c_str()); - MerlinLine nl(lines[lc].wholetext); // create a new clean line (without errors,data) + MerlinLine nl(lines[lc].wholetext,options); // create a new clean line (without errors,data) expand_macro.lines.push_back(nl); } expand_macro.running = true; @@ -2603,7 +2648,7 @@ int CLASS::doline(int lineno, std::string line) UNUSED(lineno); - MerlinLine l(line); + MerlinLine l(line,options); op = Poco::toLower(l.opcode); if (op == "merlin") @@ -2614,7 +2659,7 @@ int CLASS::doline(int lineno, std::string line) { syntax = SYNTAX_ORCA; } - l.syntax = syntax; + //l.syntax = syntax; lines.push_back(l); if ((op == "use") || (op == "put")) @@ -2653,7 +2698,7 @@ int CLASS::doline(int lineno, std::string line) #define CLASS T65816Link -CLASS::CLASS() : TFileProcessor() +CLASS::CLASS(ConfigOptions &opt) : TFileProcessor(opt) { } diff --git a/asm.h b/asm.h index ea844bf..36f78e7 100644 --- a/asm.h +++ b/asm.h @@ -5,27 +5,6 @@ // #define OPHANDLER(ACB) std::bind(ACB, this, std::placeholders::_1, std::placeholders::_2) -#define MODE_6502 0 -#define MODE_65C02 1 -#define MODE_65816 2 - -#define SYNTAX_MERLIN 0x01 -#define SYNTAX_MERLIN32 0x02 -#define SYNTAX_APW 0x04 -#define SYNTAX_MPW 0x08 -#define SYNTAX_ORCA 0x10 -#define SYNTAX_CC65 0x20 -#define SYNTAX_LISA 0x40 - -#define SYNTAX_QASM (0x80 | SYNTAX_MERLIN) -#define OPTION_ALLOW_A_OPERAND 0x0100 -#define OPTION_ALLOW_LOCAL 0x0200 -#define OPTION_ALLOW_COLON 0x0400 -#define OPTION_FORCE_REPSEP 0x0800 -#define OPTION_NO_REPSEP 0x1000 -#define OPTION_CFG_REPSEP 0x2000 -#define OPTION_M32_VARS 0x4000 -#define OPTION_M16_PLUS 0x8000 #define FLAG_FORCELONG 0x01 #define FLAG_FORCEABS 0x02 @@ -196,7 +175,8 @@ class MerlinLine { public: - uint32_t syntax; + //uint32_t syntax; + ConfigOptions *options; std::string wholetext; std::string lable; std::string printlable; @@ -233,8 +213,8 @@ public: std::vector outbytes; public: - MerlinLine(); - MerlinLine(std::string line); + MerlinLine(ConfigOptions &opt); + MerlinLine(std::string line, ConfigOptions &opt); void clear(); void set(std::string line); void print(uint32_t lineno); @@ -255,11 +235,12 @@ protected: uint32_t filecount; // how many files have been read in (because of included files from source public: + ConfigOptions &options; uint32_t errorct; std::string filename; uint32_t format_flags; - TFileProcessor(); + TFileProcessor(ConfigOptions &opt); virtual ~TFileProcessor(); virtual std::string processFilename(std::string p, std::string currentdir, int level); virtual int processfile(std::string p, std::string &newfilename); @@ -268,7 +249,7 @@ public: virtual void process(void); virtual void complete(void); virtual void errorOut(uint16_t code); - virtual void setSyntax(uint32_t syn); + virtual void setProduct(string product); }; @@ -277,6 +258,7 @@ public: #define CONVERT_CRLF 0x02 #define CONVERT_COMPRESS 0x04 #define CONVERT_HIGH 0x08 +#define CONVERT_TABS 0x10 #define CONVERT_MERLIN (CONVERT_HIGH|CONVERT_COMPRESS) #define CONVERT_LINUX (CONVERT_LF) #define CONVERT_WINDOWS (CONVERT_CRLF) @@ -284,19 +266,22 @@ public: #define CONVERT_MPW (CONVERT_NONE) #define CONVERT_TEST (CONVERT_COMPRESS|CONVERT_LF) + +#if 1 class TMerlinConverter : public TFileProcessor { protected: std::vector lines; public: - TMerlinConverter(); + TMerlinConverter(ConfigOptions &opt); virtual ~TMerlinConverter(); virtual void init(void); virtual int doline(int lineno, std::string line); virtual void process(void); virtual void complete(void); }; +#endif class TLUPstruct { @@ -466,7 +451,7 @@ public: uint16_t pass; - T65816Asm(); + T65816Asm(ConfigOptions &opt); virtual ~T65816Asm(); virtual void init(void); @@ -527,7 +512,7 @@ public: class T65816Link : public TFileProcessor { public: - T65816Link(); + T65816Link(ConfigOptions &opt); virtual ~T65816Link(); virtual void init(void); virtual int doline(int lineno, std::string line); diff --git a/cider.h b/cider.h index f3bd6d5..e2c1ccb 100644 --- a/cider.h +++ b/cider.h @@ -17,7 +17,7 @@ class CLASS : public TFileProcessor protected: std::vector lines; public: - CLASS(); + CLASS(ConfigOptions &opt); virtual ~CLASS(); int CreateVolume(string OSName, string VolName, uint64_t size, CIDER_VOLFORMAT format); int RunScript(string path); diff --git a/config.h b/config.h index ce82ecb..7314337 100644 --- a/config.h +++ b/config.h @@ -15,7 +15,7 @@ #define NO_TTY_SETUP // help text -#define HELP_USAGE " " +#define HELP_USAGE " file1 " #define HELP_PURPOSE "\nMerlin 8/16(+)/32 Compatible 65816 Development Tool" diff --git a/opcodes.cpp b/opcodes.cpp index 4c2d760..b8486ab 100644 --- a/opcodes.cpp +++ b/opcodes.cpp @@ -202,7 +202,8 @@ int CLASS::doMVN(MerlinLine &line, TSymbol &sym) setOpcode(line, op); // these bytes are the two bank registers - if (((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) && (v<256)) + if (options.isMerlin32() && (v<256)) + //if (((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) && (v<256)) { // merlin32 uses the low byte of the two operands line.outbytes.push_back((v) & 0xFF); diff --git a/parms.json b/parms.json index df3eb64..8d8c0ef 100644 --- a/parms.json +++ b/parms.json @@ -1,7 +1,7 @@ { "version": "1.1", "general": { - "color_output": true, + "nocolor": false, "prefix": [ { "0": "${PWD}" @@ -18,12 +18,12 @@ ] }, "asm": { - "syntax": "merlin16plus", //merlin8, merlin16, merlin16plus,merlin32 + "syntax": "merlin16plus", "cpu": "M6502", "startmx": 3, "listmode": "on", - "casesend": true, - "lst": false, + "casesen": true, + "start_lst": false, "showmx": true, "allowduplicate": true, "trackrep": false, @@ -32,7 +32,7 @@ "allowA": true, "allowLocal": true, "allowColon": true, - "repsep": "force", //force,no,cfg + "repsep": "force", "linebytes": 4, "line2bytes": 8 }, diff --git a/psuedo.cpp b/psuedo.cpp index fdae7e5..60750fd 100644 --- a/psuedo.cpp +++ b/psuedo.cpp @@ -179,31 +179,32 @@ int CLASS::doMAC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) } else // it is EOM or <<< { - while (a.macrostack.size() > 0) + if (a.macrostack.size()>0) { - a.currentmacro.end = line.lineno - 1; - a.currentmacro.len = 0; - if (a.currentmacro.end >= a.currentmacro.start) + while (a.macrostack.size() > 0) { - a.currentmacro.len = a.currentmacro.end - a.currentmacro.start; - //printf("macro len=%d\n",a.currentmacro.len); + a.currentmacro.end = line.lineno - 1; + a.currentmacro.len = 0; + if (a.currentmacro.end >= a.currentmacro.start) + { + a.currentmacro.len = a.currentmacro.end - a.currentmacro.start; + //printf("macro len=%d\n",a.currentmacro.len); + } + a.currentmacro.running = false; + + std::pair p(a.currentmacro.name, a.currentmacro); + //printf("macro insert %s\n",a.currentmacro.name.c_str()); + a.macros.insert(p); + + a.currentmacro = a.macrostack.top(); + a.macrostack.pop(); } - a.currentmacro.running = false; - - std::pair p(a.currentmacro.name, a.currentmacro); - //printf("macro insert %s\n",a.currentmacro.name.c_str()); - a.macros.insert(p); - - a.currentmacro = a.macrostack.top(); - a.macrostack.pop(); } -#if 0 else { err = errUnexpectedOp; goto out; } -#endif } out: if (err) @@ -351,27 +352,27 @@ int CLASS::doDATA(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) const char *ptr = (const char *)op.c_str(); switch (strhash(ptr) ) { - case strhash((const char *)"DA"): - case strhash((const char *)"DW"): - wordsize = 2; - break; - case strhash((const char *)"DDB"): - wordsize = 2; - endian = 1; - break; - case strhash((const char *)"DFB"): - case strhash((const char *)"DB"): - wordsize = 1; - break; - case strhash((const char *)"ADR"): - wordsize = 3; - break; - case strhash((const char *)"ADRL"): - wordsize = 4; - break; - default: - wordsize = 0; - break; + case strhash((const char *)"DA"): + case strhash((const char *)"DW"): + wordsize = 2; + break; + case strhash((const char *)"DDB"): + wordsize = 2; + endian = 1; + break; + case strhash((const char *)"DFB"): + case strhash((const char *)"DB"): + wordsize = 1; + break; + case strhash((const char *)"ADR"): + wordsize = 3; + break; + case strhash((const char *)"ADRL"): + wordsize = 4; + break; + default: + wordsize = 0; + break; } for (auto itr = tok.begin(); itr != tok.end(); ++itr) @@ -666,12 +667,12 @@ int CLASS::doHEX(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) // Got a good char, append to hex string and see if we've got a byte switch (ct) { - case 0: - b = (hv << 4); - break; - case 1: - b |= hv; - break; + case 0: + b = (hv << 4); + break; + case 1: + b |= hv; + break; } ct = (ct + 1) & 0x01; if (!ct) @@ -695,7 +696,8 @@ out: return bytect; } -static int usr_hash(std::string os) { +static int usr_hash(std::string os) +{ int hash = 0; os.resize(4, ' '); @@ -704,7 +706,10 @@ static int usr_hash(std::string os) { hash = (os[0] & 0x1f) << 11; hash |= (os[1] & 0x1f) << 6; hash |= (os[2] & 0x1f) << 1; - if (os[3] == 'L') hash |= 0x01; + if (os[3] == 'L') + { + hash |= 0x01; + } return hash; } @@ -727,34 +732,43 @@ int CLASS::doUSR(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) char c = os.empty() ? 0 : os.front(); - if (c == '$' && os.length() > 1) { + if (c == '$' && os.length() > 1) + { for (uint32_t i = 1; i < os.length(); ++i) { char hv = hexVal(os[i]); - if (hv < 0) { + if (hv < 0) + { line.setError(errIllegalCharOperand); bytect = 0; - goto out; + goto out; } hash <<= 4; hash |= hv; } - } else if ((c == '\'' || c == '\"') && os.front() == os.back() && os.length() == 6) { + } + else if ((c == '\'' || c == '\"') && os.front() == os.back() && os.length() == 6) + { hash = usr_hash(os.substr(1, 4)); - } else if (os.length() > 0 && os.length() <= 4) { + } + else if (os.length() > 0 && os.length() <= 4) + { hash = usr_hash(os); - } else { + } + else + { printf("line.setError(errBadOperand);\n"); line.setError(errBadOperand); bytect = 0; - goto out; + goto out; } - if (a.pass > 0) { - line.outbytes.push_back(hash & 0xff); - line.outbytes.push_back(hash >> 8); + if (a.pass > 0) + { + line.outbytes.push_back(hash & 0xff); + line.outbytes.push_back(hash >> 8); } out: @@ -778,7 +792,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) uint8_t ct = 0; uint8_t delimiter = 0; uint32_t ss = 0; - uint32_t lastdelimidx = 0; + uint32_t lastdelimidx = 0; std::vector bytes; @@ -809,7 +823,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) } bytes.push_back(c); - lastdelimidx = (uint32_t)(bytes.size() - 1); + lastdelimidx = (uint32_t)(bytes.size() - 1); } } @@ -847,12 +861,12 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) // Got a hex char, append to hex string and see if we've got a byte switch (ct) { - case 0: - b = (hv << 4); - break; - case 1: - b |= hv; - break; + case 0: + b = (hv << 4); + break; + case 1: + b |= hv; + break; } ct = (ct + 1) & 0x01; if (!ct) @@ -885,33 +899,33 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) //printf("bytect=%d bytes.size()=%zu\n",bytect,bytes.size()); switch (strhash(ptr) ) { - case strhash((const char *)"STRL"): - addlen = 2; - break; - case strhash((const char *)"STR"): - addlen = 1; - break; - case strhash((const char *)"REV"): - reverse = true; - break; - case strhash((const char *)"FLS"): - andval = (uint8_t)~0xC0; - orval = (uint8_t)0x40; - break; - case strhash((const char *)"INV"): - andval = (uint8_t)~0xC0; - orval = 0x00; - break; - case strhash((const char *)"DCI"): - dci = true; - break; - case strhash((const char *)"ASC"): - break; - default: - line.setError(errBadOpcode); - bytect = 0; - addlen = 0; - break; + case strhash((const char *)"STRL"): + addlen = 2; + break; + case strhash((const char *)"STR"): + addlen = 1; + break; + case strhash((const char *)"REV"): + reverse = true; + break; + case strhash((const char *)"FLS"): + andval = (uint8_t)~0xC0; + orval = (uint8_t)0x40; + break; + case strhash((const char *)"INV"): + andval = (uint8_t)~0xC0; + orval = 0x00; + break; + case strhash((const char *)"DCI"): + dci = true; + break; + case strhash((const char *)"ASC"): + break; + default: + line.setError(errBadOpcode); + bytect = 0; + addlen = 0; + break; } if (a.pass > 0) { @@ -930,7 +944,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) b = bytes[i]; } - b1 = b & 0x7F; + b1 = b & 0x7F; if ((andval != 0xFF) || (orval != 0x00)) { b = b1; @@ -947,17 +961,17 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) // SGQ BUG - Merlin16+ does it like Merlin32 and now does the last // byte not the way merlin816 and earlier do it documented below. // use OPTION_M16_PLUS when implemented. - - //lr - Merlin only toggles the high bit of string chars, not hex values - // 8D,'Hello',8D,'there',8D becomes 8D 48 65 6C 6C 6F 8D 74 68 65 72 E5 - // - // The DCI instruction is documented to work like this on page 108 - // (regardless of how this effects the desired lda, (bpl/bmi) functionality) - // - // I am now checking the delimiter character to determine hi/lo toggle (reversed) - // and am tracking the index to the last delimited character put into 'bytes'. - // This produces the same results as Merlin 16+ in my testing. - if ( firstdelim >= '\'' ) + + //lr - Merlin only toggles the high bit of string chars, not hex values + // 8D,'Hello',8D,'there',8D becomes 8D 48 65 6C 6C 6F 8D 74 68 65 72 E5 + // + // The DCI instruction is documented to work like this on page 108 + // (regardless of how this effects the desired lda, (bpl/bmi) functionality) + // + // I am now checking the delimiter character to determine hi/lo toggle (reversed) + // and am tracking the index to the last delimited character put into 'bytes'. + // This produces the same results as Merlin 16+ in my testing. + if ( firstdelim >= '\'' ) { b |= 0x80; } @@ -982,108 +996,116 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) int CLASS::ProcessOpcode(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) { int res = 0; - std::string s; + std::string s,sp; switch (opinfo.opcode) { - default: - res = -1; // undefined p-op - line.setError(errUnimplemented); - break; - case P_DS: - res = doDS(a, line, opinfo); - break; - case P_PUT: - case P_USE: - // both of these are handled by the input file processor, just allow them to be - // processed with no errors here - break; - case P_DUM: - case P_DEND: - res = doDUM(a, line, opinfo); - line.flags |= FLAG_FORCEADDRPRINT; + default: + res = -1; // undefined p-op + line.setError(errUnimplemented); + break; + case P_DS: + res = doDS(a, line, opinfo); + break; + case P_PUT: + case P_USE: + // both of these are handled by the input file processor, just allow them to be + // processed with no errors here + break; + case P_DUM: + case P_DEND: + res = doDUM(a, line, opinfo); + line.flags |= FLAG_FORCEADDRPRINT; - break; - case P_ORG: - if (line.operand_expr.length() > 0) - { - a.PC.orgsave = a.PC.currentpc; - a.PC.currentpc = line.expr_value; - line.startpc = line.expr_value; - } - else - { - a.PC.currentpc = a.PC.orgsave; - line.startpc = a.PC.orgsave; - } + break; + case P_ORG: + if (line.operand_expr.length() > 0) + { + a.PC.orgsave = a.PC.currentpc; + a.PC.currentpc = line.expr_value; + line.startpc = line.expr_value; + } + else + { + a.PC.currentpc = a.PC.orgsave; + line.startpc = a.PC.orgsave; + } #if 0 - // Merlin32 seems to have a bug where ORG seems like it can only be 16 bits - if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) - { - // so clear the bank word in all variables - a.PC.orgsave &= 0xFFFF; - a.PC.currentpc &= 0xFFFF; - line.startpc &= 0xFFFF; - } + // Merlin32 seems to have a bug where ORG seems like it can only be 16 bits + if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) + { + // so clear the bank word in all variables + a.PC.orgsave &= 0xFFFF; + a.PC.currentpc &= 0xFFFF; + line.startpc &= 0xFFFF; + } #endif - line.flags |= FLAG_FORCEADDRPRINT; - break; - case P_SAV: + line.flags |= FLAG_FORCEADDRPRINT; + break; + case P_SAV: + sp = getConfig("option.objfile", ""); + if (sp=="") + { a.savepath = a.processFilename(line.operand, Poco::Path::current(), 0); - break; - case P_CAS: - s = Poco::toUpper(line.operand); - if (s == "SE") + } + else // if they specified an output name on the command line, use it. + { + a.savepath = sp; + } + break; + case P_CAS: + s = Poco::toUpper(line.operand); + if (s == "SE") + { + a.casesen = true; + } + if (s=="IN") + { + a.casesen=false; + } + res = 0; + break; + case P_MAC: + res = doMAC(a, line, opinfo); + break; + case P_ERR: + if (a.pass > 0) + { + if ((line.expr_value != 0) || (line.eval_result < 0)) { - a.casesen = true; + line.setError(errErrOpcode); + //a.passcomplete=true; // terminate assembly } - if (s=="IN") - { - a.casesen=false; - } - res = 0; - break; - case P_MAC: - res = doMAC(a, line, opinfo); - break; - case P_ERR: - if (a.pass > 0) - { - if ((line.expr_value != 0) || (line.eval_result < 0)) - { - line.setError(errErrOpcode); - //a.passcomplete=true; // terminate assembly - } - } - res = 0; - break; - case P_LST: - res = doLST(a, line, opinfo); - break; - case P_HEX: - res = doHEX(a, line, opinfo); - break; - case P_DATA: - res = doDATA(a, line, opinfo); - break; - case P_LUP: - res = doLUP(a, line, opinfo); - break; - case P_DO: - res = doDO(a, line, opinfo); - break; - case P_TR: - res = doTR(a, line, opinfo); - break; - case P_ASC: - res = doASC(a, line, opinfo); - break; + } + res = 0; + break; + case P_LST: + res = doLST(a, line, opinfo); + break; + case P_HEX: + res = doHEX(a, line, opinfo); + break; + case P_DATA: + res = doDATA(a, line, opinfo); + break; + case P_LUP: + res = doLUP(a, line, opinfo); + break; + case P_DO: + res = doDO(a, line, opinfo); + break; + case P_TR: + res = doTR(a, line, opinfo); + break; + case P_ASC: + res = doASC(a, line, opinfo); + break; - case P_USR: - res = doUSR(a, line, opinfo); - break; + case P_USR: + res = doUSR(a, line, opinfo); + break; } return (res); diff --git a/qasm.cpp b/qasm.cpp index 32d21b7..b23d399 100644 --- a/qasm.cpp +++ b/qasm.cpp @@ -6,7 +6,6 @@ #define CLASS PAL_APPCLASS - // return a pointer to the actual Application class PAL_BASEAPP *PAL::appFactory(void) { @@ -21,8 +20,16 @@ programOption PAL::appOptions[] = #endif //{ "config", "f", "load configuration data from a ", "", false, false}, { "exec", "x", "execute a command [asm, link, format, script] default=asm", "", false, false}, - { "objfile", "o", "write output to file", "", false, false}, - { "syntax", "s", "enforce syntax of other assembler [qasm, merlin, merlin32, ORCA, APW, MPW, CC65]", "", false, false}, + { "objfile", "o", "write output to ", "", false, false}, + { "instruction", "i", "force the CPU instruction set ('xc' ingored) [6502, 65C02, 65816]", "", false, false}, + + { "type", "t", "enforce syntax/features/bugs of other assembler [qasm, merlin8, merlin16, merlin16plus, merlin32, orca, apw, mpw, lisa, ca65]", "", false, false}, + { "quiet", "q", "print as little as possible, equivalent to lst off in the assembler ('lst' opcodes will be ignored)", "", false, true}, + { "list", "l", "force assembly listing ('lst' opcodes will be ignored)", "", false, true}, + + { "color", "c", "colorize the output", "", false, true}, + { "parms", "p", "show the working parameters/options", "", false, true}, + { "", "", "", "", false, false} @@ -75,62 +82,49 @@ int CLASS::runCommandLineApp(void) TFileProcessor *t = NULL; std::string line; std::string startdirectory; + std::string appPath; std::string fname; - uint32_t syntax; + //uint32_t syntax; + string product=""; + string syn; int res = -1; + ConfigOptions options; +//Poco::Util::Application::instance().config() + + utils=new QUtils(); + + //LOG_NOTE << "this is it!" << endl; startdirectory = Poco::Path::current(); - + appPath=utils->getAppPath(); if (commandargs.size() == 0) { displayHelp(); return (res); } - options.ReadFile(startdirectory+"/parms.json"); + options.ReadFile(Poco::Path::config()+"/parms.json"); + options.ReadFile(appPath+"/parms.json"); + options.ReadFile(Poco::Path::configHome()+"/parms.json"); + options.ReadFile(Poco::Path::current()+"/parms.json"); - string syn=options.GetString("assembler.syntax","QASM"); + syn="QASM"; + //syn=options.GetString("assembler.syntax","QASM"); - string cmdsyn = Poco::toUpper(getConfig("option.syntax", "")); + string cmdsyn = Poco::toUpper(getConfig("option.type", "")); if (cmdsyn!="") { syn=cmdsyn; // if they overrode the syntax on the command line, use it } syn=Poco::toUpper(syn); - syn=Poco::trim(syn); - syntax=SYNTAX_QASM; - if ((syn=="MERLIN") || (syn=="MERLIN16") || (syn=="MERLIN8") || (syn=="MERLIN16PLUS")) - { - syntax=SYNTAX_MERLIN; - } - else if (syn=="MERLIN32") - { - syntax=SYNTAX_MERLIN32; - } - else if (syn=="QASM") - { - syntax=SYNTAX_QASM; - } - else if (syn=="APW") - { - syntax=SYNTAX_APW; - } - else if (syn=="ORCA") - { - syntax=SYNTAX_ORCA; - } - else if (syn=="MPW") - { - syntax=SYNTAX_MPW; - } - else if (syn=="CC65") - { - syntax=SYNTAX_CC65; - } + product=Poco::trim(syn); - //printf("SYNTAX: |%s|\n",syn.c_str()); + if (isDebug()>0) + { + printf("SYNTAX: |%s|\n",syn.c_str()); + } try { @@ -196,7 +190,7 @@ int CLASS::runCommandLineApp(void) { format_flags=CONVERT_TEST; } - + options.format_flags=format_flags; cmd=toks[0]; } } @@ -205,13 +199,14 @@ int CLASS::runCommandLineApp(void) if (cmd == "FORMAT") { res = 0; - t = new TMerlinConverter(); + t = new TMerlinConverter(options); + //t=NULL; if (t != NULL) { try { t->init(); - t->setSyntax(syntax); + t->setProduct(product); t->format_flags=format_flags; std::string f = path.toString(); @@ -239,13 +234,14 @@ int CLASS::runCommandLineApp(void) else if (cmd == "ASM") { int x; - t = new T65816Asm(); + t = new T65816Asm(options); if (t != NULL) { try { t->init(); - t->setSyntax(syntax); + t->setProduct(product); + std::string f = path.toString(); t->filename = f; @@ -275,13 +271,13 @@ int CLASS::runCommandLineApp(void) else if (cmd == "SCRIPT") { res = 0; - t = new CiderPress(); + t = new CiderPress(options); if (t!=NULL) { try { t->init(); - t->setSyntax(syntax); + t->setProduct(product); std::string f = path.toString(); t->filename = f; diff --git a/qasm.h b/qasm.h index b26efb3..96a0eba 100644 --- a/qasm.h +++ b/qasm.h @@ -5,6 +5,7 @@ #include #include #include +#include "app.h" #include "qoptions.h" #include "util.h" //#include @@ -27,7 +28,10 @@ protected: virtual void displayVersion(); public: - QOptions options; + QOptions options; + }; +extern PAL_LOGGER logger; + #undef CLASS diff --git a/qoptions.cpp b/qoptions.cpp index ef136b3..4c4851b 100644 --- a/qoptions.cpp +++ b/qoptions.cpp @@ -9,6 +9,7 @@ CLASS::CLASS() jsonin=""; jsonobj=NULL; parser.reset(); + parser.setAllowComments(true); } int CLASS::ReadFile(string path) @@ -17,6 +18,8 @@ int CLASS::ReadFile(string path) Poco::FileInputStream fs(path); Poco::StreamCopier::copyToString(fs,jsonin); + parser.reset(); + parser.setAllowComments(true); jsonobj=parser.parse(jsonin); config.load(path); diff --git a/qoptions.h b/qoptions.h index dba7d09..36a91ab 100644 --- a/qoptions.h +++ b/qoptions.h @@ -1,12 +1,237 @@ #pragma once -#include "app.h" +#include "qasm.h" +#define MAX_PREFIX 32 + +#define MODE_6502 0 +#define MODE_65C02 1 +#define MODE_65816 2 + +#define SYNTAX_MERLIN 0x01 +#define SYNTAX_MERLIN32 0x02 +#define SYNTAX_APW 0x04 +#define SYNTAX_MPW 0x08 +#define SYNTAX_ORCA 0x10 +#define SYNTAX_CC65 0x20 +#define SYNTAX_LISA 0x40 +#define SYNTAX_QASM (0x80 | SYNTAX_MERLIN) + +#define OPTION_ALLOW_A_OPERAND 0x0100 +#define OPTION_ALLOW_LOCAL 0x0200 +#define OPTION_ALLOW_COLON 0x0400 +#define OPTION_FORCE_REPSEP 0x0800 +#define OPTION_NO_REPSEP 0x1000 +#define OPTION_CFG_REPSEP 0x2000 +#define OPTION_M32_VARS 0x4000 +#define OPTION_M16_PLUS 0x8000 + + +#undef CLASS +#define CLASS ConfigOptions +class CLASS +{ +protected: + vector> configs; + +public: + Poco::JSON::Parser parser; + string jsonin; + Dynamic::Var jsonobj=NULL; + uint16_t format_flags; + + uint16_t cpu_mode; + string product; + uint16_t productlevel; + string prefixes[MAX_PREFIX]; + + uint8_t start_mx; + bool start_listmode; + bool listmode; + + bool casesen; + bool showmx; + bool allowDuplicate; + bool trackrep; + bool merlinerrors; + bool m32vars; + bool allowA; + bool allowLocal; + bool allowColon; + bool oldevaluation; + int16_t linebytes; + int16_t overflowbytes; + + //Poco::Util::LayeredConfiguration config; + + bool usecolor; + + CLASS() + { + setDefaults(); + setProduct("QASM"); + } + ~CLASS() + { + + } + + void clear() + { + //configs.clear(); + } + + bool useColor(void) + { + bool res=false; + if (getBool("option.color",false)) + { + res=true; + } + if ((!isatty(STDOUT_FILENO)) || (0)) + { + res=false; + } + + return(res); + } + bool isQuiet(void) + { + bool res; + res=getBool("option.quiet",false); + if (isDebug()>0) + { + res=false; + } + return(res); + } + bool isList(void) + { + bool res; + res=getBool("option.list",false); + return(res); + } + + int ReadFile(string path) + { + int ret=-1; + Poco::Util::JSONConfiguration *jc; + + Poco::Path pp(path); + //pp=pp.expand(); + Poco::File pf(pp); + if (isDebug()>1) + { + printf("parmsfile: %s\n",pp.toString().c_str()); + } + if ((pf.exists()) && (pf.canRead()) && ((pf.isFile()) || (pf.isLink()))) + { + //printf("OK: %s\n",pp.toString().c_str()); + + jc=new Poco::Util::JSONConfiguration(); + //Poco::FileInputStream fs(path); + //Poco::StreamCopier::copyToString(fs,jsonin); + //parser.reset(); + //parser.setAllowComments(true); + //jsonobj=parser.parse(jsonin); + if (jc!=NULL) + { + bool success=false; + try + { + jc->load(pp.toString()); + success=true; + } + catch(...) + { + success=false; + } + if (success) + { + //configs.push_back(shared_ptr(jc)); + ret=0; + } + else + { + printf("unable to load/parts file: %s\n",pp.toString().c_str()); + } + } + } + return(ret); + } + + void printCurrentOptions(void) + { + printf("Current Options:"); + printf(" product: %s\n",product.c_str()); + //printf(" start_mx: \%%02d\n",start_mx); + } + + bool isMerlin32(void) + { + return(true); + } + + bool isMerlin(void) + { + return(false); + } + + void setDefaults(void) + { + cpu_mode=MODE_6502; + product="QASM"; + productlevel=0; + for (int i=0; i +#define UTIL_CPP +#include -bool isMerlin32(void) +#undef CLASS +#define CLASS QUtils + +CLASS::CLASS() : appInstance(Poco::Util::Application::instance()) +{ +} + +bool CLASS::isMerlin32(void) { return(false); } -bool isMerlin816(void) +bool CLASS::isMerlin816(void) { return(true); } +string CLASS::getAppPath() +{ + char buff[PATH_MAX+1]; + char *x; + + string res=""; + res=appInstance.commandPath(); + x=realpath(res.c_str(),buff); + if (x!=NULL) + { + res=buff; + } + else + res=""; + return(res); +} + + diff --git a/util.h b/util.h index 691941d..c22d584 100644 --- a/util.h +++ b/util.h @@ -1,5 +1,19 @@ #pragma once -#include +#include -bool isMerlin32(void); -bool isMerlin816(void); \ No newline at end of file +class QUtils +{ +protected: + Poco::Util::Application &appInstance; +public: + QUtils(); + bool isMerlin32(void); + bool isMerlin816(void); + string getAppPath(); +}; + +#ifdef UTIL_CPP +QUtils *utils=NULL; +#else +extern QUtils *utils; +#endif