diff --git a/asm.cpp b/asm.cpp index ef1afe0..b480bcb 100644 --- a/asm.cpp +++ b/asm.cpp @@ -34,8 +34,6 @@ void CLASS::print(uint32_t lineno) uint32_t b = 4; // how many bytes show on the first line - bool merlinstyle = true; - if (datafillct > 0) { l = datafillct; @@ -50,7 +48,7 @@ void CLASS::print(uint32_t lineno) } if (errorcode > 0) { - if (merlinstyle) + if (merlinerrors) { //printf("errorcode=%d\n",errorcode); printf("\n%s in line: %d", errStrings[errorcode].c_str(), lineno + 1); @@ -77,7 +75,7 @@ void CLASS::print(uint32_t lineno) nc = nc1; } - if ((!isatty(STDOUT_FILENO)) || (merlinstyle)) + if ((!isatty(STDOUT_FILENO)) || (merlinerrors)) { nc = true; } @@ -207,7 +205,7 @@ void CLASS::print(uint32_t lineno) pcol += printf("%s ", operand.c_str()); //pcol += printf("%-12s %-8s %-10s ", printlable.c_str(), opcode.c_str(), operand.c_str()); } - if ((errorcode > 0) && (!merlinstyle)) + if ((errorcode > 0) && (!merlinerrors)) { while (pcol < commentcol) { @@ -293,6 +291,7 @@ void CLASS::clear() operand_expr = ""; operand_expr2 = ""; addrtext = ""; + merlinerrors = false; linemx = 0; bytect = 0; opflags = 0; @@ -377,10 +376,12 @@ void CLASS::set(std::string line) } break; case 3: + { if (c > ' ') { opcode += c; } +#if 1 else { // SGQ @@ -418,7 +419,41 @@ void CLASS::set(std::string line) state = 4; } - break; +#else + else + { + // SGQ + // this is bad, but the only way I currently know how to do this. + // the problem is, is that the ASCII generating psuedo-ops in Merlin + // use any char > space and less than apostrophe, and > apostrophe + // as delimiters. + // however, those characters also contain valid opcode expression characters + // so we see a character here, it looks like a delim, and we keep reading to EOL + // which might include a comment. All of that, then goes into the operand, and + // comments cause errors on evaluation. + // So, at this point in the code, we must determine if the opcode is one of our + // ascii psuedo-ops and treat the first char as a delim. + // otherwise, we must parse the operand as an express. + // this parser should know NOTHING about what the code does...but it needs to in + // this case. + + opupper = Poco::toUpper(opcode); + + auto itr = a.opcodes.find(op); + if (itr != a.opcodes.end()) + { + TSymbol s = itr->second; + if (1) + { + isascii = true; + } + } + + state = 4; + } +#endif + } + break; case 4: // read whitespace between opcode and operand if (c == ';') { @@ -987,11 +1022,18 @@ void CLASS::pushopcode(std::string op, uint8_t opcode, uint16_t flags, TOpCallba opcodes.insert(p); } -TSymbol *CLASS::addSymbol(std::string sym, uint32_t val, bool replace) +TSymbol *CLASS::addSymbol(std::string symname, uint32_t val, bool replace) { TSymbol *res = NULL; TSymbol *fnd = NULL; + std::string sym = symname; + if (!casesen) + { + sym = Poco::toUpper(sym); + } + + //printf("addSymbol: |%s|\n",sym.c_str()); if (sym.length() > 0) { TSymbol s; @@ -1002,7 +1044,7 @@ TSymbol *CLASS::addSymbol(std::string sym, uint32_t val, bool replace) s.value = val; s.used = false; s.cb = NULL; - std::pair p(Poco::toUpper(sym), s); + std::pair p(sym, s); if (sym[0] == ':') { @@ -1062,6 +1104,11 @@ TSymbol *CLASS::findSymbol(std::string symname) { TSymbol *res = NULL; + std::string sym = symname; + if (!casesen) + { + sym = Poco::toUpper(sym); + } if (symname.length() > 0) { if (symname[0] == ':') @@ -1072,7 +1119,7 @@ TSymbol *CLASS::findSymbol(std::string symname) } else { - auto itr = currentsym->locals.find(Poco::toUpper(symname)); + auto itr = currentsym->locals.find(sym); if (itr != currentsym->locals.end()) { res = &itr->second; @@ -1083,7 +1130,7 @@ TSymbol *CLASS::findSymbol(std::string symname) else { //printf("finding: %s\n",symname.c_str()); - auto itr = symbols.find(Poco::toUpper(symname)); + auto itr = symbols.find(sym); if (itr != symbols.end()) { //printf("Found: %s 0x%08X\n",itr->second.name.c_str(),itr->second.value); @@ -1096,11 +1143,17 @@ out: return (res); } -TSymbol *CLASS::addVariable(std::string sym, std::string val, bool replace) +TSymbol *CLASS::addVariable(std::string symname, std::string val, bool replace) { TSymbol *res = NULL; TSymbol *fnd = NULL; + std::string sym = symname; + if (!casesen) + { + sym = Poco::toUpper(sym); + } + //printf("addvariable\n"); fnd = findVariable(sym); @@ -1128,7 +1181,7 @@ TSymbol *CLASS::addVariable(std::string sym, std::string val, bool replace) //printf("addvariable: %s %s\n", s.name.c_str(), s.text.c_str()); - std::pair p(Poco::toUpper(sym), s); + std::pair p(sym, s); variables.insert(p); res = findVariable(sym); return (res); @@ -1389,6 +1442,8 @@ void CLASS::initpass(void) casesen = getBool("asm.casesen", true); listing = getBool("asm.lst", true); showmx = getBool("asm.showmx", false); + merlinerrors = getBool("asm.merlinerrors", true); + trackrep = getBool("asm.trackrep", false); merlincompat = getBool("asm.merlincompatible", true); allowdup = getBool("asm.allowduplicate", true); @@ -1427,8 +1482,10 @@ void CLASS::initpass(void) } mx = getInt("asm.startmx", mx);; + savepath = getConfig("option.objfile", ""); + lastcarry = false; relocatable = false; currentsym = &topSymbol; // this is the default symbol for :locals without a global above; currentsymstr = ""; @@ -1485,6 +1542,14 @@ void CLASS::complete(void) f.put(line.outbytes[i]); } } + if ((line.datafillct > 0) && ((line.flags & FLAG_INDUM) == 0)) + { + for (uint32_t i = 0; i < line.datafillct; i++) + { + f.put(line.datafillbyte & 0xFF); + } + + } } } else @@ -1618,6 +1683,35 @@ int CLASS::getAddrMode(MerlinLine & line) if (i > 0) { v = valEx.match(s, 0, 0); + if (v) + { + if (pass == 0) + { + // can only check on pass 0, because if the A" + // symbol is defined later, we will generate different + // bytes on the next pass + + if (Poco::toUpper(oper) == "A") // check the whole operand, not just the expression + { + // SGQ + // Merlin32 supports the 'A" operand for immediate + // mode for opcodes like "ROR A". Problem is, Merlin16 + // does not, and 'A' could be a lable. + TSymbol *sym = findSymbol("A"); + if (sym == NULL) + { + line.flags |= FLAG_FORCEIMPLIED; + mode = syn_implied; // if the label hasn't been defined yet, assume Immediate addressing + goto out; + } + } + } + else if (line.flags & FLAG_FORCEIMPLIED) + { + mode = syn_implied; + goto out; + } + } } } if (!v) @@ -1646,7 +1740,7 @@ int CLASS::getAddrMode(MerlinLine & line) } idx++; } - +out: if (mode == syn_none) { mode = syn_err; @@ -1779,6 +1873,7 @@ void CLASS::process(void) line.linemx = mx; line.bytect = 0; line.showmx = showmx; + line.merlinerrors = merlinerrors; if ((line.lable != "")) { @@ -1828,6 +1923,7 @@ void CLASS::process(void) int64_t value = -1; x = evaluate(line, line.operand_expr, value); + line.eval_result = x; if (x == 0) { value &= 0xFFFFFFFF; diff --git a/asm.h b/asm.h index 27f9de8..cae8a1e 100644 --- a/asm.h +++ b/asm.h @@ -17,9 +17,10 @@ #define FLAG_DP 0x08 #define FLAG_BIGNUM 0x10 #define FLAG_INDUM 0x20 +#define FLAG_FORCEIMPLIED 0x40 #define FLAG_FORCEADDRPRINT 0x0100 -#define FLAG_NOLINEPRINT 0x2000 +#define FLAG_NOLINEPRINT 0x0200 #define OP_A 0x0001 #define OP_XY 0x0002 @@ -189,6 +190,7 @@ public: uint8_t linemx; uint8_t tabs[16]; bool showmx; + bool merlinerrors; uint8_t truncdata; uint32_t lineno; uint32_t flags; @@ -197,7 +199,7 @@ public: uint32_t addressmode; uint32_t expr_value; uint8_t expr_shift; // after an eval, this byte will reflect any shift code on expr (|^<>) - uint32_t eval_result; // this is the error code from the evaluate routing (0 or neg) + int32_t eval_result; // this is the error code from the evaluate routing (0 or neg) uint32_t errorcode; std::string errorText; @@ -334,6 +336,7 @@ public: bool showmx; bool trackrep; bool merlincompat; + bool merlinerrors; bool allowdup; uint8_t mx; uint8_t cpumode; // 0=6502, 1=65C02, 2=65816 @@ -344,6 +347,7 @@ public: uint32_t dumstartaddr; bool skiplist; // used if lst is on, but LST opcode turns it off uint32_t lineno; + bool lastcarry; std::string savepath; TSymbol *currentsym; diff --git a/eval.cpp b/eval.cpp index 8b1d461..ff7be25 100644 --- a/eval.cpp +++ b/eval.cpp @@ -27,16 +27,18 @@ std::deque CLASS::exprToTokens(const std::string& expr) int state = 0; char c; char delim; - std::string ident, asc; + std::string ident; + //, asc; std::string ops = "+-*//^!.&()"; std::string c1; char *tokptr; char *tptr; bool numexpect; + bool highascii = false; Token::Type t; - delim=0; + delim = 0; numexpect = true; for (const auto* p = expr.c_str(); *p; ++p) { @@ -56,18 +58,20 @@ std::deque CLASS::exprToTokens(const std::string& expr) if ((c < ' ') || (c == delim)) { // SGQ - convert ascii to a number here - asc = "0"; - //printf("ident=|%s|\n",ident.c_str()); + //asc = "0"; + //printf("ascii ident=|%s|\n", ident.c_str()); if (ident.length() > 0) { // SGQ - convert ascii to a number here } - t = Token::Type::Number; + ident = delim + ident + delim; + + t = Token::Type::Ascii; int pr = 1; // precedence - bool ra = false; // rightAssociative + bool ra = false; tokens.push_back(Token { - t, asc, pr, ra + t, ident, pr, ra }); ident = ""; state = 0; @@ -75,6 +79,8 @@ std::deque CLASS::exprToTokens(const std::string& expr) { p--; } + highascii = false; + delim = 0; } else { @@ -150,6 +156,7 @@ std::deque CLASS::exprToTokens(const std::string& expr) { delim = c; state = 11; + highascii = true; numexpect = false; } else if (((c == '-') || (c == '+')) && (numexpect)) @@ -220,7 +227,7 @@ std::deque CLASS::shuntingYard(const std::deque& tokens) token.type = Token::Type::Number; if (token.str == "*") { - sprintf(buff, "%u", assembler.PC.currentpc); + sprintf(buff, "$%X", assembler.PC.currentpc); token.str = buff; } else @@ -231,7 +238,7 @@ std::deque CLASS::shuntingYard(const std::deque& tokens) if (sym != NULL) { sym->used = true; - sprintf(buff, "%d", sym->value); + sprintf(buff, "$%X", sym->value); token.str = buff; } else @@ -243,6 +250,7 @@ std::deque CLASS::shuntingYard(const std::deque& tokens) } queue.push_back(token); break; + case Token::Type::Ascii: case Token::Type::Number: // If the token is a number, then add it to the output queue queue.push_back(token); @@ -363,9 +371,54 @@ std::deque CLASS::shuntingYard(const std::deque& tokens) return queue; } +int CLASS::parseAscii(std::string n, int64_t &val) +{ + int res = -1; + val = 0; + bool err = false; + uint64_t tval = 0; + bool high = false; + uint8_t c; + + uint32_t l = n.length(); + for (uint32_t i = 0; i < l - 1; i++) + { + c = n[i]; + if (i == 0) + { + if (c == '"') + { + high = true; + } + } + else + { + tval <<= 8; + if (high) + { + c |= 0x80; + } + else + { + c &= 0x7F; + } + tval = ((tval & 0xFFFFFF00) | c); + } + } + + if (!err) + { + val = (uint32_t)(tval & 0xFFFFFFFF); + res = 0; + } + + //printf("parseASCII |%s| %d %016lX\n", n.c_str(), res, val); + return (res); +} + int CLASS::parseNumber(std::string n, int64_t &val) { - int res = DEF_VAL; + int res = -1; int state = 0; char c; std::string s; @@ -376,8 +429,7 @@ int CLASS::parseNumber(std::string n, int64_t &val) int64_t tval = 0; val = 0; - - + //printf("parseNumber |%s|\n",n.c_str()); i = 0; l = n.length(); s = ""; @@ -483,12 +535,13 @@ int CLASS::parseNumber(std::string n, int64_t &val) } } - if (tval > (int64_t)0xFFFFFFFF) + uint32_t tv = (uint32_t)tval; + uint64_t tv1 = tv; + if (tv1 > (int64_t)0xFFFFFFFF) { setError(Token::overflowErr); } - //printf("parsenumber: |%s|\n",s.c_str()); if ((state == 99) || (err)) { @@ -507,6 +560,13 @@ int CLASS::parseNumber(std::string n, int64_t &val) //printf("value=%08lX\n", val); res = 0; } + if (res != 0) + { + if (isDebug() > 2) + { + printf("parsenumber error result: %d\n", res); + } + } return (res); } @@ -527,7 +587,7 @@ int CLASS::evaluate(std::string & e, int64_t &res, uint8_t &_shiftmode) // const std::string expr = "3+4*2/(1-5)^2^3"; // Wikipedia's example // const std::string expr = "20-30/3+4*2^3"; - _shiftmode=shiftmode=0; + _shiftmode = shiftmode = 0; res = DEF_VAL; setError(Token::noError); @@ -560,6 +620,19 @@ int CLASS::evaluate(std::string & e, int64_t &res, uint8_t &_shiftmode) //op = "Push " + token.str; //printf("shouldn't get this kind of token\n"); break; + case Token::Type::Ascii: + + val = 0; + u = parseAscii(token.str, val); + if (u < 0) + { + setError(Token::numberErr); + val = DEF_VAL; + } + stack.push_back(val); + //op = "Push " + token.str; + break; + case Token::Type::Number: val = 0; u = parseNumber(token.str, val); @@ -580,21 +653,21 @@ int CLASS::evaluate(std::string & e, int64_t &res, uint8_t &_shiftmode) { rhs = stack.back(); stack.pop_back(); - shiftmode=token.str[0]; + shiftmode = token.str[0]; - if (token.str=="^") + if (token.str == "^") { //rhs = (rhs >> 16) &0xFFFF ; } - else if (token.str=="|") + else if (token.str == "|") { //rhs = (rhs >> 16) & 0xFFFF; } - else if (token.str=="<") + else if (token.str == "<") { //rhs = (rhs << 8 ) & 0xFFFF; } - else if (token.str==">") + else if (token.str == ">") { //rhs=(rhs>>8) & 0xFFFF; } @@ -698,7 +771,7 @@ out: { setError(Token::syntaxErr); } - _shiftmode=shiftmode; + _shiftmode = shiftmode; res = v; return (evalerror); } diff --git a/eval.h b/eval.h index e9cf182..73b6c54 100644 --- a/eval.h +++ b/eval.h @@ -41,6 +41,7 @@ public: Unknown = 0, Number, Symbol, + Ascii, Shift, Operator, LeftParen, @@ -71,6 +72,8 @@ public: std::deque shuntingYard(const std::deque& tokens); std::deque exprToTokens(const std::string& expr); int parseNumber(std::string n, int64_t &val); + int parseAscii(std::string n, int64_t &val); + int evaluate(std::string &expr, int64_t &res, uint8_t &_shiftmode); }; diff --git a/opcodes.cpp b/opcodes.cpp index f852835..58afdbd 100644 --- a/opcodes.cpp +++ b/opcodes.cpp @@ -226,7 +226,7 @@ int CLASS::doNoPattern(MerlinLine &line, TSymbol &sym) op = (m == syn_abs ? 0x64 : op); op = (m == syn_absx ? 0x74 : op); - if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags&FLAG_FORCEABS))) + if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { res++; op = (op == 0x64) ? 0x9C : op; @@ -236,7 +236,7 @@ int CLASS::doNoPattern(MerlinLine &line, TSymbol &sym) case 2: // TSB res++; op = (m == syn_abs ? 0x04 : op); - if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags&FLAG_FORCEABS))) + if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { res++; op = 0x0C; @@ -245,7 +245,7 @@ int CLASS::doNoPattern(MerlinLine &line, TSymbol &sym) case 3: // TRB res++; op = (m == syn_abs ? 0x14 : op); - if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags&FLAG_FORCEABS))) + if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { res++; op = 0x1C; @@ -422,7 +422,7 @@ int CLASS::doBRANCH(MerlinLine & line, TSymbol & sym) if ((offset < -128) || (offset > 127)) { err = true; - op=0x00; // merlin does this + op = 0x00; // merlin does this } } else if (res == 3) // long branch @@ -439,8 +439,8 @@ int CLASS::doBRANCH(MerlinLine & line, TSymbol & sym) setOpcode(line, op); for (i = 0; i < (res - 1); i++) { - uint8_t v=(offset >> (i*8)); - v=err?0x00:v; + uint8_t v = (offset >> (i * 8)); + v = err ? 0x00 : v; line.outbytes.push_back(v); } line.outbytect = res; @@ -489,7 +489,7 @@ int CLASS::doBase6502(MerlinLine & line, TSymbol & sym) bbb = 0x02; } - else if ((bbb > 0) && ((line.expr_value >= 0x100) || (line.flags&FLAG_FORCEABS))) + else if ((bbb > 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { bbb |= 0x02; bytelen++; @@ -571,9 +571,9 @@ int CLASS::doBase6502(MerlinLine & line, TSymbol & sym) bytelen++; } } - if ( ((m==syn_absx) || (m==syn_diix)) && ((sym.opcode==4) || (sym.opcode==5))) // these are STX,LDX + if ( ((m == syn_absx) || (m == syn_diix)) && ((sym.opcode == 4) || (sym.opcode == 5))) // these are STX,LDX { - err=true; + err = true; } if ((m == syn_absx) || (m == syn_abs) || (m == syn_absy)) { @@ -747,6 +747,30 @@ int CLASS::doBYTE(MerlinLine & line, TSymbol & sym) setOpcode(line, sym.opcode); line.outbytect = res; } + + // SGQ merlin32 apparently tracks XCE instructions when tracking MX status + // who know how they determine this. I am assuming the NEXT instruction + // after a SEC/CLC instruction must be an XCE + if (sym.opcode == 0x38) // SEC + { + lastcarry = true; + } + else if (sym.opcode == 0x18) // CLC + { + lastcarry = false; + } + else if (sym.opcode==0xFB) // XCE + { + if (trackrep) + { + if (lastcarry) + { + mx=0x03; + } + } + } + + return (res); } @@ -755,23 +779,23 @@ int CLASS::doBRK(MerlinLine & line, TSymbol & sym) UNUSED(sym); int res = 1; - int bytes=0; + int bytes = 0; - if (line.operand_expr!="") + if (line.operand_expr != "") { bytes++; } if (pass > 0) { setOpcode(line, sym.opcode); - for (int i=0;i>(8*i))&0xFF); + line.outbytes.push_back((line.expr_value >> (8 * i)) & 0xFF); } - line.outbytect = res+bytes; + line.outbytect = res + bytes; } - return (res+bytes); + return (res + bytes); } void CLASS::insertOpcodes(void) diff --git a/psuedo.cpp b/psuedo.cpp index 7b598f1..6d9f163 100644 --- a/psuedo.cpp +++ b/psuedo.cpp @@ -14,13 +14,30 @@ CLASS::~CLASS() } +uint32_t CLASS::doShift(uint32_t value, uint8_t shift) +{ + if (shift == '<') + { + value = (value) & 0xFF; + } + if (shift == '>') + { + value = (value >> 8) & 0xFF; + } + else if ((shift == '^') || (shift == '|')) + { + value = (value >> 16) & 0xFF; + } + return (value); +} + int CLASS::doDO(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) { UNUSED(opinfo); TEvaluator eval(a); - int64_t eval_result = 0; + int64_t eval_value = 0; uint8_t shift; uint32_t result32; int res = 0; @@ -51,8 +68,8 @@ int CLASS::doDO(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) } shift = 0; - eval_result = 0; - int x = eval.evaluate(line.operand_expr, eval_result, shift); + eval_value = 0; + int x = eval.evaluate(line.operand_expr, eval_value, shift); if (x < 0) { @@ -65,7 +82,7 @@ int CLASS::doDO(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) goto out; } - result32 = eval_result & 0xFFFFFFFF; + result32 = eval_value & 0xFFFFFFFF; a.curDO.doskip = (result32 != 0) ? false : true; goto out; @@ -119,7 +136,7 @@ int CLASS::doLUP(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) TEvaluator eval(a); - int64_t eval_result = 0; + int64_t eval_value = 0; uint8_t shift; int lidx, len; int res = 0; @@ -135,16 +152,16 @@ int CLASS::doLUP(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) { shift = 0; - eval_result = 0; - int x = eval.evaluate(line.operand_expr, eval_result, shift); + eval_value = 0; + int x = eval.evaluate(line.operand_expr, eval_value, shift); a.LUPstack.push(a.curLUP); a.curLUP.lupoffset = len; - a.curLUP.lupct = eval_result & 0xFFFF; // evaluate here + a.curLUP.lupct = eval_value & 0xFFFF; // evaluate here a.curLUP.luprunning++; - if ((x < 0) || (eval_result <= 0) || (eval_result > 0x8000)) + if ((x < 0) || (eval_value <= 0) || (eval_value > 0x8000)) { // merlin just ignores LUP if the value is out of range a.curLUP.lupct = 0; @@ -226,6 +243,9 @@ int CLASS::doDATA(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) //printf("DFB TOK1 : |%s|\n", oper.c_str()); + + line.eval_result = 0; // since this is an data p-op, clear the global 'bad operand' flag + Poco::StringTokenizer tok(oper, ",", Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY); @@ -264,7 +284,7 @@ int CLASS::doDATA(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) //printf("DFB TOK : |%s|\n", expr.c_str()); - int64_t eval_result = 0; + int64_t eval_value = 0; uint8_t shift; int r; uint8_t b; @@ -277,9 +297,9 @@ int CLASS::doDATA(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) expr = Poco::trim(expr); } shift = 0; - eval_result = 0; + eval_value = 0; //printf("DFB EVAL: |%s|\n", expr.c_str()); - r = eval.evaluate(expr, eval_result, shift); + r = eval.evaluate(expr, eval_value, shift); if (r < 0) { //printf("error %d\n",r); @@ -288,18 +308,7 @@ int CLASS::doDATA(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) line.setError(errBadEvaluation); } } - if (shift == '>') - { - eval_result = (eval_result) & 0xFF; - } - if (shift == '<') - { - eval_result = (eval_result >> 8) & 0xFF; - } - else if ((shift == '^') || (shift == '|')) - { - eval_result = (eval_result >> 16) & 0xFF; - } + eval_value = (uint64_t)doShift((uint32_t)eval_value, shift); } outct += wordsize; @@ -309,7 +318,7 @@ int CLASS::doDATA(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) { for (i = 0; i < wordsize; i++) { - b = (eval_result >> (8 * i)) & 0xFF; + b = (eval_value >> (8 * i)) & 0xFF; line.outbytes.push_back(b); //printf("%02X\n",b); } @@ -319,7 +328,7 @@ int CLASS::doDATA(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) // big endian for (i = 0; i < wordsize; i++) { - b = (eval_result >> ((wordsize - 1 - i) * 8)) & 0xFF; + b = (eval_value >> ((wordsize - 1 - i) * 8)) & 0xFF; line.outbytes.push_back(b); //printf("%02X\n",b); } @@ -336,23 +345,87 @@ int CLASS::doDS(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) UNUSED(opinfo); int res = 0; - int32_t v = line.expr_value; - if (line.eval_result != 0) - { - line.setError(errForwardRef); - } - else if ((v < 0) || ((a.PC.currentpc + v) >= 0x10000)) // no neg, or crossing bank bound - { - line.setError(errOverflow); - } - else - { - res = v; - line.datafillbyte = line.eval_result & 0xFF; - line.datafillct = v; + TEvaluator eval(a); + int64_t eval_value = 0; + uint8_t shift; + + line.eval_result = 0; // since this is an data p-op, clear the global 'bad operand' flag + line.flags|=FLAG_FORCEADDRPRINT; + std::string s; + Poco::StringTokenizer tok(line.operand, ",", Poco::StringTokenizer::TOK_TRIM | + Poco::StringTokenizer::TOK_IGNORE_EMPTY); + + int32_t datact = 0; + uint8_t fill = 0x0; + bool pagefill = false; + int32_t v = 0; + + + int ct = 0; + for (auto itr = tok.begin(); itr != tok.end(); ++itr) + { + s = *itr; + if (ct == 0) + { + if (s == "\\") + { + pagefill = true; + } + else + { + + shift = 0; + eval_value = 0; + int x = eval.evaluate(s, eval_value, shift); + if (x < 0) + { + line.setError(errBadOperand); + goto out; + } + eval_value = (uint64_t)doShift((uint32_t)eval_value, shift); + datact = eval_value & 0xFFFF; + if (datact < 0) + { + line.setError(errBadOperand); + goto out; + } + } + } + else if (ct == 1) + { + + shift = 0; + eval_value = 0; + int x = eval.evaluate(s, eval_value, shift); + if (x < 0) + { + line.setError(errBadOperand); + goto out; + } + eval_value = (uint64_t)doShift((uint32_t)eval_value, shift); + fill = eval_value & 0xFF; + } + else if (ct > 1) + { + line.setError(errBadOperand); + } + ct++; } + + line.datafillbyte = fill; + v = datact; + if (pagefill) + { + v=line.startpc&0xFF; + v=0x100-v; + } + line.datafillct = (uint16_t)v & 0xFFFF; + res=line.datafillct; + +out: + //printf("res=%d %04X\n",res,res); return (res); } @@ -468,6 +541,8 @@ int CLASS::doHEX(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) std::string os = Poco::trim(line.operand); + line.eval_result = 0; // since this is an data p-op, clear the global 'bad operand' flag + uint32_t bytect = 0; uint8_t b = 0; uint8_t ct = 0; @@ -528,19 +603,21 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) std::string os = line.operand; std::string op = Poco::toUpper(line.opcode); - uint8_t lastdelimbyte = 0x00; - uint8_t firstdelim = 0xFF; + uint8_t firstdelim = 0; uint32_t bytect = 0; uint8_t b = 0; uint8_t b1; uint8_t ct = 0; - char delimiter = 0; + uint8_t delimiter = 0; uint32_t ss = 0; + uint32_t lastdelimidx = 0; + std::vector bytes; + line.eval_result = 0; // since this is an ASCII p-op, clear the global 'bad operand' flag for ( uint32_t i = 0; i < os.length(); ++i ) { - char c = os[i]; + uint8_t c = os[i]; // are we inside a delimited string? if ( delimiter ) @@ -562,9 +639,9 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) { c |= 0x80; } - lastdelimbyte = c; + bytes.push_back(c); - //line.outbytes.push_back(c); + lastdelimidx = (uint32_t)(bytes.size() - 1); } } @@ -587,7 +664,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) { // if not a hex value, then consider the character to be the string delimiter delimiter = c; - if (firstdelim == 0xFF) + if( ! firstdelim ) { firstdelim = c; } @@ -615,7 +692,6 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) if (a.pass > 0) { bytes.push_back(b); - //line.outbytes.push_back(b); } b = 0; bytect++; @@ -636,8 +712,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) uint8_t andval = 0xFF; uint8_t orval = 0x00; uint8_t addlen = 0; - uint8_t firstbyte = 0x00; - uint32_t truebytect = bytes.size(); + uint32_t truebytect = (uint32_t)bytes.size(); const char *ptr = (const char *)op.c_str(); //printf("bytect=%d bytes.size()=%zu\n",bytect,bytes.size()); switch (strhash(ptr) ) @@ -686,24 +761,31 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) { b = bytes[i]; } - if (!i) + + b1 = b & 0x7F; + if ((andval != 0xFF) || (orval != 0x00)) { - firstbyte = b; + b = b1; } - b1 = b & 0x7F; - if ((andval!=0xFF) || (orval!=0x00)) - b=b1; + if ((b1 < 0x60)) { b &= andval; // strip whatever bits needed to flash or invert b |= orval; } - if ((dci) && (i == (truebytect - 1))) + + if (dci && (i == lastdelimidx)) { - // this one might be a bug. I am going to compare the first byte in the string for - // bit seven, and invert it on this byte. The confusion arises because this text string - // could have high ASCII, but low HEX values. - if (firstbyte < 0x80) + //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; } diff --git a/psuedo.h b/psuedo.h index 469b1c4..1270e00 100644 --- a/psuedo.h +++ b/psuedo.h @@ -28,6 +28,8 @@ class CLASS public: CLASS(); ~CLASS(); + uint32_t doShift(uint32_t value, uint8_t shift); + int ProcessOpcode(T65816Asm &a, MerlinLine &line, TSymbol &opinfo); int doLST(T65816Asm &a, MerlinLine &line, TSymbol &opinfo); int doDUM(T65816Asm &a, MerlinLine &line, TSymbol &opinfo); diff --git a/qasm.ini b/qasm.ini index 78c0ba2..2aad0ca 100644 --- a/qasm.ini +++ b/qasm.ini @@ -26,8 +26,9 @@ startmx=3 lst=true ; can be M6502, M65C02, M65816 cpu=M65816 -trackrep=false +trackrep=true allowduplicate=true +merlinerrors=false merlincompatible=true symcolumns=3 diff --git a/src/main.s b/src/main.s index b64d017..fe7a468 100644 --- a/src/main.s +++ b/src/main.s @@ -415,6 +415,8 @@ L00BC bit L00BC asc 02,15,"123456 asc 0215"1234"1502 + dci 8D,'Hello',8D,'there',8D + dci 8D,"Hello",8D,"there",8D lst lup_start: diff --git a/testdata/2007-labels-and-symbols.S b/testdata/2007-labels-and-symbols.S index 2c3b071..e5400cf 100644 --- a/testdata/2007-labels-and-symbols.S +++ b/testdata/2007-labels-and-symbols.S @@ -160,7 +160,7 @@ nosym equ $3300 ;should not match anything lda projalso lda nosym - bra :next + bra next target0 nop target1 nop ;point everything here @@ -186,7 +186,7 @@ t4a jml target0 t4b jml target1 t4c jml target2 -:next +next jsr t0 jsr t1a jsr t1b