qasm/asm.h

510 lines
10 KiB
C
Raw Permalink Normal View History

2019-11-11 23:56:03 +00:00
#pragma once
2019-11-11 23:56:03 +00:00
#include "app.h"
2021-08-20 15:35:37 +00:00
//
2019-11-11 23:56:03 +00:00
#define OPHANDLER(ACB) std::bind(ACB, this, std::placeholders::_1, std::placeholders::_2)
2019-11-13 23:45:39 +00:00
#define FLAG_FORCELONG 0x01
#define FLAG_FORCEABS 0x02
#define FLAG_FORCEDP 0x04
#define FLAG_DP 0x08
#define FLAG_BIGNUM 0x10
#define FLAG_INDUM 0x20
2019-11-18 12:50:02 +00:00
#define FLAG_FORCEIMPLIED 0x40
2019-11-13 23:45:39 +00:00
2019-11-16 02:51:30 +00:00
#define FLAG_FORCEADDRPRINT 0x0100
2019-11-18 12:50:02 +00:00
#define FLAG_NOLINEPRINT 0x0200
2019-11-13 23:45:39 +00:00
#define OP_A 0x0001
#define OP_XY 0x0002
#define OP_PSUEDO 0x0004
#define OP_SPECIAL 0x0008
// these bits are actually the CC (last 2 bits) of opcode addressing
2019-11-16 00:15:58 +00:00
#define OP_CLASS0 0x0000
2019-11-13 23:45:39 +00:00
#define OP_CLASS1 0x0100
#define OP_CLASS2 0x0200
#define OP_CLASS3 0x0300
// these ORd bits specify specific classes of opcodes and subgroups
#define OP_STD (0x1000 | OP_CLASS1)
#define OP_ASL (0x2000 | OP_CLASS2)
#define OP_C0 (0x4000 | OP_CLASS0)
2019-11-17 04:39:09 +00:00
#define OP_STX (0x8000 | OP_ASL|OP_CLASS2)
2019-11-11 23:56:03 +00:00
enum asmErrors
{
errNone,
errWarn,
errDebug,
2019-11-11 23:56:03 +00:00
errIncomplete,
2019-11-14 03:37:26 +00:00
errUnimplemented,
2019-11-11 23:56:03 +00:00
errFatal,
errBadAddressMode,
errBadOpcode,
errIncompatibleOpcode,
errBadByteCount,
2019-11-12 03:51:26 +00:00
errBadBranch,
errForwardRef,
2019-11-12 08:15:47 +00:00
errNoRedefinition,
errDupSymbol,
errBadDUMop,
errOverflow,
errRecursiveOp,
2019-11-16 00:15:58 +00:00
errOpcodeNotStarted,
errDuplicateFile,
errFileNotFound,
errFileNoAccess,
errBadEvaluation,
2019-11-16 17:27:24 +00:00
errIllegalCharOperand,
2019-11-16 00:15:58 +00:00
errBadCharacter,
2019-11-16 02:30:12 +00:00
errUnexpectedOp,
errUnexpectedEOF,
2019-11-16 06:27:43 +00:00
errBadLUPOperand,
2019-11-16 17:27:24 +00:00
errBadLabel,
errBadOperand,
errErrOpcode,
2019-11-11 23:56:03 +00:00
errMAX
};
#ifdef ADD_ERROR_STRINGS
const std::string errStrings[errMAX + 1] =
{
2019-11-11 23:56:03 +00:00
"No Error",
"Warning",
"Debug Error",
2019-11-11 23:56:03 +00:00
"Unfinished Opcode",
2019-11-14 03:37:26 +00:00
"Unimplemented Instruction",
2019-11-11 23:56:03 +00:00
"Fatal",
"Unsupported Addressing Mode",
2019-11-16 18:48:01 +00:00
"Bad opcode",
2019-11-12 03:51:26 +00:00
"Opcode not available under CPU mode",
2019-11-11 23:56:03 +00:00
"Byte output differs between passes",
2019-11-17 06:48:24 +00:00
"Bad branch",
2019-11-12 08:15:47 +00:00
"Forward Reference to symbol",
"Unable to redefine symbol",
"Duplicate Symbol",
"Invalid use of DUM/DEND",
"Overflow detected",
"Recursive Operand",
2019-11-16 00:15:58 +00:00
"Opcode without start",
"File already included",
"File not found",
"File no access",
"Unable to evaluate",
2019-11-16 17:27:24 +00:00
"Illegal char in operand",
2019-11-16 02:30:12 +00:00
"Unexpected character in input",
"Unexpected opcode",
"Unexpected End of File",
2019-11-16 17:27:24 +00:00
"LUP value must be 0 < VAL <= $8000",
"Unknown label",
"Bad operand",
"Break",
2019-11-14 17:32:11 +00:00
2019-11-12 08:15:47 +00:00
""
2019-11-11 23:56:03 +00:00
};
#else
2019-11-12 18:13:15 +00:00
extern const std::string errStrings[errMAX];
2019-11-11 23:56:03 +00:00
extern uint8_t opCodeCompatibility[256];
#endif
2019-11-13 04:32:10 +00:00
class TOriginSection
{
// SGQ - if you do something unusual here, be aware of copy constructor
// may be needed
2019-11-13 04:32:10 +00:00
public:
uint32_t origin;
uint32_t currentpc;
uint32_t totalbytes;
uint32_t orgsave;
2019-11-13 23:45:39 +00:00
// leave this code here in case we ever need a copy/assignment constructor
#if 0
TOriginSection(const TOriginSection &old)
{
origin = old.origin;
currentpc = old.currentpc;
2019-11-16 00:15:58 +00:00
orgsave = old.orgsave;
totalbytes = old.totalbytes;
};
TOriginSection& operator=(const TOriginSection &other)
{
origin = other.origin;
currentpc = other.currentpc;
totalbytes = other.totalbytes;
2019-11-16 00:15:58 +00:00
orgsave = other.orgsave;
return (*this);
};
TOriginSection()
{
origin = 0;
currentpc = 0;
totalbytes = 0;
2019-11-16 00:15:58 +00:00
orgsave = 0;
};
~TOriginSection()
{
}
#endif
2019-11-13 04:32:10 +00:00
};
2019-11-11 23:56:03 +00:00
class MerlinLine
{
public:
2023-02-07 06:27:19 +00:00
//uint32_t syntax;
ConfigOptions *options;
std::string wholetext;
2019-11-11 23:56:03 +00:00
std::string lable;
std::string printlable;
std::string printoperand;
std::string strippedoperand;
2019-11-11 23:56:03 +00:00
std::string opcode;
std::string opcodelower;
std::string orig_operand;
2019-11-11 23:56:03 +00:00
std::string operand;
std::string operand_expr;
2019-11-12 03:51:26 +00:00
std::string operand_expr2;
2019-11-11 23:56:03 +00:00
std::string comment;
std::string addrtext;
char shiftchar;
2019-11-12 08:15:47 +00:00
uint8_t linemx;
2019-11-17 03:33:22 +00:00
uint8_t tabs[16];
bool showmx;
2019-11-18 14:07:44 +00:00
bool merlinerrors;
2019-11-16 19:14:51 +00:00
uint8_t truncdata;
2019-11-12 03:51:26 +00:00
uint32_t lineno;
2019-11-11 23:56:03 +00:00
uint32_t flags;
uint16_t opflags;
2019-11-12 03:51:26 +00:00
int32_t startpc;
2019-11-11 23:56:03 +00:00
uint32_t addressmode;
2019-11-13 23:45:39 +00:00
uint32_t expr_value;
uint8_t expr_shift; // after an eval, this byte will reflect any shift code on expr (|^<>)
2019-11-18 12:50:02 +00:00
int32_t eval_result; // this is the error code from the evaluate routing (0 or neg)
2019-11-11 23:56:03 +00:00
uint32_t errorcode;
2019-11-12 18:13:15 +00:00
std::string errorText;
2019-11-11 23:56:03 +00:00
uint16_t pass0bytect;
uint16_t bytect;
2019-11-15 07:35:04 +00:00
uint16_t datafillct;
uint8_t datafillbyte;
2019-11-11 23:56:03 +00:00
uint16_t outbytect;
std::vector<uint8_t> outbytes;
public:
2023-02-07 06:27:19 +00:00
MerlinLine(ConfigOptions &opt);
MerlinLine(std::string line, ConfigOptions &opt);
2019-11-11 23:56:03 +00:00
void clear();
void set(std::string line);
void print(uint32_t lineno);
void setError(uint32_t ecode);
};
class TFileProcessor
{
protected:
int win_columns;
int win_rows;
2019-11-14 17:32:11 +00:00
std::string initialdir;
std::vector<std::string> filenames;
//uint32_t syntax;
2019-11-12 03:51:26 +00:00
uint64_t starttime;
2019-11-17 03:33:22 +00:00
uint8_t tabs[16];
2019-11-16 02:30:12 +00:00
2019-11-14 15:28:42 +00:00
uint32_t filecount; // how many files have been read in (because of included files from source
2019-11-11 23:56:03 +00:00
public:
2023-02-07 06:27:19 +00:00
ConfigOptions &options;
uint32_t errorct;
2019-11-14 17:32:11 +00:00
std::string filename;
uint32_t format_flags;
2019-11-11 23:56:03 +00:00
2023-02-07 06:27:19 +00:00
TFileProcessor(ConfigOptions &opt);
2019-11-11 23:56:03 +00:00
virtual ~TFileProcessor();
2019-11-16 00:15:58 +00:00
virtual std::string processFilename(std::string p, std::string currentdir, int level);
virtual int processfile(std::string p, std::string &newfilename);
2019-11-11 23:56:03 +00:00
virtual void init(void);
virtual int doline(int lineno, std::string line);
virtual void process(void);
virtual void complete(void);
virtual void errorOut(uint16_t code);
virtual void setLanguage(string lang,bool force);
};
#define CONVERT_NONE 0x00
#define CONVERT_LF 0x01
#define CONVERT_CRLF 0x02
#define CONVERT_COMPRESS 0x04
#define CONVERT_HIGH 0x08
2023-02-07 06:27:19 +00:00
#define CONVERT_TABS 0x10
#define CONVERT_MERLIN (CONVERT_HIGH|CONVERT_COMPRESS)
#define CONVERT_LINUX (CONVERT_LF)
#define CONVERT_WINDOWS (CONVERT_CRLF)
#define CONVERT_APW (CONVERT_NONE)
#define CONVERT_MPW (CONVERT_NONE)
#define CONVERT_TEST (CONVERT_COMPRESS|CONVERT_LF)
2019-11-11 23:56:03 +00:00
2023-02-07 06:27:19 +00:00
#if 1
class TMerlinConverter : public TFileProcessor
{
protected:
std::vector<MerlinLine> lines;
2019-11-13 04:32:10 +00:00
public:
2023-02-07 06:27:19 +00:00
TMerlinConverter(ConfigOptions &opt);
virtual ~TMerlinConverter();
virtual void init(void);
virtual int doline(int lineno, std::string line);
virtual void process(void);
virtual void complete(void);
};
2023-02-07 06:27:19 +00:00
#endif
2019-11-16 00:15:58 +00:00
class TLUPstruct
{
public:
TLUPstruct()
{
clear();
}
void clear(void)
{
lupct = 0;
lupoffset = 0;
luprunning = 0;
lupskip = false;
2019-11-16 00:15:58 +00:00
}
uint16_t lupct;
2019-11-16 17:27:24 +00:00
bool lupskip;
2019-11-16 00:15:58 +00:00
uint32_t lupoffset;
uint16_t luprunning;
};
2019-11-16 17:27:24 +00:00
class TDOstruct
{
public:
TDOstruct()
{
clear();
}
void clear(void)
{
doskip = false;
value = 0;
2019-11-16 17:27:24 +00:00
}
uint32_t value;
2019-11-16 18:48:01 +00:00
bool doskip;
2019-11-16 17:27:24 +00:00
};
2019-11-11 23:56:03 +00:00
class TSymbol;
typedef int (*TOpCB)(MerlinLine &line, TSymbol &sym);
typedef std::function<int (MerlinLine &line, TSymbol &sym)> TOpCallback;
class TSymbol
{
public:
std::string namelc;
std::string name;
//std::string text;
std::string var_text;
2019-11-11 23:56:03 +00:00
uint32_t value;
uint16_t stype;
uint8_t opcode;
2019-11-12 08:15:47 +00:00
bool used;
2019-11-11 23:56:03 +00:00
TOpCallback cb;
Poco::HashMap<std::string, TSymbol>locals;
TSymbol()
{
clear();
2019-11-11 23:56:03 +00:00
};
void clear(void)
{
value = 0;
used = false;
//text = "";
var_text = "";
name = "";
namelc = "";
stype = 0;
opcode = 0;
locals.clear();
}
2019-11-11 23:56:03 +00:00
};
2019-11-21 16:47:03 +00:00
//typedef Poco::HashMap<std::string, TSymbol> variable_t;
class TVariable
{
public:
uint32_t id;
Poco::HashMap<std::string, TSymbol> vars;
TVariable()
{
// SGQ - must fix this so it is guaranteed unique for each one
id=rand();
}
2019-11-21 16:47:03 +00:00
};
class TMacro
{
public:
std::string name;
std::string lcname;
2019-11-21 16:47:03 +00:00
TVariable variables;
2019-11-21 05:50:00 +00:00
std::vector<MerlinLine> lines;
2019-11-21 16:47:03 +00:00
uint32_t start, end, currentline, len;
uint32_t sourceline;
2019-11-21 05:50:00 +00:00
bool running;
TMacro()
{
clear();
}
void clear(void)
{
2019-11-21 16:47:03 +00:00
name = "";
lcname = "";
variables.vars.clear();
2019-11-21 05:50:00 +00:00
lines.clear();
2019-11-21 16:47:03 +00:00
sourceline = 0;
currentline = 0;
len = 0;
start = 0;
2019-11-21 16:47:03 +00:00
end = 0;
2019-11-21 05:50:00 +00:00
running = false;
}
};
class TPsuedoOp;
2019-11-11 23:56:03 +00:00
class T65816Asm : public TFileProcessor
{
protected:
public:
std::vector<uint8_t> outputbytes;
// options
2019-11-11 23:56:03 +00:00
bool casesen;
bool showmx;
bool trackrep;
2019-11-18 14:07:44 +00:00
bool merlinerrors;
2019-11-13 23:45:39 +00:00
bool allowdup;
uint8_t mx;
uint8_t cpumode; // 0=6502, 1=65C02, 2=65816
bool passcomplete;
bool relocatable;
int dumstart; // must be signed
uint32_t dumstartaddr;
2019-11-12 03:51:26 +00:00
bool skiplist; // used if lst is on, but LST opcode turns it off
2019-11-11 23:56:03 +00:00
uint32_t lineno;
2019-11-18 12:50:02 +00:00
bool lastcarry;
2019-11-13 04:32:10 +00:00
2019-11-12 08:15:47 +00:00
std::string savepath;
2019-11-11 23:56:03 +00:00
TSymbol *currentsym;
2019-11-18 03:05:50 +00:00
TSymbol topSymbol;
2019-11-17 16:02:55 +00:00
std::string currentsymstr;
2019-11-11 23:56:03 +00:00
std::vector<MerlinLine> lines;
Poco::HashMap<std::string, TMacro> macros;
2019-11-21 05:50:00 +00:00
Poco::HashMap<std::string, TSymbol> opcodes;
2019-11-11 23:56:03 +00:00
Poco::HashMap<std::string, TSymbol> symbols;
2019-11-21 16:47:03 +00:00
TVariable variables;
2019-11-13 04:32:10 +00:00
TOriginSection PC;
2019-11-16 17:27:24 +00:00
TLUPstruct curLUP;
TDOstruct curDO;
2019-11-21 05:50:00 +00:00
TMacro currentmacro;
TMacro expand_macro;
2019-11-16 19:14:51 +00:00
bool listing;
uint8_t truncdata; // for the TR opcode
2019-11-16 17:27:24 +00:00
2019-11-13 04:32:10 +00:00
std::stack<TOriginSection> PCstack;
2019-11-16 00:15:58 +00:00
std::stack<TLUPstruct> LUPstack;
2019-11-16 17:27:24 +00:00
std::stack<TDOstruct> DOstack;
2019-11-16 19:14:51 +00:00
std::stack<bool> LSTstack;
2019-11-21 05:50:00 +00:00
std::stack<TMacro> macrostack;
std::stack<TMacro> expand_macrostack;
2019-11-16 00:15:58 +00:00
TPsuedoOp *psuedoops;
2019-11-11 23:56:03 +00:00
uint16_t pass;
2023-02-07 06:27:19 +00:00
T65816Asm(ConfigOptions &opt);
2019-11-11 23:56:03 +00:00
virtual ~T65816Asm();
virtual void init(void);
virtual int doline(int lineno, std::string line);
virtual void process(void);
virtual void complete(void);
void insertOpcodes(void);
void pushopcode(std::string op, uint8_t opcode, uint16_t flags, TOpCallback cb);
int callOpCode(std::string op, MerlinLine &line);
2019-11-21 05:50:00 +00:00
TMacro *findMacro(std::string sym);
2019-11-11 23:56:03 +00:00
TSymbol *findSymbol(std::string sym);
TSymbol *addSymbol(std::string sym, uint32_t val, bool replace);
2019-11-21 16:47:03 +00:00
TSymbol *findVariable(std::string sym, TVariable &vars);
TSymbol *addVariable(std::string sym, std::string val, TVariable &vars, bool replace);
2019-11-11 23:56:03 +00:00
void initpass(void);
2019-11-12 08:15:47 +00:00
void showSymbolTable(bool alpha);
void showMacros(bool alpha);
2019-11-21 16:47:03 +00:00
void showVariables(TVariable &vars);
2019-11-16 00:15:58 +00:00
int evaluate(MerlinLine &line, std::string expr, int64_t &value);
2019-11-11 23:56:03 +00:00
int substituteVariables(MerlinLine & line, std::string &outop);
2019-11-16 17:27:24 +00:00
bool codeSkipped(void);
2019-11-22 03:20:59 +00:00
bool doOFF(void);
2019-11-16 17:27:24 +00:00
2019-11-11 23:56:03 +00:00
int parseOperand(MerlinLine &line);
int getAddrMode(MerlinLine &line);
void setOpcode(MerlinLine &line, uint8_t op);
int doPSEUDO(MerlinLine &line, TSymbol &sym);
int doEND(MerlinLine &line, TSymbol &sym);
int doBase6502(MerlinLine &line, TSymbol &sym);
int doBRANCH(MerlinLine &line, TSymbol &sym);
int doJMP(MerlinLine &line, TSymbol &sym);
int doAddress(MerlinLine &line, TSymbol &sym);
int doNoPattern(MerlinLine &line, TSymbol &sym);
2019-11-12 03:51:26 +00:00
int doMVN(MerlinLine &line, TSymbol &sym);
2019-11-12 08:15:47 +00:00
int doPER(MerlinLine &line, TSymbol &sym);
2019-11-18 00:14:52 +00:00
int doBRK(MerlinLine & line, TSymbol & sym);
2019-11-11 23:56:03 +00:00
int doEQU(MerlinLine &line, TSymbol &sym);
int doXC(MerlinLine &line, TSymbol &sym);
int doMX(MerlinLine &line, TSymbol &sym);
int doBYTE(MerlinLine &line, TSymbol &sym);
int doUNK(MerlinLine &line, TSymbol &sym);
};
class T65816Link : public TFileProcessor
{
public:
2023-02-07 06:27:19 +00:00
T65816Link(ConfigOptions &opt);
2019-11-11 23:56:03 +00:00
virtual ~T65816Link();
virtual void init(void);
virtual int doline(int lineno, std::string line);
virtual void process(void);
virtual void complete(void);
};