From 25377e4c032020ab769c58d0703dafaaaa07a60f Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 13 Jun 2011 20:27:18 +0000 Subject: [PATCH] Initial commit. Harptool, some docs, and the initial logo attempt. git-svn-id: http://www.cdkersey.com/harp/harptool@1 0246edb2-e076-4747-b392-db732a341fa2 --- src/Makefile | 22 + src/WISHLIST | 17 + src/args.cpp | 52 + src/core.cpp | 95 ++ src/enc.cpp | 468 +++++++++ src/harptool.cpp | 378 +++++++ src/include/archdef.h | 87 ++ src/include/args.h | 61 ++ src/include/asm-tokens.h | 10 + src/include/core.h | 43 + src/include/enc.h | 84 ++ src/include/help.h | 34 + src/include/instruction.h | 93 ++ src/include/mem.h | 163 +++ src/include/obj.h | 200 ++++ src/include/types.h | 25 + src/include/util.h | 24 + src/instruction.cpp | 225 ++++ src/lex.yy.cc | 2032 +++++++++++++++++++++++++++++++++++++ src/mem.cpp | 209 ++++ src/obj.cpp | 635 ++++++++++++ src/scanner.lex | 129 +++ src/test/2thread.s | 51 + src/test/Makefile | 32 + src/test/boot.4w.s | 41 + src/test/boot.s | 52 + src/test/lib.s | 50 + src/test/sieve.s | 81 ++ src/util.cpp | 70 ++ 29 files changed, 5463 insertions(+) create mode 100644 src/Makefile create mode 100644 src/WISHLIST create mode 100644 src/args.cpp create mode 100644 src/core.cpp create mode 100644 src/enc.cpp create mode 100644 src/harptool.cpp create mode 100644 src/include/archdef.h create mode 100644 src/include/args.h create mode 100644 src/include/asm-tokens.h create mode 100644 src/include/core.h create mode 100644 src/include/enc.h create mode 100644 src/include/help.h create mode 100644 src/include/instruction.h create mode 100644 src/include/mem.h create mode 100644 src/include/obj.h create mode 100644 src/include/types.h create mode 100644 src/include/util.h create mode 100644 src/instruction.cpp create mode 100644 src/lex.yy.cc create mode 100644 src/mem.cpp create mode 100644 src/obj.cpp create mode 100644 src/scanner.lex create mode 100644 src/test/2thread.s create mode 100644 src/test/Makefile create mode 100644 src/test/boot.4w.s create mode 100644 src/test/boot.s create mode 100644 src/test/lib.s create mode 100644 src/test/sieve.s create mode 100644 src/util.cpp diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..068f6e0b --- /dev/null +++ b/src/Makefile @@ -0,0 +1,22 @@ +################################################################################ +# HARPtools by Chad D. Kersey, Summer 2011 # +################################################################################ +CXXFLAGS=-g + +harptool: harptool.o args.o obj.o mem.o core.o instruction.o enc.o util.o lex.yy.o + g++ -o $@ args.o obj.o mem.o core.o harptool.o instruction.o enc.o util.o lex.yy.o -pthread + +args.o : args.cpp include/args.h +enc.o : enc.cpp include/types.h include/util.h include/enc.h include/archdef.h include/instruction.h +harptool.o : harptool.cpp include/types.h include/core.h include/enc.h include/instruction.h include/mem.h include/obj.h include/archdef.h include/args.h include/help.h +instruction.o : instruction.cpp include/instruction.h include/obj.h +obj.o : obj.cpp include/types.h include/obj.h include/util.h include/asm-tokens.h +util.o : util.cpp include/types.h include/util.h +mem.o : mem.cpp include/types.h include/util.h include/mem.h +core.o : core.cpp include/types.h include/util.h include/mem.h include/archdef.h + +lex.yy.cc: scanner.lex + flex scanner.lex + +clean: + rm -f *~ \#* *.o include/*~ include/\#* harptool *.HOF a.out.* diff --git a/src/WISHLIST b/src/WISHLIST new file mode 100644 index 00000000..27953e62 --- /dev/null +++ b/src/WISHLIST @@ -0,0 +1,17 @@ +- .string directive in assembler +- mmaped mem devices (including ROM and file-backed RAM). +- Anonymous chunks whose names are not saved by the object writer. +- 32-bit coding for larger-pointered architecture versions. +- HOFDump mode for HARPTool/HOFTool +- Make operation information tables into functions of Instruction, if possible. +- Anonymous assigned values in the assembler. +- References (pointers) as .word directive contents in the assembler. +- .byte directive for assembler. + - Make assembler writer capable of writing binary data without making size of + output a multiple of word size. Useful in pre-assembled code. +- Instruction validation before encoding. +- Make readError in obj.cpp throw something instead of printing the whine and + exiting. +- Limit checking for byte/word encoders (e.g. 255 pRegs, 256 regs for byte) +- Eliminate the tmp_buf nonsense from the chunk encoder. +- Loosen arch restrictions imposed for interoperability. diff --git a/src/args.cpp b/src/args.cpp new file mode 100644 index 00000000..e0e2fc25 --- /dev/null +++ b/src/args.cpp @@ -0,0 +1,52 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#include "include/args.h" + +#include +#include + +using namespace HarpTools; +using std::string; + +std::string CommandLineArg::helpString; +std::map CommandLineArg::longArgs; +std::map CommandLineArg::shortArgs; + +CommandLineArg::CommandLineArg(string s, string l, const char *helpText) +{ + helpString += helpText; + longArgs[l] = this; + shortArgs[s] = this; +} + +CommandLineArg::CommandLineArg(string l, const char *helpText) { + helpString += helpText; + longArgs[l] = this; +} + +void CommandLineArg::readArgs(int argc, char **argv) { + for (int i = 0; i < argc; i++) { + std::map::iterator + s = shortArgs.find(std::string(argv[i])), + l = longArgs.find(std::string(argv[i])); + + if (s != shortArgs.end()) { + i += s->second->read(argc - i, &argv[i]); + } else if (l != longArgs.end()) { + i += l->second->read(argc - i, &argv[i]); + } else { + throw BadArg(string(argv[i])); + } + } +} + +void CommandLineArg::clearArgs() { + shortArgs.clear(); + longArgs.clear(); + helpString = ""; +} + +void CommandLineArg::showHelp(std::ostream &os) { + os << helpString; +} diff --git a/src/core.cpp b/src/core.cpp new file mode 100644 index 00000000..6f06a44f --- /dev/null +++ b/src/core.cpp @@ -0,0 +1,95 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ + +#include + +#include "include/types.h" +#include "include/util.h" +#include "include/archdef.h" +#include "include/mem.h" +#include "include/enc.h" +#include "include/core.h" + +using namespace Harp; +using namespace std; + +Core::Core(const ArchDef &a, Decoder &d, MemoryUnit &mem) : + a(a), iDec(d), mem(mem), pc(0), interruptEnable(false), supervisorMode(true), + activeThreads(1), + reg(a.getNThds(), vector(a.getNRegs())), + pred(a.getNPRegs(), vector(a.getNPRegs())), + shadowReg(), shadowPReg(), interruptEntry(0) +{ } + +void Core::step() { + Size fetchPos(0), decPos, wordSize(a.getWordSize()); + vector fetchBuffer(wordSize); + + if (activeThreads == 0) return; + + /* Fetch and decode. */ + if (wordSize < sizeof(pc)) pc &= ((1ll<<(wordSize*8))-1); + Instruction *inst; + bool fetchMore; + do { + /* Todo: speed this up for the byte encoder? */ + try { + fetchMore = false; + fetchBuffer.resize(fetchPos + wordSize); + Word fetched = mem.fetch(pc + fetchPos, supervisorMode); + writeWord(fetchBuffer, fetchPos, wordSize, fetched); + decPos = 0; + inst = iDec.decode(fetchBuffer, decPos); + } catch (OutOfBytes o) { + //cout << "Caught OutOfBytes. Fetching more.\n"; + fetchMore = true; + } catch (MemoryUnit::PageFault pf) { + fetchPos = 0; + fetchMore = true; + reg[0][1] = pf.faultAddr; + interrupt(pf.notFound?1:2); + } + } while (fetchMore); + //cout << "0x" << hex << pc << ": " << *inst << '\n'; + + /* Update pc */ + pc += decPos; + + /* Execute */ + try { + inst->executeOn(*this); + } catch (MemoryUnit::PageFault pf) { + pc -= decPos; /* Reset to beginning of faulting address. */ + reg[0][1] = pf.faultAddr; + interrupt(pf.notFound?1:2); + } catch (DivergentBranchException e) { + pc -= decPos; + interrupt(4); + } catch (DomainException e) { + interrupt(5); + } + + /* Clean up. */ + delete inst; +} + +bool Core::interrupt(Word r0) { + if (!interruptEnable) return false; + + //cout << "Interrupt: " << r0 << '\n'; + + shadowActiveThreads = activeThreads; + shadowInterruptEnable = interruptEnable; /* For traps. */ + shadowSupervisorMode = supervisorMode; + shadowReg = reg[0]; + shadowPReg = pred[0]; + shadowPc = pc; + activeThreads = 1; + interruptEnable = false; + supervisorMode = true; + reg[0][0] = r0; + pc = interruptEntry; + + return true; +} diff --git a/src/enc.cpp b/src/enc.cpp new file mode 100644 index 00000000..95da161f --- /dev/null +++ b/src/enc.cpp @@ -0,0 +1,468 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "include/types.h" +#include "include/util.h" +#include "include/enc.h" +#include "include/archdef.h" +#include "include/instruction.h" + +using namespace std; +using namespace Harp; + +ByteDecoder::ByteDecoder(const ArchDef &ad) { + wordSize = ad.getWordSize(); +} + +static void decodeError(string msg) { + cout << "Instruction decoder error: " << msg << '\n'; + exit(1); +} + +void Encoder::encodeChunk(DataChunk &dest, const TextChunk &src) { + typedef vector::const_iterator vec_it; + const vector &s(src.instructions); + vector &d(dest.contents); + + /* Keep encoding the instructions. */ + Size n = 0; + + /* For each instruction. */ + for (vec_it i = s.begin(); i != s.end(); i++) { + Ref *ref; + + /* Perform the encoding. */ + n += encode(ref, d, n, **i); + + /* Add reference if necessary. */ + if (ref != NULL) { + ref->ibase = n; + dest.refs.push_back(ref); + } + } + + dest.alignment = src.alignment; + dest.flags = src.flags; + dest.address = src.address; + dest.bound = src.bound; + if (src.isGlobal()) dest.setGlobal(); + + d.resize(n); + dest.size = n; +} + +void Decoder::decodeChunk(TextChunk &dest, const DataChunk &src) { + typedef vector::const_iterator vec_it; + const vector &v(src.contents); + Size n = 0; + + setRefs(src.refs); + + while (n < src.contents.size()) { + Instruction *inst = decode(v, n); + if (inst->hasRefLiteral()) { + dest.refs.push_back(inst->getRefLiteral()); + } + + dest.instructions.push_back(inst); + } + + dest.alignment = src.alignment; + dest.flags = src.flags; + dest.address = src.address; + dest.bound = src.bound; + if (src.isGlobal()) dest.setGlobal(); + + clearRefs(); +} + +void Decoder::setRefs(const std::vector &refVec) { + haveRefs = true; + + typedef std::vector::const_iterator vec_ci; + + for (vec_ci i = refVec.begin(); i != refVec.end(); i++) { + OffsetRef *oref = dynamic_cast(*i); + if (oref) { + refMap[oref->getOffset()] = *i; + } else { + decodeError("Unknown Ref type in Decoder::setRefs"); + } + } +} + +Instruction *ByteDecoder::decode(const vector &v, Size &n) { + Instruction &inst = *(new Instruction()); + + RegNum pred = readByte(v, n); + if (pred) inst.setPred(pred - 1); + + unsigned op = readByte(v, n); + inst.setOpcode(Instruction::Opcode(op)); + + bool usedImm = false; + + switch (Instruction::argClasses[op]) { + case Instruction::AC_NONE: + break; + case Instruction::AC_2REG: + inst.setDestReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + break; + case Instruction::AC_2IMM: + inst.setDestReg(readByte(v, n)); + inst.setSrcImm(readWord(v, n, wordSize)); + usedImm = true; + break; + case Instruction::AC_3REG: + inst.setDestReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + break; + case Instruction::AC_3PREG: + inst.setDestPReg(readByte(v, n)); + inst.setSrcPReg(readByte(v, n)); + inst.setSrcPReg(readByte(v, n)); + break; + case Instruction::AC_3IMM: + inst.setDestReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + inst.setSrcImm(readWord(v, n, wordSize)); + usedImm = true; + break; + case Instruction::AC_3REGSRC: + inst.setSrcReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + break; + case Instruction::AC_1IMM: + inst.setSrcImm(readWord(v, n, wordSize)); + usedImm = true; + break; + case Instruction::AC_1REG: + inst.setSrcReg(readByte(v, n)); + break; + case Instruction::AC_3IMMSRC: + inst.setSrcReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + inst.setSrcImm(readWord(v, n, wordSize)); + usedImm = true; + break; + case Instruction::AC_PREG_REG: + inst.setDestPReg(readByte(v, n)); + inst.setSrcReg(readByte(v, n)); + break; + case Instruction::AC_2PREG: + inst.setDestPReg(readByte(v, n)); + inst.setSrcPReg(readByte(v, n)); + break; + default: + decodeError("Unknown argument class."); + } + + if (haveRefs && usedImm && + refMap.find(n - wordSize) != refMap.end()) { + OffsetRef *oref = dynamic_cast(refMap[n - wordSize]); + if (!oref) { + decodeError("Expected OffsetRef when decoding instruction stream."); + } + Ref *r = new SimpleRef(oref->name, *(Addr*)(inst.setSrcImm()), + inst.hasRelImm()); + inst.setImmRef(*r); + } + + return &inst; +} + +ByteEncoder::ByteEncoder(const ArchDef &ad) { + wordSize = ad.getWordSize(); +} + +Size ByteEncoder::encode(Ref *&ref, vector &v, Size n0, Instruction &i) { + Size n(n0); + + if (i.hasPred()) writeByte(v, n, i.getPred() + 1); + else writeByte(v, n, 0); + + writeByte(v, n, Byte(i.getOpcode())); + + if (i.hasRDest()) { + writeByte(v, n, Byte(i.getRDest())); + } else if (i.hasPDest()) { + writeByte(v, n, Byte(i.getPDest())); + } + + for (RegNum j = 0; j < i.getNRSrc(); j++) { + writeByte(v, n, Byte(i.getRSrc(j))); + } + + for (RegNum j = 0; j < i.getNPSrc(); j++) { + writeByte(v, n, Byte(i.getPSrc(j))); + } + + ref = NULL; + if (i.hasImm()) { + if (i.hasRefLiteral()) { + Ref *r = i.getRefLiteral(); + ref = new OffsetRef(r->name, v, n, wordSize*8, wordSize, i.hasRelImm()); + } + + writeWord(v, n, wordSize, i.getImm()); + } + + return n - n0; +} + +static unsigned ceilLog2(RegNum x) { + unsigned z = 0; + bool nonZeroInnerValues(false); + + if (x == 0) return 0; + + while (x != 1) { + z++; + if (x&1) nonZeroInnerValues = true; + x >>= 1; + } + + if (nonZeroInnerValues) z++; + + return z; +} + +static Word mask(Size bits) { + return (1l< r) r = p; + oMask = mask(o); rMask = mask(r); pMask = mask(p); + i1Mask = mask(i1); i2Mask = mask(i2); i3Mask = mask(i3); +} + +Word signExt(Word w, Size bit, Word mask) { + if (w>>(bit-1)) w |= ~mask; + return w; +} + +Instruction *WordDecoder::decode(const std::vector &v, Size &idx) { + Word code(readWord(v, idx, n/8)); + Instruction &inst = * new Instruction(); + + bool predicated = (code>>(i1+o+p)); + if (predicated) { inst.setPred((code>>(i1+o))&p); } + + Instruction::Opcode op = (Instruction::Opcode)((code>>i1)&oMask); + inst.setOpcode(op); + + bool usedImm(false); + switch(Instruction::argClasses[op]) { + case Instruction::AC_NONE: + break; + case Instruction::AC_1IMM: + inst.setSrcImm(signExt(code&i1Mask, i1, i1Mask)); + usedImm = true; + break; + case Instruction::AC_2IMM: + inst.setDestReg((code>>i2)&rMask); + inst.setSrcImm(signExt(code&i2Mask, i2, i2Mask)); + usedImm = true; + break; + case Instruction::AC_3IMM: + inst.setDestReg((code>>i2)&rMask); + inst.setSrcReg((code>>i3)&rMask); + inst.setSrcImm(signExt(code&i3Mask, i3, i3Mask)); + usedImm = true; + break; + case Instruction::AC_3IMMSRC: + inst.setSrcReg((code>>i2)&rMask); + inst.setSrcReg((code>>i3)&rMask); + inst.setSrcImm(signExt(code&i3Mask, i3, i3Mask)); + usedImm = true; + break; + case Instruction::AC_1REG: + inst.setSrcReg((code>>i2)&rMask); + break; + case Instruction::AC_2REG: + inst.setDestReg((code>>i2)&rMask); + inst.setSrcReg((code>>i3)&rMask); + break; + case Instruction::AC_3REG: + inst.setDestReg((code>>i2)&rMask); + inst.setSrcReg((code>>i3)&rMask); + inst.setSrcReg((code>>(i3-r))&rMask); + break; + case Instruction::AC_3REGSRC: + inst.setSrcReg((code>>i2)&rMask); + inst.setSrcReg((code>>i3)&rMask); + inst.setSrcReg((code>>(i3-r))&rMask); + break; + case Instruction::AC_PREG_REG: + inst.setDestPReg((code>>i2)&pMask); + inst.setSrcReg((code>>i3)&rMask); + break; + case Instruction::AC_2PREG: + inst.setDestPReg((code>>i2)&pMask); + inst.setSrcPReg((code>>i3)&pMask); + break; + case Instruction::AC_3PREG: + inst.setDestPReg((code>>i2)&pMask); + inst.setSrcPReg((code>>i3)&pMask); + inst.setSrcPReg((code>>(i3-r))&pMask); + break; + defualt: + cout << "Unrecognized argument class in word decoder.\n"; + exit(1); + } + + if (haveRefs && usedImm && refMap.find(idx-n/8) != refMap.end()) { + Ref *srcRef = refMap[idx-n/8]; + + /* Create a new ref tied to this instruction. */ + Ref *r = new SimpleRef(srcRef->name, *(Addr*)inst.setSrcImm(), + inst.hasRelImm()); + inst.setImmRef(*r); + } + + //cout << "Decoded 0x" << hex << code << " into: " << inst << '\n'; + + return &inst; +} + +WordEncoder::WordEncoder(const ArchDef &arch) { + getSizes(arch, n, o, r, p, i1, i2, i3); + if (p > r) r = p; + oMask = mask(o); rMask = mask(r); pMask = mask(p); + i1Mask = mask(i1); i2Mask = mask(i2); i3Mask = mask(i3); +} + +Size WordEncoder::encode(Ref *&ref, std::vector &v, + Size idx, Instruction &i) +{ + Word code = 0; + Size bitsWritten = 0; + + /* Predicate/predicated bit */ + if (i.hasPred()) { + code = 1 << p; + code |= (i.getPred()&pMask); + if (i.getPred() > pMask) { + cout << "Predicate in " << i << " does not fit in encoding.\n"; + exit(1); + } + } + bitsWritten += (1 + p); + + /* Opcode */ + code <<= o; + code |= (i.getOpcode()&oMask); + if (i.getOpcode() > oMask) { + cout << "Opcode in " << i << " does not fit in encoding.\n"; + exit(1); + } + bitsWritten += o; + + if (i.hasRDest()) { + code <<= r; + code |= i.getRDest(); + bitsWritten += r; + if (i.getRDest() > rMask) { + cout << "Destination register in " << i << " does not fit in encoding.\n"; + exit(1); + } + } + + if (i.hasPDest()) { + code <<= r; + code |= i.getPDest(); + bitsWritten += r; + if (i.getPDest() > rMask) { + cout << "Destination predicate in " < rMask) { + cout << "Source register " << j << " in " << i + << " does not fit in encoding.\n"; + exit(1); + } + } + + for (Size j = 0; j < i.getNPSrc(); j++) { + code <<= r; + code |= i.getPSrc(j); + bitsWritten += r; + if (i.getPSrc(j) > rMask) { + cout << "Source predicate " << j << " in " << i + << " does not fit in encoding.\n"; + exit(1); + } + } + + if (i.hasRefLiteral()) { + Ref *r = i.getRefLiteral(); + ref = new OffsetRef(r->name, v, idx, n - bitsWritten, n, i.hasRelImm()); + } else { + ref = NULL; + } + + if (i.hasImm()) { + if (bitsWritten == n - i1) { + code <<= i1; + code |= (i.getImm()&i1Mask); + bitsWritten += i1; + Word_s ws(i.getImm()); + if ((ws >> i1) != 0 && (ws >> i1) != -1) goto tooBigImm; + } else if (bitsWritten == n - i2) { + code <<= i2; + code |= (i.getImm()&i2Mask); + bitsWritten += i2; + Word_s ws(i.getImm()); + if ((ws >> i2) != 0 && (ws >> i2) != -1) goto tooBigImm; + } else if (bitsWritten == n - i3) { + code <<= i3; + code |= (i.getImm()&i3Mask); + bitsWritten += i3; + Word_s ws(i.getImm()); + if ((ws >> i3) != 0 && (ws >> i3) != -1) goto tooBigImm; + } else { + cout << "WordEncoder::encode() could not encode: " << i << '\n'; + exit(1); + } + } + + if (bitsWritten < n) code <<= (n - bitsWritten); + + writeWord(v, idx, n/8, code); + + return n/8; + +tooBigImm: + cout << "Immediate in " << i << " too large to encode.\n"; + exit(1); +} diff --git a/src/harptool.cpp b/src/harptool.cpp new file mode 100644 index 00000000..c1564e2c --- /dev/null +++ b/src/harptool.cpp @@ -0,0 +1,378 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "include/types.h" +#include "include/core.h" +#include "include/enc.h" +#include "include/instruction.h" +#include "include/mem.h" +#include "include/obj.h" +#include "include/archdef.h" + +#include "include/args.h" +#include "include/help.h" + +using namespace Harp; +using namespace HarpTools; +using namespace std; + +enum HarpToolMode { HARPTOOL_MODE_ASM, HARPTOOL_MODE_DISASM, HARPTOOL_MODE_EMU, + HARPTOOL_MODE_LD, HARPTOOL_MODE_HELP }; + +HarpToolMode findMode(int argc, char** argv) { + bool mode_asm, mode_disasm, mode_emu, mode_ld, mode_help; + + if (argc == 0) return HARPTOOL_MODE_HELP; + + CommandLineArgFlag("--help", "-h", "", mode_help); + CommandLineArgFlag("-A", "--asm", "", mode_asm); + CommandLineArgFlag("-D", "--disasm", "", mode_disasm); + CommandLineArgFlag("-E", "--emu", "", mode_emu); + CommandLineArgFlag("-L", "--ld", "", mode_ld); + + CommandLineArg::readArgs((argc == 0?0:1), argv); + CommandLineArg::clearArgs(); + + if (mode_asm) return HARPTOOL_MODE_ASM; + if (mode_disasm) return HARPTOOL_MODE_DISASM; + if (mode_emu) return HARPTOOL_MODE_EMU; + if (mode_ld) return HARPTOOL_MODE_LD; + return HARPTOOL_MODE_HELP; +} + +int asm_main(int argc, char **argv) { + string archString("8w32/32/8"), outFileName("a.out.HOF"), + inFileName(argv[argc-1]); + bool showHelp; + + /* Get command line arguments. */ + CommandLineArgFlag("-h", "--help", "", showHelp); + CommandLineArgSetter("-o", "--output", "", outFileName); + CommandLineArgSetter("-a", "--arch", "", archString); + + CommandLineArg::readArgs(argc-1, argv); + + if (showHelp || argc == 0) { + cout << Help::asmHelp; + exit(0); + } + + ArchDef arch(archString); + + /* Create an appropriate encoder. */ + Encoder *enc; + switch (arch.getEncChar()) { + case 'b': enc = new ByteEncoder(arch); break; + case 'w': enc = new WordEncoder(arch); break; + defaulet: + cout << "Unknown encoding type, \"" << arch.getEncChar() << "\"\n"; + exit(1); + } + + /* Open files. */ + if (outFileName == "") { + cout << "HARP Assembler: No output filename given.\n"; + exit(1); + } + + ifstream asmFile(inFileName.c_str()); + ofstream outFile(outFileName.c_str()); + + if (!asmFile) { + cout << "Could not open \"" << inFileName << "\" for reading.\n"; + exit(1); + } + + if (!outFile) { + cout << "Could not open \"" << outFileName << "\" for writing.\n"; + exit(1); + } + + /* Read an Obj from the assembly file. */ + AsmReader ar(arch); + Obj *o = ar.read(asmFile); + + /* Encode the text chunks read from the assembly file. */ + for (Size j = 0; j < o->chunks.size(); j++) { + Chunk *&c = o->chunks[j]; + TextChunk *tc; + DataChunk *dc; + if ((tc = dynamic_cast(c)) != NULL) { + /* Encode it. */ + dc = new DataChunk(tc->name); + enc->encodeChunk(*dc, *tc); + + /* Delete the text chunk. */ + delete tc; + + /* Do the switch. */ + c = dc; + } + } + asmFile.close(); + delete enc; + + /* Write a HOF binary. */ + HOFWriter hw(arch); + hw.write(outFile, *o); + outFile.close(); + + delete o; + + return 0; +} + +int disasm_main(int argc, char **argv) { + bool showHelp; + string outFileName("a.out.s"), archString("8w32/32/8"); + + + /* Get command line arguments. */ + CommandLineArgFlag("-h", "--help", "", showHelp); + CommandLineArgSetter("-a", "--arch", "", archString); + CommandLineArgSetter("-o", "--output", "", outFileName); + + if (argc != 0) CommandLineArg::readArgs(argc-1, argv); + + if (argc == 0 || showHelp) { + cout << Help::disasmHelp; + exit(0); + } + + ifstream objFile(argv[argc-1]); + ofstream outFile(outFileName.c_str()); + ArchDef arch(archString); + + if (!objFile) { + cout << "Disassembler could not open \"" << argv[argc-1] + << "\" for reading.\n"; + exit(1); + } + + if (!outFile) { + cout << "Disassembler could not open \"" << outFileName + << "\" for output.\n"; + exit(1); + } + + HOFReader hr(arch); + Obj *o = hr.read(objFile); + objFile.close(); + Decoder *dec; + + switch (arch.getEncChar()) { + case 'b': dec = new ByteDecoder(arch); break; + case 'w': dec = new WordDecoder(arch); break; + default: + cout << "Unrecognized encoding character for disassembler.\n"; + exit(1); + } + + /* Decode the chunks read from the object. */ + for (Size j = 0; j < o->chunks.size(); j++) { + Chunk *&c = o->chunks[j]; + if (c->flags & EX_USR) { + TextChunk *tc; + DataChunk *dc; + if ((dc = dynamic_cast(c)) != NULL) { + TextChunk *tc = new TextChunk(dc->name); + dec->decodeChunk(*tc, *dc); + delete dc; + c = tc; + } + } + } + delete dec; + + AsmWriter aw(arch); + aw.write(outFile, *o); + outFile.close(); + + delete o; + + return 0; +} + +int emu_main(int argc, char **argv) { + string archString("8w32/32/8"), imgFileName("a.out.bin"); + bool showHelp; + + /* Read the command line arguments. */ + CommandLineArgFlag("-h", "--help", "", showHelp); + CommandLineArgSetter("-c", "--core", "", imgFileName); + CommandLineArgSetter("-a", "--arch", "", archString); + + CommandLineArg::readArgs(argc, argv); + + if (showHelp) { + cout << Help::emuHelp; + return 0; + } + + /* Instantiate a Core, RAM, and console output. */ + ArchDef arch(archString); + + Decoder *dec; + + switch (arch.getEncChar()) { + case 'b': dec = new ByteDecoder(arch); break; + case 'w': dec = new WordDecoder(arch); break; + default: + cout << "Unrecognized decoder type: '" << arch.getEncChar() << "'.\n"; + return 1; + } + + MemoryUnit mu(4096, arch.getWordSize()); + Core core(arch, *dec, mu); + + RamMemDevice mem(imgFileName.c_str(), arch.getWordSize()); + ConsoleMemDevice console(arch.getWordSize(), cout, core); + mu.attach(mem, 0); + mu.attach(console, 1ll<<(arch.getWordSize()*8 - 1)); + + while (core.running()) { console.poll(); core.step(); } + + return 0; +} + +int ld_main(int argc, char **argv) { + bool showHelp, mustResolveRefs(true); + string outFileName("a.out.bin"), archString("8w32/32/8"), formatString("bin"); + Size nObjects; + Addr binOffset(0); + + /* Get command line arguments. */ + CommandLineArgFlag("-h", "--help", "", showHelp); + CommandLineArgSetter("-a", "--arch", "", archString); + CommandLineArgSetter("-f", "--format", "", formatString); + CommandLineArgSetter("--offset", "", binOffset); + CommandLineArgSetter("-o", "--output", "", outFileName); + + int firstInput(0), newArgc; + for (size_t i = 0; i < argc; i++) { + if (*(argv[i]) != '-') { firstInput = i; newArgc = i; break; } + else if (string(argv[i]) == "--") { firstInput = i+1; newArgc = i; break; } + else i++; /* Skip both the switch and its argument. */ + } + nObjects = argc - firstInput; + + if (argc != 0) CommandLineArg::readArgs(newArgc, argv); + + if (argc == 0 || showHelp) { + cout << Help::ldHelp; + exit(0); + } + + if (firstInput == argc) { + cout << "Linker: no input files given.\n"; + exit(1); + } + + ArchDef arch(archString); + + /* Read all of the objects, assign addresses to their chunks, and place them + in an address map.*/ + vector objects(nObjects); + vector chunks; + map gChunkMap; + Addr nextOffset(binOffset); + + for (Size i = 0; i < nObjects; i++) { + map lChunkMap; + + /* Read the object. */ + HOFReader hr(arch); + ifstream objFile(argv[firstInput + i]); + if (!objFile) { + cout << "Could not open \"" << argv[firstInput + i] + << "\" for reading.\n"; + exit(1); + } + objects[i] = hr.read(objFile); + + /* Assign addresses to chunks. */ + Obj &obj = *objects[i]; + for (Size j = 0; j < obj.chunks.size(); j++) { + DataChunk *c = dynamic_cast(obj.chunks[j]); + if (c->alignment != 0 && nextOffset % c->alignment) + nextOffset += c->alignment - (nextOffset % c->alignment); + c->bind(nextOffset); + chunks.push_back(c); + if (obj.chunks[j]->name != "") { + if (c->isGlobal()) gChunkMap[c->name] = nextOffset; + else lChunkMap[c->name] = nextOffset; + } + nextOffset += (c->size); + } + + /* Resolve local references. */ + for (Size i = 0; i < obj.chunks.size(); i++) { + DataChunk *dc = dynamic_cast(obj.chunks[i]); + for (Size j = 0; j < dc->refs.size(); j++) { + Ref &ref = *(dc->refs[j]); + if (lChunkMap.find(dc->refs[j]->name) != lChunkMap.end()) { + dc->refs[j]->bind(lChunkMap[dc->refs[j]->name], + dc->address + dc->refs[j]->ibase); + } + } + } + } + + /* Resolve references. */ + for (Size i = 0; i < chunks.size(); i++) { + DataChunk *dc = chunks[i]; + for (Size j = 0; j < dc->refs.size(); j++) { + Ref &ref = *(dc->refs[j]); + if (!ref.bound && (gChunkMap.find(ref.name) != gChunkMap.end())) { + ref.bind(gChunkMap[ref.name], dc->address + ref.ibase); + } else if (!ref.bound && mustResolveRefs) { + cout << "Undefined symbol: \"" << ref.name << "\"\n"; + exit(1); + } + } + } + + /* Write out the chunks. */ + ofstream outFile(outFileName.c_str()); + for (Size i = 0; i < chunks.size(); i++) { + if (outFile.tellp() > chunks[i]->address - binOffset) { + cout << "Linker internal error. Wrote past next chunk address.\n"; + exit(1); + } + while (outFile.tellp() < chunks[i]->address - binOffset) outFile.put('\0'); + outFile.seekp(chunks[i]->address - binOffset); + outFile.write((char*)&chunks[i]->contents[0], chunks[i]->contents.size()); + } + + /* Clean up. */ + for (Size i = 0; i < nObjects; i++) delete objects[i]; + + return 0; +} + +int main(int argc, char** argv) { + try { + switch (findMode(argc - 1, argv + 1)) { + case HARPTOOL_MODE_ASM: return asm_main (argc - 2, argv + 2); + case HARPTOOL_MODE_DISASM: return disasm_main(argc - 2, argv + 2); + case HARPTOOL_MODE_EMU: return emu_main (argc - 2, argv + 2); + case HARPTOOL_MODE_LD: return ld_main (argc - 2, argv + 2); + case HARPTOOL_MODE_HELP: + default: + cout << "Usage:\n" << Help::mainHelp; + return 0; + } + } catch (BadArg ba) { + cout << "Unrecognized argument \"" << ba.arg << "\".\n"; + return 1; + } + + return 0; +} diff --git a/src/include/archdef.h b/src/include/archdef.h new file mode 100644 index 00000000..b7cf97e7 --- /dev/null +++ b/src/include/archdef.h @@ -0,0 +1,87 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __ARCHDEF_H +#define __ARCHDEF_H + +#include +#include + +#include "types.h" + +namespace Harp { + class ArchDef { + public: + struct Undefined {}; + + ArchDef(const std::string &s) { + std::istringstream iss(s.c_str()); + + iss >> wordSize; + if (!iss) { extent = EXT_NULL; return; } + iss >> encChar; + if (!iss) { extent = EXT_WORDSIZE; return; } + iss >> nRegs; + if (!iss) { extent = EXT_ENC; return; } + char sep; + iss >> sep >> nPRegs; + if (!iss || sep != '/') { extent = EXT_REGS; return; } + iss >> sep >> nThds; + if (!iss || sep != '/') { extent = EXT_PREGS; return; } + extent = EXT_THDS; + } + + operator std::string () const { + if (extent == EXT_NULL) return ""; + + std::ostringstream oss; + if (extent >= EXT_WORDSIZE) oss << wordSize; + if (extent >= EXT_ENC ) oss << encChar; + if (extent >= EXT_REGS ) oss << nRegs; + if (extent >= EXT_PREGS ) oss << '/' << nPRegs; + if (extent >= EXT_THDS ) oss << '/' << nThds; + + return oss.str(); + } + + bool operator==(const ArchDef &r) const { + return (extent == r.extent) && (wordSize == r.wordSize) && + (encChar == r.encChar) && (nRegs == r.nRegs) && + (nPRegs == r.nPRegs) && (nThds == r.nThds); + } + + bool operator!=(const ArchDef &r) const { return !(*this == r); } + + Size getWordSize() const { + if (extent < EXT_WORDSIZE) throw Undefined(); else return wordSize; + } + + char getEncChar() const { + if (extent +#include +#include +#include + +namespace HarpTools { + struct BadArg { BadArg(std::string s) : arg(s) {} std::string arg; }; + + class CommandLineArg { + public: + CommandLineArg(std::string s, std::string l, const char *helpText); + CommandLineArg(std::string l, const char *helpText); + virtual int read(int argc, char** argv) = 0; + + static void readArgs(int argc, char **argv); + static void clearArgs(); + static void showHelp(std::ostream &os); + + private: + static std::string helpString; + static std::map longArgs; + static std::map shortArgs; + }; + + template class CommandLineArgSetter : public CommandLineArg { + public: + CommandLineArgSetter(std::string s, std::string l, const char *ht, T &x) : + CommandLineArg(s, l, ht), x(x) {} + CommandLineArgSetter(std::string l, const char *ht, T &x) : + CommandLineArg(l, ht), x(x) {} + + int read(int argc, char **argv) { + std::istringstream iss(argv[1]); + iss >> x; + return 1; + } + private: + T &x; + }; + + class CommandLineArgFlag : public CommandLineArg { + public: + CommandLineArgFlag(std::string s, std::string l, const char *ht, bool &x) : + CommandLineArg(s, l, ht), x(x) { x = false; } + CommandLineArgFlag(std::string l, const char *ht, bool &x) : + CommandLineArg(l, ht), x(x) { x = false; } + + int read(int argc, char **argv) { x = true; return 0; } + private: + bool &x; + }; + +}; + +#endif diff --git a/src/include/asm-tokens.h b/src/include/asm-tokens.h new file mode 100644 index 00000000..3359a3c3 --- /dev/null +++ b/src/include/asm-tokens.h @@ -0,0 +1,10 @@ +namespace HarpTools { + enum AsmTokens { + ASM_T_DIR_DEF = 1, ASM_T_DIR_PERM, ASM_T_DIR_BYTE, ASM_T_DIR_WORD, + ASM_T_DIR_STRING, ASM_T_DIR_ALIGN, ASM_T_DIR_ENTRY, ASM_T_DIR_GLOBAL, + ASM_T_DIR_ARG_NUM, ASM_T_DIR_ARG_STRING, ASM_T_DIR_ARG_SYM, + ASM_T_DIR_ARG_R, ASM_T_DIR_ARG_W, ASM_T_DIR_ARG_X, ASM_T_DIR_END, + ASM_T_LABEL, ASM_T_PRED, ASM_T_INST, ASM_T_PREG, ASM_T_REG, ASM_T_LIT, + ASM_T_SYM, ASM_T_PEXP + }; +}; diff --git a/src/include/core.h b/src/include/core.h new file mode 100644 index 00000000..728735a5 --- /dev/null +++ b/src/include/core.h @@ -0,0 +1,43 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __CORE_H +#define __CORE_H + +#include +#include + +#include "types.h" +#include "archdef.h" +#include "enc.h" +#include "mem.h" + +namespace Harp { + class Core { + public: + Core(const ArchDef &a, Decoder &d, MemoryUnit &mem); + void step(); + bool interrupt(Word r0); + bool running() const { return activeThreads; } + + private: + const ArchDef &a; + Decoder &iDec; + MemoryUnit &mem; + + Word pc, interruptEntry, shadowPc; + Size activeThreads, shadowActiveThreads; + std::vector > reg; + std::vector > pred; + + std::vector shadowReg; + std::vector shadowPReg; + + bool interruptEnable, shadowInterruptEnable, supervisorMode, + shadowSupervisorMode; + + friend class Instruction; + }; +}; + +#endif diff --git a/src/include/enc.h b/src/include/enc.h new file mode 100644 index 00000000..ea74f618 --- /dev/null +++ b/src/include/enc.h @@ -0,0 +1,84 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __ENC_H +#define __ENC_H + +#include + +#include "types.h" +#include "instruction.h" +#include "obj.h" + +namespace Harp { + class DataChunk; + class TextChunk; + class Ref; + + class Encoder { + public: + Encoder() {} + virtual ~Encoder() {} + + virtual Size encode(Ref *&ref, std::vector &v, Size n, + Instruction &i) = 0; + void encodeChunk(DataChunk &dest, const TextChunk &src); + }; + + class Decoder { + public: + Decoder() : haveRefs(false) {} + Decoder(const std::vector &refVec) : haveRefs(true) { + setRefs(refVec); + } + + virtual ~Decoder() {} + + void setRefs(const std::vector &); + void clearRefs() { refMap.clear(); } + virtual Instruction *decode(const std::vector &v, Size &n) = 0; + void decodeChunk(TextChunk &dest, const DataChunk &src); + protected: + bool haveRefs; + std::map refMap; + }; + + class WordDecoder : public Decoder { + public: + WordDecoder(const ArchDef &); + virtual Instruction *decode(const std::vector &v, Size &n); + + private: + Size n, o, r, p, i1, i2, i3; + Word oMask, rMask, pMask, i1Mask, i2Mask, i3Mask; + }; + + class ByteDecoder : public Decoder { + public: + ByteDecoder(const ArchDef &); + virtual Instruction *decode(const std::vector &v, Size &n); + private: + Size wordSize; + }; + + class WordEncoder : public Encoder { + public: + WordEncoder(const ArchDef &); + virtual Size encode(Ref *&ref, std::vector &v, + Size n, Instruction &i); + private: + Size n, o, r, p, i1, i2, i3; + Word oMask, rMask, pMask, i1Mask, i2Mask, i3Mask; + }; + + class ByteEncoder : public Encoder { + public: + ByteEncoder(const ArchDef &); + virtual Size encode(Ref *&ref, std::vector &v, + Size n, Instruction &i); + private: + Size wordSize; + }; +}; + +#endif diff --git a/src/include/help.h b/src/include/help.h new file mode 100644 index 00000000..52947572 --- /dev/null +++ b/src/include/help.h @@ -0,0 +1,34 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __HELP_H +#define __HELP_H + +/* Help messages. */ +namespace HarpTools { + namespace Help { + const char *mainHelp = + "--help, -h, no arguments\n" + " Print this message.\n" + "-E, --emu; -A, --asm; -L, --ld; -D, --disasm\n" + " Invoke the emulator, assembler, linker, and disassembler, " + "respectively.\n" + " --help\n" + " Display contextual help.\n", + *emuHelp = "HARP Emulator command line arguments:\n" + " -c, --core RAM image\n" + " -a, --arch Architecture string\n", + *asmHelp = "HARP Assembler command line arguments:\n" + " -a, --arch \n" + " -o, --output \n", + *ldHelp = "HARP Linker command line arguments:\n" + " -o, --output \n" + " -a, --arch \n" + " -f, --format \n" + " --offset \n", + *disasmHelp = "HARP Disassembler command line arguments:\n" + " -a, --arch Architecture string.\n" + " -o, --output Output filename.\n"; + }; +}; +#endif diff --git a/src/include/instruction.h b/src/include/instruction.h new file mode 100644 index 00000000..d809a6d5 --- /dev/null +++ b/src/include/instruction.h @@ -0,0 +1,93 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __INSTRUCTION_H +#define __INSTRUCTION_H + +#include + +#include "types.h" + +namespace Harp { + class Core; + class Ref; + + static const Size MAX_REG_SOURCES(3); + static const Size MAX_PRED_SOURCES(2); + + class Instruction; + + struct DivergentBranchException {}; + struct DomainException {}; + + std::ostream &operator<<(std::ostream &, Instruction &); + + class Instruction { + public: + enum Opcode { NOP, DI, EI, TLBADD, TLBFLUSH, NEG, NOT, + AND, OR, XOR, ADD, SUB, MUL, DIV, MOD, SHL, SHR, + ANDI, ORI, XORI, ADDI, SUBI, MULI, DIVI, MODI, SHLI, SHRI, + JALI, JALR, JMPI, JMPR, CLONE, JALIS, JALRS, + JMPRT, LD, ST, LDI, RTOP, ANDP, ORP, XORP, NOTP, ISNEG, + ISZERO, HALT, TRAP, JMPRU, SKEP, RETI, TLBRM }; + enum ArgClass { + AC_NONE, AC_2REG, AC_2IMM, AC_3REG, AC_3PREG, AC_3IMM, AC_3REGSRC, + AC_1IMM, AC_1REG, AC_3IMMSRC, AC_PREG_REG, AC_2PREG + }; + static const char *opStrings[]; + static const bool allSrcArgs[], privileged[], relAddress[], isControlFlow[]; + static const ArgClass argClasses[]; + + Instruction() : + predicated(false), nRsrc(0), nPsrc(0), immsrcPresent(false), + rdestPresent(false), pdestPresent(false), refLiteral(NULL) {} + + void executeOn(Core &core); + friend std::ostream &operator<<(std::ostream &, Instruction &); + + /* Setters used to "craft" the instruction. */ + void setOpcode (Opcode opc) { op = opc; } + void setPred (RegNum pReg) { predicated = true; pred = pReg; } + void setDestReg (RegNum destReg) { rdestPresent = true; rdest = destReg; } + void setSrcReg (RegNum srcReg) { rsrc[nRsrc++] = srcReg; } + void setDestPReg(RegNum dPReg) { pdestPresent = true; pdest = dPReg; } + void setSrcPReg (RegNum srcPReg) { psrc[nPsrc++] = srcPReg; } + Word *setSrcImm () { immsrcPresent = true; immsrc = 0xa5; return &immsrc;} + void setSrcImm (Word srcImm) { immsrcPresent = true; immsrc = srcImm; } + void setImmRef (Ref &r) { refLiteral = &r; } + + /* Getters used by encoders. */ + Opcode getOpcode() const { return op; } + bool hasPred() const { return predicated; } + RegNum getPred() const { return pred; } + RegNum getNRSrc() const { return nRsrc; } + RegNum getRSrc(RegNum i) const { return rsrc[i]; } + RegNum getNPSrc() const { return nPsrc; } + RegNum getPSrc(RegNum i) const { return psrc[i]; } + bool hasRDest() const { return rdestPresent; } + RegNum getRDest() const { return rdest; } + bool hasPDest() const { return pdestPresent; } + RegNum getPDest() const { return pdest; } + bool hasImm() const { return immsrcPresent; } + Word getImm() const { return immsrc; } + bool hasRefLiteral() const { return refLiteral != NULL; } + Ref *getRefLiteral() const { return refLiteral; } + + /* Getters used as table lookup. */ + bool hasRelImm() const { return relAddress[op]; } + + private: + bool predicated; + RegNum pred; + Opcode op; + int nRsrc, nPsrc; + RegNum rsrc[MAX_REG_SOURCES], psrc[MAX_PRED_SOURCES]; + bool immsrcPresent; + Word immsrc; + bool rdestPresent, pdestPresent; + RegNum rdest, pdest; + Ref *refLiteral; + }; +}; + +#endif diff --git a/src/include/mem.h b/src/include/mem.h new file mode 100644 index 00000000..4306a180 --- /dev/null +++ b/src/include/mem.h @@ -0,0 +1,163 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __MEM_H +#define __MEM_H + +#include +#include +#include +#include + +#include "types.h" + +namespace Harp { + void *consoleInputThread(void *); + struct BadAddress {}; + + class MemDevice { + public: + virtual ~MemDevice() {} + virtual Size size() const = 0; + virtual Word read(Addr) = 0; + virtual void write(Addr, Word) = 0; + virtual Byte *base() { return NULL; } /* Null if unavailable. */ + }; + + class RamMemDevice : public MemDevice { + public: + RamMemDevice(Size size, Size wordSize); + RamMemDevice(const char* filename, Size wordSize); + ~RamMemDevice() {} + + virtual Size size() const { return contents.size(); }; + virtual Word read(Addr); + virtual void write(Addr, Word); + virtual Byte *base() { return &contents[0]; } + + protected: + Size wordSize; + std::vector contents; + }; + + class RomMemDevice : public RamMemDevice { + public: + RomMemDevice(const char* filename, Size wordSize) : + RamMemDevice(filename, wordSize) {} + RomMemDevice(Size size, Size wordSize) : + RamMemDevice(size, wordSize) {} + ~RomMemDevice(); + + virtual void write(Addr, Word); + }; + + class Core; + class ConsoleMemDevice : public MemDevice { + public: + ConsoleMemDevice(Size wS, std::ostream &o, Core &core); + ~ConsoleMemDevice() {} + + //virtual Size wordSize() const { return wordSize; } + virtual Size size() const { return wordSize; } + virtual Word read(Addr) { pthread_mutex_lock(&cBufLock); + char c = cBuf.front(); + cBuf.pop(); + pthread_mutex_unlock(&cBufLock); + return Word(c); } + virtual void write(Addr a, Word w) { output << char(w); } + + void poll(); + + friend void *Harp::consoleInputThread(void *); + + private: + std::ostream &output; + Size wordSize; + Core &core; + + std::queue cBuf; + pthread_mutex_t cBufLock; + }; + + class DiskControllerMemDevice : public MemDevice { + public: + DiskControllerMemDevice(Size wordSize, Size blockSize, Core &c) : + wordSize(wordSize), blockSize(blockSize), core(c), disks() {} + + void addDisk(Byte *file, Size n) { disks.push_back(Disk(file, n)); } + + virtual Size size() const { return wordSize * 6; } + virtual Word read(Addr); + virtual void write(Addr, Word); + + private: + Word curDisk, curBlock, nBlocks, physAddr, command, status; + enum Status { OK = 0, INVALID_DISK, INVALID_BLOCK }; + struct Disk { + Disk(Byte *f, Size n): file(f), blocks(n) {} + Byte *file; + Size blocks; + }; + std::vector disks; + Core &core; + Size wordSize, blockSize;; + }; + + class MemoryUnit { + public: + MemoryUnit(Size pageSize, Size addrBytes) : + pageSize(pageSize), addrBytes(addrBytes), ad() + { + tlb[0] = TLBEntry(0, 077); + } + void attach(MemDevice &m, Addr base); + + //Size wordSize(); + struct PageFault { + PageFault(Addr a, bool nf) : faultAddr(a), notFound(nf) {} + Addr faultAddr; + bool notFound; + }; /* Thrown on page fault. */ + + Word read(Addr, bool sup); /* For data accesses. */ + Word fetch(Addr, bool sup); /* For instruction accesses. */ + Byte *getPtr(Addr, Size); + void write(Addr, Word, bool sup); + void tlbAdd(Addr virt, Addr phys, Word flags); + void tlbRm(Addr va); + void tlbFlush() { tlb.clear(); } + + private: + class ADecoder { + public: + ADecoder() : zeroChild(NULL), oneChild(NULL), range(0) {} + ADecoder(MemDevice &md, Size range) : + zeroChild(NULL), oneChild(NULL), range(range), md(&md) {} + Byte *getPtr(Addr a, Size sz, Size wordSize); + Word read(Addr a, bool sup, Size wordSize); + void write(Addr a, Word w, bool sup, Size wordSize); + void map(Addr a, MemDevice &md, Size range, Size bit); + private: + MemDevice &doLookup(Addr a, Size &bit); + ADecoder *zeroChild, *oneChild; + MemDevice *md; + Size range; + }; + + ADecoder ad; + + struct TLBEntry { + TLBEntry() {} + TLBEntry(Word pfn, Word flags): pfn(pfn), flags(flags) {} + Word flags; + Word pfn; + }; + + std::map tlb; + TLBEntry tlbLookup(Addr vAddr, Word flagMask); + + Size pageSize, addrBytes; + }; +}; + +#endif diff --git a/src/include/obj.h b/src/include/obj.h new file mode 100644 index 00000000..8db3fd8b --- /dev/null +++ b/src/include/obj.h @@ -0,0 +1,200 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __OBJ_H +#define __OBJ_H + +#include +#include +#include +#include +#include + +#include "types.h" +#include "archdef.h" +#include "enc.h" + +namespace Harp { + class Decoder; + class Encoder; + + class Ref { + public: + std::string name; + Ref(const std::string &n, bool r, Size ib = 0): + name(n), bound(false), relative(r), ibase(ib) { } + virtual ~Ref() { } + virtual void bind(Addr addr, Addr base = 0) = 0; + virtual Addr getAddr() const = 0; + + bool bound, relative; + Size ibase; + }; + + /* Used in not-yet-encoded code objects, plain old data. */ + class SimpleRef : public Ref { + public: + SimpleRef(const std::string &name, Addr &addr, bool rel = false) : + Ref(name, rel), addr(addr) { } + virtual void bind(Addr addr, Addr base = 0) { + std::cout << "Attempted to bind a SimpleRef.\n"; + exit(1); + } + virtual Addr getAddr() const { return this->addr; } + Byte *getAddrPtr() { return (Byte*)&addr; } + + private: + Addr &addr; + }; + + /* Used in already-encoded code objects. */ + class OffsetRef : public Ref { + public: + OffsetRef( + const std::string &name, std::vector &v, Size offset, Size bits, + Size ws, bool rel = false, Size ibase = 0 + ) : Ref(name, rel, ibase), data(v), offset(offset), bits(bits), wordSize(ws) + {} + + virtual void bind(Addr addr, Addr base = 0) { + Size bytes = bits/8, remainder = bits%8, i; + + if (relative) { + addr = addr - base; + Word_s addr_s(addr); + if ((addr_s >> bits) != -1 && (addr_s >> bits) != 0) goto noFit; + } else { + Addr mask = (1ll< mask) goto noFit; + } + + { Byte mask((1<>= 8; + } + data[offset+i] &= ~mask; + data[offset+i] |= (addr&mask); + bound = true; + } + + return; + noFit: + std::cout << "Attempt to bind a symbol to an address it cannot reach.\n"; + exit(1); + } + + virtual Addr getAddr() const { + Size bytes = bits/8, remainder = bits%8; + Byte mask((1< &data; + Size offset, bits, wordSize; + }; + + class Chunk { + public: + Chunk(std::string n, Size a = 0, Word f = 0) : + name(n), alignment(a), bound(false), flags(f), global(false) {} + virtual ~Chunk() { for (Size i = 0; i < refs.size(); i++) delete refs[i]; } + void bind(Addr a) { address = a; bound = true; } + void setGlobal() { global = true; } + bool isGlobal() const { return global; } + std::string name; + Size alignment; + bool bound, global; + Addr address; + Word flags; + std::vector refs; + }; + + class TextChunk : public Chunk { + public: + TextChunk(std::string n, Size a = 0, Word f = 0) + : Chunk(n, a, f), instructions() {} + + ~TextChunk() { + for (Size i = 0; i < instructions.size(); i++) delete instructions[i]; + } + + std::vector instructions; + }; + + class DataChunk : public Chunk { + public: + DataChunk(std::string n, Size a = 0, Word f = 0) + : Chunk(n, a, f), size(0), contents() {} + Size size; + std::vector contents; /* 0 to size bytes in length. */ + }; + + class Obj { + public: + ~Obj() { for (Size i = 0; i < chunks.size(); i++) delete chunks[i]; } + std::vector chunks; + Size entry; + }; + + class DynObj : public Obj { + public: + std::vector deps; + }; + + class ObjReader { + public: + virtual Obj *read(std::istream &input) = 0; + private: + }; + + class ObjWriter { + public: + virtual void write(std::ostream &output, const Obj &o) = 0; + private: + }; + + class AsmReader : public ObjReader { + public: + AsmReader(ArchDef arch) : wordSize(arch.getWordSize()) {} + virtual Obj *read(std::istream &input); + private: + Size wordSize; + }; + + class HOFReader : public ObjReader { + public: + HOFReader(ArchDef arch) : arch(arch) {} + Obj *read(std::istream &input); + private: + const ArchDef &arch; + }; + + class AsmWriter : public ObjWriter { + public: + AsmWriter(ArchDef arch): wordSize(arch.getWordSize()) {} + virtual void write(std::ostream &output, const Obj &obj); + private: + Size wordSize; + }; + + class HOFWriter : public ObjWriter { + public: + HOFWriter(ArchDef arch) : arch(arch) {} + virtual void write(std::ostream &output, const Obj &obj); + private: + const ArchDef &arch; + }; +}; + +#endif diff --git a/src/include/types.h b/src/include/types.h new file mode 100644 index 00000000..e71f018e --- /dev/null +++ b/src/include/types.h @@ -0,0 +1,25 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __TYPES_H +#define __TYPES_H + +#include + +namespace Harp { + typedef uint8_t Byte; + typedef uint64_t Word; + typedef uint64_t Word_u; + typedef int64_t Word_s; + + typedef Word Addr; + typedef Word Size; + + typedef unsigned RegNum; + typedef unsigned ThdNum; + + enum MemFlags {RD_USR = 1, WR_USR = 2, EX_USR = 4, + RD_SUP = 8, WR_SUP = 16, EX_SUP = 32}; +}; + +#endif diff --git a/src/include/util.h b/src/include/util.h new file mode 100644 index 00000000..006612e3 --- /dev/null +++ b/src/include/util.h @@ -0,0 +1,24 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#ifndef __UTIL_H +#define __UTIL_H + +#include +#include "types.h" + +namespace Harp { + Word_u bytesToWord(const Byte *b, Size wordSize); + void wordToBytes(Byte *b, Word_u w, Size wordSize); + Word_u flagsToWord(bool r, bool w, bool x); + void wordToFlags(bool &r, bool &w, bool &x, Word_u f); + + class OutOfBytes {}; + + Byte readByte(const std::vector &b, Size &n); + Word_u readWord(const std::vector &b, Size &n, Size wordSize); + void writeByte(std::vector &p, Size &n, Byte b); + void writeWord(std::vector &p, Size &n, Size wordSize, Word w); +}; + +#endif diff --git a/src/instruction.cpp b/src/instruction.cpp new file mode 100644 index 00000000..0311498b --- /dev/null +++ b/src/instruction.cpp @@ -0,0 +1,225 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#include +#include + +#include "include/instruction.h" +#include "include/obj.h" +#include "include/core.h" + +using namespace Harp; +using namespace std; + +/* It is important that this stays consistent with the Harp::Instruction::Opcode + enum. */ +const char *Instruction::opStrings[] = { + "nop", "di", "ei", "tlbadd", "tlbflush", "neg", "not", "and", "or", "xor", + "add", "sub", "mul", "div", "mod", "shl", "shr","andi", + "ori", "xori", "addi", "subi", "muli", "divi", "modi", "shli", "shri", + "jali", "jalr", "jmpi", "jmpr", "clone", "jalis", "jalrs", + "jmprt", "ld", "st", "ldi", "rtop", "andp", "orp", "xorp", "notp", + "isneg", "iszero", "halt", "trap", "jmpru", "skep", "reti", "tlbrm", 0 +}; + +const bool Instruction::isControlFlow[] = { + false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + true, true, true, true, true, true, true, + true, false, false, false, false, false, false, false, false, + false, false, false, false, true, false, true, false +}; + +const bool Instruction::relAddress[] = { + false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + true, false, true, false, false, true, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false +}; + +const bool Instruction::allSrcArgs[] = { + false, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, true, true, false, false, false, + true, false, true, false, false, false, false, false, false, + false, false, false, false, true, true, false, false +}; + +const bool Instruction::privileged[] = { + false, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, + false, false, true, false, true, true, true, true +}; + +const Instruction::ArgClass Instruction::argClasses[] = { + AC_NONE, AC_NONE, AC_NONE, AC_3REGSRC, AC_NONE, AC_2REG, AC_2REG, AC_3REG, + AC_3REG, AC_3REG, + AC_3REG, AC_3REG, AC_3REG, AC_3REG, AC_3REG, AC_3REG, AC_3REG, AC_3IMM, + AC_3IMM, AC_3IMM, AC_3IMM, AC_3IMM, AC_3IMM, AC_3IMM, AC_3IMM, AC_3IMM, + AC_3IMM, + AC_2IMM, AC_2REG, AC_1IMM, AC_1REG, AC_1REG, AC_3IMM, AC_3REG, + AC_1REG, AC_3IMM, AC_3IMMSRC, AC_2IMM, AC_PREG_REG, AC_3PREG, AC_3PREG, + AC_3PREG, AC_2PREG, + AC_PREG_REG, AC_PREG_REG, AC_NONE, AC_NONE, AC_1REG, AC_1REG, AC_NONE, + AC_1REG +}; + +ostream &Harp::operator<<(ostream& os, Instruction &inst) { + if (inst.predicated) { + os << "@p" << inst.pred << " ? "; + } + + os << Instruction::opStrings[inst.op] << ' '; + if (inst.rdestPresent) os << "%r" << inst.rdest << ' '; + if (inst.pdestPresent) os << "@p" << inst.pdest << ' '; + for (int i = 0; i < inst.nRsrc; i++) { + os << "%r" << inst.rsrc[i] << ' '; + } + for (int i = 0; i < inst.nPsrc; i++) { + os << "@p" << inst.psrc[i] << ' '; + } + if (inst.immsrcPresent) { + if (inst.refLiteral) os << inst.refLiteral->name; + else os << "#0x" << hex << inst.immsrc; + } + + os << ';'; + return os; +} + +void Instruction::executeOn(Core &c) { + /* If I try to execute a privileged instruction in user mode, throw an + exception 3. */ + if (privileged[op] && !c.supervisorMode) { + c.interrupt(3); + return; + } + + if (predicated && isControlFlow[op]) { + bool p0 = c.pred[0][pred]; + for (Size t = 1; t < c.activeThreads; t++) { + if (c.pred[t][pred] != p0) throw DivergentBranchException(); + } + } + + Size nextActiveThreads = c.activeThreads; + + for (Size t = 0; t < c.activeThreads; t++) { + vector ®(c.reg[t]); + vector &pReg(c.pred[t]); + + if (predicated && !pReg[pred]) continue; + + Word memAddr; + switch (op) { + case NOP: break; + case DI: c.interruptEnable = false; + break; + case EI: c.interruptEnable = true; + break; + case TLBADD: c.mem.tlbAdd(reg[rsrc[0]], reg[rsrc[1]], reg[rsrc[2]]); + break; + case TLBFLUSH: c.mem.tlbFlush(); + break; + case ADD: reg[rdest] = reg[rsrc[0]] + reg[rsrc[1]]; + break; + case SUB: reg[rdest] = reg[rsrc[0]] - reg[rsrc[1]]; + break; + case MUL: reg[rdest] = reg[rsrc[0]] + reg[rsrc[1]]; + break; + case DIV: if (reg[rsrc[1]] == 0) throw DomainException(); + reg[rdest] = reg[rsrc[0]] / reg[rsrc[1]]; + break; + case SHL: reg[rdest] = reg[rsrc[0]] << reg[rsrc[1]]; + break; + case MOD: if (reg[rsrc[1]] == 0) throw DomainException(); + reg[rdest] = reg[rsrc[0]] % reg[rsrc[1]]; + break; + case AND: reg[rdest] = reg[rsrc[0]] & reg[rsrc[1]]; + break; + case NEG: reg[rdest] = -(Word_s)reg[rsrc[0]]; + break; + case ADDI: reg[rdest] = reg[rsrc[0]] + immsrc; + break; + case SUBI: reg[rdest] = reg[rsrc[0]] - immsrc; + break; + case MULI: reg[rdest] = reg[rsrc[0]] * immsrc; + break; + case DIVI: if (immsrc == 0) throw DomainException(); + reg[rdest] = reg[rsrc[0]] / immsrc; + break; + case MODI: if (immsrc == 0) throw DomainException(); + reg[rdest] = reg[rsrc[0]] % immsrc; + break; + case SHRI: reg[rdest] = reg[rsrc[0]] >> immsrc; + break; + case SHLI: reg[rdest] = reg[rsrc[0]] << immsrc; + break; + case ANDI: reg[rdest] = reg[rsrc[0]] & immsrc; + break; + case JMPI: c.pc += immsrc; + break; + case JALI: reg[rdest] = c.pc; + c.pc += immsrc; + break; + case JMPR: c.pc = reg[rsrc[0]]; + break; + case CLONE: c.reg[reg[rsrc[0]]] = reg; + break; + case JALIS: nextActiveThreads = reg[rsrc[0]]; + reg[rdest] = c.pc; + c.pc += immsrc; + break; + case JMPRT: nextActiveThreads = 1; + c.pc = reg[rsrc[0]]; + break; + case LD: memAddr = reg[rsrc[0]] + immsrc; + reg[rdest] = c.mem.read(memAddr, c.supervisorMode); + break; + case ST: memAddr = reg[rsrc[1]] + immsrc; + c.mem.write(memAddr, reg[rsrc[0]], c.supervisorMode); + break; + case LDI: reg[rdest] = immsrc; + break; + case RTOP: pReg[pdest] = reg[rsrc[0]]; + break; + case NOTP: pReg[pdest] = !(pReg[psrc[0]]); + break; + case ISNEG: pReg[pdest] = (1ll<<(c.a.getWordSize()*8 - 1))®[rsrc[0]]; + break; + case HALT: c.activeThreads = 0; + nextActiveThreads = 0; + break; + case TRAP: c.interrupt(0); + break; + case JMPRU: c.supervisorMode = false; + c.pc = reg[rsrc[0]]; + break; + case SKEP: c.interruptEntry = reg[rsrc[0]]; + break; + case RETI: if (t == 0) { + nextActiveThreads = c.shadowActiveThreads; + c.interruptEnable = c.shadowInterruptEnable; + c.supervisorMode = c.shadowSupervisorMode; + reg = c.shadowReg; + pReg = c.shadowPReg; + c.pc = c.shadowPc; + } + break; + default: + cout << "ERROR: Unsupported instruction: " << *this << "\n"; + exit(1); + } + + if (isControlFlow[op]) break; + } + + c.activeThreads = nextActiveThreads; +} diff --git a/src/lex.yy.cc b/src/lex.yy.cc new file mode 100644 index 00000000..f547ecf5 --- /dev/null +++ b/src/lex.yy.cc @@ -0,0 +1,2032 @@ + +#line 3 "lex.yy.cc" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + + /* The c++ scanner is a mess. The FlexLexer.h header file relies on the + * following macro. This is required in order to pass the c++-multiple-scanners + * test in the regression suite. We get reports that it breaks inheritance. + * We will address this in a future release of flex, or omit the C++ scanner + * altogether. + */ + #define yyFlexLexer yyFlexLexer + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ +#include +#include +#include +#include +#include +/* end standard C++ headers. */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int yyleng; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + + std::istream* yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +#define yytext_ptr yytext +#define YY_INTERACTIVE + +#include + +int yyFlexLexer::yywrap() { return 1; } + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 41 +#define YY_END_OF_BUFFER 42 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[222] = + { 0, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 21, 21, 39, 39, 42, 40, + 39, 14, 40, 40, 40, 13, 40, 12, 26, 40, + 40, 25, 25, 24, 30, 40, 27, 28, 29, 33, + 40, 40, 32, 32, 31, 41, 40, 34, 37, 40, + 40, 36, 36, 38, 40, 21, 23, 40, 40, 40, + 40, 22, 40, 19, 15, 39, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, 11, 26, + 25, 25, 25, 0, 25, 24, 30, 33, 32, 32, + 32, 0, 32, 31, 0, 35, 0, 34, 37, 36, + + 36, 36, 0, 36, 38, 21, 23, 0, 18, 18, + 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 25, 32, + 35, 36, 18, 18, 18, 0, 18, 0, 17, 17, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, + 16, 0, 0, 2, 0, 0, 0, 0, 0, 1, + 0, 0, 10, 0, 0, 18, 17, 17, 17, 0, + 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 16, 16, 0, 16, 0, 4, 0, 0, + + 3, 0, 5, 0, 17, 0, 0, 0, 0, 0, + 0, 16, 7, 8, 0, 0, 0, 0, 9, 6, + 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 5, 6, 1, 7, 8, 1, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, + 1, 22, 23, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 1, 26, 1, 27, 25, 1, 28, 29, 30, 31, + + 32, 33, 34, 25, 35, 25, 25, 36, 37, 38, + 39, 40, 25, 41, 42, 43, 25, 25, 44, 45, + 46, 25, 1, 47, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[48] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 2, 3, 1, + 1, 1, 1, 1, 4, 1, 1, 2, 2, 2, + 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 1 + } ; + +static yyconst flex_int16_t yy_base[237] = + { 0, + 0, 0, 47, 0, 93, 98, 143, 0, 190, 0, + 236, 253, 101, 104, 271, 0, 96, 108, 696, 702, + 691, 702, 683, 291, 672, 702, 633, 653, 702, 668, + 101, 309, 104, 0, 702, 666, 702, 702, 702, 702, + 665, 108, 311, 111, 0, 702, 236, 0, 702, 664, + 113, 319, 115, 702, 663, 663, 702, 661, 246, 622, + 363, 702, 622, 0, 702, 659, 702, 624, 613, 626, + 619, 619, 622, 607, 609, 240, 326, 621, 702, 702, + 324, 118, 123, 0, 228, 0, 702, 702, 331, 328, + 333, 0, 335, 0, 242, 702, 329, 0, 702, 341, + + 343, 345, 0, 349, 702, 628, 702, 365, 409, 415, + 401, 0, 0, 0, 0, 0, 403, 406, 607, 603, + 453, 422, 0, 585, 575, 560, 542, 527, 512, 508, + 501, 427, 438, 440, 486, 428, 499, 435, 0, 0, + 342, 0, 319, 702, 501, 0, 507, 439, 513, 521, + 459, 455, 542, 490, 488, 495, 493, 0, 511, 534, + 544, 445, 434, 702, 418, 421, 388, 381, 383, 702, + 355, 563, 702, 0, 565, 530, 535, 702, 574, 0, + 582, 551, 560, 572, 580, 0, 586, 588, 0, 590, + 592, 543, 702, 609, 0, 619, 374, 702, 343, 359, + + 702, 292, 702, 445, 599, 596, 598, 606, 616, 625, + 627, 636, 702, 702, 288, 232, 629, 635, 702, 702, + 702, 674, 677, 680, 683, 687, 690, 693, 697, 259, + 257, 247, 240, 121, 114, 111 + } ; + +static yyconst flex_int16_t yy_def[237] = + { 0, + 221, 1, 221, 3, 222, 222, 221, 7, 221, 9, + 222, 222, 222, 222, 221, 15, 222, 222, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 223, 221, 221, + 221, 221, 221, 224, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 225, 221, 226, 227, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 228, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 229, 221, 223, 221, 221, + 221, 221, 221, 230, 221, 224, 221, 221, 221, 221, + 221, 231, 221, 225, 226, 221, 226, 227, 221, 221, + + 221, 221, 232, 221, 221, 221, 221, 221, 221, 221, + 221, 61, 61, 61, 61, 61, 61, 61, 221, 221, + 221, 221, 228, 221, 221, 221, 221, 221, 221, 221, + 221, 229, 229, 229, 229, 221, 221, 221, 230, 231, + 226, 232, 221, 221, 221, 233, 221, 221, 221, 221, + 61, 61, 121, 61, 61, 121, 121, 121, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 234, 221, 233, 221, 221, 221, 235, + 221, 61, 61, 153, 153, 153, 121, 121, 153, 121, + 121, 221, 221, 221, 236, 221, 221, 221, 221, 221, + + 221, 221, 221, 234, 235, 153, 153, 153, 153, 121, + 121, 236, 221, 221, 221, 221, 153, 153, 221, 221, + 0, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221 + } ; + +static yyconst flex_int16_t yy_nxt[750] = + { 0, + 20, 21, 22, 23, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 24, 25, 20, 20, 20, 26, + 20, 20, 20, 27, 28, 20, 20, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 20, 20, 21, 29, + 30, 20, 20, 20, 20, 20, 20, 20, 31, 20, + 31, 20, 25, 32, 33, 20, 20, 20, 20, 20, + 20, 34, 20, 20, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 20, 21, 35, 36, 21, 46, 21, + + 35, 36, 21, 54, 55, 21, 54, 55, 25, 21, + 46, 25, 212, 25, 65, 205, 25, 81, 82, 25, + 85, 85, 204, 25, 89, 90, 65, 93, 93, 100, + 101, 104, 104, 37, 85, 85, 38, 39, 37, 83, + 83, 38, 39, 20, 21, 40, 41, 20, 20, 20, + 20, 20, 20, 20, 42, 20, 42, 20, 25, 43, + 44, 20, 20, 20, 20, 20, 20, 45, 20, 20, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 20, + 20, 21, 46, 20, 47, 20, 20, 20, 20, 20, + + 20, 20, 20, 20, 20, 25, 20, 20, 20, 20, + 20, 20, 20, 20, 48, 20, 20, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 20, 21, 49, 50, + 96, 176, 133, 134, 85, 85, 96, 51, 142, 51, + 135, 25, 52, 53, 21, 49, 50, 108, 140, 108, + 139, 97, 109, 110, 51, 220, 51, 97, 25, 52, + 53, 20, 56, 57, 58, 20, 59, 60, 20, 61, + 20, 20, 20, 20, 20, 20, 25, 20, 20, 20, + 62, 20, 20, 20, 63, 64, 20, 20, 64, 64, + + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 20, 68, 69, + 143, 70, 71, 219, 72, 83, 83, 91, 91, 216, + 73, 144, 74, 141, 75, 102, 102, 136, 144, 136, + 83, 83, 137, 138, 93, 93, 96, 91, 91, 91, + 91, 93, 93, 84, 97, 92, 171, 102, 102, 104, + 104, 102, 102, 103, 112, 104, 104, 97, 84, 113, + 113, 114, 115, 113, 116, 92, 116, 173, 113, 117, + 118, 109, 110, 119, 120, 103, 215, 121, 214, 113, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + + 121, 121, 121, 121, 121, 121, 121, 121, 121, 113, + 143, 213, 148, 203, 148, 202, 143, 149, 150, 151, + 152, 144, 154, 155, 201, 145, 145, 144, 144, 133, + 134, 147, 147, 159, 144, 159, 171, 135, 160, 161, + 133, 134, 133, 134, 137, 138, 171, 153, 135, 200, + 135, 175, 175, 146, 112, 149, 150, 173, 199, 113, + 113, 114, 115, 113, 116, 198, 116, 173, 113, 156, + 157, 182, 183, 119, 120, 151, 152, 158, 197, 113, + 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, + 158, 158, 158, 158, 158, 158, 158, 158, 158, 113, + + 171, 170, 143, 153, 154, 155, 182, 183, 143, 190, + 191, 187, 188, 144, 177, 172, 172, 145, 145, 144, + 144, 173, 177, 147, 147, 178, 144, 160, 161, 179, + 179, 143, 178, 178, 153, 192, 177, 181, 181, 189, + 178, 169, 144, 174, 192, 192, 193, 178, 168, 144, + 194, 194, 167, 193, 178, 193, 193, 180, 184, 185, + 196, 196, 193, 193, 171, 166, 171, 182, 183, 186, + 186, 186, 186, 186, 186, 177, 182, 183, 195, 172, + 172, 175, 175, 177, 165, 173, 178, 173, 206, 207, + 179, 179, 164, 178, 178, 153, 208, 209, 181, 181, + + 177, 178, 187, 188, 210, 211, 210, 211, 190, 191, + 192, 178, 206, 207, 217, 218, 189, 163, 178, 162, + 192, 193, 217, 218, 113, 194, 194, 113, 193, 106, + 189, 193, 208, 209, 189, 196, 196, 192, 193, 79, + 189, 210, 211, 210, 211, 217, 218, 131, 193, 130, + 189, 217, 218, 129, 128, 193, 127, 126, 125, 124, + 66, 122, 111, 107, 106, 105, 99, 88, 87, 189, + 80, 79, 77, 189, 20, 20, 20, 20, 78, 78, + 78, 86, 76, 86, 94, 67, 94, 95, 95, 95, + 95, 98, 66, 98, 123, 221, 123, 132, 132, 132, + + 132, 19, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221 + } ; + +static yyconst flex_int16_t yy_chk[750] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 5, 5, 5, 17, 17, 6, + + 6, 6, 13, 13, 13, 14, 14, 14, 5, 18, + 18, 17, 236, 6, 17, 235, 13, 31, 31, 14, + 33, 33, 234, 18, 42, 42, 18, 44, 44, 51, + 51, 53, 53, 5, 82, 82, 5, 5, 6, 83, + 83, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, + 47, 233, 76, 76, 85, 85, 95, 11, 232, 11, + 76, 11, 11, 11, 12, 12, 12, 59, 231, 59, + 230, 47, 59, 59, 12, 216, 12, 95, 12, 12, + 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 24, 24, + 143, 24, 24, 215, 24, 32, 32, 43, 43, 202, + 24, 143, 24, 97, 24, 52, 52, 77, 143, 77, + 81, 81, 77, 77, 90, 90, 141, 89, 89, 91, + 91, 93, 93, 32, 97, 43, 171, 100, 100, 101, + 101, 102, 102, 52, 61, 104, 104, 141, 81, 61, + 61, 61, 61, 61, 61, 89, 61, 171, 61, 61, + 61, 108, 108, 61, 61, 100, 200, 61, 199, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 109, 197, 111, 169, 111, 168, 110, 111, 111, 117, + 117, 109, 118, 118, 167, 109, 109, 110, 109, 132, + 132, 110, 110, 122, 110, 122, 138, 132, 122, 122, + 133, 133, 134, 134, 136, 136, 204, 117, 133, 166, + 134, 138, 138, 109, 121, 148, 148, 138, 165, 121, + 121, 121, 121, 121, 121, 163, 121, 204, 121, 121, + 121, 152, 152, 121, 121, 151, 151, 121, 162, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + + 137, 135, 145, 151, 155, 155, 154, 154, 147, 157, + 157, 156, 156, 145, 149, 137, 137, 145, 145, 147, + 145, 137, 150, 147, 147, 149, 147, 159, 159, 149, + 149, 176, 149, 150, 154, 160, 177, 150, 150, 156, + 150, 131, 176, 137, 192, 161, 160, 177, 130, 176, + 160, 160, 129, 160, 177, 192, 161, 149, 153, 153, + 161, 161, 192, 161, 172, 128, 175, 182, 182, 153, + 153, 153, 153, 153, 153, 179, 183, 183, 160, 172, + 172, 175, 175, 181, 127, 172, 179, 175, 184, 184, + 179, 179, 126, 179, 181, 182, 185, 185, 181, 181, + + 205, 181, 187, 187, 188, 188, 190, 190, 191, 191, + 194, 205, 206, 206, 207, 207, 184, 125, 205, 124, + 196, 194, 208, 208, 120, 194, 194, 119, 194, 106, + 187, 196, 209, 209, 190, 196, 196, 212, 196, 78, + 206, 210, 210, 211, 211, 217, 217, 75, 212, 74, + 208, 218, 218, 73, 72, 212, 71, 70, 69, 68, + 66, 63, 60, 58, 56, 55, 50, 41, 36, 210, + 30, 28, 27, 217, 222, 222, 222, 222, 223, 223, + 223, 224, 25, 224, 225, 23, 225, 226, 226, 226, + 226, 227, 21, 227, 228, 19, 228, 229, 229, 229, + + 229, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "scanner.lex" +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#line 8 "scanner.lex" +#include +#include +#include +#include +#include +#include +#include + +#include "include/asm-tokens.h" + +static int64_t read_number(const char *s) { + long long u; + while (!isdigit(*s) && *s != '-' && *s != '+') s++; + + sscanf(s, "%lli", &u); + return u; +} + +static std::string label_name(const char *cs) { + return std::string(cs, strlen(cs)-1); +} + +struct rval_t { std::string s; uint64_t u; } yylval; +unsigned yyline(1); + +using namespace HarpTools; + + + +#line 688 "lex.yy.cc" + +#define INITIAL 0 +#define DEFARGS 1 +#define PERMARGS 2 +#define WORDARGS 3 +#define STRINGARGS 4 +#define ALIGNARGS 5 +#define EMPTYARGS 6 +#define INSTARGS 7 +#define EATCOLON 8 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +#define ECHO LexerOutput( yytext, yyleng ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ +\ + if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) LexerError( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 +#define YY_DECL int yyFlexLexer::yylex() +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 50 "scanner.lex" + +#line 803 "lex.yy.cc" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = & std::cin; + + if ( ! yyout ) + yyout = & std::cout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 222 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 702 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 51 "scanner.lex" +{ + /* Ignore comments but keep line count consistent. */ + for (const char *c = YYText(); *c; c++) if (*c == '\n') yyline++; +} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 56 "scanner.lex" +{ BEGIN DEFARGS; return ASM_T_DIR_DEF; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 57 "scanner.lex" +{ BEGIN PERMARGS; return ASM_T_DIR_PERM; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 58 "scanner.lex" +{ BEGIN WORDARGS; return ASM_T_DIR_BYTE; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 59 "scanner.lex" +{ BEGIN WORDARGS; return ASM_T_DIR_WORD; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 60 "scanner.lex" +{ BEGIN STRINGARGS; return ASM_T_DIR_STRING; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 61 "scanner.lex" +{ BEGIN ALIGNARGS; return ASM_T_DIR_ALIGN; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 62 "scanner.lex" +{ BEGIN EMPTYARGS; return ASM_T_DIR_ENTRY; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 63 "scanner.lex" +{ BEGIN EMPTYARGS; return ASM_T_DIR_GLOBAL; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 65 "scanner.lex" +{ yylval.u = read_number(YYText()); + return ASM_T_PRED; } + YY_BREAK +case 11: +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 67 "scanner.lex" +{ BEGIN EATCOLON; + yylval.s = std::string(YYText()); + return ASM_T_LABEL; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 70 "scanner.lex" +{ BEGIN INSTARGS; + yylval.s = std::string(YYText()); + return ASM_T_INST; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 73 "scanner.lex" +{} + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 74 "scanner.lex" +{yyline++;} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 76 "scanner.lex" +{ BEGIN INITIAL; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 79 "scanner.lex" +{ yylval.u = read_number(YYText()); + return ASM_T_PREG; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 81 "scanner.lex" +{ yylval.u = read_number(YYText()); + return ASM_T_REG; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 83 "scanner.lex" +{ yylval.u = read_number(YYText()); + return ASM_T_LIT; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 85 "scanner.lex" +{ yylval.s = std::string(YYText()); return ASM_T_SYM; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 86 "scanner.lex" +{ yylval.s = std::string(YYText()); return ASM_T_PEXP; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 88 "scanner.lex" +{} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 89 "scanner.lex" +{ BEGIN INITIAL; return ASM_T_DIR_END; } + YY_BREAK +case 23: +/* rule 23 can match eol */ +YY_RULE_SETUP +#line 90 "scanner.lex" +{ BEGIN INITIAL; yyline++; return ASM_T_DIR_END; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 93 "scanner.lex" +{ yylval.s = std::string(YYText()); + return ASM_T_DIR_ARG_SYM; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 95 "scanner.lex" +{ yylval.u = read_number(YYText()); + return ASM_T_DIR_ARG_NUM; } + YY_BREAK +case 26: +/* rule 26 can match eol */ +YY_RULE_SETUP +#line 97 "scanner.lex" +{ yyline++; BEGIN INITIAL; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 100 "scanner.lex" +{ return ASM_T_DIR_ARG_R; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 101 "scanner.lex" +{ return ASM_T_DIR_ARG_W; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 102 "scanner.lex" +{ return ASM_T_DIR_ARG_X; } + YY_BREAK +case 30: +/* rule 30 can match eol */ +YY_RULE_SETUP +#line 103 "scanner.lex" +{ BEGIN INITIAL; yyline++; return ASM_T_DIR_END; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 106 "scanner.lex" +{ yylval.s = std::string(YYText()); + return ASM_T_DIR_ARG_SYM; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 108 "scanner.lex" +{ yylval.u = read_number(YYText()); + return ASM_T_DIR_ARG_NUM; } + YY_BREAK +case 33: +/* rule 33 can match eol */ +YY_RULE_SETUP +#line 110 "scanner.lex" +{ BEGIN INITIAL; yyline++; return ASM_T_DIR_END; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 112 "scanner.lex" +{ yylval.s = std::string(YYText()); + return ASM_T_DIR_ARG_SYM; } + YY_BREAK +case 35: +/* rule 35 can match eol */ +YY_RULE_SETUP +#line 114 "scanner.lex" +{ BEGIN INITIAL; + yylval.s = std::string(YYText()); + yylval.s = yylval.s.substr(1, + yylval.s.length() - 2); + return ASM_T_DIR_ARG_STRING; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 120 "scanner.lex" +{ yylval.u = read_number(YYText()); + return ASM_T_DIR_ARG_NUM; } + YY_BREAK +case 37: +/* rule 37 can match eol */ +YY_RULE_SETUP +#line 122 "scanner.lex" +{ yyline++; BEGIN INITIAL; } + YY_BREAK +case 38: +/* rule 38 can match eol */ +YY_RULE_SETUP +#line 125 "scanner.lex" +{ yyline++; BEGIN INITIAL; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 127 "scanner.lex" +{ /*Ignore inter-token whitespace.*/ } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 128 "scanner.lex" +{ std::cout << "Unexpected character on line " << std::dec << yyline << '\n'; + exit(1); } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 130 "scanner.lex" +ECHO; + YY_BREAK +#line 1125 "lex.yy.cc" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(DEFARGS): +case YY_STATE_EOF(PERMARGS): +case YY_STATE_EOF(WORDARGS): +case YY_STATE_EOF(STRINGARGS): +case YY_STATE_EOF(ALIGNARGS): +case YY_STATE_EOF(EMPTYARGS): +case YY_STATE_EOF(INSTARGS): +case YY_STATE_EOF(EATCOLON): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* The contents of this function are C++ specific, so the () macro is not used. + */ +yyFlexLexer::yyFlexLexer( std::istream* arg_yyin, std::ostream* arg_yyout ) +{ + yyin = arg_yyin; + yyout = arg_yyout; + yy_c_buf_p = 0; + yy_init = 0; + yy_start = 0; + yy_flex_debug = 0; + yylineno = 1; // this will only get updated if %option yylineno + + yy_did_buffer_switch_on_eof = 0; + + yy_looking_for_trail_begin = 0; + yy_more_flag = 0; + yy_more_len = 0; + yy_more_offset = yy_prev_more_offset = 0; + + yy_start_stack_ptr = yy_start_stack_depth = 0; + yy_start_stack = NULL; + + yy_buffer_stack = 0; + yy_buffer_stack_top = 0; + yy_buffer_stack_max = 0; + + yy_state_buf = 0; + +} + +/* The contents of this function are C++ specific, so the () macro is not used. + */ +yyFlexLexer::~yyFlexLexer() +{ + delete [] yy_state_buf; + yyfree(yy_start_stack ); + yy_delete_buffer( YY_CURRENT_BUFFER ); + yyfree(yy_buffer_stack ); +} + +/* The contents of this function are C++ specific, so the () macro is not used. + */ +void yyFlexLexer::switch_streams( std::istream* new_in, std::ostream* new_out ) +{ + if ( new_in ) + { + yy_delete_buffer( YY_CURRENT_BUFFER ); + yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) ); + } + + if ( new_out ) + yyout = new_out; +} + +#ifdef YY_INTERACTIVE +int yyFlexLexer::LexerInput( char* buf, int /* max_size */ ) +#else +int yyFlexLexer::LexerInput( char* buf, int max_size ) +#endif +{ + if ( yyin->eof() || yyin->fail() ) + return 0; + +#ifdef YY_INTERACTIVE + yyin->get( buf[0] ); + + if ( yyin->eof() ) + return 0; + + if ( yyin->bad() ) + return -1; + + return 1; + +#else + (void) yyin->read( buf, max_size ); + + if ( yyin->bad() ) + return -1; + else + return yyin->gcount(); +#endif +} + +void yyFlexLexer::LexerOutput( const char* buf, int size ) +{ + (void) yyout->write( buf, size ); +} + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +int yyFlexLexer::yy_get_next_buffer() +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + yy_state_type yyFlexLexer::yy_get_previous_state() +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 222 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 222 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 221); + + return yy_is_jam ? 0 : yy_current_state; +} + + void yyFlexLexer::yyunput( int c, register char* yy_bp) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + + int yyFlexLexer::yyinput() +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyFlexLexer::yyrestart( std::istream* input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + + void yyFlexLexer::yy_load_buffer_state() +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( std::istream* file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +extern "C" int isatty (int ); + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, std::istream* file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yyFlexLexer::yypush_buffer_state (YY_BUFFER_STATE new_buffer) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yyFlexLexer::yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +void yyFlexLexer::yyensure_buffer_stack(void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + + void yyFlexLexer::yy_push_state( int new_state ) +{ + if ( (yy_start_stack_ptr) >= (yy_start_stack_depth) ) + { + yy_size_t new_size; + + (yy_start_stack_depth) += YY_START_STACK_INCR; + new_size = (yy_start_stack_depth) * sizeof( int ); + + if ( ! (yy_start_stack) ) + (yy_start_stack) = (int *) yyalloc(new_size ); + + else + (yy_start_stack) = (int *) yyrealloc((void *) (yy_start_stack),new_size ); + + if ( ! (yy_start_stack) ) + YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); + } + + (yy_start_stack)[(yy_start_stack_ptr)++] = YY_START; + + BEGIN(new_state); +} + + void yyFlexLexer::yy_pop_state() +{ + if ( --(yy_start_stack_ptr) < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN((yy_start_stack)[(yy_start_stack_ptr)]); +} + + int yyFlexLexer::yy_top_state() +{ + return (yy_start_stack)[(yy_start_stack_ptr) - 1]; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +void yyFlexLexer::LexerError( yyconst char msg[] ) +{ + std::cerr << msg << std::endl; + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 130 "scanner.lex" diff --git a/src/mem.cpp b/src/mem.cpp new file mode 100644 index 00000000..ec44282a --- /dev/null +++ b/src/mem.cpp @@ -0,0 +1,209 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "include/types.h" +#include "include/util.h" +#include "include/mem.h" +#include "include/core.h" + +using namespace std; +using namespace Harp; + +RamMemDevice::RamMemDevice(const char *filename, Size wordSize) : + wordSize(wordSize), contents() +{ + ifstream input(filename); + + if (!input) { + cout << "Error reading file \"" << filename << "\" into RomMemDevice.\n"; + exit(1); + } + + do { contents.push_back(input.get()); } while (input); +} + +RamMemDevice::RamMemDevice(Size size, Size wordSize) : + contents(size), wordSize(wordSize) {} + +void RomMemDevice::write(Addr, Word) { + cout << "Attempt to write to ROM.\n"; + exit(1); +} + +Word RamMemDevice::read(Addr addr) { + Word w = readWord(contents, addr, wordSize); + return w; +} + +void RamMemDevice::write(Addr addr, Word w) { + writeWord(contents, addr, wordSize, w); +} + +MemDevice &MemoryUnit::ADecoder::doLookup(Addr a, Size &bit) { + if (range == 0 || (a&((1ll<= range) { + ADecoder *p(((a>>bit)&1)?oneChild:zeroChild); + if (p) { bit--; return p->doLookup(a, bit); } + else {cout << "lookup failed.\n"; throw BadAddress();} + } else { + return *md; + } +} + +void MemoryUnit::ADecoder::map(Addr a, MemDevice &m, Size r, Size bit) +{ + if ((1llu << bit) <= r) { + md = &m; + range = m.size(); + } else { + ADecoder *&child(((a>>bit)&1)?oneChild:zeroChild); + if (!child) child = new ADecoder(); + child->map(a, m, r, bit-1); + } +} + +Byte *MemoryUnit::ADecoder::getPtr(Addr a, Size sz, Size wordSize) { + Size bit = wordSize - 1; + MemDevice &m(doLookup(a, bit)); + a &= (2<::iterator i; + if ((i = tlb.find(vAddr/pageSize)) != tlb.end()) { + TLBEntry &t = i->second; + if (t.flags & flagMask) return t; + else throw PageFault(vAddr, false); + } else { + throw PageFault(vAddr, true); + } +} + +Word MemoryUnit::read(Addr vAddr, bool sup) { + Word flagMask = sup?8:1; + TLBEntry t = tlbLookup(vAddr, flagMask); + Addr pAddr = t.pfn*pageSize + vAddr%pageSize; + return ad.read(pAddr, sup, 8*addrBytes); +} + +Word MemoryUnit::fetch(Addr vAddr, bool sup) { + Word flagMask = sup?32:4; + TLBEntry t = tlbLookup(vAddr, flagMask); + Addr pAddr = t.pfn*pageSize + vAddr%pageSize; + return ad.read(pAddr, sup, 8*addrBytes); +} + +void MemoryUnit::write(Addr vAddr, Word w, bool sup) { + Word flagMask = sup?16:2; + TLBEntry t = tlbLookup(vAddr, flagMask); + Addr pAddr = t.pfn*pageSize + vAddr%pageSize; + ad.write(pAddr, w, sup, 8*addrBytes); +} + +void MemoryUnit::tlbAdd(Addr virt, Addr phys, Word flags) { + tlb[virt/pageSize] = TLBEntry(phys/pageSize, flags); +} + +void MemoryUnit::tlbRm(Addr va) { + if (tlb.find(va/pageSize) != tlb.end()) tlb.erase(tlb.find(va/pageSize)); +} + +void *Harp::consoleInputThread(void* arg_vp) { + ConsoleMemDevice *arg = (ConsoleMemDevice *)arg_vp; + char c; + while (cin) { + c = cin.get(); + pthread_mutex_lock(&arg->cBufLock); + arg->cBuf.push(c); + pthread_mutex_unlock(&arg->cBufLock); + } + cout << "Console input ended. Exiting.\n"; + exit(4); +} + +ConsoleMemDevice::ConsoleMemDevice(Size wS, std::ostream &o, Core &core) : + wordSize(wS), output(o), core(core), cBuf() +{ + pthread_t *thread = new pthread_t; + pthread_create(thread, NULL, consoleInputThread, (void*)this); + pthread_mutex_init(&cBufLock, NULL); +} + +void ConsoleMemDevice::poll() { + pthread_mutex_lock(&cBufLock); + if (!cBuf.empty()) core.interrupt(8); + pthread_mutex_unlock(&cBufLock); +} + +Word DiskControllerMemDevice::read(Addr a) { + switch (a/8) { + case 0: return curDisk; + case 1: return curBlock; + case 2: return disks[curDisk].blocks * blockSize; + case 3: return physAddr; + case 4: return command; + case 5: return status; + default: + cout << "Attempt to read invalid disk controller register.\n"; + exit(1); + } +} + +void DiskControllerMemDevice::write(Addr a, Word w) { + switch (a/8) { + case 0: if (w <= disks.size()) { + curDisk = w; + status = OK; + } else { + status = INVALID_DISK; + } + break; + case 1: if (w < disks[curDisk].blocks) { + curBlock = w; + } else { + status = INVALID_BLOCK; + } + break; + case 2: nBlocks = w >= disks[curDisk].blocks?disks[curDisk].blocks - 1 : w; + status = OK; + break; + case 3: physAddr = w; + status = OK; + break; + case 4: if (w == 0) { + } else { + } + cout << "TODO: Implement disk read and write!\n"; + break; + } +} diff --git a/src/obj.cpp b/src/obj.cpp new file mode 100644 index 00000000..47775b64 --- /dev/null +++ b/src/obj.cpp @@ -0,0 +1,635 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#include "include/types.h" +#include "include/obj.h" +#include "include/util.h" +#include "include/asm-tokens.h" + +#include +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace Harp; +using namespace HarpTools; + +extern struct rval_t { std::string s; uint64_t u; } yylval; +extern unsigned yyline; + +static void asmReaderError(unsigned line, const string &message) { + cout << "Assembly reader error, line " << line << ": " << message << '\n'; + exit(1); +} + +static int skip_parens(const string &s, int i) { + int paren_level = 1; + do { + i++; + if (s[i] == '(') paren_level++; + if (s[i] == ')') paren_level--; + } while (paren_level > 0); + + return i; +} + +// Probably the worst recursive descent parser ever written, but it's an easy +// way to make our assembly language pretty. +static uint64_t readParenExpression(const string &s, const map &d, + int start=0, int end=-1) +{ + uint64_t (* const rPE)(const string&, const map&, int, int) + = readParenExpression; + + if (end==-1) end = s.length(); + + while (isspace(s[start])) start++; + while (isspace(s[end-1])) end--; + + for (int i = start; i < end; i++) { + if (s[i] == '(') { i = skip_parens(s, i); continue; } + + if (s[i] == '<') return rPE(s, d, start, i) << rPE(s, d, i+2, end); + if (s[i] == '>') return rPE(s, d, start, i) >> rPE(s, d, i+2, end); + } + + for (int i = start; i < end; i++) { + if (s[i] == '(') { i = skip_parens(s, i); continue; } + if (s[i] == '+') return rPE(s, d, start, i) + rPE(s, d, i+1, end); + if (s[i] == '-') return rPE(s, d, start, i) - rPE(s, d, i+1, end); + if (s[i] == '|') return rPE(s, d, start, i) | rPE(s, d, i+1, end); + if (s[i] == '^') return rPE(s, d, start, i) ^ rPE(s, d, i+1, end); + } + + for (int i = start; i < end; i++) { + if (s[i] == '(') { i = skip_parens(s, i); continue; } + if (s[i] == '*') return rPE(s, d, start, i) * rPE(s, d, i+1, end); + if (s[i] == '/') return rPE(s, d, start, i) / rPE(s, d, i+1, end); + if (s[i] == '%') return rPE(s, d, start, i) % rPE(s, d, i+1, end); + if (s[i] == '&') return rPE(s, d, start, i) & rPE(s, d, i+1, end); + } + + if (isdigit(s[start])) { + unsigned long long u; + sscanf(s.substr(start, end-start).c_str(), "%lli", &u); + return u; + } + + if (s[start] == '(') return rPE(s, d, start+1, end-1); + + map::const_iterator it = d.find(s.substr(start, end-start)); + if (it != d.end()) return it->second; + + cout << "TODO: Error message.\n"; + exit(1); +} + +Obj *AsmReader::read(std::istream &input) { + FlexLexer *f = new yyFlexLexer(&input); + Obj *o = new Obj(); + std::vector::reverse_iterator cur; + bool permR(true), permW(false), permX(false), entry(false), nextPred(false), + global(false); + + map defs; + + /* Pre-defined defs. */ + defs["__WORD"] = wordSize; + + map opMap; + + // Build opMap + for (size_t i = 0; Instruction::opStrings[i]; i++) + opMap[std::string(Instruction::opStrings[i])] = Instruction::Opcode(i); + + enum { + ST_INIT, ST_DEF1, ST_DEF2, ST_PERM, ST_WORD1, ST_WORD2, ST_STRING1, + ST_STRING2, ST_BYTE1, ST_BYTE2, ST_ALIGN, ST_INST1, ST_INST2 + } state(ST_INIT); + + enum { OS_NOCHUNK, OS_TEXTCHUNK, OS_DATACHUNK } outstate(OS_NOCHUNK); + TextChunk *tc; + DataChunk *dc; + Instruction *curInst; + string string_arg, next_chunk_name; + Size next_chunk_align(0); + uint64_t num_arg; + RegNum nextPredNum; + + AsmTokens t; + while ((t = (AsmTokens)f->yylex()) != 0) { + switch (t) { + case ASM_T_DIR_DEF: + if (state == ST_INIT) state = ST_DEF1; + else { asmReaderError(yyline, "Unexpected .def"); } + break; + case ASM_T_DIR_PERM: + if (state == ST_INIT) { + state = ST_PERM; + permR = permW = permX = false; + if (outstate != OS_NOCHUNK) { + outstate = OS_NOCHUNK; + entry = false; + global = false; + } + } else { asmReaderError(yyline, "Unexpected .perm"); } + break; + case ASM_T_DIR_BYTE: + if (state == ST_INIT) { + state = ST_BYTE1; + } else { asmReaderError(yyline, "Unexpected .byte"); } + break; + case ASM_T_DIR_WORD: + if (state == ST_INIT) { + state = ST_WORD1; + } else { asmReaderError(yyline, "Unexpected .word"); } + break; + case ASM_T_DIR_STRING: + if (state == ST_INIT) { + state = ST_STRING1; + } else { asmReaderError(yyline, "Unexpected .string"); } + break; + case ASM_T_DIR_ALIGN: + if (state == ST_INIT) { + state = ST_ALIGN; + } else { asmReaderError(yyline, "Unexpected .align"); } + break; + case ASM_T_DIR_ENTRY: + outstate = OS_NOCHUNK; + entry = true; + break; + case ASM_T_DIR_GLOBAL: + outstate = OS_NOCHUNK; + global = true; + break; + case ASM_T_DIR_ARG_NUM: + switch (state) { + case ST_DEF2: defs[string_arg] = yylval.u; state = ST_INIT; break; + case ST_WORD1: dc->size += (yylval.u)*wordSize; + state = ST_INIT; + break; + case ST_WORD2: if (outstate == OS_DATACHUNK) { + dc->size += wordSize; + dc->contents.resize(dc->size); + wordToBytes(&*(dc->contents.end()-wordSize), + yylval.u, wordSize); + } else { + asmReaderError(yyline, "Word not in data chunk" + "(internal error)"); + } + state = ST_INIT; + break; + case ST_BYTE1: dc->size += yylval.u; + state = ST_INIT; + break; + case ST_BYTE2: if (outstate == OS_DATACHUNK) { + dc->size++; + dc->contents.resize(dc->size); + *(dc->contents.end() - 1) = yylval.u; + } else { + asmReaderError(yyline, "Byte not in data chunk" + "(internal error)"); + } + state = ST_INIT; + break; + case ST_ALIGN: next_chunk_align = yylval.u; + if (outstate != OS_NOCHUNK) { + outstate = OS_NOCHUNK; + entry = false; + global = false; + } + state = ST_INIT; + break; + default: asmReaderError(yyline, "Unexpected literal argument"); + } + break; + case ASM_T_DIR_ARG_STRING: + if (state == ST_STRING2 || + (state == ST_STRING1 && outstate == OS_DATACHUNK)) + { + const char *s = yylval.s.c_str(); + do { + if (*s == '\\') { + switch (*(++s)) { + case 'n': dc->contents.push_back('\n'); break; + case '"': dc->contents.push_back(*s); break; + default: dc->contents.push_back(*s); break; + } + } else { + dc->contents.push_back(*s); + } + dc->size++; + } while(*(s++)); + } else { + asmReaderError(yyline, "Unexpected string literal."); + } + state = ST_INIT; + break; + case ASM_T_DIR_ARG_SYM: + switch (state) { + case ST_DEF1: string_arg = yylval.s; state = ST_DEF2; break; + case ST_WORD1: { + state = ST_WORD2; + outstate = OS_DATACHUNK; + dc = new DataChunk(yylval.s, next_chunk_align? + next_chunk_align:wordSize, + flagsToWord(permR, permW, permX)); + next_chunk_align = 0; + o->chunks.push_back(dc); + if (entry) o->entry = o->chunks.size() - 1; + if (global) dc->setGlobal(); + } break; + case ST_BYTE1: { + state = ST_BYTE2; + outstate = OS_DATACHUNK; + dc = new DataChunk(yylval.s, next_chunk_align, + flagsToWord(permR, permW, permX)); + next_chunk_align = 0; + o->chunks.push_back(dc); + if (entry) o->entry = o->chunks.size() - 1; + if (global) dc->setGlobal(); + } break; + case ST_STRING1: { + state = ST_STRING2; + outstate = OS_DATACHUNK; + dc = new DataChunk(yylval.s, next_chunk_align, + flagsToWord(permR, permW, permX)); + next_chunk_align = 0; + o->chunks.push_back(dc); + if (entry) o->entry = o->chunks.size() - 1; + if (global) dc->setGlobal(); + } break; + default: asmReaderError(yyline, ""); + }; + break; + case ASM_T_DIR_ARG_R: + permR = true; + break; + case ASM_T_DIR_ARG_W: + permW = true; + break; + case ASM_T_DIR_ARG_X: + permX = true; + break; + case ASM_T_DIR_END: + if (state == ST_INST1 || state == ST_INST2) { + if (outstate == OS_TEXTCHUNK) { + tc->instructions.push_back(curInst); + } else { + asmReaderError(yyline, "Inst not in text chunk(internal error)"); + } + } + state = ST_INIT; + break; + case ASM_T_LABEL: + if (outstate != OS_NOCHUNK) { + entry = false; + global = false; + outstate = OS_NOCHUNK; + } + next_chunk_name = yylval.s; + break; + case ASM_T_PRED: + nextPred = true; + nextPredNum = yylval.u; + break; + case ASM_T_INST: + if (state == ST_INIT) { + Instruction::Opcode opc = opMap[yylval.s]; + if (outstate != OS_TEXTCHUNK) { + tc = new TextChunk(next_chunk_name, next_chunk_align, + flagsToWord(permR, permW, permX)); + next_chunk_align = 0; + o->chunks.push_back(tc); + if (entry) o->entry = o->chunks.size() - 1; + if (global) tc->setGlobal(); + outstate = OS_TEXTCHUNK; + } + curInst = new Instruction(); + curInst->setOpcode(opc); + if (nextPred) { + nextPred = false; + curInst->setPred(nextPredNum); + } + state = Instruction::allSrcArgs[opc]?ST_INST2:ST_INST1; + } else { asmReaderError(yyline, "Unexpected token"); } + break; + case ASM_T_PREG: + switch (state) { + case ST_INST1: curInst->setDestPReg(yylval.u); + state = ST_INST2; + break; + case ST_INST2: curInst->setSrcPReg(yylval.u); + break; + default: asmReaderError(yyline, "Unexpected predicate register"); + } + break; + case ASM_T_REG: + switch (state) { + case ST_INST1: curInst->setDestReg(yylval.u); + state = ST_INST2; + break; + case ST_INST2: curInst->setSrcReg(yylval.u); + break; + default: asmReaderError(yyline, "Unexpected register"); + } + break; + case ASM_T_PEXP: + // Decode the paren expression. + yylval.u = readParenExpression(yylval.s, defs); + case ASM_T_LIT: + switch (state) { + case ST_INST1: asmReaderError(yyline, "Unexpected literal"); + case ST_INST2: curInst->setSrcImm(yylval.u); + break; + default: asmReaderError(yyline, "Unexpected literal"); + } + break; + case ASM_T_SYM: + switch (state) { + case ST_INST1: asmReaderError(yyline, "Unexpected symbol"); + case ST_INST2: if (defs.find(yylval.s) != defs.end()) { + curInst->setSrcImm(defs[yylval.s]); + } else { + Ref *r = new + SimpleRef(yylval.s, *curInst->setSrcImm(), + curInst->hasRelImm()); + tc->refs.push_back(r); + curInst->setImmRef(*r); + } + break; + default: asmReaderError(yyline, "Unexpected symbol"); + } + break; + default: asmReaderError(yyline, "Invalid state(internal error)"); + }; + } + + return o; +} + +void AsmWriter::write(std::ostream &output, const Obj &obj) { + unsigned anonWordNum(0); + + Word prevFlags(0); + + for (size_t j = 0; j < obj.chunks.size(); j++) { + Chunk * const &c = obj.chunks[j]; + + /* Write out the flags. */ + if (c->flags != prevFlags) { + bool r, w, x; + wordToFlags(r, w, x, c->flags); + output << ".perm "; + if (r) output << 'r'; + if (w) output << 'w'; + if (x) output << 'x'; + output << '\n'; + prevFlags = c->flags; + } + + /* Write align if set. */ + if (c->alignment) output << ".align 0x" << hex << c->alignment << '\n'; + + TextChunk * const tc = dynamic_cast(c); + DataChunk * const dc = dynamic_cast(c); + + if (tc) { + if (j == obj.entry) output << "\n.entry\n"; + if (c->isGlobal()) output << "\n.global\n"; + if (tc->name != "") output << tc->name << ':'; + + for (size_t i = 0; i < tc->instructions.size(); i++) { + output << "\t" << *(tc->instructions[i]) << '\n'; + } + } else if (dc) { + Size i; + for (i = 0; i < dc->contents.size();) { + Size tmpWordSize = (dc->contents.size() - i < wordSize) ? + dc->contents.size() - i : wordSize; + + i += tmpWordSize; + Word w = 0; + for (size_t j = 0; j < tmpWordSize; j++) { + w <<= 8; + w |= dc->contents[i - j - 1]; + } + + if (i == tmpWordSize && c->name != "") { + output << ".word " << c->name << " 0x" << hex << w << '\n'; + } else { + output << ".word __anonWord" << anonWordNum++ << " 0x" + << hex << w << '\n'; + } + } + + if (i % wordSize) i += (wordSize - (i%wordSize)); + + if (dc->size > i) { + Size fillSize = (dc->size - i)/wordSize; + output << ".word 0x" << hex << fillSize << '\n'; + } + } else { + cout << "Unrecognized chunk type in AsmWriter.\n"; + exit(1); + } + } +} + +enum HOFFlag { HOF_GLOBAL = 1 }; + +Word getHofFlags(Chunk &c) { + Word w = 0; + if (c.isGlobal()) w |= HOF_GLOBAL; + return w; +} + +static void outputWord(std::ostream &out, Word w, + vector &tmp, Size wordSize) +{ + Size n(0); + writeWord(tmp, n, wordSize, w); + out.write((char*)&tmp[0], wordSize); +} + +void HOFWriter::write(std::ostream &output, const Obj &obj) { + string archString(arch); + Size wordSize(arch.getWordSize()), n, offsetVectorPos; + + vector tmp; + vector offsets(obj.chunks.size()); + + /* Magic number, arch string, and padding. */ + output.write("HARP", 4); + output.write(archString.c_str(), archString.length()+1); + Size padBytes = (wordSize-(4+archString.length()+1)%wordSize)%wordSize; + for (Size i = 0; i < padBytes; i++) output.put(0); + + /* Write out the entry chunk index. */ + outputWord(output, obj.entry, tmp, wordSize); + + /* Write out the number of chunks. */ + outputWord(output, obj.chunks.size(), tmp, wordSize); + + /* Skip the chunk size offset vector. */ + offsetVectorPos = output.tellp(); + output.seekp(output.tellp() + streampos(wordSize * obj.chunks.size())); + + /* Write out the chunks, keeping track of their offsets. */ + for (Size i = 0; i < obj.chunks.size(); i++) { + offsets[i] = output.tellp(); + + /* Chunk name */ + DataChunk *dc = dynamic_cast(obj.chunks[i]); + if (!dc) { cout << "HOFWriter::write(): invalid chunk type.\n"; exit(1); } + output.write(dc->name.c_str(), dc->name.length() + 1); + + /* Padding */ + padBytes = (wordSize - (dc->name.length()+1)%wordSize)%wordSize; + for (Size i = 0; i < padBytes; i++) output.put(0); + + /* Chunk alignment, flags, address, size (in RAM and disk) */ + outputWord(output, dc->alignment, tmp, wordSize); + outputWord(output, dc->flags, tmp, wordSize); + outputWord(output, getHofFlags(*dc), tmp, wordSize); + outputWord(output, dc->bound?dc->address:0, tmp, wordSize); + outputWord(output, dc->size, tmp, wordSize); + outputWord(output, dc->contents.size(), tmp, wordSize); + + /* References */ + outputWord(output, dc->refs.size(), tmp, wordSize); + for (Size j = 0; j < dc->refs.size(); j++) { + OffsetRef *r = dynamic_cast(dc->refs[j]); + if (!r) { cout << "HOFWriter::write(): invalid ref type.\n"; exit(1); } + /* Reference name */ + output.write(r->name.c_str(), r->name.length() + 1); + /* Padding */ + padBytes = (wordSize - (r->name.length() + 1)%wordSize)%wordSize; + for (Size i = 0; i < padBytes; i++) output.put(0); + /* Compute flags word. */ + Word rFlags(0); + if (r->relative) rFlags |= 1; + /* Output flags word. */ + outputWord(output, rFlags, tmp, wordSize); + /* Offset from which relative branches are computed. */ + outputWord(output, r->ibase, tmp, wordSize); + /* Reference offset in block. */ + outputWord(output, r->getOffset(), tmp, wordSize); + /* Reference size in bits. */ + outputWord(output, r->getBits(), tmp, wordSize); + } + + /* Chunk data. */ + output.write((char*)&(dc->contents[0]), dc->contents.size()); + + /* Chunk padding. */ + padBytes = (wordSize - dc->contents.size()%wordSize)%wordSize; + for (Size i = 0; i < padBytes; i++) output.put(0); + } + + /* Write out the chunk offset vector. */ + output.seekp(offsetVectorPos); + for (Size i = 0; i < obj.chunks.size(); i++) { + outputWord(output, offsets[i], tmp, wordSize); + } +} + +static Word inputWord(std::istream &input, Size wordSize, vector &tmp) { + Size n(0), pos(input.tellg()); + if (tmp.size() < wordSize) tmp.resize(wordSize); + + /* Seek to the next word-aligned place. */ + if (input.tellg()%wordSize) { + input.seekg(input.tellg() + + streampos((wordSize - input.tellg()%wordSize)%wordSize)); + } + + input.read((char*)&tmp[0], wordSize); + + return readWord(tmp, n, wordSize); +} + +static string inputString(std::istream &input) { + string s; + char c; + + while (input && (c = input.get()) != '\0') s += c; + + return s; +} + +Obj *HOFReader::read(std::istream &input) { + Size wordSize(arch.getWordSize()); + Obj *o = new Obj(); + + vector tmp(4); + + input.read((char*)&tmp[0], 4); + if (tmp[0] != 'H' || tmp[1] != 'A' || tmp[2] != 'R' || tmp[3] != 'P') { + cout << "Bad magic number in HOFReader::read().\n"; + exit(1); + } + + string archString(inputString(input)); + ArchDef fileArch(archString); + if (fileArch != arch) { + cout << "File arch does not match reader arch in HOFReader::read().\n"; + exit(1); + } + + o->entry = inputWord(input, wordSize, tmp); + + Size nChunks(inputWord(input, wordSize, tmp)); + + vector chunkOffsets(nChunks); + + /* Read in the chunk offsets. */ + for (Size i = 0; i < nChunks; i++) { + chunkOffsets[i] = inputWord(input, wordSize, tmp); + } + + /* Read in the chunks. */ + o->chunks.resize(nChunks); + for (Size i = 0; i < nChunks; i++) { + input.seekg(chunkOffsets[i]); + string name(inputString(input)); + Word alignment(inputWord(input, wordSize, tmp)), + flags(inputWord(input, wordSize, tmp)), + hofFlags(inputWord(input, wordSize, tmp)), + address(inputWord(input, wordSize, tmp)), + size(inputWord(input, wordSize, tmp)), + dSize(inputWord(input, wordSize, tmp)), + nRefs(inputWord(input, wordSize, tmp)); + DataChunk *dc = new DataChunk(name, alignment, flags); + if (hofFlags & HOF_GLOBAL) dc->setGlobal(); + dc->address = address; + dc->bound = address?true:false; + dc->contents.resize(dSize); + + /* Get the refs. */ + for (Size j = 0; j < nRefs; j++) { + string rName(inputString(input)); + Word rFlags(inputWord(input, wordSize, tmp)), + ibase(inputWord(input, wordSize, tmp)), + offset(inputWord(input, wordSize, tmp)), + bits(inputWord(input, wordSize, tmp)); + OffsetRef *r = + new OffsetRef(rName, dc->contents, offset, bits, wordSize, rFlags&1, + ibase); + dc->refs.push_back(r); + } + + /* Get the contents. */ + input.read((char*)&dc->contents[0], dSize); + dc->size = size; + + o->chunks[i] = dc; + } + + return o; +} diff --git a/src/scanner.lex b/src/scanner.lex new file mode 100644 index 00000000..5792978a --- /dev/null +++ b/src/scanner.lex @@ -0,0 +1,129 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +%option c++ +%option noyywrap + +%{ +#include +#include +#include +#include +#include +#include +#include + +#include "include/asm-tokens.h" + +static int64_t read_number(const char *s) { + long long u; + while (!isdigit(*s) && *s != '-' && *s != '+') s++; + + sscanf(s, "%lli", &u); + return u; +} + +static std::string label_name(const char *cs) { + return std::string(cs, strlen(cs)-1); +} + +struct rval_t { std::string s; uint64_t u; } yylval; +unsigned yyline(1); + +using namespace HarpTools; + +%} + +%start DEFARGS PERMARGS WORDARGS STRINGARGS ALIGNARGS EMPTYARGS INSTARGS +%start EATCOLON + +sym [A-Za-z_][A-Za-z0-9_]* +decnum [1-9][0-9]* +hexnum 0x[0-9a-f]+ +octnum 0[0-9]* +num [+-]?({decnum}|{hexnum}|{octnum}) +space [ \t]* +peoperator ("+"|"-"|"*"|"/"|"%"|"&"|"|"|"^"|"<<"|">>") +parenexp "("({num}|{sym}|{peoperator}|{space}|"("|")")+")" +endl \r?\n + +%% +\/\*([^*]|\*[^/]|{endl})*\*\/ { + /* Ignore comments but keep line count consistent. */ + for (const char *c = YYText(); *c; c++) if (*c == '\n') yyline++; +} + +\.def { BEGIN DEFARGS; return ASM_T_DIR_DEF; } +\.perm { BEGIN PERMARGS; return ASM_T_DIR_PERM; } +\.byte { BEGIN WORDARGS; return ASM_T_DIR_BYTE; } +\.word { BEGIN WORDARGS; return ASM_T_DIR_WORD; } +\.string { BEGIN STRINGARGS; return ASM_T_DIR_STRING; } +\.align { BEGIN ALIGNARGS; return ASM_T_DIR_ALIGN; } +\.entry { BEGIN EMPTYARGS; return ASM_T_DIR_ENTRY; } +\.global { BEGIN EMPTYARGS; return ASM_T_DIR_GLOBAL; } + +@p{num}{space}\? { yylval.u = read_number(YYText()); + return ASM_T_PRED; } +{sym}/: { BEGIN EATCOLON; + yylval.s = std::string(YYText()); + return ASM_T_LABEL; } +{sym} { BEGIN INSTARGS; + yylval.s = std::string(YYText()); + return ASM_T_INST; } +; {} +{endl} {yyline++;} + +: { BEGIN INITIAL; } + + +@p{num}{space}[,;]? { yylval.u = read_number(YYText()); + return ASM_T_PREG; } +%r{num}{space}[,;]? { yylval.u = read_number(YYText()); + return ASM_T_REG; } +#{num}{space}[,;]? { yylval.u = read_number(YYText()); + return ASM_T_LIT; } +{sym} { yylval.s = std::string(YYText()); return ASM_T_SYM; } +{parenexp} { yylval.s = std::string(YYText()); return ASM_T_PEXP; } + +{space} {} +; { BEGIN INITIAL; return ASM_T_DIR_END; } +{endl} { BEGIN INITIAL; yyline++; return ASM_T_DIR_END; } + + +{sym} { yylval.s = std::string(YYText()); + return ASM_T_DIR_ARG_SYM; } +{num} { yylval.u = read_number(YYText()); + return ASM_T_DIR_ARG_NUM; } +{endl} { yyline++; BEGIN INITIAL; } + + +r { return ASM_T_DIR_ARG_R; } +w { return ASM_T_DIR_ARG_W; } +x { return ASM_T_DIR_ARG_X; } +{endl} { BEGIN INITIAL; yyline++; return ASM_T_DIR_END; } + + +{sym} { yylval.s = std::string(YYText()); + return ASM_T_DIR_ARG_SYM; } +{num} { yylval.u = read_number(YYText()); + return ASM_T_DIR_ARG_NUM; } +{endl} { BEGIN INITIAL; yyline++; return ASM_T_DIR_END; } + +{sym} { yylval.s = std::string(YYText()); + return ASM_T_DIR_ARG_SYM; } +\"([^\"]|\\\")*\" { BEGIN INITIAL; + yylval.s = std::string(YYText()); + yylval.s = yylval.s.substr(1, + yylval.s.length() - 2); + return ASM_T_DIR_ARG_STRING; } + +{num} { yylval.u = read_number(YYText()); + return ASM_T_DIR_ARG_NUM; } +{endl} { yyline++; BEGIN INITIAL; } + + +{endl} { yyline++; BEGIN INITIAL; } + +{space} { /*Ignore inter-token whitespace.*/ } +. { std::cout << "Unexpected character on line " << std::dec << yyline << '\n'; + exit(1); } diff --git a/src/test/2thread.s b/src/test/2thread.s new file mode 100644 index 00000000..8eea77f5 --- /dev/null +++ b/src/test/2thread.s @@ -0,0 +1,51 @@ +/* 2-SIMD-thread test program! */ + +.perm x +.entry +.global +entry: ldi %r0, #0; + + ldi %r2, #1; + ldi %r1, Array2; + clone %r2; + ldi %r1, Array1; + ldi %r5, #2; + jalis %r5, %r5, sumArr; + ldi %r7, Array1; + ld %r7, %r7, #0; + jali %r5, printdec; + ldi %r7, Array2;; + ld %r7, %r7, #0; + jali %r5, printdec + trap; + +/* Sum multiple arrays at once through the magic of SIMD! */ +sumArr: ldi %r3, #0; + ldi %r4, #8; +loop: ld %r2, %r1, #0; + add %r3, %r3, %r2; + addi %r1, %r1, #8; + subi %r4, %r4, #1; + rtop @p0, %r4; + @p0 ? jmpi loop; + st %r3, %r1, #-64; + jmprt %r5; + +.perm rw +.word Array1 -1 +.word Array1_01 -2 +.word Array1_02 -3 +.word Array1_03 -4 +.word Array1_04 -5 +.word Array1_05 -6 +.word Array1_06 -7 +.word Array1_07 -8 + +.word Array2 1 +.word Array2_00 2 +.word Array2_01 3 +.word Array2_02 4 +.word Array2_03 5 +.word Array2_04 6 +.word Array2_05 7 +.word Array2_06 8 diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 00000000..4bad025d --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,32 @@ +HARPLD = ../harptool -L +HARPAS = ../harptool -A +4WARCH = 2b16/1/8 + +all: sieve.bin 2thread.bin sieve.4w.bin 2thread.4w.bin + +2thread.bin : lib.HOF 2thread.HOF boot.HOF + $(HARPLD) -o 2thread.bin boot.HOF 2thread.HOF lib.HOF + +2thread.4w.bin : lib.4w.HOF 2thread.4w.HOF boot.4w.HOF + $(HARPLD) --arch $(4WARCH) -o 2thread.4w.bin boot.4w.HOF 2thread.4w.HOF 2thread.4w.HOF lib.4w.HOF + +sieve.bin : lib.HOF sieve.HOF boot.HOF + $(HARPLD) -o sieve.bin boot.HOF sieve.HOF lib.HOF + +sieve.4w.bin : lib.4w.HOF sieve.4w.HOF boot.4w.HOF + $(HARPLD) --arch $(4WARCH) -o sieve.4w.bin boot.4w.HOF sieve.4w.HOF lib.4w.HOF + +%.4w.bin : %.4w.HOF + $(HARPLD) --arch $(4WARCH) -o $@ $< + +%.bin : %.HOF + $(HARPLD) -o $@ $< + +%.4w.HOF : %.s + $(HARPAS) --arch $(4WARCH) -o $@ $< + +%.HOF : %.s + $(HARPAS) -o $@ $< + +clean: + rm -f *.HOF *.bin *~ diff --git a/src/test/boot.4w.s b/src/test/boot.4w.s new file mode 100644 index 00000000..93fc523d --- /dev/null +++ b/src/test/boot.4w.s @@ -0,0 +1,41 @@ +.perm x + +.entry +boot: ldi %r5 kernEnt; + skep %r5 ; + ldi %r0 #0x1; + ldi %r1 #0x18; + ldi %r2 #0x4; + muli %r2 %r2 #0x8; + subi %r2 %r2 #0x1; + shl %r0 %r0 %r2 ; + tlbadd %r0 %r0 %r1 ; + ei ; + ldi %r5 entry; + jmpru %r5 ; +kernEnt: subi %r0 %r0 #0x8; + rtop @p0 %r0 ; + @p0 ? reti ; + ldi %r8 #0x1; + ldi %r1 #0x4; + muli %r1 %r1 #0x8; + subi %r1 %r1 #0x1; + shl %r8 %r8 %r1 ; + ld %r0 %r8 #0x0; + subi %r1 %r0 #0x71; + rtop @p0 %r1 ; + notp @p0 @p0 ; + @p0 ? halt ; + st %r0 %r8 #0x0; + ldi %r0 #0xa; + st %r0 %r8 #0x0; + reti ; +entry: ldi %r7 hello; + jali %r5 puts; + jmpi entry; +.perm rw +.word hello 0x6c6c6548 +.word __anonWord0 0x41202c6f +.word __anonWord1 0x6e616c74 +.word __anonWord2 0xa216174 +.word __anonWord3 0x0 diff --git a/src/test/boot.s b/src/test/boot.s new file mode 100644 index 00000000..cf9c2c3e --- /dev/null +++ b/src/test/boot.s @@ -0,0 +1,52 @@ +/* Bootstrap program for HARP. */ + +.perm x +.entry + +boot: ldi %r5, kernEnt; + skep %r5; + +/* ldi %r0, #1; + ldi %r1, #033; + ldi %r2, __WORD; + muli %r2, %r2, #8; + subi %r2, %r2, #1; + shl %r0, %r0, %r2; + tlbadd %r0, %r0, %r1; */ + + ei; + + ldi %r5, entry; + jmpru %r5; + +.perm x +/* The Kernel Entry Point / Interrupt service routine. */ +kernEnt: subi %r0, %r0, #1; + rtop @p0, %r0; + @p0 ? jmpi kernEnt1; /* If it's not page not found, try again. */ + + ldi %r0, #077; /* Just map virt to phys, any address. */ + tlbadd %r1, %r1, %r0; + reti; + +kernEnt1: subi %r0, %r0, #7; /* If it's not console input, halt.*/ + rtop @p0, %r0; + @p0 ? halt; + + ldi %r8, #1; + ldi %r1, __WORD; + muli %r1, %r1, #8; + subi %r1, %r1, #1; + shl %r8, %r8, %r1; + + ld %r0, %r8, #0; + subi %r1, %r0, #0x71 + rtop @p0, %r1 + notp @p0, @p0 + @p0 ? halt; /* If it's 'q', halt. */ + st %r0, %r8, #0; + ldi %r0, #0xa; + st %r0, %r8, #0; + reti; + + diff --git a/src/test/lib.s b/src/test/lib.s new file mode 100644 index 00000000..9878ba30 --- /dev/null +++ b/src/test/lib.s @@ -0,0 +1,50 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +******************************************************************************** + + Sample HARP assmebly programs. These should work on anything from a 4x up. + +*******************************************************************************/ +/* Library: print decimals and strings! */ +.perm x +.global +printdec: ldi %r8, #1; + shli %r8, %r8, (__WORD*8 - 1); + and %r6, %r8, %r7; + rtop @p0, %r6; + @p0 ? ldi %r6, #0x2d; + @p0 ? st %r6, %r8, #0; + @p0 ? neg %r7, %r7; +printdec_l1: modi %r6, %r7, #10; + divi %r7, %r7, #10; + addi %r6, %r6, #0x30; + st %r6, %r9, digstack; + addi %r9, %r9, __WORD; + rtop @p0, %r7; + @p0 ? jmpi printdec_l1; +printdec_l2: subi %r9, %r9, __WORD; + ld %r6, %r9, digstack; + st %r6, %r8, #0; + rtop @p0, %r9; + @p0 ? jmpi printdec_l2; + ldi %r6, #0x0a; + st %r6, %r8, #0; + jmpr %r5 + +.global +puts: ldi %r8, #1; + shli %r8, %r8, (__WORD*8 - 1); + +puts_l: ld %r6, %r7, #0; + andi %r6, %r6, #0xff; + rtop @p0, %r6; + notp @p0, @p0; + @p0 ? jmpi puts_end; + st %r6, %r8, #0; + addi %r7, %r7, #1; + jmpi puts_l; +puts_end: jmpr %r5 + +.perm rw +.word digstack 0 +.word 9 diff --git a/src/test/sieve.s b/src/test/sieve.s new file mode 100644 index 00000000..f90cd3be --- /dev/null +++ b/src/test/sieve.s @@ -0,0 +1,81 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +******************************************************************************** + + Sample HARP assmebly program. + +*******************************************************************************/ +/* sieve of erastophanes: Find some primes. */ +.def SIZE 0x2000 /* TODO: How should I write constants? */ + +.align 4096 +.perm x +.entry +.global +entry: ldi %r7, hello + jali %r5, puts + ldi %r0, #2; /* i = 2 */ +loop1: muli %r1, %r0, __WORD; + st %r0, %r1, array; + addi %r0, %r0, #1; + subi %r1, %r0, SIZE; + rtop @p0, %r1; + @p0 ? jmpi loop1; + + ldi %r0, #1; + +loop2: addi %r0, %r0, #1; + muli %r1, %r0, __WORD; + ld %r1, %r1, array; + rtop @p0, %r1; + notp @p0, @p0; + @p0 ? jmpi loop2; + + mul %r2, %r1, %r1; + subi %r3, %r2, SIZE; + neg %r3, %r3 + isneg @p0, %r3; + @p0 ? jmpi end; + + ldi %r3, #0; +loop3: muli %r4, %r2, __WORD; + st %r3, %r4, array; + add %r2, %r2, %r1; + ldi %r4, SIZE; + sub %r4, %r2, %r4; + isneg @p0, %r4; + notp @p0, @p0; + @p0 ? jmpi loop2; + jmpi loop3; + +end: ldi %r0, __WORD; /* i = 2 */ + shli %r0, %r0, #1; + ldi %r11, #0; +loop4: ld %r1, %r0, array; + rtop @p0, %r1; + @p0 ? addi %r7, %r1, #0; + @p0 ? jali %r5, printdec; + rtop @p0, %r1; + @p0 ? addi %r11, %r11, #1; + addi %r0, %r0, __WORD; + ldi %r5, __WORD; + muli %r5, %r5, SIZE; + sub %r1, %r0, %r5; + rtop @p0, %r1; + @p0 ? jmpi loop4; + + addi %r7, %r11, #0; + jali %r5, printdec; + trap; /* All traps currently cause a halt. */ + +.perm rw /* TODO: How should I write section permissions? */ +/* TODO: String literals! */ +.string hello "\"Harp!\" is how a harp seal says hello!\n" + +.global +.word array 0 /* Basically, 0 and 1 are pre-cleared. */ +.word _0 0 /* I would love to not have to give this a name. */ +.word 0x1ffe /* Should arithmetic be possible? Technically SIZE-2, but that + would be hard. Should making symbols happen here be possible + in general? Currently if it's not a name it must be a + literal. */ diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 00000000..8cf0df97 --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,70 @@ +/******************************************************************************* + HARPtools by Chad D. Kersey, Summer 2011 +*******************************************************************************/ +#include + +#include "include/types.h" +#include "include/util.h" + +using namespace Harp; +using namespace std; + +void Harp::wordToBytes(Byte *b, Word_u w, Size wordSize) { + while (wordSize--) { + *(b++) = w & 0xff; + w >>= 8; + } +} + +Word_u Harp::bytesToWord(const Byte *b, Size wordSize) { + Word_u w = 0; + b += wordSize-1; + while (wordSize--) { + w <<= 8; + w |= *(b--); + } + return w; +} + +Word_u Harp::flagsToWord(bool r, bool w, bool x) { + Word_u word = 0; + if (r) word |= RD_USR; + if (w) word |= WR_USR; + if (x) word |= EX_USR; + return word; +} + +void Harp::wordToFlags(bool &r, bool &w, bool &x, Word_u f) { + r = f & RD_USR; + w = f & WR_USR; + x = f & EX_USR; +} + +Byte Harp::readByte(const vector &b, Size &n) { + if (b.size() <= n) throw OutOfBytes(); + return b[n++]; +} + +Word_u Harp::readWord(const vector &b, Size &n, Size wordSize) { + if (b.size() - n < wordSize) throw OutOfBytes(); + Word_u w(0); + n += wordSize; + for (Size i = 0; i < wordSize; i++) { + w <<= 8; + w |= b[n - i - 1]; + } + return w; +} + +void Harp::writeByte(vector &p, Size &n, Byte b) { + if (p.size() <= n) p.resize(n+1); + p[n++] = b; +} + +void Harp::writeWord(vector &p, Size &n, Size wordSize, Word w) { + if (p.size() < (n+wordSize)) p.resize(n+wordSize); + while (wordSize--) { + p[n++] = w & 0xff; + w >>= 8; + } +}