might be broken, work on addressing modes and shift operators < > | ^

This commit is contained in:
Shawn Quick 2023-02-08 10:14:55 -08:00
parent 88e0251a16
commit 4380f4e8ca
16 changed files with 1154 additions and 596 deletions

4
.vscode/launch.json vendored
View File

@ -9,8 +9,8 @@
"program": "${workspaceFolder}/build/qasm", "program": "${workspaceFolder}/build/qasm",
"args": [ "args": [
"${workspaceFolder}/test.s", "${workspaceFolder}/test.s",
"-s", "-d",
"-d" "-l"
], ],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",

270
asm.cpp
View File

@ -11,12 +11,12 @@
#define CLASS MerlinLine #define CLASS MerlinLine
CLASS::CLASS(ConfigOptions &opt) //: options(opt) CLASS::CLASS(ConfigOptions &opt) : options(&opt)
{ {
clear(); clear();
} }
CLASS::CLASS(std::string line, ConfigOptions &opt) //: options(opt) CLASS::CLASS(std::string line, ConfigOptions &opt) : options(&opt)
{ {
clear(); clear();
set(line); set(line);
@ -68,11 +68,17 @@ void CLASS::print(uint32_t lineno)
bool np=(flags & FLAG_NOLINEPRINT)?true:false; bool np=(flags & FLAG_NOLINEPRINT)?true:false;
if (options->isQuiet()) if (options->isQuiet())
{
np=true; np=true;
}
if (options->isList()) if (options->isList())
np=false; {
if (force)
np=false; np=false;
}
if (force)
{
np=false;
}
if (np) if (np)
{ {
return; return;
@ -221,6 +227,8 @@ void CLASS::print(uint32_t lineno)
} }
//pcol += printf("%-12s %-8s %-10s ", printlable.c_str(), opcode.c_str(), operand.c_str()); //pcol += printf("%-12s %-8s %-10s ", printlable.c_str(), opcode.c_str(), operand.c_str());
} }
//printf("merlinerrors=%d\n",merlinerrors);
//merlinerrors=false;
if ((errorcode > 0) && (!merlinerrors)) if ((errorcode > 0) && (!merlinerrors))
{ {
while (pcol < commentcol) while (pcol < commentcol)
@ -245,7 +253,7 @@ void CLASS::print(uint32_t lineno)
if ((options->useColor()) && (errorcode > 0)) if ((options->useColor()) && (errorcode > 0))
{ {
SetColor(CL_NORMAL | BG_NORMAL); SetColor(CL_NORMAL);
} }
uint32_t obc = datafillct; uint32_t obc = datafillct;
@ -297,6 +305,7 @@ void CLASS::print(uint32_t lineno)
void CLASS::clear() void CLASS::clear()
{ {
shiftchar=0;
wholetext = ""; wholetext = "";
lable = ""; lable = "";
printlable = ""; printlable = "";
@ -305,6 +314,7 @@ void CLASS::clear()
operand = ""; operand = "";
printoperand = ""; printoperand = "";
orig_operand=""; orig_operand="";
strippedoperand="";
comment = ""; comment = "";
operand_expr = ""; operand_expr = "";
operand_expr2 = ""; operand_expr2 = "";
@ -317,16 +327,15 @@ void CLASS::clear()
startpc = 0; startpc = 0;
errorcode = 0; errorcode = 0;
errorText = ""; errorText = "";
outbytect = 0;
datafillct = 0; datafillct = 0;
datafillbyte = 0; datafillbyte = 0;
lineno = 0; lineno = 0;
outbytes.clear();
addressmode = 0; addressmode = 0;
expr_value = 0; expr_value = 0;
eval_result = 0; eval_result = 0;
flags = 0; flags = 0;
outbytes.clear(); outbytes.clear();
outbytect = 0;
} }
std::string operEx[] = std::string operEx[] =
@ -556,9 +565,9 @@ CLASS::~CLASS()
{ {
} }
void CLASS::setLanguage(string lang) void CLASS::setLanguage(string lang,bool force)
{ {
options.setLanguage(lang); options.setLanguage(lang,force);
} }
void CLASS::errorOut(uint16_t code) void CLASS::errorOut(uint16_t code)
@ -614,7 +623,7 @@ void CLASS::complete(void)
//cout << "Processing Time: " << n - starttime << "ms" << endl; //cout << "Processing Time: " << n - starttime << "ms" << endl;
uint64_t x = n - starttime; uint64_t x = n - starttime;
uint32_t x1 = x & 0xFFFFFFFF; uint32_t x1 = x & 0xFFFFFFFF;
if ((!getBool("option.quiet",false)) && (isDebug()>0)) //if ((!getBool("option.quiet",false)) && (isDebug()>0))
{ {
printf("Elapsed time: %u ms\n", x1); printf("Elapsed time: %u ms\n", x1);
} }
@ -1639,7 +1648,7 @@ int CLASS::callOpCode(std::string op, MerlinLine &line)
break; break;
case '>': case '>':
#if 0 #if 0
if ((syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) if (options.isMerlin32())
{ {
// bug in M32 or not, do what it does // bug in M32 or not, do what it does
line.flags |= FLAG_FORCEABS; line.flags |= FLAG_FORCEABS;
@ -1768,16 +1777,17 @@ void CLASS::initpass(void)
showmx = getBool("asm.showmx", true); showmx = getBool("asm.showmx", true);
merlinerrors = getBool("asm.merlinerrors", true); merlinerrors = getBool("asm.merlinerrors", true);
outputbytes.clear();
trackrep = getBool("asm.trackrep", false); trackrep = getBool("asm.trackrep", false);
if (syntax == SYNTAX_MERLIN32) if (options.isMerlin32())
{ {
trackrep = true; // can't turn this off in M32 trackrep = true; // can't turn this off in M32
} }
else if (syntax == SYNTAX_MERLIN) else if (options.isMerlin())
{ {
trackrep = false; // can't turn this ON in M16 trackrep = false; // can't turn this ON in M16
} }
else if (syntax == SYNTAX_QASM) else if (options.isQASM())
{ {
// we will allow this to be settable default off // we will allow this to be settable default off
trackrep = false; trackrep = false;
@ -1797,28 +1807,33 @@ void CLASS::initpass(void)
s = getConfig("asm.cpu", "M6502"); s = getConfig("asm.cpu", "M6502");
s = Poco::trim(Poco::toUpper(s)); s = Poco::trim(Poco::toUpper(s));
cpumode = MODE_65816; s=PAL::getString("option.instruction","");
mx = 0x03; if (s!="")
if (s == "M65816")
{ {
printf("CPU command line %s\n",s.c_str());
cpumode = MODE_65816; cpumode = MODE_65816;
mx = 0x03; mx = 0x03;
}
else if (s == "M65C02") if (s == "M65816")
{ {
cpumode = MODE_65C02; cpumode = MODE_65816;
mx = 0x03; mx = 0x03;
} }
else if (s == "M6502") else if (s == "M65C02")
{ {
cpumode = MODE_6502; cpumode = MODE_65C02;
mx = 0x03; mx = 0x03;
} }
else else if (s == "M6502")
{ {
printf("Unknown CPU type in .ini\n"); cpumode = MODE_6502;
mx = 0x03; mx = 0x03;
}
else
{
printf("Unknown CPU type in .ini\n");
mx = 0x03;
}
} }
mx = getInt("asm.startmx", mx);; mx = getInt("asm.startmx", mx);;
@ -1829,7 +1844,7 @@ void CLASS::initpass(void)
lastcarry = false; lastcarry = false;
relocatable = false; relocatable = false;
currentsym = NULL; currentsym = NULL;
if ((syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) if (options.isMerlin32())
{ {
// M32 allows locals that don't have a global above. this is the catchall for that // M32 allows locals that don't have a global above. this is the catchall for that
currentsym = &topSymbol; // this is the default symbol for :locals without a global above; currentsym = &topSymbol; // this is the default symbol for :locals without a global above;
@ -1875,46 +1890,76 @@ void CLASS::initpass(void)
void CLASS::complete(void) void CLASS::complete(void)
{ {
bool writeerr=false;
if (savepath != "") if (savepath != "")
{ {
if (errorct == 0) if (errorct == 0)
{ {
std::string currentdir = Poco::Path::current(); std::string currentdir = Poco::Path::current();
savepath = processFilename(savepath, currentdir, 0); //savepath = processFilename(savepath, currentdir, 0);
savepath=options.formatPath(savepath);
if (!options.isQuiet()) if (!options.isQuiet())
{ {
printf("saving to file: %s\n", savepath.c_str()); printf("saving to file: %s\n", savepath.c_str());
} }
std::ofstream f(savepath); std::ofstream f(savepath, std::ios::out|std::ios::trunc);
uint32_t lineno = 0; if (f.is_open())
uint32_t l = (uint32_t)lines.size();
while (lineno < l)
{ {
MerlinLine &line = lines.at(lineno++); #if 0
if ((line.outbytect > 0) && ((line.flags & FLAG_INDUM) == 0)) uint32_t lineno = 0;
uint32_t l = (uint32_t)lines.size();
while (lineno < l)
{ {
for (uint32_t i = 0; i < line.outbytect; i++) MerlinLine &line = lines.at(lineno++);
if ((line.outbytect > 0) && ((line.flags & FLAG_INDUM) == 0))
{ {
f.put(line.outbytes[i]); for (uint32_t i = 0; i < line.outbytect; i++)
{
f.put(line.outbytes[i]);
}
} }
} if ((line.datafillct > 0) && ((line.flags & FLAG_INDUM) == 0))
if ((line.datafillct > 0) && ((line.flags & FLAG_INDUM) == 0))
{
for (uint32_t i = 0; i < line.datafillct; i++)
{ {
f.put(line.datafillbyte & 0xFF); for (uint32_t i = 0; i < line.datafillct; i++)
} {
f.put(line.datafillbyte & 0xFF);
}
}
} }
#else
for (unsigned int i=0; i<outputbytes.size(); i++)
{
f.put(outputbytes[i]);
}
f.flush();
//printf("outbytect=%ld\n",outputbytes.size());
if (f.fail())
{
writeerr=true;
}
f.close();
#endif
}
else
{
writeerr=true;
} }
} }
else else
{ {
printf("\nErrors in assembly. Output not SAVED.\n\n"); printf("\nErrors in assembly. Output not SAVED.\n\n");
} }
if (writeerr)
{
printf("unable to save file.\n"); // TODO SGQ need to push error up the so exit code is non-zero
}
} }
if ((!options.isQuiet()) || (options.isList())) if ((!options.isQuiet()) || (options.isList()))
{ {
@ -2001,12 +2046,77 @@ int CLASS::getAddrMode(MerlinLine & line)
int idx, x; int idx, x;
std::string s, oper; std::string s, oper;
std::vector<std::string> groups; std::vector<std::string> groups;
char shiftchar;
oper = line.operand; oper = line.operand;
int l=oper.length();
if ((line.opcode.length() == 0) || (line.operand.length() == 0)) if ((line.opcode.length() == 0) || (l <= 0))
{ {
return (syn_implied); return (syn_none);
}
bool supportbar=false;
bool modified=false;
shiftchar=oper[0];
if (shiftchar=='#')
{
shiftchar=0;
if (l>1)
{
shiftchar=oper[1];
//oper=oper.substr(1);
//oper="#"+oper;
}
}
if (shiftchar=='^')
{
if (options.isMerlin())
{
return(syn_err);
//shiftchar=0x00; // merlin8 does not support the bank addr
}
}
if (shiftchar=='|')
{
if (options.isMerlinCompat())
{
if ((options.isMerlin() || options.isMerlin16())) // merlin8 and merlin16 do not support the bar
{
return(syn_err);
}
else
{
supportbar=true;
}
}
}
if ((shiftchar=='^') || (shiftchar=='<') || (shiftchar=='>') || (supportbar && shiftchar=='|'))
{
modified=true;
}
if (supportbar)
{
}
if (modified)
{
line.shiftchar=shiftchar;
if (oper[0]=='#')
{
oper=oper.substr(2);
oper="#"+oper;
l=oper.length();
}
else if (shiftchar!=0)
{
oper=oper.substr(1);
l=oper.length();
}
printf("old: |%s| new: |%s|\n",line.operand.c_str(),oper.c_str());
line.strippedoperand=oper;
} }
idx = 0; idx = 0;
@ -2136,9 +2246,35 @@ int CLASS::parseOperand(MerlinLine & line)
{ {
//errorOut(errBadAddressMode); //errorOut(errBadAddressMode);
} }
printf("addressmode=%d %s\n",res,addrModeEnglish(res).c_str());
return (res); return (res);
} }
string CLASS::addrModeEnglish(int mode)
{
string res="<none>";
switch(mode)
{
case syn_err: res="addrmode_error";break;
case syn_none: res="addrmode_none";break;
case syn_implied: res="implied";break;
case syn_s: res="dp,s";break;
case syn_sy: res="(dp,s),y";break;
case syn_imm: res="#immediate";break;
case syn_diix: res="(dp,x)";break;
case syn_diiy: res="(dp),y";break;
case syn_di: res="(dp)";break;
case syn_iyl: res="[expr],y";break;
case syn_dil: res="[expr]";break;
case syn_absx: res="abs,x";break;
case syn_absy: res="abs,y";break;
case syn_bm: res="block move";break;
case syn_abs: res="absolute";break;
default: res="addr_mode bad";break;
}
return(res);
}
int CLASS::substituteVariables(MerlinLine & line, std::string &outop) int CLASS::substituteVariables(MerlinLine & line, std::string &outop)
{ {
int res = 0; int res = 0;
@ -2580,6 +2716,24 @@ void CLASS::process(void)
line.errorText = line.operand_expr; line.errorText = line.operand_expr;
} }
line.bytect = x; line.bytect = x;
if (pass>0)
{
if ((line.flags & FLAG_INDUM) == 0) // don't write bytes if inside DUM section
{
for (unsigned int i=0; i<line.outbytes.size(); i++)
{
outputbytes.push_back(line.outbytes[i]);
}
if (line.datafillct>0)
{
for (int i=0; i<line.datafillct; i++)
{
outputbytes.push_back(line.datafillbyte);
}
}
}
}
PC.currentpc += x; PC.currentpc += x;
PC.totalbytes += x; PC.totalbytes += x;
} }
@ -2623,6 +2777,9 @@ void CLASS::process(void)
line.print(lineno); line.print(lineno);
} }
skiplist = false; skiplist = false;
line.outbytes.clear(); // clear the outbytes on the line so LUP works correctly
line.outbytect=0;
} }
lineno++; lineno++;
} }
@ -2654,15 +2811,6 @@ int CLASS::doline(int lineno, std::string line)
MerlinLine l(line,options); MerlinLine l(line,options);
op = Poco::toLower(l.opcode); 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); lines.push_back(l);
if ((op == "use") || (op == "put")) if ((op == "use") || (op == "put"))

12
asm.h
View File

@ -37,6 +37,7 @@ enum asmErrors
{ {
errNone, errNone,
errWarn, errWarn,
errDebug,
errIncomplete, errIncomplete,
errUnimplemented, errUnimplemented,
errFatal, errFatal,
@ -72,6 +73,7 @@ const std::string errStrings[errMAX + 1] =
{ {
"No Error", "No Error",
"Warning", "Warning",
"Debug Error",
"Unfinished Opcode", "Unfinished Opcode",
"Unimplemented Instruction", "Unimplemented Instruction",
"Fatal", "Fatal",
@ -181,6 +183,7 @@ public:
std::string lable; std::string lable;
std::string printlable; std::string printlable;
std::string printoperand; std::string printoperand;
std::string strippedoperand;
std::string opcode; std::string opcode;
std::string opcodelower; std::string opcodelower;
std::string orig_operand; std::string orig_operand;
@ -189,6 +192,7 @@ public:
std::string operand_expr2; std::string operand_expr2;
std::string comment; std::string comment;
std::string addrtext; std::string addrtext;
char shiftchar;
uint8_t linemx; uint8_t linemx;
uint8_t tabs[16]; uint8_t tabs[16];
bool showmx; bool showmx;
@ -228,7 +232,7 @@ protected:
int win_rows; int win_rows;
std::string initialdir; std::string initialdir;
std::vector<std::string> filenames; std::vector<std::string> filenames;
uint32_t syntax; //uint32_t syntax;
uint64_t starttime; uint64_t starttime;
uint8_t tabs[16]; uint8_t tabs[16];
@ -249,7 +253,7 @@ public:
virtual void process(void); virtual void process(void);
virtual void complete(void); virtual void complete(void);
virtual void errorOut(uint16_t code); virtual void errorOut(uint16_t code);
virtual void setLanguage(string lang); virtual void setLanguage(string lang,bool force);
}; };
@ -403,6 +407,9 @@ class TPsuedoOp;
class T65816Asm : public TFileProcessor class T65816Asm : public TFileProcessor
{ {
protected:
std::vector<uint8_t> outputbytes;
public: public:
// options // options
bool casesen; bool casesen;
@ -486,6 +493,7 @@ public:
int parseOperand(MerlinLine &line); int parseOperand(MerlinLine &line);
int getAddrMode(MerlinLine &line); int getAddrMode(MerlinLine &line);
string addrModeEnglish(int mode);
void setOpcode(MerlinLine &line, uint8_t op); void setOpcode(MerlinLine &line, uint8_t op);

View File

@ -607,7 +607,7 @@ int CLASS::evaluate(std::string & e, int64_t &res, uint8_t &_shiftmode)
std::string expr = Poco::trim(e); std::string expr = Poco::trim(e);
expr += " "; // add a space at end to make parsing easier expr += " "; // add a space at end to make parsing easier
if (isDebug() >= 1) if (isDebug() >= 3)
{ {
printf("eval: expression: |%s|\n", expr.c_str()); printf("eval: expression: |%s|\n", expr.c_str());
} }

View File

@ -7,6 +7,7 @@ void CLASS::setOpcode(MerlinLine &line, uint8_t op)
{ {
if (pass > 0) if (pass > 0)
{ {
//printf("cpumode=%d\n",cpumode);
if (cpumode < MODE_65816) // instructions are valid if we are in 65816 if (cpumode < MODE_65816) // instructions are valid if we are in 65816
{ {
uint8_t m = opCodeCompatibility[op]; uint8_t m = opCodeCompatibility[op];
@ -40,6 +41,15 @@ int CLASS::doXC(MerlinLine &line, TSymbol &sym)
std::string s; std::string s;
int res = 0; int res = 0;
if (options.isMerlin()) // in merlin8 mode we don't support XC psuedoop
{
if (line.errorcode == 0) // don't replace other errors
{
line.setError(errIncompatibleOpcode);
}
return(res);
}
if (cpumode < MODE_65816) if (cpumode < MODE_65816)
{ {
cpumode++; cpumode++;
@ -203,7 +213,7 @@ int CLASS::doMVN(MerlinLine &line, TSymbol &sym)
// these bytes are the two bank registers // these bytes are the two bank registers
if (options.isMerlin32() && (v<256)) if (options.isMerlin32() && (v<256))
//if (((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) && (v<256)) //if (((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) && (v<256))
{ {
// merlin32 uses the low byte of the two operands // merlin32 uses the low byte of the two operands
line.outbytes.push_back((v) & 0xFF); line.outbytes.push_back((v) & 0xFF);
@ -248,40 +258,40 @@ int CLASS::doNoPattern(MerlinLine &line, TSymbol &sym)
switch (sym.opcode) switch (sym.opcode)
{ {
case 1: // STZ case 1: // STZ
res++; res++;
op = (m == syn_abs ? 0x64 : op); op = (m == syn_abs ? 0x64 : op);
op = (m == syn_absx ? 0x74 : 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;
op = (op == 0x74) ? 0x9E : op;
}
break;
case 2: // TSB
res++; res++;
op = (m == syn_abs ? 0x04 : op); op = (op == 0x64) ? 0x9C : op;
if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) op = (op == 0x74) ? 0x9E : op;
{ }
res++; break;
op = 0x0C; case 2: // TSB
} res++;
break; op = (m == syn_abs ? 0x04 : op);
case 3: // TRB if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS)))
{
res++; res++;
op = (m == syn_abs ? 0x14 : op); op = 0x0C;
if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) }
{ break;
res++; case 3: // TRB
op = 0x1C; res++;
} op = (m == syn_abs ? 0x14 : op);
break; if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS)))
default: {
op = 0; res++;
err = errBadOpcode; op = 0x1C;
break; }
break;
default:
op = 0;
err = errBadOpcode;
break;
} }
if (op == 0x00) if (op == 0x00)
@ -316,15 +326,15 @@ int CLASS::doAddress(MerlinLine &line, TSymbol &sym)
//} //}
switch(line.expr_shift) switch(line.expr_shift)
{ {
case '^': case '^':
line.expr_value=(line.expr_value>>16)&0xFFFF; line.expr_value=(line.expr_value>>16)&0xFFFF;
break; break;
case '<': case '<':
line.expr_value=(line.expr_value)&0xFF; line.expr_value=(line.expr_value)&0xFF;
break; break;
case '>': case '>':
line.expr_value=(line.expr_value>>8)&0xFFFF; line.expr_value=(line.expr_value>>8)&0xFFFF;
break; break;
} }
//line.setError(errIncomplete); //line.setError(errIncomplete);
@ -347,12 +357,12 @@ int CLASS::doAddress(MerlinLine &line, TSymbol &sym)
uint8_t newmx = (line.expr_value & 0x30) >> 4; uint8_t newmx = (line.expr_value & 0x30) >> 4;
switch (sym.opcode) switch (sym.opcode)
{ {
case 0xC2: // REP case 0xC2: // REP
mx &= ~newmx; mx &= ~newmx;
break; break;
case 0xE2: // SEP case 0xE2: // SEP
mx |= newmx; mx |= newmx;
break; break;
} }
line.linemx = mx; line.linemx = mx;
} }
@ -544,21 +554,21 @@ int CLASS::doBase6502(MerlinLine & line, TSymbol & sym)
int add = 0; int add = 0;
switch (sym.opcode) switch (sym.opcode)
{ {
case 7: // CPX case 7: // CPX
case 6: // CPY case 6: // CPY
case 5: // LDY case 5: // LDY
case 4: // STY case 4: // STY
if ((mx & 0x01) == 0) if ((mx & 0x01) == 0)
{ {
add = 1; add = 1;
} }
break; break;
case 1: // BIT case 1: // BIT
if ((mx & 0x02) == 0) if ((mx & 0x02) == 0)
{ {
add = 1; add = 1;
} }
break; break;
} }
bytelen += add; bytelen += add;
@ -571,34 +581,55 @@ int CLASS::doBase6502(MerlinLine & line, TSymbol & sym)
{ {
switch (m) switch (m)
{ {
case syn_diix: amode = 0; break; case syn_diix:
case syn_abs: amode = 1; break; amode = 0;
case syn_imm: amode = 2; break; break;
case syn_diiy: amode = 4; break; case syn_abs:
case syn_absx: amode = 5; break; amode = 1;
case syn_absy: amode = 6; break; break;
default: case syn_imm:
err = true; amode = 2;
break; break;
case syn_diiy:
amode = 4;
break;
case syn_absx:
amode = 5;
break;
case syn_absy:
amode = 6;
break;
default:
err = true;
break;
} }
} }
else if (cc == 0x02) else if (cc == 0x02)
{ {
switch (m) switch (m)
{ {
case syn_imm: amode = 0; break; case syn_imm:
case syn_abs: amode = 1; break; amode = 0;
case syn_implied: amode = 2; bytelen = 0; break; break;
case syn_absy: case syn_abs:
if ((opflags & OP_STX) == OP_STX) amode = 1;
{ break;
amode = 5; case syn_implied:
} amode = 2;
break; bytelen = 0;
case syn_absx: amode = 5; break; // this is actually Y addressing because X register is used break;
default: case syn_absy:
err = true; if ((opflags & OP_STX) == OP_STX)
break; {
amode = 5;
}
break;
case syn_absx:
amode = 5;
break; // this is actually Y addressing because X register is used
default:
err = true;
break;
} }
if ((opflags & OP_STX) == OP_STX) if ((opflags & OP_STX) == OP_STX)
@ -715,17 +746,32 @@ int CLASS::doBase6502(MerlinLine & line, TSymbol & sym)
err = false; err = false;
switch (m) switch (m)
{ {
case syn_s: amode = 0; break; case syn_s:
case syn_sy: amode = 4; break; amode = 0;
case syn_di: cc = 0x02; amode = 4; break; break;
case syn_iyl: amode = 5; break; case syn_sy:
case syn_dil: amode = 1; break; amode = 4;
case syn_absx: amode = 7; break; break;
case syn_abs: amode = 3; break; case syn_di:
default: cc = 0x02;
//printf("bad syn_mode=%d\n", m); amode = 4;
err = true; break;
break; case syn_iyl:
amode = 5;
break;
case syn_dil:
amode = 1;
break;
case syn_absx:
amode = 7;
break;
case syn_abs:
amode = 3;
break;
default:
//printf("bad syn_mode=%d\n", m);
err = true;
break;
} }
if (!err) if (!err)
{ {
@ -750,15 +796,29 @@ out:
if (err) if (err)
{ {
line.setError(errBadAddressMode); line.setError(errBadAddressMode);
//printf("bad address mode %d\n",line.addressmode); printf("bad address mode %d\n",line.addressmode);
op = 0x00; op = 0x00;
res = 0; res = 0;
bytelen = 0; bytelen = 0;
} }
res += bytelen; res += bytelen;
//if (options.isMerlin32())
{
if ((op==0xB9) || (op==0x79) || (op==0xF9) || (op==0x99))
{
// there are 4 instructions that don't have (dp),y addressing so convert to (abs),
if (bytelen<2)
{
res++;
bytelen++;
}
}
}
if ((pass > 0) && (res > 0)) if ((pass > 0) && (res > 0))
{ {
setOpcode(line, op); setOpcode(line, op);
for (i = 0; i < (res - 1); i++) for (i = 0; i < (res - 1); i++)
{ {
@ -794,23 +854,26 @@ int CLASS::doBYTE(MerlinLine & line, TSymbol & sym)
} }
// SGQ merlin32 apparently tracks XCE instructions when tracking MX status // SGQ merlin32 apparently tracks XCE instructions when tracking MX status
// who know how they determine this. I am assuming the NEXT instruction // who knows how they determine this. I am assuming the NEXT instruction
// after a SEC/CLC instruction must be an XCE // after a SEC/CLC instruction must be an XCE
if (sym.opcode == 0x38) // SEC if (options.isMerlin32())
{ {
lastcarry = true; if (sym.opcode == 0x38) // SEC
}
else if (sym.opcode == 0x18) // CLC
{
lastcarry = false;
}
else if (sym.opcode == 0xFB) // XCE
{
if (trackrep)
{ {
if (lastcarry) lastcarry = true;
}
else if (sym.opcode == 0x18) // CLC
{
lastcarry = false;
}
else if (sym.opcode == 0xFB) // XCE
{
if (trackrep)
{ {
mx = 0x03; if (lastcarry)
{
mx = 0x03;
}
} }
} }
} }
@ -847,11 +910,11 @@ void CLASS::insertOpcodes(void)
{ {
pushopcode("=", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEQU)); pushopcode("=", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEQU));
pushopcode("EQU", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEQU)); pushopcode("EQU", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEQU));
pushopcode("END", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEND)); pushopcode("END", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEND));
pushopcode("MX", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doMX)); pushopcode("MX", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doMX));
pushopcode("XC", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doXC)); pushopcode("XC", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doXC));
pushopcode("EXT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("EXT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("ENT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ENT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("ORG", P_ORG, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ORG", P_ORG, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("DSK", P_SAV, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DSK", P_SAV, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));

View File

@ -7,20 +7,26 @@
"0": "${PWD}" "0": "${PWD}"
}, },
{ {
"1": "0/source" "1": "${QASM_BASE}"
}, },
{ {
"2": "0/object" "2": "0/object"
}, },
{ {
"3": "0/macros" "3": "1/macros"
},
{
"4": "1/toolmacs"
},
{
"5": "../backup"
} }
] ]
}, },
"language": "qasm",
"asm": { "asm": {
"language": "merlin16plus", "cpu": "M65816",
"cpu": "M6502", "start_mx": 0,
"start_mx": 2,
"listmode": "on", "listmode": "on",
"casesen": true, "casesen": true,
"start_lst": false, "start_lst": false,

View File

@ -793,6 +793,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
uint8_t delimiter = 0; uint8_t delimiter = 0;
uint32_t ss = 0; uint32_t ss = 0;
uint32_t lastdelimidx = 0; uint32_t lastdelimidx = 0;
bool dci = false;
std::vector<uint8_t> bytes; std::vector<uint8_t> bytes;
@ -890,7 +891,6 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
{ {
uint32_t i; uint32_t i;
bool reverse = false; bool reverse = false;
bool dci = false;
uint8_t andval = 0xFF; uint8_t andval = 0xFF;
uint8_t orval = 0x00; uint8_t orval = 0x00;
uint8_t addlen = 0; uint8_t addlen = 0;
@ -956,28 +956,42 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
b |= orval; b |= orval;
} }
if (dci && (i == lastdelimidx)) if ((line.options->isMerlin32()) || (line.options->isMerlin16plus()))
{ {
// SGQ BUG - Merlin16+ does it like Merlin32 and now does the last // invert last byte of total bytes out
// 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 if ((dci) && ((i+1)>=truebytect))
// 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; b^=0x80;
} }
else }
else
{
printf("bug\n");
// invert last byte of last string (old merlin way (pre-merlin16+))
if (dci && (i == lastdelimidx))
{ {
b &= 0x7F; // 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 >= '\'' )
{
b |= 0x80;
}
else
{
b &= 0x7F;
}
} }
} }
line.outbytes.push_back(b); line.outbytes.push_back(b);
@ -986,7 +1000,7 @@ int CLASS::doASC(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
bytect = bytect + addlen; bytect = bytect + addlen;
} }
//printf("XXX bytect=%d bytes.size()=%zu\n",bytect,bytes.size()); //printf("XXX bytect=%d bytes.size()=%zu\n",bytect,bytes.size());
line.outbytect = bytect; line.outbytect = bytect;
return bytect; return bytect;
@ -1033,7 +1047,8 @@ int CLASS::ProcessOpcode(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
#if 0 #if 0
// Merlin32 seems to have a bug where ORG seems like it can only be 16 bits // Merlin32 seems to have a bug where ORG seems like it can only be 16 bits
if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) //if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32)
if (options.isMerlin32())
{ {
// so clear the bank word in all variables // so clear the bank word in all variables
a.PC.orgsave &= 0xFFFF; a.PC.orgsave &= 0xFFFF;
@ -1048,7 +1063,8 @@ int CLASS::ProcessOpcode(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
sp = getConfig("option.objfile", ""); sp = getConfig("option.objfile", "");
if (sp=="") if (sp=="")
{ {
a.savepath = a.processFilename(line.operand, Poco::Path::current(), 0); //a.savepath = a.processFilename(line.operand, Poco::Path::current(), 0);
a.savepath=line.operand;
} }
else // if they specified an output name on the command line, use it. else // if they specified an output name on the command line, use it.
{ {

View File

@ -115,10 +115,11 @@ int CLASS::runCommandLineApp(void)
return (res); return (res);
} }
options.ReadFile(Poco::Path::config()+"/parms.json"); //printf("apppath: |%s|\n",appPath.c_str());
options.ReadFile(appPath+"/parms.json"); options.ReadFile(Poco::Path::config()+"/parms.json",false);
options.ReadFile(Poco::Path::configHome()+"/parms.json"); options.ReadFile(appPath+"/parms.json",true);
options.ReadFile(Poco::Path::current()+"/parms.json"); options.ReadFile(Poco::Path::configHome()+"/parms.json",false);
options.ReadFile(Poco::Path::current()+"/parms.json",false);
syn="QASM"; syn="QASM";
@ -145,6 +146,7 @@ int CLASS::runCommandLineApp(void)
} }
language=syn; language=syn;
options.setLanguage(syn,true);
if (isDebug()>0) if (isDebug()>0)
{ {
@ -237,7 +239,7 @@ int CLASS::runCommandLineApp(void)
try try
{ {
t->init(); t->init();
t->setLanguage(language); t->setLanguage(language,true);
t->format_flags=format_flags; t->format_flags=format_flags;
std::string f = path.toString(); std::string f = path.toString();
@ -271,7 +273,7 @@ int CLASS::runCommandLineApp(void)
try try
{ {
t->init(); t->init();
t->setLanguage(language); t->setLanguage(language,true);
std::string f = path.toString(); std::string f = path.toString();
@ -308,7 +310,7 @@ int CLASS::runCommandLineApp(void)
try try
{ {
t->init(); t->init();
t->setLanguage(language); t->setLanguage(language,true);
std::string f = path.toString(); std::string f = path.toString();
t->filename = f; t->filename = f;

View File

@ -3,6 +3,8 @@
using namespace Poco; using namespace Poco;
#define ENV_QASM "QASM_BASE"
#define MAX_PREFIX 32 #define MAX_PREFIX 32
#define MODE_6502 0 #define MODE_6502 0
@ -10,13 +12,15 @@ using namespace Poco;
#define MODE_65816 2 #define MODE_65816 2
#define SYNTAX_MERLIN 0x01 #define SYNTAX_MERLIN 0x01
#define SYNTAX_MERLIN32 0x02 #define SYNTAX_MERLIN16 0x02
#define SYNTAX_APW 0x04 #define SYNTAX_MERLIN16PLUS 0x04
#define SYNTAX_MPW 0x08 #define SYNTAX_MERLIN32 0x08
#define SYNTAX_ORCA 0x10 #define SYNTAX_APW 0x10
#define SYNTAX_CC65 0x20 #define SYNTAX_MPW 0x20
#define SYNTAX_LISA 0x40 #define SYNTAX_ORCA 0x40
#define SYNTAX_QASM (0x80 | SYNTAX_MERLIN) #define SYNTAX_CC65 0x80
#define SYNTAX_LISA 0x100
#define SYNTAX_QASM (0x200 | SYNTAX_MERLIN)
#define OPTION_ALLOW_A_OPERAND 0x0100 #define OPTION_ALLOW_A_OPERAND 0x0100
#define OPTION_ALLOW_LOCAL 0x0200 #define OPTION_ALLOW_LOCAL 0x0200
@ -41,11 +45,11 @@ class CLASS
{ {
protected: protected:
//vector<shared_ptr<JSONConfiguration>> configs; //vector<shared_ptr<JSONConfiguration>> configs;
vector<std::string> valid_files;
public: public:
Poco::JSON::Parser parser; //Poco::JSON::Parser parser;
string jsonin; //string jsonin;
Dynamic::Var jsonobj=NULL; //Dynamic::Var jsonobj=NULL;
uint16_t format_flags; uint16_t format_flags;
uint16_t cpu_mode; uint16_t cpu_mode;
@ -70,23 +74,34 @@ public:
int16_t linebytes; int16_t linebytes;
int16_t overflowbytes; int16_t overflowbytes;
myLayeredConfiguration config; myLayeredConfiguration *config=NULL;
bool usecolor; bool usecolor;
CLASS() CLASS()
{ {
language="";
setEnvironment();
clear();
setDefaults(); setDefaults();
setLanguage("QASM"); setLanguage("QASM",true);
setCurrent();
} }
~CLASS() ~CLASS()
{ {
clear();
} }
void clear() void clear()
{ {
//configs.clear(); if (config!=NULL)
{
delete config;
config=NULL;
}
config=new myLayeredConfiguration();
valid_files.clear();
} }
bool useColor(void) bool useColor(void)
@ -125,6 +140,8 @@ public:
int printDefaults(string lang) int printDefaults(string lang)
{ {
int res=-1; int res=-1;
string s;
int i;
string l=Poco::toUpper(lang); string l=Poco::toUpper(lang);
if (l=="") if (l=="")
{ {
@ -132,24 +149,46 @@ public:
} }
if (l!="") if (l!="")
{ {
setLanguage(l); setLanguage(l,false);
setCurrent(); setCurrent();
printf("Defaults for language (%s)\n",language.c_str()); printf("Defaults for language (%s)\n",language.c_str());
printf("\tLanguage:\t\t\t\t\t%s\n",language.c_str()); printf("\t\tLanguage:\t\t\t%s\n",language.c_str());
printf("\t\tlanguageLevel:\t\t\t\t%d\n",langlevel); printf("\t\tlanguageLevel:\t\t\t%d\n",langlevel);
printf("\t\tcpu_mode:\t\t\t\t%d\n",cpu_mode); s="<unknown>";
printf("\t\tstart_mx:\t\t\t\t%d\n",start_mx); switch(cpu_mode)
{
case 0:
s="M6502";
break;
case 1:
s="M65C02";
break;
case 2:
s="M65816";
break;
}
printf("\t\tcpu_mode:\t\t\t%s\n",s.c_str());
printf("\t\tstart_mx:\t\t\t%%%d%d\n",start_mx&0x02?1:0,start_mx&0x01?1:0);
//printf("\t\tstart_mx:\t\t\t%d\n",start_mx);
printf("\t\tPrefixes:\n"); printf("\t\tPrefixes:\n");
for (int i=0; i<MAX_PREFIX; i++) for (i=0; i<MAX_PREFIX; i++)
{ {
if (prefixes[i].length()>0) if (prefixes[i].length()>0)
{ {
printf("\t\t\t%02d:\t\t\t%s\n",i,prefixes[i].c_str()); printf("\t\t\t%2d:\t%s\n",i,prefixes[i].c_str());
} }
} }
printf("\n");
for (unsigned long ii=0; ii<valid_files.size(); ii++)
{
if (prefixes[ii].length()>0)
{
printf("\t\tSettings files read: \t%s\n",valid_files[ii].c_str());
}
}
//uint16_t format_flags; //uint16_t format_flags;
@ -160,68 +199,292 @@ public:
return(res); return(res);
} }
int ReadFile(string path) string getAppPath()
{ {
char buff[PATH_MAX+1];
char *x;
string res="";
res=Poco::Util::Application::instance().commandPath();
x=realpath(res.c_str(),buff);
if (x!=NULL)
{
res=buff;
}
else
{
res="";
}
return(res);
}
int ReadFile(string path, bool backtrack)
{
//int levels=0;
bool done=false;
int ret=-1; int ret=-1;
unsigned long ii;
Poco::Util::JSONConfiguration *jc; Poco::Util::JSONConfiguration *jc;
Poco::Path pp(path); while(!done)
//pp=pp.expand();
Poco::File pf(pp);
if (isDebug()>1)
{ {
printf("parmsfile: %s\n",pp.toString().c_str()); Poco::Path pp(path);
} //pp=pp.absolute(Poco::Path("/"));
if ((pf.exists()) && (pf.canRead()) && ((pf.isFile()) || (pf.isLink()))) pp=pp.absolute();
{
//printf("OK: %s\n",pp.toString().c_str());
jc=new Poco::Util::JSONConfiguration(); std::string basename=pp.getFileName();
//Poco::FileInputStream fs(path);
//Poco::StreamCopier::copyToString(fs,jsonin); Poco::File pf(pp);
//parser.reset(); if (isDebug()>1)
//parser.setAllowComments(true);
//jsonobj=parser.parse(jsonin);
if (jc!=NULL)
{ {
bool success=false; //pf.
try printf(" %d parmsfile: %s ",backtrack,pf.path().c_str());
}
if ((pf.exists()) && (pf.canRead()) && ((pf.isFile()) || (pf.isLink())))
{
if (isDebug()>1)
{ {
jc->load(pp.toString()); printf("...found!\n");
success=true;
} }
catch(...) //printf("OK: %s\n",pp.toString().c_str());
done=false;
for (ii=0; ii<valid_files.size(); ii++)
{ {
success=false; if (pf.path()==valid_files[ii])
{
done=true;
}
} }
if (success) if (!done)
{ {
//configs.push_back(shared_ptr<JSONConfiguration>(jc)); done=true; // we found a valid file
config.add(jc);
ret=0; 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<JSONConfiguration>(jc));
config->add(jc);
valid_files.push_back(pp.toString());
ret=0;
}
else
{
delete jc;
jc=NULL;
printf("...unable to load/parts file: %s\n",pp.toString().c_str());
}
}
} }
else
}
else
{
if (isDebug()>1)
{ {
printf("unable to load/parts file: %s\n",pp.toString().c_str()); printf("...not found\n");
} }
} }
if (!backtrack)
{
done=true;
}
if (!done)
{
//string ss=pp.current();
string ss=pp.toString();
pp=pp.popDirectory();
string ss1=pp.toString();
//printf("|%s| |%s|\n",ss.c_str(),ss1.c_str());
//assert(0);
path=ss1;
pp=Path(path);
if (path=="/")
{
done=true;
}
//path=path+"/"+basename;
}
} }
return(ret); return(ret);
} }
bool isMerlin32(void) bool isMerlin32(void)
{ {
return(true); bool res=false;
if (language=="MERLIN32")
{
res=true;
}
return(res);
} }
bool isMerlin(void) bool isMerlin(void)
{ {
return(false); bool res=false;
if (language=="MERLIN")
{
res=true;
}
return(res);
}
bool isQASM(void)
{
bool res=false;
if (language=="QASM")
{
res=true;
}
return(res);
}
bool isMerlinCompat()
{
bool res=false;
string s=language;
if (s=="QASM")
{
return(true);
}
bool b=s.find("MERLIN"); // any of the merlin varieties
if (b)
{
res=true;
return(res);
}
return(res);
}
bool isMerlin16(void)
{
bool res=false;
if (language=="MERLIN16")
{
res=true;
}
return(res);
}
bool isMerlin16plus(void)
{
bool res=false;
if (language=="MERLIN16PLUS")
{
res=true;
}
return(res);
}
void setEnvironment()
{
string s="";
//s=Poco::Environment::get("QASM");
if (!Poco::Environment::has(ENV_QASM))
{
s=Poco::Util::Application::instance().commandPath();
Poco::Path pp(getAppPath());
pp=pp.absolute(Poco::Path());
//pp=pp.absolute(Poco::Path("/"));
s=pp.toString();
//printf("program: %s\n",s.c_str());
Poco::Environment::set(ENV_QASM,s);
}
}
string formatPath(string p)
{
string res=p;
string s;
Poco::Path pp(p);
s=pp.expand(pp.toString()); // replace environment variable references
pp=Poco::Path(s);
if (s!="")
{
Poco::StringTokenizer toks(s,"/");
if (toks.count()>0)
{
uint32_t n;
bool success=false;
try
{
n=Poco::NumberParser::parseUnsigned(toks[0]);
if (n<MAX_PREFIX)
{
success=true;
}
}
catch(const std::exception& e)
{
success=false;
}
if (success)
{
s=s.substr(toks[0].length(),s.length());
s=prefixes[n]+s;
pp=Poco::Path(s);
}
}
//pp=pp.absolute(Poco::Path("/"));
pp=pp.absolute();
res=pp.toString();
}
return(res);
} }
void setCurrent(void) void setCurrent(void)
{ {
char buff[1024];
string s,n;
int i;
start_mx=GetInteger("asm.start_mx",3); start_mx=GetInteger("asm.start_mx",3);
for (i=0; i<MAX_PREFIX; i++)
{
sprintf(buff,"general.prefix[%d].%d",i,i);
n=buff;
n=GetString(n,"");
n=formatPath(n);
prefixes[i]=n;
}
s=GetString("asm.cpu","M6502");
if (s=="M6502")
{
cpu_mode=MODE_6502;
}
else if (s=="M65C02")
{
cpu_mode=MODE_65C02;
}
else if (s=="M65816")
{
cpu_mode=MODE_65816;
}
else
{
printf("unknown cpu_mode in settings (%s) [M6502, M65C02, M65816]\n",s.c_str());
cpu_mode=MODE_6502;
}
allowDuplicate=GetBool("asm.allowduplicate",false);
} }
void setDefaults(void) void setDefaults(void)
{ {
@ -251,15 +514,15 @@ public:
usecolor=true; usecolor=true;
} }
void setLanguage(string lang) void setLanguage(string lang, bool force)
{ {
//printf("request language options to %s from %s\n",lang.c_str(),language.c_str()); //printf("request language options to %s from %s\n",lang.c_str(),language.c_str());
string old=language; string old=language;
string pn=Poco::toUpper(lang); string pn=Poco::toUpper(lang);
if (old!=pn) if ((old!=pn) || (force))
{ {
//printf("setting language options to %s\n",pn.c_str()); printf("setting language options to %s\n",pn.c_str());
language=pn; language=pn;
setCurrent(); setCurrent();
if (pn=="QASM") if (pn=="QASM")
@ -333,6 +596,8 @@ public:
bool res=def; bool res=def;
try try
{ {
res=config->getBool(name);
//Dynamic::Var jresult=GetObject(name); //Dynamic::Var jresult=GetObject(name);
//if (!jresult.isEmpty()) //if (!jresult.isEmpty())
//{ //{
@ -358,7 +623,7 @@ public:
string res=def; string res=def;
try try
{ {
//config res=config->getString(name);
} }
catch(...) catch(...)
{ {
@ -373,8 +638,8 @@ public:
#if 0 #if 0
std::vector<std::string> keys; std::vector<std::string> keys;
config.keys(keys); config->keys(keys);
for (unsigned int i=0;i<keys.size();i++) for (unsigned int i=0; i<keys.size(); i++)
{ {
printf("key[%d]: %s\n",i,keys[i].c_str()); printf("key[%d]: %s\n",i,keys[i].c_str());
} }
@ -382,7 +647,7 @@ public:
try try
{ {
res=config.getInt(name); res=config->getInt(name);
} }
catch(...) catch(...)
{ {

View File

@ -29,10 +29,14 @@ for S in $SRC ; do
BASE=${BASE/.s/} BASE=${BASE/.s/}
#./qasm -o 0/$OUTDIR/$S1 ./testdata/$S #./qasm -o 0/$OUTDIR/$S1 ./testdata/$S
./qasm --syntax merlin32 -o 0/$OUTDIR/$S1 ./testdata/$S >> $TMPFILE ./qasm -l -t merlin32 -i M65816 -o 0/$OUTDIR/$S1 ./testdata/$S >> $TMPFILE
X="./qasm -l -t merlin32 -i M65816 -o 0/$OUTDIR/$S1 ./testdata/$S"
#echo $X
R=?$ R=?$
#echo $S " " $S1 #echo $S " " $S1
#cat $TMPFILE
R=`cat $TMPFILE | grep "End qASM assembly"` R=`cat $TMPFILE | grep "End qASM assembly"`
E=`echo $R | awk -e '{ print $6; }'` E=`echo $R | awk -e '{ print $6; }'`
ect=`echo $(($E))` ect=`echo $(($E))`
@ -64,8 +68,12 @@ for S in $SRC ; do
if [ $pct != 0 ] ; then if [ $pct != 0 ] ; then
printf 'FAIL: (%3s) ' $ect printf 'FAIL: (%3s) ' $ect
printf '%s ' $CX printf '%s ' $CX
echo " $S"
FAILCT=$(($FAILCT+1)) FAILCT=$(($FAILCT+1))
cat $TMPFILE
echo $X
exit 255
else else
printf "PASS: " printf "PASS: "
fi fi

33
test.s
View File

@ -10,9 +10,36 @@
xc off xc off
xc xc
xc xc
lst
;lst OFF ;lst OFF
ZP equ $00 ZP equ $00
org $2000 org $2000
lda $04,y
adc $04,y
sbc $04,y
sta $04,y
lda <$fff0 ;zp
lda >$fff0 ;ABS (lo word)
lda ^$fff0 ;ABS (hi word)
lda |$fff0 ;ABS (long in 65816 mode)
lda <$FFF0+$FFFF
lda <$fff0+24 ;zp
lda >$fff0+24 ;ABS (lo word)
lda ^$fff0+24 ;ABS (hi word)
lda |$fff0+24 ;ABS (long in 65816 mode)
lda #<$fff0 ;zp
lda #>$fff0 ;ABS (lo word)
lda #^$fff0 ;ABS (hi word)
lda #<$FFF0+$FFFF
lda #>$FFF0+$FFFF
lst off
end
ora ($00) ora ($00)
lda ($00) lda ($00)
bit: $FFFE,X bit: $FFFE,X
@ -51,11 +78,15 @@ another lda #$00 ;line with everything
lda ]m lda ]m
bra ]m bra ]m
--^ --^
sav 2/test.bin
end
]1 nop ]1 nop
nop nop
;lst ;lst
bra ]1 bra ]1
;typ $06 ;typ $06
sav 0/test.bin db 255
;lst off ;lst off

View File

@ -1,8 +1,9 @@
; Copyright 2018 faddenSoft. All Rights Reserved. ; Copyright 2018 faddenSoft. All Rights Reserved.
; See the LICENSE.txt file for distribution terms (Apache 2.0). ; See the LICENSE.txt file for distribution terms (Apache 2.0).
; ;
; Assembler: Merlin 32 ; Assembler: Merlin 32
xc off
ZP EQU $00 ZP EQU $00
ABS EQU $0000 ABS EQU $0000

View File

@ -4,7 +4,9 @@
; Assembler: Merlin 32 ; Assembler: Merlin 32
org $1000 org $1000
xc off
xc
xc
; 65816 with short regs ; 65816 with short regs
clc clc
xce xce

View File

@ -2,7 +2,9 @@
; See the LICENSE.txt file for distribution terms (Apache 2.0). ; See the LICENSE.txt file for distribution terms (Apache 2.0).
; ;
; Assembler: Merlin 32 ; Assembler: Merlin 32
xc off
xc
xc
absl equ $1029 absl equ $1029
absh equ $feed absh equ $feed
zip equ $cd zip equ $cd

View File

@ -1,4 +1,4 @@
;lst off lst off
* *
* main.s * main.s
* Merlin32 Test * Merlin32 Test
@ -6,401 +6,403 @@
* Created by Lane Roathe on 8/26/19. * Created by Lane Roathe on 8/26/19.
* Copyright B) 2019 Ideas From the Deep. All rights reserved. * Copyright B) 2019 Ideas From the Deep. All rights reserved.
* *
//]XCODESTART ; Keep this at the start and put your code after this //]XCODESTART ; Keep this at the start and put your code after this
xc off xc off
xc xc
xc xc
mx %00 mx %00
*========================================================== *==========================================================
* monitor addresses * monitor addresses
TEXT = $FB39 ;Reset text window TEXT = $FB39 ;Reset text window
TABV = $FB5B ;Complete vtab, using contents of 'A' TABV = $FB5B ;Complete vtab, using contents of 'A'
MONBELL = $FBE4 ;random bell noise! MONBELL = $FBE4 ;random bell noise!
HOME = $FC58 ;Clear text window HOME = $FC58 ;Clear text window
WAIT = $FCA8 ;delay routine WAIT = $FCA8 ;delay routine
CROUT = $FD8E ;Print a CR CROUT = $FD8E ;Print a CR
PRBYTE = $FDDA ;Print 'A' as a hex number PRBYTE = $FDDA ;Print 'A' as a hex number
PRHEX = $FDE3 ;as above, but bits 0-3 only PRHEX = $FDE3 ;as above, but bits 0-3 only
COUT = $FDED ;Monitor char out COUT = $FDED ;Monitor char out
MOVE = $FE2C ;memory move routine MOVE = $FE2C ;memory move routine
INVERSE = $FE80 ;Print in inverse INVERSE = $FE80 ;Print in inverse
NORMAL = $FE84 ;Normal print NORMAL = $FE84 ;Normal print
* Jump Vectors * Jump Vectors
CONNECT = $3EA ;Connect DOS CONNECT = $3EA ;Connect DOS
DOSWARM = $3D0 ;exit to DOS prompt DOSWARM = $3D0 ;exit to DOS prompt
RSTVEC = $3F2 ;reset vector RSTVEC = $3F2 ;reset vector
TSTADDR = $1000 ;absolute address for testing TSTADDR = $1000 ;absolute address for testing
*========================================================== *==========================================================
* Data Index DUM section test * Data Index DUM section test
DUM 0 DUM 0
dum0 ds 1 ;fractional byte dum0 ds 1 ;fractional byte
dum1 ds 1 dum1 ds 1
dumSize = * dumSize = *
DEND DEND
;lst off ;lst off
*========================================================== *==========================================================
* zero page (all zp var names are prefixed with _) * zero page (all zp var names are prefixed with _)
DUM 0 DUM 0
_ptr ds 2 _ptr ds 2
_tmp ds 2 _tmp ds 2
_num1 ds dumSize ;first and second operand values _num1 ds dumSize ;first and second operand values
; test ORG with DUM section ; test ORG with DUM section
ORG $20 ORG $20
_LFT ds 1 ;Window edge 0..39 _LFT ds 1 ;Window edge 0..39
DEND DEND
*========================================================== *==========================================================
* Program Entry * Program Entry
START START
adc (0,x) adc (0,x)
adc ($80,x) adc ($80,x)
adc (_tmp,x) adc (_tmp,x)
adc (_tmp+0,x) adc (_tmp+0,x)
adc (_tmp+$10,x) adc (_tmp+$10,x)
adc ($10+_tmp,x) adc ($10+_tmp,x)
adc (_tmp+dum0,x) adc (_tmp+dum0,x)
adc (_tmp+dum1,x) adc (_tmp+dum1,x)
adc (_tmp+dum1+1,x) adc (_tmp+dum1+1,x)
adc (_tmp+dum0+dum1,x) adc (_tmp+dum0+dum1,x)
adc 0 adc 0
adc $80 adc $80
adc _tmp adc _tmp
adc #0 adc #0
adc #$1111 adc #$1111
adc $1111 adc $1111
sta TSTADDR+dum0 sta TSTADDR+dum0
sta TSTADDR+_num1+dum0 sta TSTADDR+_num1+dum0
sta TSTADDR+_num1+dum0,x sta TSTADDR+_num1+dum0,x
lda _num1+dum0 lda _num1+dum0
adc _num1+dum1 adc _num1+dum1
sbc _num1+dum1 sbc _num1+dum1
bit _num1+dum0 bit _num1+dum0
sta _num1+dum0 ;(FIXED): can't use sta _num1+dum0 ' sta _num1+dum0 ;(FIXED): can't use sta _num1+dum0 '
stz _num1+dum0 stz _num1+dum0
lda _num1+dum0,x lda _num1+dum0,x
adc _num1+dum0,x adc _num1+dum0,x
sbc _num1+dum0,x sbc _num1+dum0,x
bit _num1+dum0,x bit _num1+dum0,x
sta _num1+dum0,x sta _num1+dum0,x
stz _num1+dum0,x stz _num1+dum0,x
lda _num1+dum0,y ;these assemble to abs accesses: lda $00C0,y lst
adc _num1+dum0,y lda _num1+dum0,y ;these assemble to abs accesses: lda $00C0,y
sbc _num1+dum0,y adc _num1+dum0,y
sta _num1+dum0,y sbc _num1+dum0,y
sta _num1+dum0,y
lst off
; Label & branching tests ; Label & branching tests
GetKey ldx $C000 GetKey ldx $C000
bpl GetKey bpl GetKey
]loop ]loop
dex dex
bne ]loop bne ]loop
tya tya
and #1 and #1
beq :err beq :err
tya tya
and #1 and #1
bne :good bne :good
:err :err
lda #0 lda #0
:good :good
bne myQuit bne myQuit
nop nop
hex 2C ;bit hex 2C ;bit
lda #1 lda #1
myQuit myQuit
jmp DOSWARM jmp DOSWARM
org $2000 org $2000
lda _LFT lda _LFT
ldx #_LFT ldx #_LFT
cpx #$20 cpx #$20
org ;return to ongoing address org ;return to ongoing address
lda $FF lda $FF
;Issue #16 (fadden) - Byte reference modifiers are ignored (no way to force DP) ;Issue #16 (fadden) - Byte reference modifiers are ignored (no way to force DP)
lda <$fff0 ;zp lda <$fff0 ;zp
lda >$fff0 ;ABS (lo word) lda >$fff0 ;ABS (lo word)
lda ^$fff0 ;ABS (hi word) lda ^$fff0 ;ABS (hi word)
lda |$fff0 ;ABS (long in 65816 mode) lda |$fff0 ;ABS (long in 65816 mode)
lda $08 lda $08
lda $0008 lda $0008
lda $FFFF-$FFF7 lda $FFFF-$FFF7
lda $FFF0+24 lda $FFF0+24
ldaz $FFF0+24 ; forced DP ldaz $FFF0+24 ; forced DP
ldaz $FFFF ; forced DP ldaz $FFFF ; forced DP
lda: $FFFF ; forced ABS (any char but 'L', 'D', and 'Z' lda: $FFFF ; forced ABS (any char but 'L', 'D', and 'Z'
ldal $FFFF ; forced long abs (3 byte address) ldal $FFFF ; forced long abs (3 byte address)
ldaz $05 ldaz $05
lda: $05 lda: $05
ldal $05 ldal $05
lda $45 lda $45
lda $2345 lda $2345
lda $012345 lda $012345
ldaz $2345 ldaz $2345
lda: $45 lda: $45
ldal $012345 ldal $012345
ldal $2345 ldal $2345
ldal $45 ldal $45
lda <$2345 lda <$2345
lda >$2345 lda >$2345
lda <$012345 lda <$012345
lda >$012345 lda >$012345
lda ^$012345 lda ^$012345
lda |$012345 lda |$012345
ora $45 ora $45
ora $2345 ora $2345
ora $012345 ora $012345
oraz $2345 oraz $2345
ora: $45 ora: $45
oral $012345 oral $012345
oral $2345 oral $2345
oral $45 oral $45
ora <$2345 ora <$2345
ora >$2345 ora >$2345
ora <$012345 ora <$012345
ora >$012345 ora >$012345
ora ^$012345 ora ^$012345
ora |$012345 ora |$012345
and $45 and $45
and $2345 and $2345
and $012345 and $012345
andz $2345 andz $2345
and: $45 and: $45
andl $012345 andl $012345
andl $2345 andl $2345
andl $45 andl $45
and <$2345 and <$2345
and >$2345 and >$2345
and <$012345 and <$012345
and >$012345 and >$012345
and ^$012345 and ^$012345
and |$012345 and |$012345
eor $45 eor $45
eor $2345 eor $2345
eor $012345 eor $012345
eorz $2345 eorz $2345
eor: $45 eor: $45
eorl $012345 eorl $012345
eorl $2345 eorl $2345
eorl $45 eorl $45
eor <$2345 eor <$2345
eor >$2345 eor >$2345
eor <$012345 eor <$012345
eor >$012345 eor >$012345
eor ^$012345 eor ^$012345
eor |$012345 eor |$012345
adc $45 adc $45
adc $2345 adc $2345
adc $012345 adc $012345
adcz $2345 adcz $2345
adc: $45 adc: $45
adcl $012345 adcl $012345
adcl $2345 adcl $2345
adcl $45 adcl $45
adc <$2345 adc <$2345
adc >$2345 adc >$2345
adc <$012345 adc <$012345
adc >$012345 adc >$012345
adc ^$012345 adc ^$012345
adc |$012345 adc |$012345
sta $45 sta $45
sta $2345 sta $2345
sta $012345 sta $012345
staz $2345 staz $2345
sta: $45 sta: $45
stal $012345 stal $012345
stal $2345 stal $2345
stal $45 stal $45
sta <$2345 sta <$2345
sta >$2345 sta >$2345
sta <$012345 sta <$012345
sta >$012345 sta >$012345
sta ^$012345 sta ^$012345
sta |$012345 sta |$012345
cmp $45 cmp $45
cmp $2345 cmp $2345
cmp $012345 cmp $012345
cmpz $2345 cmpz $2345
cmp: $45 cmp: $45
cmpl $012345 cmpl $012345
cmpl $2345 cmpl $2345
cmpl $45 cmpl $45
cmp <$2345 cmp <$2345
cmp >$2345 cmp >$2345
cmp <$012345 cmp <$012345
cmp >$012345 cmp >$012345
cmp ^$012345 cmp ^$012345
cmp |$012345 cmp |$012345
sbc $45 sbc $45
sbc $2345 sbc $2345
sbc $012345 sbc $012345
sbcz $2345 sbcz $2345
sbc: $45 sbc: $45
sbcl $012345 sbcl $012345
sbcl $2345 sbcl $2345
sbcl $45 sbcl $45
sbc <$2345 sbc <$2345
sbc >$2345 sbc >$2345
sbc <$012345 sbc <$012345
sbc >$012345 sbc >$012345
sbc ^$012345 sbc ^$012345
sbc |$012345 sbc |$012345
;asll $1234 ;asll $1234
lda <$fff0+24 ;zp lda <$fff0+24 ;zp
lda >$fff0+24 ;ABS (lo word) lda >$fff0+24 ;ABS (lo word)
lda ^$fff0+24 ;ABS (hi word) lda ^$fff0+24 ;ABS (hi word)
lda |$fff0+24 ;ABS (long in 65816 mode) lda |$fff0+24 ;ABS (long in 65816 mode)
mx %11 mx %11
lda #<$fff0+24 ;byte lda #<$fff0+24 ;byte
lda #>$fff0+24 ;page lda #>$fff0+24 ;page
lda #^$fff0+24 ;bank lda #^$fff0+24 ;bank
lda #<$1234 ;byte lda #<$1234 ;byte
lda #>$1234 ;page lda #>$1234 ;page
lda #^$1234 ;bank lda #^$1234 ;bank
lda #^$A51234 ;bank lda #^$A51234 ;bank
mx %00 mx %00
lda #<$fff0+24 ;byte lda #<$fff0+24 ;byte
lda #>$fff0+24 ;page lda #>$fff0+24 ;page
lda #^$fff0+24 ;bank lda #^$fff0+24 ;bank
lda #<$1234 ;byte lda #<$1234 ;byte
lda #>$1234 ;page lda #>$1234 ;page
lda #^$1234 ;bank lda #^$1234 ;bank
lda #^$A51234 ;bank lda #^$A51234 ;bank
lda $0008 ;ZP lda $0008 ;ZP
lda $08 ;ZP lda $08 ;ZP
lda $ffff-$fff7 ;ZP lda $ffff-$fff7 ;ZP
lda $fff0+24 ;ABS (long in 65816 mode) lda $fff0+24 ;ABS (long in 65816 mode)
;Issue #8 fadden) - STX zp,y fails to assemble ;Issue #8 fadden) - STX zp,y fails to assemble
org $bc org $bc
L00BC bit L00BC L00BC bit L00BC
org org
stx $bc,y stx $bc,y
ldx L00BC,y ldx L00BC,y
stx L00BC,y stx L00BC,y
* Data Storage Tests * Data Storage Tests
hex ;no error hex ;no error
hex 11,22,33,44,55,66,77,88,99 hex 11,22,33,44,55,66,77,88,99
;hex 112233445566778899F ;hex 112233445566778899F
;hex 112233445I566778899FF ;hex 112233445I566778899FF
hex aabb,CC,0123456789abcdefABCDEF,ff hex aabb,CC,0123456789abcdefABCDEF,ff
ds 36 ds 36
da $A55A da $A55A
da $A55A,$1234 da $A55A,$1234
dw $A55A dw $A55A
dw $A55A,$1234 dw $A55A,$1234
ddb $A55A ddb $A55A
ddb $A55A,$1234 ddb $A55A,$1234
dfb $A55A dfb $A55A
dfb $A55A,$1234 dfb $A55A,$1234
db $A55A db $A55A
db $A55A,$1234 db $A55A,$1234
adr $01A55A adr $01A55A
adr $01A55A,$011234 adr $01A55A,$011234
adrl $01A55A adrl $01A55A
adrl $01A55A,$011234 adrl $01A55A,$011234
dw >$01A55A,>$011234 dw >$01A55A,>$011234
dw <$01A55A,<$011234 dw <$01A55A,<$011234
dw ^$01A55A,^$011234 dw ^$01A55A,^$011234
dw |$01A55A,|$011234 dw |$01A55A,|$011234
db >$01A55A,>$011234 db >$01A55A,>$011234
db <$01A55A,<$011234 db <$01A55A,<$011234
db ^$01A55A,^$011234 db ^$01A55A,^$011234
db |$01A55A,|$011234 db |$01A55A,|$011234
asc 02,15,"123456" asc 02,15,"123456"
asc 02,15,z123456z asc 02,15,z123456z
asc 0215,"123456" asc 0215,"123456"
asc 02,15,'123456' asc 02,15,'123456'
asc 02,15,!123456! asc 02,15,!123456!
asc 02,15,@123456@ asc 02,15,@123456@
asc 02,15,#123456# asc 02,15,#123456#
asc 02,15,$123456$ asc 02,15,$123456$
asc 02,15,%123456% asc 02,15,%123456%
asc 02,15,^123456^ asc 02,15,^123456^
asc 02,15,&123456& asc 02,15,&123456&
asc 02,15,*123456* asc 02,15,*123456*
asc 02,15,(123456( asc 02,15,(123456(
asc 02,15,)123456) asc 02,15,)123456)
asc 02,15,/123456/ asc 02,15,/123456/
asc 02,15,?123456? asc 02,15,?123456?
asc 02,15,>123456> asc 02,15,>123456>
asc 02,15,<123456< asc 02,15,<123456<
asc 02,15,05,"123456" asc 02,15,05,"123456"
asc 02,15,"123456" asc 02,15,"123456"
asc 0215"1234"1502 asc 0215"1234"1502
dci 8D,'Hello',8D,'there',8D dci 8D,'Hello',8D,'there',8D
dci 8D,"Hello",8D,"there",8D dci 8D,"Hello",8D,"there",8D
lst lst
lup_start: lup_start:
lup 0 lup 0
db 0 ; outside db 0 ; outside
--^ --^
;lst off ;lst off
//]XCODEEND ; Keep this at the end and put your code above this //]XCODEEND ; Keep this at the end and put your code above this
;lst off lst off

View File

@ -1,6 +1,10 @@
* *
* explicit a operand (inc a, etc) is dropped. * explicit a operand (inc a, etc) is dropped.
* *
xc OFF
xc
xc
mx %11
inc a inc a
dec a dec a