Merge pull request #18 from marketideas/sgq_qasm_main

Sgq qasm main
This commit is contained in:
marketideas 2019-11-19 08:40:45 -08:00 committed by GitHub
commit 3ad9f76075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 465 additions and 193 deletions

294
asm.cpp
View File

@ -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;
@ -312,6 +311,16 @@ void CLASS::clear()
outbytes.clear();
}
std::string operEx[] =
{
"^(\\S*)(#?)([<>\\^|]?)([\"\'])(.*)(\\4)([\\S]*)", // catches the normal delims
"^(\\s*)([!-~])([!-~]*?)([^;]*)\\2(\\S*)", // catches the unusual delims
"^(\\s*)(\\S+)", // captures everything else
""
};
std::string commentEx = "^(\\s*)((;|\\/{2}))+(.*)";
void CLASS::set(std::string line)
{
int state = 0;
@ -320,19 +329,28 @@ void CLASS::set(std::string line)
int x;
char c, delim;
bool isascii;
std::string opupper;
std::string opupper, s;
std::string restofline;
std::string tline = line;
clear();
isascii = false;
delim = 0;
//printf("line: |%s|\n", line.c_str());
while (i < l)
{
c = line[i++];
//printf("state: %d\n",state);
c = tline[i++];
switch (state)
{
case 7:
if (c >= ' ')
{
comment += c;
}
else
{
i = l;
}
break;
case 0: // start of line state
if ((c == ';') || (c == '*') || (c == '/'))
{
@ -377,125 +395,110 @@ void CLASS::set(std::string line)
}
break;
case 3:
{
if (c > ' ')
{
opcode += c;
}
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);
if (opupper.length() > 0)
{
if (
(opupper == "STRL")
|| (opupper == "STR")
|| (opupper == "ASC")
|| (opupper == "DCI")
|| (opupper == "INV")
|| (opupper == "FLS")
|| (opupper == "REV")
)
{
isascii = true;
}
}
i--;
state = 4;
}
break;
}
break;
case 4: // read whitespace between opcode and operand
if (c == ';')
{
std::vector<std::string> strs;
std::string s;
Poco::RegularExpression comEx(commentEx, 0, true);
restofline = Poco::trim(tline.substr(i, tline.length())) + " ";
//printf("ROL: |%s|\n",restofline.c_str());
strs.clear();
x = 0;
try
{
comment += c;
state = 7;
x = comEx.split(restofline, strs, 0);
}
else if (c > ' ')
catch (Poco::Exception &e)
{
operand += c;
if ((c <= '/') && (isascii))
x = 0;
if (isDebug() > 3)
{
delim = c;
state = 8;
}
else
{
state = 5;
cout << e.displayText() << endl;
}
}
break;
case 5:
if (c > ' ')
if (x > 0)
{
if ((c == '\'') || (c == '"'))
// if the comment detector above is true, then the rest of line is comment;
operand = "";
comment = strs[0];
//printf("comment=%s\n", comment.c_str());
i = l;
break;
}
int ct = 0;
int x = 0;
bool match = false;
s = operEx[ct];
while (s != "")
{
RegularExpression regex(s, 0, true);
strs.clear();
x = 0;
try
{
delim = c;
operand += c;
state = 8;
x = regex.split(restofline, strs, 0);
}
else
catch (Poco::Exception &e)
{
operand += c;
x = 0;
if (isDebug() > 3)
{
cout << e.displayText() << endl;
}
}
if (x > 0)
{
//printf("%d regex %d match |%s|\n", ct, x, restofline.c_str());
operand = strs[0];
//printf("which=%d operand=|%s|\n",ct,operand.c_str());
i = operand.length();
restofline = restofline.substr(i, restofline.length());
comment = Poco::trim(restofline);
match = true;
break;
}
ct++;
s = operEx[ct];
}
else
i = l;
if (!match)
{
state = 6;
opcode = ":::"; // let assembler figure out this is a bad opcode
// SGQ maybe error here
//printf("---No Match %s\n", restofline.c_str());
}
break;
case 6:
if (c > ' ')
{
comment += c;
state = 7;
}
break;
case 7:
comment += c;
break;
case 9:
break;
case 8:
if (c < ' ')
{
}
else if (c == delim)
{
operand += c;
state = 5;
}
else
{
operand += c;
}
break;
}
break;
}
}
printlable = lable;
x = lable.length();
if (x > 1)
{
// SGQ M32 syntax
#if 0
while ((x > 1) && (lable[x - 1] == ':'))
{
lable = lable.substr(0, x - 1);
x--;
}
//printf("linelable: |%s|\n", lable.c_str());
#endif
}
opcodelower = Poco::toLower(opcode);
@ -683,6 +686,7 @@ int CLASS::processfile(std::string p, std::string &newfilename)
linect = 0;
done = false;
p = Poco::trim(p);
currentdir = Poco::Path::current();
if (filecount == 0)
@ -753,10 +757,14 @@ int CLASS::processfile(std::string p, std::string &newfilename)
}
if ((fn.isDirectory()) || (!fn.canRead()))
{
//LOG_DEBUG << "File is a directory: " << p1 << endl;
LOG_DEBUG << "File is a directory: " << p1 << endl;
valid = false;
}
}
else
{
printf("file does not exist |%s|\n", p1.c_str());
}
newfilename = p1;
if (!valid)
@ -880,10 +888,11 @@ int CLASS::doline(int lineno, std::string line)
void CLASS::process(void)
{
uint32_t len, t, pos;
uint32_t ct = lines.size();
uint32_t len, t, pos;
for (uint32_t lineno = 0; lineno < ct; lineno++)
{
MerlinLine &line = lines.at(lineno);
@ -987,11 +996,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 +1018,7 @@ TSymbol *CLASS::addSymbol(std::string sym, uint32_t val, bool replace)
s.value = val;
s.used = false;
s.cb = NULL;
std::pair<std::string, TSymbol> p(Poco::toUpper(sym), s);
std::pair<std::string, TSymbol> p(sym, s);
if (sym[0] == ':')
{
@ -1058,10 +1074,15 @@ out:
return (res);
}
TSymbol *CLASS::findSymbol(std::string symname)
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 +1093,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 +1104,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 +1117,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,13 +1155,13 @@ 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<std::string, TSymbol> p(Poco::toUpper(sym), s);
std::pair<std::string, TSymbol> p(sym, s);
variables.insert(p);
res = findVariable(sym);
return (res);
}
TSymbol *CLASS::findVariable(std::string symname)
TSymbol * CLASS::findVariable(std::string symname)
{
TSymbol *res = NULL;
@ -1389,6 +1416,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 +1456,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 +1516,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 +1657,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 +1714,7 @@ int CLASS::getAddrMode(MerlinLine & line)
}
idx++;
}
out:
if (mode == syn_none)
{
mode = syn_err;
@ -1750,6 +1818,17 @@ bool CLASS::codeSkipped(void)
void CLASS::process(void)
{
#if 0
uint32_t ct = lines.size();
for (uint32_t lineno = 0; lineno < ct; lineno++)
{
//MerlinLine &line = lines.at(lineno);
//printf("|%s| |%s| |%s| |%s|\n", line.lable.c_str()
// , line.opcode.c_str(), line.operand.c_str(), line.comment.c_str());
}
#else
uint32_t l;
int x;;
char c;
@ -1779,6 +1858,7 @@ void CLASS::process(void)
line.linemx = mx;
line.bytect = 0;
line.showmx = showmx;
line.merlinerrors = merlinerrors;
if ((line.lable != ""))
{
@ -1828,6 +1908,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;
@ -1919,7 +2000,7 @@ void CLASS::process(void)
#endif
pass++;
}
#endif
}
int CLASS::doline(int lineno, std::string line)
@ -1948,6 +2029,7 @@ int CLASS::doline(int lineno, std::string line)
{
std::string fn;
x = processfile(l.operand, fn);
//printf("processfile : %d\n",x);
if (x < 0)
{
switch (x)

8
asm.h
View File

@ -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;

View File

@ -14,6 +14,7 @@
//#define USE_JSON
//#define USE_XML
#define NO_TTY_SETUP
// help text
#define HELP_USAGE "<options> <list of files>"
#define HELP_PURPOSE "\nMerlin 16+ Compatible 65816 Development Tool"

115
eval.cpp
View File

@ -27,16 +27,18 @@ std::deque<Token> 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<Token> 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<Token> CLASS::exprToTokens(const std::string& expr)
{
p--;
}
highascii = false;
delim = 0;
}
else
{
@ -150,6 +156,7 @@ std::deque<Token> 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<Token> CLASS::shuntingYard(const std::deque<Token>& 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<Token> CLASS::shuntingYard(const std::deque<Token>& 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<Token> CLASS::shuntingYard(const std::deque<Token>& 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<Token> CLASS::shuntingYard(const std::deque<Token>& 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);
}

3
eval.h
View File

@ -41,6 +41,7 @@ public:
Unknown = 0,
Number,
Symbol,
Ascii,
Shift,
Operator,
LeftParen,
@ -71,6 +72,8 @@ public:
std::deque<Token> shuntingYard(const std::deque<Token>& tokens);
std::deque<Token> 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);
};

View File

@ -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<bytes;i++)
for (int i = 0; i < bytes; i++)
{
line.outbytes.push_back((line.expr_value>>(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)

View File

@ -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 = doShift(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 = doShift(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 = doShift(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;
@ -538,6 +613,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
uint32_t ss = 0;
std::vector<uint8_t> 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];
@ -691,8 +767,10 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
firstbyte = b;
}
b1 = b & 0x7F;
if ((andval!=0xFF) || (orval!=0x00))
b=b1;
if ((andval != 0xFF) || (orval != 0x00))
{
b = b1;
}
if ((b1 < 0x60))
{
b &= andval; // strip whatever bits needed to flash or invert

View File

@ -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);

View File

@ -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

View File

@ -27,6 +27,8 @@ for S in $SRC ; do
BASE=${S/.S/}
BASE=${BASE/.s/}
#./qasm -o 0/$OUTDIR/$S1 ./testdata/$S
./qasm -o 0/$OUTDIR/$S1 ./testdata/$S >> $TMPFILE
R=?$

View File

@ -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

View File

@ -155,5 +155,5 @@ LOCAL1 lda #$2c ;EDIT: format as ASCII
beq LOCAL1
LOCAL2 lda $2c ;EDIT: format as ASCII
ldx $5678 ;put empty variable table here
beq LOCAL2
;beq LOCAL2
rts

View File

@ -1,9 +1,11 @@
(0) 2019-11-17 - BRK does not detect a lable that can't be evaluated
(0) 2019-11-17 - ASCII parsing in both eval and for ASC type commands
(0) 2019-11-17 - IF processing for character compare mode
(0) 2019-11-17 -
(0) 2019-11-17 -
(0) 2019-11-17 -
(0) 2019-11-17 - Note (syntax) Merlin doesn't allow 'A' implied addressing
(0) 2019-11-17 - Note (syntax): Merlin doesn't allow local labels without a previous global
(0) 2019-11-17 - Note (syntax): Merlin doesn't allow local colons after label which is ignored
(0) 2019-11-17 - Note (syntax): Merlin doesn't allow for 'rep/sep/xce' tracking
(0) 2019-11-17 - Bug (evaluation routine puts ascii bytes in reverse order (#"AB")
(0) 2019-11-17 -
(0) 2019-11-17 -
(0) 2019-11-17 -