DUM complete, DS working/not done, work on shift operators

This commit is contained in:
marketideas 2019-11-13 06:54:48 -08:00
parent 0af8c9765a
commit 8608bf5a94
11 changed files with 312 additions and 121 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
**/build
*.xcuserstate
*.xcbkptlist

View File

@ -33,7 +33,7 @@ install:
-cd ./build && cmake -P cmake_install.cmake
reformat:
qasm -r src/main.s
qasm -x REFORMAT src/main.s
asm:

141
asm.cpp
View File

@ -163,6 +163,7 @@ void CLASS::clear()
outbytes.clear();
addressmode = 0;
expr_value = 0;
eval_result = 0;
flags = 0;
outbytes.clear();
}
@ -451,7 +452,7 @@ int CLASS::processfile(std::string &p)
}
else
{
printf("file %s does not exist\n", p.c_str());
fprintf(stderr,"File <%s> does not exist.\n\n", p.c_str());
}
//printf("\n\nfile read result: %d\n", res);
@ -499,7 +500,6 @@ void CLASS::init(void)
int CLASS::doline(int lineno, std::string line)
{
MerlinLine l(line);
lines.push_back(l);
return 0;
@ -513,7 +513,7 @@ void CLASS::process(void)
for (uint32_t lineno = 0; lineno < ct; lineno++)
{
MerlinLine &line = lines[lineno];
MerlinLine &line = lines.at(lineno);
pos = 0;
len = 0;
@ -734,6 +734,8 @@ void CLASS::showSymbolTable(bool alpha)
std::map<std::string, uint32_t> alphamap;
std::map<uint32_t, std::string> nummap;
int columns = 4;
int column = columns;
for (auto itr = symbols.begin(); itr != symbols.end(); itr++)
{
@ -746,19 +748,29 @@ void CLASS::showSymbolTable(bool alpha)
if (alpha)
{
printf("\nSymbol table sorted alphabetically:\n");
printf("\n\nSymbol table sorted alphabetically:\n\n");
for (auto itr = alphamap.begin(); itr != alphamap.end(); ++itr)
{
printf("%-16s 0x%08X\n", itr->first.c_str(), itr->second);
printf("%16s 0x%08X", itr->first.c_str(), itr->second);
if( !--column )
{
printf("\n");
column = columns;
}
}
}
else
{
printf("\nSymbol table sorted numerically:\n");
printf("\n\nSymbol table sorted numerically:\n\n");
for (auto itr = nummap.begin(); itr != nummap.end(); ++itr)
{
printf("0x%08X %-16s\n", itr->first, itr->second.c_str());
printf("0x%08X %-16s", itr->first, itr->second.c_str());
if( !--column )
{
printf("\n");
column = columns;
}
}
}
}
@ -825,12 +837,11 @@ const TaddrMode addrRegEx[] =
{
{ "^(?'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}(?'shift'[<,>,^,|]?)(.+)$", syn_imm, "immediate"}, //#expr,#^expr,#|expr,#<expr,#>expr
{"^#{1}(.+)$", syn_imm, "immediate"}, //#expr,#^expr,#|expr,#<expr,#>expr
{"^[(]{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)
{"^\\[{1}(?'expr'.+)\\]{1}[,]{1}[(Y|y)]{1}$", syn_iyl, "[e],y"}, // [expr],y
//{"^\\[{1}(?'expr'.+)\\]{1}[,]{1}[(X|x)]{1}$", syn_iyl, "[e],x"}, // [expr],x
{"^\\[(?'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
@ -839,7 +850,11 @@ const TaddrMode addrRegEx[] =
{"", 0, ""}
};
const std::string valExpression = "^([$%\\+\\-:-~][^\\],()]*)$";
// 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 = "^([^\\]\\[,();]+)$";
// opcode check. emitted opcodes are compared against this
// table, and if the XC status doesn't meet the requirements
@ -895,6 +910,8 @@ void CLASS::initpass(void)
PC.origin = 0x8000;
PC.currentpc = PC.origin;
PC.totalbytes=0;
PC.orgsave=PC.origin;
s = getConfig("asm.cpu", "M65816");
s = Poco::trim(Poco::toUpper(s));
@ -923,10 +940,12 @@ void CLASS::initpass(void)
}
relocatable = false;
currentsym = NULL;
PC.totalbytes = 0;
lineno = 0;
errorct = 0;
passcomplete = false;
dumstartaddr=0;
dumstart=0;
variables.clear(); // clear the variables for each pass
while (!PCstack.empty())
@ -944,19 +963,18 @@ void CLASS::complete(void)
{
if (errorct == 0)
{
MerlinLine *line;
std::ofstream f(savepath);
uint32_t lineno = 0;
uint32_t l = lines.size();
while (lineno < l)
{
line = &lines[lineno++];
if (line->outbytect > 0)
MerlinLine &line=lines.at(lineno++);
if (line.outbytect > 0)
{
for (uint32_t i = 0; i < line->outbytect; i++)
for (uint32_t i = 0; i < line.outbytect; i++)
{
f.put(line->outbytes[i]);
f.put(line.outbytes[i]);
}
}
}
@ -986,7 +1004,7 @@ int CLASS::evaluate(std::string expr, int64_t &value)
TEvaluator eval(*this);
res = eval.evaluate(expr, result);
res = eval.evaluate(expr, result, mx);
if (res != 0)
{
if (isDebug() > 2)
@ -1006,6 +1024,10 @@ int CLASS::evaluate(std::string expr, int64_t &value)
value = 0;
res = 0;
}
if (isDebug()>=3)
{
printf("Eval Result: %08lX (status=%d)\n",value,res);
}
return (res);
}
@ -1127,13 +1149,13 @@ int CLASS::parseOperand(MerlinLine & line)
void CLASS::process(void)
{
uint32_t l;
int x, evalresult;
int x;;
char c;
std::string op, operand;
//uint32_t operand_eval;
//uint16_t addrmode;
MerlinLine *line;
//MerlinLine *line;
pass = 0;
while (pass < 2)
{
@ -1142,100 +1164,115 @@ void CLASS::process(void)
l = lines.size();
while ((lineno < l) && (!passcomplete))
{
evalresult = 0;
line = &lines[lineno];
MerlinLine &line=lines[lineno];
line->lineno = lineno + 1;
//printf("lineno: %d %d |%s|\n",lineno,l,line->operand.c_str());
line.eval_result=0;
line.lineno = lineno + 1;
//printf("lineno: %d %d |%s|\n",lineno,l,line.operand.c_str());
op = Poco::toLower(line->opcode);
operand = Poco::toLower(line->operand);
line->startpc = PC.currentpc;
line->linemx = mx;
line->bytect = 0;
line->showmx = showmx;
op = Poco::toLower(line.opcode);
operand = Poco::toLower(line.operand);
line.startpc = PC.currentpc;
line.linemx = mx;
line.bytect = 0;
line.showmx = showmx;
if ((line->lable != "") && (pass == 0))
if ((line.lable != "") && (pass == 0))
{
std::string lable = Poco::trim(line->lable);
std::string lable = Poco::trim(line.lable);
TSymbol *sym = NULL;
bool dupsym = false;
c = line->lable[0];
c = line.lable[0];
switch (c)
{
case ']':
sym = addVariable(line->lable, "", true);
sym = addVariable(line.lable, "", true);
if (sym == NULL) { dupsym = true; }
break;
case ':':
break;
default:
sym = addSymbol(line->lable, PC.currentpc, false);
sym = addSymbol(line.lable, PC.currentpc, false);
if (sym == NULL) { dupsym = true; }
break;
}
if (dupsym)
{
line->setError(errDupSymbol);
line.setError(errDupSymbol);
}
}
x = parseOperand(*line);
x = parseOperand(line);
if (x >= 0)
{
line->addressmode = x;
line.addressmode = x;
}
int64_t value = -1;
x = evaluate(line->operand_expr, value);
evalresult = x;
x = evaluate(line.operand_expr, value);
line.eval_result=x;
if (x == 0)
{
value &= 0xFFFFFFFF;
line->expr_value = value;
line.expr_value = value;
}
else
{
line->expr_value = 0;
line.expr_value = 0;
}
x = 0;
if (op.length() > 0)
{
x = callOpCode(op, *line);
x = callOpCode(op, line);
}
if (x > 0)
{
if ((evalresult != 0) && (pass > 0))
if ((line.eval_result != 0) && (pass > 0))
{
line->setError(errBadOperand);
line->errorText = line->operand_expr;
line.setError(errBadOperand);
line.errorText = line.operand_expr;
}
line->bytect = x;
line.bytect = x;
PC.currentpc += x;
PC.totalbytes += x;
}
if (pass == 0)
{
line->pass0bytect = line->bytect;
line.pass0bytect = line.bytect;
}
if (dumstart>0) // starting a dummy section
{
PCstack.push(PC);
PC.origin=dumstartaddr;
PC.currentpc=PC.origin;
dumstart=0;
dumstartaddr=0;
}
if (dumstart<0)
{
PC=PCstack.top();
PCstack.pop();
dumstart=0;
dumstartaddr=0;
}
if (pass == 1)
{
if ((line->pass0bytect != line->bytect) && (line->errorcode == 0))
if ((line.pass0bytect != line.bytect) && (line.errorcode == 0))
{
line->setError(errBadByteCount);
line.setError(errBadByteCount);
}
if (line->errorcode != 0)
if (line.errorcode != 0)
{
errorct++;
}
if (((!skiplist) && (listing) && (pass == 1)) || (line->errorcode != 0))
if (((!skiplist) && (listing) && (pass == 1)) || (line.errorcode != 0))
{
line->print(lineno);
line.print(lineno);
}
skiplist = false;
}

48
asm.h
View File

@ -38,10 +38,14 @@ enum asmErrors
errBadByteCount,
errBadBranch,
errUnimplemented,
errForwardReference,
errForwardRef,
errNoRedefinition,
errBadOperand,
errDupSymbol,
errBadDUMop,
errOverflow,
errRecursiveOp,
errOpcodeNotStarted,
errMAX
};
@ -62,7 +66,10 @@ const std::string errStrings[errMAX + 1] =
"Unable to redefine symbol",
"Unable to evaluate",
"Duplicate Symbol",
"Invalid use of DUM/DEND",
"Overflow detected",
"Recursive Operand",
"Opcode without start",
""
};
#else
@ -96,10 +103,42 @@ enum
class TOriginSection
{
// SGQ - if you do something unusual here, be aware of copy constructor
// may be needed
public:
uint32_t origin;
uint32_t currentpc;
uint32_t totalbytes;
uint32_t orgsave;
#if 0
TOriginSection(const TOriginSection &old)
{
origin = old.origin;
currentpc = old.currentpc;
orgsave=old.orgsave;
totalbytes = old.totalbytes;
};
TOriginSection& operator=(const TOriginSection &other)
{
origin = other.origin;
currentpc = other.currentpc;
totalbytes = other.totalbytes;
orgsave=other.orgsave;
return (*this);
};
TOriginSection()
{
origin = 0;
currentpc = 0;
totalbytes = 0;
orgsave=0;
};
~TOriginSection()
{
}
#endif
};
class MerlinLine
@ -124,6 +163,7 @@ public:
int32_t startpc;
uint32_t addressmode;
int32_t expr_value;
int32_t eval_result; // this is the error code from the evaluate routing (0 or neg)
uint32_t errorcode;
std::string errorText;
@ -223,10 +263,10 @@ public:
bool passcomplete;
bool relocatable;
int dumstart; // must be signed
uint32_t dumstartaddr;
bool skiplist; // used if lst is on, but LST opcode turns it off
uint32_t lineno;
//uint32_t origin;
//uint32_t currentpc;
std::string savepath;
TSymbol *currentsym;

View File

@ -118,11 +118,19 @@ std::deque<Token> CLASS::exprToTokens(const std::string& expr)
numexpect = false;
}
else if ((numexpect) && ( (c == '^') || (c == '<') || (c == '>') || (c == '|')))
{
ident = c;
tokens.push_back(Token{Token::Type::Shift, ident, 1, true});
ident = "";
}
else if ((c == '*') && (numexpect))
{
numexpect = false;
state = 20;
state = 0;
ident += c;
tokens.push_back(Token{Token::Type::Symbol, ident, 1, false});
ident = "";
}
else if ((c == '%') && (numexpect))
{
@ -155,14 +163,7 @@ std::deque<Token> CLASS::exprToTokens(const std::string& expr)
numexpect = false;
}
else if ((c >= 'a') && (c <= 'z'))
{
state = 20;
ident += c;
numexpect = false;
}
else if ((c >= 'A') && (c <= 'Z'))
else if (c >= ':')
{
state = 20;
ident += c;
@ -229,7 +230,6 @@ std::deque<Token> CLASS::shuntingYard(const std::deque<Token>& tokens)
if (sym != NULL)
{
sym->used = true;
//printf("symbol found\n");
sprintf(buff, "%d", sym->value);
token.str = buff;
}
@ -247,6 +247,9 @@ std::deque<Token> CLASS::shuntingYard(const std::deque<Token>& tokens)
queue.push_back(token);
break;
case Token::Type::Shift:
stack.push_back(token);
break;
case Token::Type::Operator:
{
// If the token is operator, o1, then:
@ -317,7 +320,7 @@ std::deque<Token> CLASS::shuntingYard(const std::deque<Token>& tokens)
{
// If the stack runs out without finding a left parenthesis,
// then there are mismatched parentheses.
printf("RightParen error (%s)\n", token.str.c_str());
//printf("RightParen error (%s)\n", token.str.c_str());
setError(Token::operatorErr);
return queue;
}
@ -327,7 +330,7 @@ std::deque<Token> CLASS::shuntingYard(const std::deque<Token>& tokens)
default:
setError(Token::syntaxErr);
printf("error (%s)\n", token.str.c_str());
//printf("error (%s)\n", token.str.c_str());
return queue;
break;
}
@ -518,11 +521,12 @@ void CLASS::setError(int ecode)
}
}
int CLASS::evaluate(std::string & e, int64_t &res)
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;
res = DEF_VAL;
setError(Token::noError);
@ -531,8 +535,10 @@ int CLASS::evaluate(std::string & e, int64_t &res)
std::string expr = Poco::trim(e);
expr += " "; // add a space at end to make parsing easier
//printf("expression: |%s|\n",expr.c_str());
if (isDebug() >= 4)
{
printf("eval: expression: |%s|\n", expr.c_str());
}
const auto tokens = exprToTokens(expr);
auto queue = shuntingYard(tokens);
std::vector<int64_t> stack;
@ -565,6 +571,41 @@ int CLASS::evaluate(std::string & e, int64_t &res)
//op = "Push " + token.str;
break;
case Token::Type::Shift:
{
auto rhs = DEF_VAL;
if (stack.size() > 0)
{
rhs = stack.back();
stack.pop_back();
shiftmode=token.str[0];
if (token.str=="^")
{
//rhs = (rhs >> 16) &0xFFFF ;
}
else if (token.str=="|")
{
//rhs = (rhs >> 16) & 0xFFFF;
}
else if (token.str=="<")
{
//rhs = (rhs << 8 ) & 0xFFFF;
}
else if (token.str==">")
{
//rhs=(rhs>>8) & 0xFFFF;
}
stack.push_back(rhs);
}
else
{
//printf("nothing on stack\n");
}
}
break;
case Token::Type::Operator:
{
@ -656,6 +697,7 @@ out:
{
setError(Token::syntaxErr);
}
_shiftmode=shiftmode;
res = v;
return (evalerror);
}

4
eval.h
View File

@ -41,6 +41,7 @@ public:
Unknown = 0,
Number,
Symbol,
Shift,
Operator,
LeftParen,
RightParen,
@ -62,6 +63,7 @@ protected:
T65816Asm &assembler;
int evalerror;
void setError(int ecode);
uint8_t shiftmode;
public:
CLASS(T65816Asm &_asm);
~CLASS();
@ -69,7 +71,7 @@ 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 evaluate(std::string &expr, int64_t &res);
int evaluate(std::string &expr, int64_t &res, uint8_t &_shiftmode);
};

View File

@ -687,7 +687,7 @@ void CLASS::insertOpcodes(void)
pushopcode("ORG", P_ORG, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("DSK", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("SAV", P_SAV, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("DS", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("DS", P_DS, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("REL", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("OBJ", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));
pushopcode("PUT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO));

View File

@ -12,11 +12,47 @@ CLASS::~CLASS()
}
int CLASS::doDS(T65816Asm &a, MerlinLine &line, TSymbol &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;
}
return (res);
}
int CLASS::doDUM(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
{
int res=-1;
//bool isdend=((opinfo.opcode==P_DEND)?true:false);
return(res);
int res = 0;
bool isdend = ((opinfo.opcode == P_DEND) ? true : false);
if (!isdend)
{
a.dumstart = 1;
a.dumstartaddr = line.expr_value;
}
else
{
a.dumstart = -1;
if (a.PCstack.size() == 0)
{
line.setError(errBadDUMop);
a.dumstart = 0;
}
}
return (res);
}
int CLASS::doLST(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
@ -51,11 +87,25 @@ int CLASS::ProcessOpcode(T65816Asm &a, MerlinLine &line, TSymbol &opinfo)
res = -1; // undefined p-op
line.setError(errUnimplemented);
break;
case P_DS:
res = doDS(a, line, opinfo);
break;
case P_DUM:
case P_DEND:
res=doDUM(a,line,opinfo);
res = doDUM(a, line, opinfo);
break;
case P_ORG:
a.PC.currentpc = line.expr_value;
if (line.operand.length()>0)
{
a.PC.orgsave=a.PC.currentpc;
a.PC.currentpc = line.expr_value;
line.startpc=line.expr_value;
}
else
{
a.PC.currentpc = a.PC.orgsave;
line.startpc=a.PC.orgsave;
}
break;
case P_SAV:
a.savepath = line.operand;

View File

@ -10,6 +10,7 @@ enum
P_SAV,
P_DUM,
P_DEND,
P_DS,
P_MAX
};
@ -22,6 +23,7 @@ public:
int ProcessOpcode(T65816Asm &a, MerlinLine &line, TSymbol &opinfo);
int doLST(T65816Asm &a, MerlinLine &line, TSymbol &opinfo);
int doDUM(T65816Asm &a, MerlinLine &line, TSymbol &opinfo);
int doDS(T65816Asm &a, MerlinLine &line, TSymbol &opinfo);

View File

@ -13,9 +13,8 @@ PAL_BASEAPP *PAL::appFactory(void)
programOption PAL::appOptions[] =
{
{ "debug", "d", "enable debug info (repeat for more verbosity)", "", false, true},
{ "config-file", "f", "load configuration data from a <file>", "file", false, false},
{ "tomerlin", "m", "convert file to merlin format ", "", false, false},
{ "reformat", "r", "convert to readable ascii", "", false, false},
{ "config", "f", "load configuration data from a <file>", "<file>", false, false},
{ "exec", "x", "execute a command", "<command>", false, false},
{ "", "", "", "", false, false}
};
@ -49,6 +48,12 @@ int CLASS::runCommandLineApp(void)
int res = -1;
//LOG_DEBUG << "command line mode" << endl;
if (commandargs.size()==0)
{
fprintf(stderr,"No files given (--help for help)\n\n");
return(res);
}
for (ArgVec::const_iterator it = commandargs.begin(); it != commandargs.end(); ++it)
{
Poco::File fn(*it);
@ -59,53 +64,60 @@ int CLASS::runCommandLineApp(void)
std::string e = toUpper(path.getExtension());
int x = getInt("option.reformat", 0);
std::string cmd = Poco::toUpper(getConfig("option.exec", "asm"));
if (x != 0)
if (cmd.length() > 0)
{
res=0;
t = new TMerlinConverter();
if (t != NULL)
if (cmd == "REFORMAT")
{
res = 0;
t = new TMerlinConverter();
if (t != NULL)
{
t->init();
std::string f = path.toString();
t->processfile(f);
t->process();
t->complete();
res = (t->errorct > 0) ? -1 : 0;
delete t;
t = NULL;
}
}
else
{
if (e == "S")
{
//logger().information("ASM: " + path.toString());
t->init();
std::string f = path.toString();
t->processfile(f);
t->process();
t->complete();
res = (t->errorct > 0) ? -1 : 0;
t = new T65816Asm();
delete t;
t = NULL;
}
}
if (e == "LNK")
else if (cmd == "ASM")
{
//logger().information("LNK: " + path.toString());
t = new T65816Link();
}
if (t != NULL)
{
t->init();
std::string f = path.toString();
t->processfile(f);
t->process();
t->complete();
res = (t->errorct > 0) ? -1 : 0;
delete t;
t = NULL;
if (e == "S")
{
//logger().information("ASM: " + path.toString());
t = new T65816Asm();
}
if (e == "LNK")
{
//logger().information("LNK: " + path.toString());
t = new T65816Link();
}
if (t != NULL)
{
t->init();
std::string f = path.toString();
t->processfile(f);
t->process();
t->complete();
res = (t->errorct > 0) ? -1 : 0;
delete t;
t = NULL;
}
else
{
printf("not supported type\n");
}
}
else
{
printf("not supported type\n");
fprintf(stderr,"Invalid command: <%s>\n\n", cmd.c_str());
}
}
}

View File

@ -1,4 +1,4 @@
;lst on
lst off
*
* main.s
* Merlin32 Test
@ -83,6 +83,7 @@ START
;adc (ZP,x)
adc (0,x)
adc ($80,x)
adc (_tmp,x)
adc (_tmp+0,x)
@ -162,7 +163,7 @@ myQuit
org ;return to ongoing address
lst
;Issue #16 (fadden) - Byte reference modifiers are ignored (no way to force DP)
lda <$fff0 ;zp
lda >$fff0 ;ABS (lo word)
@ -182,6 +183,8 @@ myQuit
lda #>$fff0 ;page
lda #^$fff0 ;bank
lst off
lda $0008 ;ZP
lda $08 ;ZP
lda $ffff-$fff7 ;ZP
@ -201,3 +204,5 @@ L00BC bit L00BC
stx L00BC,y
//]XCODEEND ; Keep this at the end and put your code above this
lst off