qasm/asm.cpp

1546 lines
27 KiB
C++
Raw Normal View History

2019-11-11 23:56:03 +00:00
#define ADD_ERROR_STRINGS
#include "asm.h"
#include "eval.h"
#include "psuedo.h"
2019-11-11 23:56:03 +00:00
#define CLASS MerlinLine
CLASS::CLASS()
{
clear();
}
CLASS::CLASS(std::string line)
{
clear();
set(line);
}
void CLASS::setError(uint32_t ecode)
{
errorcode = ecode;
}
void CLASS::print(uint32_t lineno)
{
2019-11-13 04:32:10 +00:00
int i, l, pcol;
int commentcol = 40;
2019-11-14 03:37:26 +00:00
static bool checked = false;
static bool nc1 = false;
2019-11-13 23:45:39 +00:00
bool nc = false;
2019-11-11 23:56:03 +00:00
l = outbytect;
if (l > 4)
{
l = 4;
}
2019-11-14 03:37:26 +00:00
if (!checked)
{
nc1 = getBool("option.nocolor", false);
checked = true;
}
else
{
nc = nc1;
}
if (!isatty(STDOUT_FILENO))
{
nc = true;
}
2019-11-13 23:45:39 +00:00
if (!nc)
2019-11-11 23:56:03 +00:00
{
2019-11-13 23:45:39 +00:00
if (errorcode > 0)
2019-11-11 23:56:03 +00:00
{
2019-11-13 23:45:39 +00:00
if (errorcode >= errFatal)
{
SetColor(CL_WHITE | CL_BOLD | BG_RED);
}
else
{
SetColor(CL_YELLOW | CL_BOLD | BG_NORMAL);
}
2019-11-11 23:56:03 +00:00
}
else
{
2019-11-13 23:45:39 +00:00
SetColor(CL_WHITE | CL_BOLD | BG_NORMAL);
2019-11-11 23:56:03 +00:00
}
}
bool empty = false;
if ((printlable == "") && (opcode == "") && (operand == ""))
2019-11-11 23:56:03 +00:00
{
empty = true;
}
int b = 4;
2019-11-13 04:32:10 +00:00
pcol = 0;
2019-11-11 23:56:03 +00:00
if (!empty)
{
2019-11-13 04:32:10 +00:00
pcol += printf("%02X/%04X:", (startpc >> 16), startpc & 0xFFFF);
2019-11-11 23:56:03 +00:00
}
else
{
2019-11-13 04:32:10 +00:00
pcol += printf(" ");
2019-11-11 23:56:03 +00:00
}
for (i = 0; i < l; i++)
{
2019-11-13 04:32:10 +00:00
pcol += printf("%02X ", outbytes[i]);
2019-11-11 23:56:03 +00:00
}
for (i = l; i < b; i++)
{
2019-11-13 04:32:10 +00:00
pcol += printf(" ");
2019-11-11 23:56:03 +00:00
}
if (showmx)
2019-11-12 08:15:47 +00:00
{
if (outbytect > 0)
{
2019-11-13 04:32:10 +00:00
pcol += printf("%%%c%c ", linemx & 02 ? '1' : '0', linemx & 01 ? '1' : '0');
2019-11-12 08:15:47 +00:00
}
else
{
2019-11-13 04:32:10 +00:00
pcol += printf(" ");
2019-11-12 08:15:47 +00:00
}
}
2019-11-12 18:13:15 +00:00
if (isDebug() > 1)
2019-11-12 08:15:47 +00:00
{
2019-11-13 04:32:10 +00:00
pcol += printf("%02X ", addressmode & 0xFF);
2019-11-12 08:15:47 +00:00
}
2019-11-13 04:32:10 +00:00
pcol += printf("%6d ", lineno + 1);
pcol = 0; // reset pcol here because this is where source code starts
2019-11-12 08:15:47 +00:00
2019-11-11 23:56:03 +00:00
if (empty)
{
2019-11-13 04:32:10 +00:00
if (comment.length() > 0)
{
if (comment[0] == ';')
{
while (pcol < commentcol)
{
pcol += printf(" ");
}
}
pcol += printf("%s", comment.c_str());
}
2019-11-11 23:56:03 +00:00
}
else
{
2019-11-13 04:32:10 +00:00
pcol += printf("%-12s %-8s %-10s ", printlable.c_str(), opcode.c_str(), operand.c_str());
2019-11-11 23:56:03 +00:00
if (errorcode > 0)
{
2019-11-13 04:32:10 +00:00
while (pcol < commentcol)
{
pcol += printf(" ");
}
pcol += printf(":[Error] %s %s", errStrings[errorcode].c_str(), errorText.c_str());
2019-11-11 23:56:03 +00:00
}
else
{
2019-11-13 04:32:10 +00:00
while (pcol < commentcol)
{
pcol += printf(" ");
}
pcol += printf("%s", comment.c_str());
2019-11-11 23:56:03 +00:00
}
}
2019-11-13 23:45:39 +00:00
if ((!nc) && (errorcode > 0))
2019-11-11 23:56:03 +00:00
{
SetColor(CL_NORMAL | BG_NORMAL);
}
printf("\n");
}
void CLASS::clear()
{
syntax = SYNTAX_MERLIN;
lable = "";
printlable = "";
2019-11-11 23:56:03 +00:00
opcode = "";
opcodelower = "";
operand = "";
comment = "";
operand_expr = "";
2019-11-12 03:51:26 +00:00
operand_expr2 = "";
2019-11-11 23:56:03 +00:00
addrtext = "";
2019-11-12 08:15:47 +00:00
linemx = 0;
2019-11-11 23:56:03 +00:00
bytect = 0;
opflags = 0;
pass0bytect = 0;
startpc = 0;
errorcode = 0;
2019-11-12 18:13:15 +00:00
errorText = "";
2019-11-11 23:56:03 +00:00
outbytect = 0;
2019-11-12 03:51:26 +00:00
lineno = 0;
2019-11-11 23:56:03 +00:00
outbytes.clear();
addressmode = 0;
expr_value = 0;
eval_result = 0;
2019-11-11 23:56:03 +00:00
flags = 0;
outbytes.clear();
}
void CLASS::set(std::string line)
{
int state = 0;
int l = line.length();
int i = 0;
int x;
2019-11-12 03:51:26 +00:00
char c, delim;
2019-11-11 23:56:03 +00:00
clear();
//printf("line: |%s|\n", line.c_str());
while (i < l)
{
c = line[i++];
//printf("state: %d\n",state);
switch (state)
{
case 0: // start of line state
2019-11-12 18:13:15 +00:00
if ((c == ';') || (c == '*') || (c == '/'))
2019-11-11 23:56:03 +00:00
{
comment += c;
state = 7;
}
else if (c > ' ')
{
lable += c;
state = 1;
}
else
{
state = 2;
};
break;
case 1: // read in entire lable until whitespace
if (c > ' ')
{
lable += c;
}
else
{
state = 2;
}
break;
case 2: // read whitespace between label and opcode
if (c == ';')
{
comment += c;
state = 7;
}
2019-11-12 18:13:15 +00:00
else if (((c == '*') || (c == '/')) && (lable.length() == 0))
{
comment += c;
state = 7;
}
2019-11-11 23:56:03 +00:00
else if (c > ' ')
{
opcode += c;
state = 3;
}
break;
case 3:
if (c > ' ')
{
opcode += c;
}
else
{
state = 4;
}
break;
case 4: // read whitespace between opcode and operand
if (c == ';')
{
comment += c;
state = 7;
}
else if (c > ' ')
{
operand += c;
if (c == '\'')
{
state = 8;
}
else
{
state = 5;
}
}
break;
case 5:
2019-11-12 03:51:26 +00:00
if ((c == '\'') || (c == '"'))
2019-11-11 23:56:03 +00:00
{
2019-11-12 03:51:26 +00:00
delim = c;
2019-11-11 23:56:03 +00:00
operand += c;
state = 8;
}
else if (c > ' ')
{
operand += c;
}
else
{
state = 6;
}
break;
case 6:
if (c > ' ')
{
comment += c;
state = 7;
}
break;
case 7:
comment += c;
break;
case 8:
if (c == delim)
{
operand += c;
state = 5;
}
else
{
operand += c;
}
break;
2019-11-12 18:13:15 +00:00
case 9:
break;
2019-11-11 23:56:03 +00:00
}
}
printlable = lable;
x = lable.length();
if (x > 1)
{
while ((x > 1) && (lable[x - 1] == ':'))
{
lable = lable.substr(0, x - 1);
x--;
}
//printf("linelable: |%s|\n", lable.c_str());
}
2019-11-11 23:56:03 +00:00
opcodelower = Poco::toLower(opcode);
}
#undef CLASS
#define CLASS TFileProcessor
CLASS::CLASS()
{
errorct = 0;
2019-11-11 23:56:03 +00:00
}
CLASS::~CLASS()
{
}
void CLASS::errorOut(uint16_t code)
{
printf("error: %d\n", code);
}
void CLASS::init(void)
{
2019-11-12 03:51:26 +00:00
starttime = GetTickCount();
2019-11-14 15:28:42 +00:00
syntax = 0;
filecount = 0;
2019-11-11 23:56:03 +00:00
}
void CLASS::complete(void)
{
2019-11-12 08:15:47 +00:00
2019-11-12 03:51:26 +00:00
uint64_t n = GetTickCount();
if (isDebug())
{
printf("Processing Time: %lu ms\n", n - starttime);
}
2019-11-11 23:56:03 +00:00
}
void CLASS::process(void)
{
}
int CLASS::doline(int lineno, std::string line)
{
int res = -1;
return (res);
}
int CLASS::processfile(std::string &p)
{
//Poco::File fn(p);
int c;
int res = -1;
uint32_t linect;
bool done, valid;
std::string p1;
std::string line, op;
linect = 0;
done = false;
Poco::Path tp(p);
Poco::Path path = tp.makeAbsolute();
2019-11-14 05:56:50 +00:00
Poco::Path parent = path.parent();
2019-11-14 15:28:42 +00:00
std::string currentdir = Poco::Path::current();
2019-11-14 05:56:50 +00:00
std::string dir = parent.toString();;
2019-11-11 23:56:03 +00:00
2019-11-14 05:56:50 +00:00
try
{
2019-11-14 06:03:34 +00:00
//printf("filename : %s\n", path.toString().c_str());
//printf("directory: %s\n", dir.c_str());
2019-11-13 23:45:39 +00:00
2019-11-14 15:28:42 +00:00
p1 = path.toString();
//LOG_DEBUG << "initial file name: " << p1 << endl;
2019-11-13 23:45:39 +00:00
2019-11-14 05:56:50 +00:00
valid = true;
Poco::File fn(p1);
2019-11-11 23:56:03 +00:00
if (!fn.exists())
{
2019-11-14 05:56:50 +00:00
fn = Poco::File(p1 + ".s");
2019-11-11 23:56:03 +00:00
if (!fn.exists())
{
2019-11-14 05:56:50 +00:00
fn = Poco::File(p1 + ".S");
2019-11-11 23:56:03 +00:00
if (!fn.exists())
{
2019-11-14 05:56:50 +00:00
fn = Poco::File(p1 + ".mac");
if (!fn.exists())
{
2019-11-14 15:28:42 +00:00
fn = Poco::File(p1);
2019-11-14 05:56:50 +00:00
valid = false;
}
2019-11-11 23:56:03 +00:00
}
}
}
2019-11-14 05:56:50 +00:00
p1 = fn.path();
2019-11-14 15:28:42 +00:00
//LOG_DEBUG << "File name: " << p1 << endl;
valid=false;
if (fn.exists())
{
valid=true;
//LOG_DEBUG << "File exists: " << p1 << endl;
if (fn.isLink())
{
//LOG_DEBUG << "File is a link: " << p1 << endl;
}
if ((fn.isDirectory()) || (!fn.canRead()))
{
//LOG_DEBUG << "File is a directory: " << p1 << endl;
valid = false;
}
}
if (!valid)
{
fprintf(stderr, "Unable to access file: %s\n", p1.c_str());
errorct = 1;
return (-1);
}
2019-11-11 23:56:03 +00:00
2019-11-14 15:28:42 +00:00
return (0);
2019-11-14 05:56:50 +00:00
if (valid)
2019-11-11 23:56:03 +00:00
{
2019-11-14 15:28:42 +00:00
if (filecount == 0)
{
// is this the first file in the compilation, or a PUT/USE?
// if first, change CWD to location of file
LOG_DEBUG << "Changing directory to: " << dir << endl;
chdir(dir.c_str()); // change directory to where the file is
}
filecount++;
2019-11-11 23:56:03 +00:00
2019-11-14 05:56:50 +00:00
std::ifstream f(p1);
if (f.is_open())
2019-11-11 23:56:03 +00:00
{
2019-11-14 05:56:50 +00:00
//printf("file is open\n");
line = "";
while ((!done) && (f.good()) && (!f.eof()))
2019-11-11 23:56:03 +00:00
{
2019-11-14 05:56:50 +00:00
c = f.get();
if (c == 0x8D) // merlin line ending
{
c = 0x0A; // convert to linux
}
if (c == 0x8A) // possible merlin line ending
{
c = 0x00; // ignore
}
c &= 0x7F;
int x;
switch (c)
{
case 0x0D:
break;
case 0x09:
line += " ";
break;
case 0x0A:
linect++;
x = doline(linect, line);
if (x < 0)
{
done = true;
}
line = "";
break;
default:
if ((c >= ' ') && (c < 0x7F))
{
line += c;
}
else
{
//printf("garbage %08X\n",c);
}
break;
}
2019-11-11 23:56:03 +00:00
}
2019-11-14 05:56:50 +00:00
if ( (f.eof()))
2019-11-11 23:56:03 +00:00
{
2019-11-14 05:56:50 +00:00
res = 0;
2019-11-11 23:56:03 +00:00
}
}
2019-11-14 05:56:50 +00:00
}
else
{
fprintf(stderr, "File <%s> does not exist.\n\n", p.c_str());
2019-11-11 23:56:03 +00:00
}
}
2019-11-14 15:28:42 +00:00
catch (...)
2019-11-11 23:56:03 +00:00
{
}
2019-11-14 05:56:50 +00:00
chdir(currentdir.c_str());
2019-11-11 23:56:03 +00:00
//printf("\n\nfile read result: %d\n", res);
return (res);
}
#undef CLASS
#define CLASS TMerlinConverter
CLASS::CLASS() : TFileProcessor()
{
}
CLASS::~CLASS()
{
}
void CLASS::init(void)
{
std::string s;
2019-11-13 04:32:10 +00:00
int ts, tabpos;
lines.clear();
2019-11-14 15:28:42 +00:00
syntax = SYNTAX_MERLIN;
2019-11-13 04:32:10 +00:00
std::string tabstr = getConfig("reformat.tabs", "8,16,32");
tabstr = Poco::trim(tabstr);
memset(tabs, 0x00, sizeof(tabs));
2019-11-13 04:32:10 +00:00
Poco::StringTokenizer t(tabstr, ",;", 0);
tabpos = 0;
for (auto itr = t.begin(); itr != t.end(); ++itr)
{
2019-11-13 04:32:10 +00:00
s = Poco::trim(*itr);
try
{
2019-11-13 04:32:10 +00:00
ts = Poco::NumberParser::parse(s);
}
2019-11-13 04:32:10 +00:00
catch (...)
{
2019-11-13 04:32:10 +00:00
ts = 0;
}
2019-11-13 04:32:10 +00:00
if ((ts >= 0) && (ts < 240))
{
2019-11-13 04:32:10 +00:00
tabs[tabpos++] = ts;
}
}
}
int CLASS::doline(int lineno, std::string line)
{
MerlinLine l(line);
lines.push_back(l);
return 0;
}
void CLASS::process(void)
{
2019-11-13 04:32:10 +00:00
uint32_t len, t, pos;
uint32_t ct = lines.size();
for (uint32_t lineno = 0; lineno < ct; lineno++)
{
MerlinLine &line = lines.at(lineno);
2019-11-11 23:56:03 +00:00
2019-11-13 04:32:10 +00:00
pos = 0;
len = 0;
2019-11-13 04:32:10 +00:00
if ((line.lable.length() == 0)
&& (line.opcode.length() == 0)
&& (line.operand.length() == 0))
{
2019-11-13 04:32:10 +00:00
if (line.comment.length() > 0)
{
char c = line.comment[0];
if ((c == '*') || (c == '/'))
{
printf("%s", line.comment.c_str());
}
else
{
t = tabs[2];
while (len < t)
{
len += printf(" ");
}
printf("%s", line.comment.c_str());
}
}
printf("\n");
}
2019-11-13 04:32:10 +00:00
else
{
2019-11-13 04:32:10 +00:00
t = tabs[pos++];
len = printf("%s ", line.printlable.c_str());
while (len < t)
{
len += printf(" ");
}
2019-11-13 04:32:10 +00:00
t = tabs[pos++];
len += printf("%s ", line.opcode.c_str());
while (len < t)
{
len += printf(" ");
}
2019-11-13 04:32:10 +00:00
t = tabs[pos++];
len += printf("%s ", line.operand.c_str());
while (len < t)
{
len += printf(" ");
}
2019-11-13 04:32:10 +00:00
t = tabs[pos++];
len += printf("%s", line.comment.c_str());
while (len < t)
{
len += printf(" ");
}
len += printf("\n");
}
}
}
void CLASS::complete(void)
{
}
#undef CLASS
2019-11-11 23:56:03 +00:00
#define CLASS T65816Asm
CLASS::CLASS() : TFileProcessor()
2019-11-11 23:56:03 +00:00
{
lines.clear();
psuedoops = new TPsuedoOp();
2019-11-11 23:56:03 +00:00
}
//#define OPHANDLER(ACB) std::bind(ACB, this, std::placeholders::_1, std::placeholders::_2)
2019-11-11 23:56:03 +00:00
CLASS::~CLASS()
{
if (psuedoops != NULL)
{
delete(psuedoops);
psuedoops = NULL;
}
2019-11-11 23:56:03 +00:00
}
void CLASS::pushopcode(std::string op, uint8_t opcode, uint16_t flags, TOpCallback cb)
{
TSymbol sym;
sym.name = op;
sym.opcode = opcode;
sym.namelc = Poco::toLower(op);
sym.stype = flags;
sym.value = 0;
sym.cb = cb;
std::pair<std::string, TSymbol> p(Poco::toUpper(op), sym);
opcodes.insert(p);
}
TSymbol *CLASS::addSymbol(std::string sym, uint32_t val, bool replace)
{
TSymbol *res = NULL;
TSymbol *fnd = NULL;
fnd = findSymbol(sym);
if ((fnd != NULL) && (!replace))
{
return (NULL); // it is a duplicate
}
if (fnd != NULL)
{
//printf("replacing symbol: %s %08X\n",sym.c_str(),val);
fnd->value = val;
return (fnd);
}
//printf("addSymbol |%s|\n",sym.c_str());
TSymbol s;
s.name = sym;
s.opcode = 0;
s.namelc = Poco::toLower(sym);
s.stype = 0;
s.value = val;
s.used = false;
s.cb = NULL;
std::pair<std::string, TSymbol> p(Poco::toUpper(sym), s);
symbols.insert(p);
res = findSymbol(sym);
return (res);
}
2019-11-11 23:56:03 +00:00
TSymbol *CLASS::findSymbol(std::string symname)
{
TSymbol *res = NULL;
2019-11-12 08:15:47 +00:00
//printf("finding: %s\n",symname.c_str());
2019-11-11 23:56:03 +00:00
auto itr = symbols.find(Poco::toUpper(symname));
if (itr != symbols.end())
{
2019-11-12 08:15:47 +00:00
//printf("Found: %s 0x%08X\n",itr->second.name.c_str(),itr->second.value);
2019-11-11 23:56:03 +00:00
res = &itr->second;
return (res);
}
return (res);
}
TSymbol *CLASS::addVariable(std::string sym, std::string val, bool replace)
2019-11-11 23:56:03 +00:00
{
TSymbol *res = NULL;
TSymbol *fnd = NULL;
//printf("addvariable\n");
fnd = findVariable(sym);
2019-11-11 23:56:03 +00:00
if ((fnd != NULL) && (!replace))
{
return (NULL); // it is a duplicate
}
if (fnd != NULL)
{
2019-11-12 08:15:47 +00:00
//printf("replacing symbol: %s %08X\n",sym.c_str(),val);
fnd->text = val;
2019-11-11 23:56:03 +00:00
return (fnd);
}
TSymbol s;
s.name = sym;
s.opcode = 0;
s.namelc = Poco::toLower(sym);
s.stype = 0;
s.value = 0;
s.text = val;
2019-11-12 18:13:15 +00:00
s.used = false;
2019-11-11 23:56:03 +00:00
s.cb = NULL;
2019-11-14 05:39:35 +00:00
//printf("addvariable: %s %s\n", s.name.c_str(), s.text.c_str());
2019-11-11 23:56:03 +00:00
std::pair<std::string, TSymbol> p(Poco::toUpper(sym), s);
variables.insert(p);
res = findVariable(sym);
return (res);
}
TSymbol *CLASS::findVariable(std::string symname)
{
TSymbol *res = NULL;
//printf("finding: %s\n",symname.c_str());
auto itr = variables.find(Poco::toUpper(symname));
if (itr != variables.end())
{
//printf("Found: %s 0x%08X\n",itr->second.name.c_str(),itr->second.value);
res = &itr->second;
return (res);
}
2019-11-11 23:56:03 +00:00
return (res);
}
void CLASS::showVariables(void)
{
2019-11-13 23:45:39 +00:00
if (variables.size() > 0)
{
2019-11-13 23:45:39 +00:00
printf("\nVariables:\n");
2019-11-13 23:45:39 +00:00
for (auto itr = variables.begin(); itr != variables.end(); ++itr)
{
printf("%-16s %s\n", itr->first.c_str(), itr->second.text.c_str());
}
}
}
2019-11-12 08:15:47 +00:00
// set alpha to true to print table sorted by name or
// false to print by value;
void CLASS::showSymbolTable(bool alpha)
2019-11-11 23:56:03 +00:00
{
2019-11-14 15:28:42 +00:00
if (symbols.size() > 0)
2019-11-11 23:56:03 +00:00
{
2019-11-14 15:28:42 +00:00
std::map<std::string, uint32_t> alphamap;
std::map<uint32_t, std::string> nummap;
2019-11-12 08:15:47 +00:00
2019-11-14 15:28:42 +00:00
int columns = 4;
int column = columns;
for (auto itr = symbols.begin(); itr != symbols.end(); itr++)
{
TSymbol ptr = itr->second;
alphamap.insert(pair<std::string, uint32_t>(ptr.name, ptr.value));
nummap.insert(pair<uint32_t, std::string>(ptr.value, ptr.name));
}
2019-11-12 08:15:47 +00:00
2019-11-14 15:28:42 +00:00
if (alpha)
2019-11-12 08:15:47 +00:00
{
2019-11-14 15:28:42 +00:00
printf("\n\nSymbol table sorted alphabetically:\n\n");
for (auto itr = alphamap.begin(); itr != alphamap.end(); ++itr)
2019-11-13 23:45:39 +00:00
{
2019-11-14 15:28:42 +00:00
printf("%-16s 0x%08X ", itr->first.c_str(), itr->second);
if ( !--column )
{
printf("\n");
column = columns;
}
2019-11-13 23:45:39 +00:00
}
2019-11-12 08:15:47 +00:00
}
2019-11-14 15:28:42 +00:00
else
2019-11-12 08:15:47 +00:00
{
2019-11-14 15:28:42 +00:00
printf("\n\nSymbol table sorted numerically:\n\n");
for (auto itr = nummap.begin(); itr != nummap.end(); ++itr)
2019-11-13 23:45:39 +00:00
{
2019-11-14 15:28:42 +00:00
printf("0x%08X %-16s ", itr->first, itr->second.c_str());
if ( !--column )
{
printf("\n");
column = columns;
}
2019-11-13 23:45:39 +00:00
}
2019-11-12 08:15:47 +00:00
}
2019-11-11 23:56:03 +00:00
}
}
int CLASS::callOpCode(std::string op, MerlinLine &line)
{
int res = -1;
char c;
if (op.length() == 4) // check for 4 digit 'L' opcodes
{
2019-11-13 23:45:39 +00:00
c = op[3] & 0x7F;
if ((c >= 'a') && (c <= 'z'))
2019-11-11 23:56:03 +00:00
{
c = c - 0x20;
}
2019-11-13 23:45:39 +00:00
switch (c)
2019-11-11 23:56:03 +00:00
{
2019-11-13 23:45:39 +00:00
case 'L':
op = op.substr(0, 3);
line.flags |= FLAG_FORCELONG; // 3 byte address
break;
default: // any char but 'L' as in Merlin 16+
if ((c != 'D') || (Poco::toUpper(op) != "DEND"))
{
op = op.substr(0, 3);
line.flags |= FLAG_FORCEABS; // 2 byte address
}
break;
case 'Z':
op = op.substr(0, 3);
line.flags |= FLAG_FORCEDP; // one byte address
break;
2019-11-11 23:56:03 +00:00
}
2019-11-13 23:45:39 +00:00
}
2019-11-11 23:56:03 +00:00
2019-11-13 23:45:39 +00:00
switch (line.expr_shift)
{
case '<':
line.expr_value &= 0xFF;
line.flags |= FLAG_DP;
break;
case '>':
line.expr_value >>= 8;
line.expr_value &= 0xFFFF;
break;
case '^':
line.expr_value = (line.expr_value >> 16) & 0xFFFF;
break;
case '|':
line.flags |= FLAG_FORCELONG;
break;
2019-11-11 23:56:03 +00:00
}
2019-11-13 23:45:39 +00:00
2019-11-11 23:56:03 +00:00
auto itr = opcodes.find(Poco::toUpper(op));
if (itr != opcodes.end())
{
TSymbol s = itr->second;
if (s.cb != NULL)
{
res = s.cb(line, s);
if (res == -1)
{
res = -2;
}
}
}
else
{
line.setError(errBadOpcode);
}
return (res);
}
typedef struct
{
std::string regEx;
uint16_t addrMode;
std::string text;
std::string expression;
} TaddrMode;
2019-11-12 03:51:26 +00:00
// these are the regular expressions that determine the addressing mode
// and extract the 'expr' part of the addr-mode
2019-11-12 08:15:47 +00:00
// ^([_,a-z,A-Z,0-9:\]].+)\,[s,S]{1}$ // might be a better syn_s
2019-11-12 18:13:15 +00:00
// "^([:-~][0-Z_-~]*)$" // this is a valid identifier
// "^([$][0-9A-Fa-f]+)$" // hex digit
// "^([%][0-1][0-1_]+[0-1])$" - binary numbera
// "^([0-9]+)$" - decimal number
// "^([:-~][^\],()]*)$" - valid expression
const TaddrMode addrRegEx[] =
2019-11-11 23:56:03 +00:00
{
{ "^(?'expr'.+)\\,[s,S]{1}$", syn_s, "e,s"}, // expr,s
{"^[(]{1}(?'expr'.+)[,]{1}[(S|s)]{1}[)]{1}[,]{1}[(Y|y)]{1}$", syn_sy, "(e,s),y"}, // (expr,s),y
{"^#{1}(.+)$", syn_imm, "immediate"}, //#expr,#^expr,#|expr,#<expr,#>expr
2019-11-11 23:56:03 +00:00
{"^[(]{1}(?'expr'.+)[,]{1}[x,X]{1}\\)$", syn_diix, "(e,x)"}, // (expr,x)
{"^[(]{1}(?'expr'.+)[\\)]{1}[\\,][(Y|y]{1}$", syn_diiy, "(e),y"}, //(expr),y
{"^[(]{1}(?'expr'.+)[\\)]{1}$", syn_di, "(e)"}, // (expr)
2019-11-12 18:13:15 +00:00
{"^\\[{1}(?'expr'.+)\\]{1}[,]{1}[(Y|y)]{1}$", syn_iyl, "[e],y"}, // [expr],y
2019-11-11 23:56:03 +00:00
{"^\\[(?'expr'.+)\\]$", syn_dil, "[e]"}, // [expr]
{"^(?'expr'.+)[,]{1}[(X|x)]{1}$", syn_absx, "e,x"}, // expr,x
{"^(?'expr'.+)[,]{1}[(Y|y)]{1}$", syn_absy, "e,y"}, // expr,y
{"^(?'expr'.+)[,]{1}(?'expr2'.+)$", syn_bm, "block"}, // block move expr,expr1
{"^(?'expr'.+)$", syn_abs, "absolute"}, // expr (MUST BE LAST)
{"", 0, ""}
};
// keep this next line for awhile
// {"^#{1}(?'shift'[<,>,^,|]?)(.+)$", syn_imm, "immediate"}, //#expr,#^expr,#|expr,#<expr,#>expr
// one or more of any character except ][,();
const std::string valExpression = "^([^\\]\\[,();]+)$";
2019-11-12 18:13:15 +00:00
2019-11-14 03:37:26 +00:00
// this one looks for ]variables
2019-11-14 05:39:35 +00:00
const std::string varExpression = "([]]{1}[:0-9A-Z_a-z]{1}[0-9A-Z_a-z]*)";
2019-11-14 03:37:26 +00:00
2019-11-12 03:51:26 +00:00
// opcode check. emitted opcodes are compared against this
// table, and if the XC status doesn't meet the requirements
// an error is thrown
// 0x00 = 6502
// 0x01 = 65C02
// 0x02 = 65816
uint8_t opCodeCompatibility[256] =
{
0x00, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x02,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x02,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02,
0x00, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x02,
0x01, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x02,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02
2019-11-11 23:56:03 +00:00
};
void CLASS::init(void)
{
2019-11-12 18:13:15 +00:00
uint8_t b = opCodeCompatibility[0];
if (b)
{
}
2019-11-11 23:56:03 +00:00
TFileProcessor::init();
lines.clear();
insertOpcodes();
}
void CLASS::initpass(void)
{
2019-11-12 08:15:47 +00:00
std::string s;
2019-11-12 18:13:15 +00:00
casesen = getBool("asm.casesen", true);
2019-11-12 08:15:47 +00:00
listing = getBool("asm.lst", true);
showmx = getBool("asm.showmx", false);
trackrep = getBool("asm.trackrep", false);
2019-11-13 23:45:39 +00:00
merlincompat = getBool("asm.merlincompatible", true);
allowdup = getBool("asm.allowduplicate", true);
2019-11-12 03:51:26 +00:00
skiplist = false;
2019-11-11 23:56:03 +00:00
2019-11-13 04:32:10 +00:00
PC.origin = 0x8000;
PC.currentpc = PC.origin;
2019-11-13 23:45:39 +00:00
PC.totalbytes = 0;
PC.orgsave = PC.origin;
2019-11-12 08:15:47 +00:00
s = getConfig("asm.cpu", "M65816");
s = Poco::trim(Poco::toUpper(s));
2019-11-11 23:56:03 +00:00
cpumode = MODE_65816;
mx = 0x00;
2019-11-12 08:15:47 +00:00
if (s == "M65816")
{
cpumode = MODE_65816;
mx = 0x00;
}
else if (s == "M65C02")
{
cpumode = MODE_65C02;
mx = 0x03;
}
else if (s == "M6502")
{
cpumode = MODE_6502;
mx = 0x03;
}
else
{
printf("Unknown CPU type in .ini\n");
}
relocatable = false;
2019-11-11 23:56:03 +00:00
currentsym = NULL;
lineno = 0;
2019-11-12 03:51:26 +00:00
errorct = 0;
2019-11-11 23:56:03 +00:00
passcomplete = false;
2019-11-13 23:45:39 +00:00
dumstartaddr = 0;
dumstart = 0;
2019-11-12 08:15:47 +00:00
variables.clear(); // clear the variables for each pass
2019-11-13 04:32:10 +00:00
while (!PCstack.empty())
{
PCstack.pop();
}
2019-11-12 08:15:47 +00:00
savepath = "";
2019-11-11 23:56:03 +00:00
}
void CLASS::complete(void)
{
2019-11-13 04:32:10 +00:00
printf("\n\n=== Assembly Complete: %d bytes %u errors.\n", PC.totalbytes, errorct);
2019-11-12 08:15:47 +00:00
if (savepath != "")
{
if (errorct == 0)
{
std::ofstream f(savepath);
uint32_t lineno = 0;
uint32_t l = lines.size();
while (lineno < l)
{
2019-11-13 23:45:39 +00:00
MerlinLine &line = lines.at(lineno++);
if ((line.outbytect > 0) && ((line.flags & FLAG_INDUM) == 0))
2019-11-12 08:15:47 +00:00
{
for (uint32_t i = 0; i < line.outbytect; i++)
2019-11-12 08:15:47 +00:00
{
f.put(line.outbytes[i]);
2019-11-12 08:15:47 +00:00
}
}
}
}
else
{
printf("\nErrors in assembly. Output not SAVED.\n\n");
}
}
2019-11-11 23:56:03 +00:00
if (listing)
{
2019-11-12 08:15:47 +00:00
showSymbolTable(true);
showSymbolTable(false);
showVariables();
2019-11-11 23:56:03 +00:00
}
2019-11-12 03:51:26 +00:00
TFileProcessor::complete();
2019-11-11 23:56:03 +00:00
}
2019-11-13 23:45:39 +00:00
int CLASS::evaluate(MerlinLine &line, std::string expr, int64_t &value)
2019-11-11 23:56:03 +00:00
{
int res = -1;
int64_t result = 0;
if (expr.length() > 0)
{
TEvaluator eval(*this);
2019-11-13 23:45:39 +00:00
line.eval_result = 0;
2019-11-11 23:56:03 +00:00
2019-11-13 23:45:39 +00:00
res = eval.evaluate(expr, result, line.expr_shift);
2019-11-12 18:13:15 +00:00
if (res != 0)
{
if (isDebug() > 2)
2019-11-12 18:13:15 +00:00
{
int c = SetColor(CL_RED);
printf("eval Error=%d %08lX |%s|\n", res, result, eval.badsymbol.c_str());
SetColor(c);
}
}
2019-11-11 23:56:03 +00:00
if (res == 0)
{
2019-11-13 23:45:39 +00:00
uint64_t v1 = (uint64_t) result;
2019-11-11 23:56:03 +00:00
value = result;
2019-11-13 23:45:39 +00:00
if ((listing) && (pass > 0) && (isDebug() > 2))
{
printf("EV1=%08lX '%c'\n", v1, line.expr_shift);
}
if (v1 >= 0x10000)
{
line.flags |= FLAG_BIGNUM;
}
if (v1 < 0x100)
{
line.flags |= FLAG_DP;
}
2019-11-11 23:56:03 +00:00
}
}
else
{
value = 0;
res = 0;
}
2019-11-13 23:45:39 +00:00
if (isDebug() >= 3)
{
2019-11-13 23:45:39 +00:00
printf("Eval Result: %08lX (status=%d)\n", value, res);
}
2019-11-12 18:13:15 +00:00
return (res);
2019-11-11 23:56:03 +00:00
}
2019-11-12 08:15:47 +00:00
int CLASS::getAddrMode(MerlinLine & line)
2019-11-11 23:56:03 +00:00
{
int res = -1;
uint16_t mode = syn_none;
int idx, x;
std::string s, oper;
std::vector<std::string> groups;
oper = line.operand;
if ((line.opcode.length() == 0) || (line.operand.length() == 0))
{
return (syn_implied);
}
idx = 0;
2019-11-12 18:13:15 +00:00
RegularExpression valEx(valExpression, 0, true);
2019-11-11 23:56:03 +00:00
while (mode == syn_none)
{
s = addrRegEx[idx].regEx;
if (s == "")
{
mode = syn_err;
}
else
{
RegularExpression regex(s, 0, true);
groups.clear();
x = 0;
try
{
x = regex.split(oper, 0, groups, 0);
}
catch (...)
{
x = 0;
}
if (x > 0)
{
mode = addrRegEx[idx].addrMode;
line.addrtext = addrRegEx[idx].text;
//cout << "mode: " << line.addrtext << endl;
2019-11-12 03:51:26 +00:00
int ct = 0;
2019-11-11 23:56:03 +00:00
for (uint32_t i = 0; i < groups.size(); i++)
{
s = groups[i];
2019-11-12 03:51:26 +00:00
//printf("ct=%zu idx=%d group: |%s|\n", groups.size(), i, s.c_str());
if (s != "")
2019-11-11 23:56:03 +00:00
{
2019-11-12 03:51:26 +00:00
if ((s != "^") && (s != "<") && (s != ">") && (s != "|"))
{
2019-11-12 18:13:15 +00:00
bool v = true;
2019-11-13 04:32:10 +00:00
if (mode == syn_abs)
2019-11-12 18:13:15 +00:00
{
2019-11-13 04:32:10 +00:00
if (i > 0)
{
v = valEx.match(s, 0, 0);
}
2019-11-12 18:13:15 +00:00
}
if (!v)
{
//printf("invalid expression |%s|\n", s.c_str());
mode = syn_none;
}
else if (ct == 1)
2019-11-12 03:51:26 +00:00
{
line.operand_expr = s;
}
else if (ct == 2)
{
line.operand_expr2 = s;
}
ct++;
//printf("line expression=|%s|\n", s.c_str());
}
else
{
// SGQ need to set a flag for a shift and process it after eval
}
2019-11-11 23:56:03 +00:00
}
}
}
}
idx++;
}
if (mode == syn_none)
{
mode = syn_err;
}
res = mode;
//printf("syn_mode=%d\n", mode);
return (res);
}
2019-11-12 08:15:47 +00:00
int CLASS::parseOperand(MerlinLine & line)
2019-11-11 23:56:03 +00:00
{
int res = -1;
line.operand_expr = "";
int m = getAddrMode(line);
if (m >= 0)
{
res = m;
}
else
{
//errorOut(errBadAddressMode);
}
return (res);
}
2019-11-14 03:37:26 +00:00
int CLASS::substituteVariables(MerlinLine & line)
{
int res = -1;
2019-11-14 05:39:35 +00:00
int x;
std::string::size_type offset, slen;
2019-11-14 03:37:26 +00:00
std::string oper = line.operand;
2019-11-14 05:39:35 +00:00
std::string s;
TSymbol *sym;
2019-11-14 05:56:50 +00:00
uint32_t len, off, ct;
2019-11-14 05:39:35 +00:00
slen = oper.length();
if (slen > 0)
2019-11-14 03:37:26 +00:00
{
std::vector<std::string> groups;
2019-11-14 05:39:35 +00:00
offset = 0;
RegularExpression varEx(varExpression, Poco::RegularExpression::RE_EXTRA, true);
Poco::RegularExpression::MatchVec mVec;
2019-11-14 03:37:26 +00:00
2019-11-14 05:39:35 +00:00
//printf("|%s|%s|\n", varExpression.c_str(), oper.c_str());
2019-11-14 03:37:26 +00:00
groups.clear();
2019-11-14 05:39:35 +00:00
ct = 0;
while (offset < slen)
{
try
{
varEx.match(oper, offset, mVec, 0);
}
catch (...)
{
offset = slen;
}
x = mVec.size();
if (x > 0)
{
res = 0;
off = mVec[0].offset;
len = mVec[0].length;
s = oper.substr(off, len);
sym = findVariable(s);
if (sym != NULL)
{
ct++;
2019-11-14 05:56:50 +00:00
if (pass > 0)
2019-11-14 05:39:35 +00:00
{
//printf("%d |%s|\n", ct, s.c_str());
}
}
offset += len;
}
else
{
offset = slen;
}
}
2019-11-14 03:37:26 +00:00
}
return (res);
}
2019-11-11 23:56:03 +00:00
void CLASS::process(void)
{
uint32_t l;
int x;;
2019-11-11 23:56:03 +00:00
char c;
2019-11-14 05:39:35 +00:00
char buff[256];
std::string op, operand, ls;
2019-11-11 23:56:03 +00:00
pass = 0;
while (pass < 2)
{
initpass();
l = lines.size();
while ((lineno < l) && (!passcomplete))
{
2019-11-13 23:45:39 +00:00
MerlinLine &line = lines[lineno];
2019-11-11 23:56:03 +00:00
2019-11-13 23:45:39 +00:00
line.eval_result = 0;
line.lineno = lineno + 1;
//printf("lineno: %d %d |%s|\n",lineno,l,line.operand.c_str());
2019-11-11 23:56:03 +00:00
op = Poco::toLower(line.opcode);
operand = Poco::toLower(line.operand);
line.startpc = PC.currentpc;
line.linemx = mx;
line.bytect = 0;
line.showmx = showmx;
2019-11-11 23:56:03 +00:00
2019-11-14 05:39:35 +00:00
if ((line.lable != ""))
2019-11-11 23:56:03 +00:00
{
std::string lable = Poco::trim(line.lable);
TSymbol *sym = NULL;
bool dupsym = false;
c = line.lable[0];
2019-11-11 23:56:03 +00:00
switch (c)
{
case ']':
2019-11-14 05:39:35 +00:00
sprintf(buff, "$%X", PC.currentpc);
ls = buff;
sym = addVariable(line.lable, ls, true);
if (sym == NULL) { dupsym = true; }
2019-11-11 23:56:03 +00:00
break;
case ':':
break;
default:
2019-11-14 05:39:35 +00:00
if (pass == 0)
{
sym = addSymbol(line.lable, PC.currentpc, false);
if (sym == NULL) { dupsym = true; }
}
2019-11-11 23:56:03 +00:00
break;
}
if (dupsym)
{
line.setError(errDupSymbol);
}
2019-11-11 23:56:03 +00:00
}
2019-11-14 03:37:26 +00:00
x = substituteVariables(line);
x = parseOperand(line);
2019-11-11 23:56:03 +00:00
if (x >= 0)
{
line.addressmode = x;
2019-11-11 23:56:03 +00:00
}
2019-11-12 18:13:15 +00:00
2019-11-11 23:56:03 +00:00
int64_t value = -1;
2019-11-13 23:45:39 +00:00
x = evaluate(line, line.operand_expr, value);
//line.eval_result=x;
2019-11-12 18:13:15 +00:00
2019-11-11 23:56:03 +00:00
if (x == 0)
{
value &= 0xFFFFFFFF;
line.expr_value = value;
2019-11-11 23:56:03 +00:00
}
else
{
line.expr_value = 0;
2019-11-11 23:56:03 +00:00
}
x = 0;
if (op.length() > 0)
{
x = callOpCode(op, line);
2019-11-11 23:56:03 +00:00
}
2019-11-12 18:13:15 +00:00
2019-11-11 23:56:03 +00:00
if (x > 0)
{
2019-11-13 23:45:39 +00:00
if (!PCstack.empty()) // are we inside a DUM section?
{
line.flags |= FLAG_INDUM;
}
if ((line.eval_result != 0) && (pass > 0))
2019-11-12 18:13:15 +00:00
{
line.setError(errBadOperand);
line.errorText = line.operand_expr;
2019-11-12 18:13:15 +00:00
}
line.bytect = x;
2019-11-13 04:32:10 +00:00
PC.currentpc += x;
PC.totalbytes += x;
2019-11-11 23:56:03 +00:00
}
if (pass == 0)
{
line.pass0bytect = line.bytect;
2019-11-11 23:56:03 +00:00
}
2019-11-13 23:45:39 +00:00
if (dumstart > 0) // starting a dummy section
{
PCstack.push(PC);
2019-11-13 23:45:39 +00:00
PC.origin = dumstartaddr;
PC.currentpc = PC.origin;
dumstart = 0;
dumstartaddr = 0;
}
2019-11-13 23:45:39 +00:00
if (dumstart < 0)
{
2019-11-13 23:45:39 +00:00
PC = PCstack.top();
PCstack.pop();
2019-11-13 23:45:39 +00:00
dumstart = 0;
dumstartaddr = 0;
}
2019-11-11 23:56:03 +00:00
if (pass == 1)
{
if ((line.pass0bytect != line.bytect) && (line.errorcode == 0))
2019-11-11 23:56:03 +00:00
{
line.setError(errBadByteCount);
2019-11-11 23:56:03 +00:00
}
if (line.errorcode != 0)
2019-11-11 23:56:03 +00:00
{
2019-11-12 03:51:26 +00:00
errorct++;
2019-11-11 23:56:03 +00:00
}
if (((!skiplist) && (listing) && (pass == 1)) || (line.errorcode != 0))
2019-11-11 23:56:03 +00:00
{
line.print(lineno);
2019-11-11 23:56:03 +00:00
}
2019-11-12 03:51:26 +00:00
skiplist = false;
2019-11-11 23:56:03 +00:00
}
lineno++;
}
pass++;
}
}
int CLASS::doline(int lineno, std::string line)
{
int res = 0;
std::string op;
MerlinLine l(line);
op = Poco::toLower(l.opcode);
if (op == "merlin")
{
syntax = SYNTAX_MERLIN;
}
else if (op == "orca")
{
syntax = SYNTAX_ORCA;
}
l.syntax = syntax;
lines.push_back(l);
if ((op == "use") || (op == "put"))
{
//printf("processing % s\n",l.operand.c_str());
processfile(l.operand);
}
return (res);
}
#undef CLASS
#define CLASS T65816Link
CLASS::CLASS() : TFileProcessor()
2019-11-11 23:56:03 +00:00
{
}
CLASS::~CLASS()
{
}
void CLASS::init(void)
{
TFileProcessor::init();
}
void CLASS::process(void)
{
}
void CLASS::complete(void)
{
}
int CLASS::doline(int lineno, std::string line)
{
int res = 0;
return (res);
}
#undef CLASS