mirror of
https://github.com/vortexgpgpu/vortex.git
synced 2025-04-24 05:47:35 -04:00
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
This commit is contained in:
commit
25377e4c03
29 changed files with 5463 additions and 0 deletions
22
src/Makefile
Normal file
22
src/Makefile
Normal file
|
@ -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.*
|
17
src/WISHLIST
Normal file
17
src/WISHLIST
Normal file
|
@ -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.
|
52
src/args.cpp
Normal file
52
src/args.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#include "include/args.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using namespace HarpTools;
|
||||
using std::string;
|
||||
|
||||
std::string CommandLineArg::helpString;
|
||||
std::map<string, CommandLineArg *> CommandLineArg::longArgs;
|
||||
std::map<string, CommandLineArg *> 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<string, CommandLineArg *>::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;
|
||||
}
|
95
src/core.cpp
Normal file
95
src/core.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#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<Word>(a.getNRegs())),
|
||||
pred(a.getNPRegs(), vector<bool>(a.getNPRegs())),
|
||||
shadowReg(), shadowPReg(), interruptEntry(0)
|
||||
{ }
|
||||
|
||||
void Core::step() {
|
||||
Size fetchPos(0), decPos, wordSize(a.getWordSize());
|
||||
vector<Byte> 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;
|
||||
}
|
468
src/enc.cpp
Normal file
468
src/enc.cpp
Normal file
|
@ -0,0 +1,468 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
|
||||
#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<Instruction*>::const_iterator vec_it;
|
||||
const vector<Instruction*> &s(src.instructions);
|
||||
vector<Byte> &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<Instruction*>::const_iterator vec_it;
|
||||
const vector<Byte> &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<Ref*> &refVec) {
|
||||
haveRefs = true;
|
||||
|
||||
typedef std::vector<Ref*>::const_iterator vec_ci;
|
||||
|
||||
for (vec_ci i = refVec.begin(); i != refVec.end(); i++) {
|
||||
OffsetRef *oref = dynamic_cast<OffsetRef*>(*i);
|
||||
if (oref) {
|
||||
refMap[oref->getOffset()] = *i;
|
||||
} else {
|
||||
decodeError("Unknown Ref type in Decoder::setRefs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Instruction *ByteDecoder::decode(const vector<Byte> &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<OffsetRef*>(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<Byte> &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<<bits)-1;
|
||||
}
|
||||
|
||||
static void getSizes(const ArchDef &arch, Size &n, Size& o, Size &r, Size &p,
|
||||
Size &i1, Size &i2, Size &i3)
|
||||
{
|
||||
n = arch.getWordSize() * 8;
|
||||
o = 6;
|
||||
r = ceilLog2(arch.getNRegs());
|
||||
p = ceilLog2(arch.getNPRegs());
|
||||
i1 = n - 1 - p - o;
|
||||
i2 = i1 - r;
|
||||
i3 = i2 - r;
|
||||
}
|
||||
|
||||
WordDecoder::WordDecoder(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);
|
||||
}
|
||||
|
||||
Word signExt(Word w, Size bit, Word mask) {
|
||||
if (w>>(bit-1)) w |= ~mask;
|
||||
return w;
|
||||
}
|
||||
|
||||
Instruction *WordDecoder::decode(const std::vector<Byte> &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<Byte> &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 " <<i<< " does not fit in encoding.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (Size j = 0; j < i.getNRSrc(); j++) {
|
||||
code <<= r;
|
||||
code |= i.getRSrc(j);
|
||||
bitsWritten += r;
|
||||
if (i.getRSrc(j) > 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);
|
||||
}
|
378
src/harptool.cpp
Normal file
378
src/harptool.cpp
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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<string>("-o", "--output", "", outFileName);
|
||||
CommandLineArgSetter<string>("-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<TextChunk*>(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<string>("-a", "--arch", "", archString);
|
||||
CommandLineArgSetter<string>("-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<DataChunk*>(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<string>("-c", "--core", "", imgFileName);
|
||||
CommandLineArgSetter<string>("-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<string>("-a", "--arch", "", archString);
|
||||
CommandLineArgSetter<string>("-f", "--format", "", formatString);
|
||||
CommandLineArgSetter<Addr>("--offset", "", binOffset);
|
||||
CommandLineArgSetter<string>("-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<Obj *> objects(nObjects);
|
||||
vector<DataChunk*> chunks;
|
||||
map<string, Addr> gChunkMap;
|
||||
Addr nextOffset(binOffset);
|
||||
|
||||
for (Size i = 0; i < nObjects; i++) {
|
||||
map <string, Addr> 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<DataChunk*>(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<DataChunk*>(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;
|
||||
}
|
87
src/include/archdef.h
Normal file
87
src/include/archdef.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __ARCHDEF_H
|
||||
#define __ARCHDEF_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#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<EXT_ENC||encChar=='x') throw Undefined(); else return encChar;
|
||||
}
|
||||
|
||||
RegNum getNRegs() const {
|
||||
if (extent < EXT_REGS) throw Undefined(); else return nRegs;
|
||||
}
|
||||
|
||||
RegNum getNPRegs() const {
|
||||
if (extent < EXT_PREGS) throw Undefined(); else return nPRegs;
|
||||
}
|
||||
|
||||
ThdNum getNThds() const {
|
||||
if (extent < EXT_THDS) throw Undefined(); else return nThds;
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
EXT_NULL, EXT_WORDSIZE, EXT_ENC, EXT_REGS, EXT_PREGS, EXT_THDS
|
||||
} extent;
|
||||
|
||||
Size wordSize;
|
||||
ThdNum nThds;
|
||||
RegNum nRegs, nPRegs;
|
||||
char encChar;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
61
src/include/args.h
Normal file
61
src/include/args.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __ARGS_H
|
||||
#define __ARGS_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
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<std::string, CommandLineArg *> longArgs;
|
||||
static std::map<std::string, CommandLineArg *> shortArgs;
|
||||
};
|
||||
|
||||
template <typename T> 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
|
10
src/include/asm-tokens.h
Normal file
10
src/include/asm-tokens.h
Normal file
|
@ -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
|
||||
};
|
||||
};
|
43
src/include/core.h
Normal file
43
src/include/core.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __CORE_H
|
||||
#define __CORE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<std::vector<Word> > reg;
|
||||
std::vector<std::vector<bool> > pred;
|
||||
|
||||
std::vector<Word> shadowReg;
|
||||
std::vector<bool> shadowPReg;
|
||||
|
||||
bool interruptEnable, shadowInterruptEnable, supervisorMode,
|
||||
shadowSupervisorMode;
|
||||
|
||||
friend class Instruction;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
84
src/include/enc.h
Normal file
84
src/include/enc.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __ENC_H
|
||||
#define __ENC_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#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<Byte> &v, Size n,
|
||||
Instruction &i) = 0;
|
||||
void encodeChunk(DataChunk &dest, const TextChunk &src);
|
||||
};
|
||||
|
||||
class Decoder {
|
||||
public:
|
||||
Decoder() : haveRefs(false) {}
|
||||
Decoder(const std::vector<Ref*> &refVec) : haveRefs(true) {
|
||||
setRefs(refVec);
|
||||
}
|
||||
|
||||
virtual ~Decoder() {}
|
||||
|
||||
void setRefs(const std::vector<Ref*> &);
|
||||
void clearRefs() { refMap.clear(); }
|
||||
virtual Instruction *decode(const std::vector<Byte> &v, Size &n) = 0;
|
||||
void decodeChunk(TextChunk &dest, const DataChunk &src);
|
||||
protected:
|
||||
bool haveRefs;
|
||||
std::map <Size, Ref*> refMap;
|
||||
};
|
||||
|
||||
class WordDecoder : public Decoder {
|
||||
public:
|
||||
WordDecoder(const ArchDef &);
|
||||
virtual Instruction *decode(const std::vector<Byte> &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<Byte> &v, Size &n);
|
||||
private:
|
||||
Size wordSize;
|
||||
};
|
||||
|
||||
class WordEncoder : public Encoder {
|
||||
public:
|
||||
WordEncoder(const ArchDef &);
|
||||
virtual Size encode(Ref *&ref, std::vector<Byte> &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<Byte> &v,
|
||||
Size n, Instruction &i);
|
||||
private:
|
||||
Size wordSize;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
34
src/include/help.h
Normal file
34
src/include/help.h
Normal file
|
@ -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"
|
||||
"<mode> --help\n"
|
||||
" Display contextual help.\n",
|
||||
*emuHelp = "HARP Emulator command line arguments:\n"
|
||||
" -c, --core <filename> RAM image\n"
|
||||
" -a, --arch <arch string> Architecture string\n",
|
||||
*asmHelp = "HARP Assembler command line arguments:\n"
|
||||
" -a, --arch <arch string>\n"
|
||||
" -o, --output <filename>\n",
|
||||
*ldHelp = "HARP Linker command line arguments:\n"
|
||||
" -o, --output <filename>\n"
|
||||
" -a, --arch <filename>\n"
|
||||
" -f, --format <foramt string>\n"
|
||||
" --offset <bytes>\n",
|
||||
*disasmHelp = "HARP Disassembler command line arguments:\n"
|
||||
" -a, --arch <arch string> Architecture string.\n"
|
||||
" -o, --output <filename> Output filename.\n";
|
||||
};
|
||||
};
|
||||
#endif
|
93
src/include/instruction.h
Normal file
93
src/include/instruction.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __INSTRUCTION_H
|
||||
#define __INSTRUCTION_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#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
|
163
src/include/mem.h
Normal file
163
src/include/mem.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __MEM_H
|
||||
#define __MEM_H
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include <pthread.h>
|
||||
|
||||
#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<Byte> 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<char> 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 <Disk> 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<Addr, TLBEntry> tlb;
|
||||
TLBEntry tlbLookup(Addr vAddr, Word flagMask);
|
||||
|
||||
Size pageSize, addrBytes;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
200
src/include/obj.h
Normal file
200
src/include/obj.h
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __OBJ_H
|
||||
#define __OBJ_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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<Byte> &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<<bits)-1;
|
||||
if (addr > mask) goto noFit;
|
||||
}
|
||||
|
||||
{ Byte mask((1<<remainder) - 1);
|
||||
for (i = 0; i < bytes; i++) {
|
||||
data[offset+i] = addr & 0xff;
|
||||
addr >>= 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<<remainder)-1);
|
||||
Addr a(data[offset]&mask);
|
||||
|
||||
for (Size i = 0; i < bytes-1; i++) {
|
||||
a |= data[offset + bytes - i - 1];
|
||||
a <<= 8;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
Size getOffset() const { return offset; }
|
||||
Size getBits() const { return bits; }
|
||||
|
||||
private:
|
||||
std::vector<Byte> &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<Ref*> 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<Instruction*> 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<Byte> contents; /* 0 to size bytes in length. */
|
||||
};
|
||||
|
||||
class Obj {
|
||||
public:
|
||||
~Obj() { for (Size i = 0; i < chunks.size(); i++) delete chunks[i]; }
|
||||
std::vector<Chunk*> chunks;
|
||||
Size entry;
|
||||
};
|
||||
|
||||
class DynObj : public Obj {
|
||||
public:
|
||||
std::vector<std::string> 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
|
25
src/include/types.h
Normal file
25
src/include/types.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __TYPES_H
|
||||
#define __TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
24
src/include/util.h
Normal file
24
src/include/util.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#ifndef __UTIL_H
|
||||
#define __UTIL_H
|
||||
|
||||
#include <vector>
|
||||
#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<Byte> &b, Size &n);
|
||||
Word_u readWord(const std::vector<Byte> &b, Size &n, Size wordSize);
|
||||
void writeByte(std::vector<Byte> &p, Size &n, Byte b);
|
||||
void writeWord(std::vector<Byte> &p, Size &n, Size wordSize, Word w);
|
||||
};
|
||||
|
||||
#endif
|
225
src/instruction.cpp
Normal file
225
src/instruction.cpp
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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<Word> ®(c.reg[t]);
|
||||
vector<bool> &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;
|
||||
}
|
2032
src/lex.yy.cc
Normal file
2032
src/lex.yy.cc
Normal file
File diff suppressed because it is too large
Load diff
209
src/mem.cpp
Normal file
209
src/mem.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#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<<bit)-1)) >= 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<<bit)-1;
|
||||
if (a + sz <= m.size()) return m.base() + a;
|
||||
}
|
||||
|
||||
Word MemoryUnit::ADecoder::read(Addr a, bool sup, Size wordSize) {
|
||||
Size bit = wordSize - 1;
|
||||
MemDevice &m(doLookup(a, bit));
|
||||
a &= (2<<bit)-1;
|
||||
return m.read(a);
|
||||
}
|
||||
|
||||
void MemoryUnit::ADecoder::write(Addr a, Word w, bool sup, Size wordSize) {
|
||||
Size bit = wordSize - 1;
|
||||
MemDevice &m(doLookup(a, bit));
|
||||
a &= (2<<bit)-1;
|
||||
m.write(a, w);
|
||||
}
|
||||
|
||||
Byte *MemoryUnit::getPtr(Addr a, Size s) {
|
||||
ad.getPtr(a, s, addrBytes*8);
|
||||
}
|
||||
|
||||
void MemoryUnit::attach(MemDevice &m, Addr base) {
|
||||
ad.map(base, m, m.size(), addrBytes*8 - 1);
|
||||
}
|
||||
|
||||
MemoryUnit::TLBEntry MemoryUnit::tlbLookup(Addr vAddr, Word flagMask) {
|
||||
map<Addr, MemoryUnit::TLBEntry>::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;
|
||||
}
|
||||
}
|
635
src/obj.cpp
Normal file
635
src/obj.cpp
Normal file
|
@ -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 <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <FlexLexer.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
|
||||
#include <map>
|
||||
|
||||
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<string, Word> &d,
|
||||
int start=0, int end=-1)
|
||||
{
|
||||
uint64_t (* const rPE)(const string&, const map<string, Word>&, 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<string, Word>::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<Chunk>::reverse_iterator cur;
|
||||
bool permR(true), permW(false), permX(false), entry(false), nextPred(false),
|
||||
global(false);
|
||||
|
||||
map <string, Word> defs;
|
||||
|
||||
/* Pre-defined defs. */
|
||||
defs["__WORD"] = wordSize;
|
||||
|
||||
map <string, Instruction::Opcode> 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<TextChunk* const>(c);
|
||||
DataChunk * const dc = dynamic_cast<DataChunk* const>(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<Byte> &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<Byte> tmp;
|
||||
vector<Size> 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<DataChunk*>(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<OffsetRef*>(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<Byte> &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<Byte> 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<Size> 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;
|
||||
}
|
129
src/scanner.lex
Normal file
129
src/scanner.lex
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
%option c++
|
||||
%option noyywrap
|
||||
|
||||
%{
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#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++;
|
||||
}
|
||||
|
||||
<INITIAL>\.def { BEGIN DEFARGS; return ASM_T_DIR_DEF; }
|
||||
<INITIAL>\.perm { BEGIN PERMARGS; return ASM_T_DIR_PERM; }
|
||||
<INITIAL>\.byte { BEGIN WORDARGS; return ASM_T_DIR_BYTE; }
|
||||
<INITIAL>\.word { BEGIN WORDARGS; return ASM_T_DIR_WORD; }
|
||||
<INITIAL>\.string { BEGIN STRINGARGS; return ASM_T_DIR_STRING; }
|
||||
<INITIAL>\.align { BEGIN ALIGNARGS; return ASM_T_DIR_ALIGN; }
|
||||
<INITIAL>\.entry { BEGIN EMPTYARGS; return ASM_T_DIR_ENTRY; }
|
||||
<INITIAL>\.global { BEGIN EMPTYARGS; return ASM_T_DIR_GLOBAL; }
|
||||
|
||||
<INITIAL>@p{num}{space}\? { yylval.u = read_number(YYText());
|
||||
return ASM_T_PRED; }
|
||||
<INITIAL>{sym}/: { BEGIN EATCOLON;
|
||||
yylval.s = std::string(YYText());
|
||||
return ASM_T_LABEL; }
|
||||
<INITIAL>{sym} { BEGIN INSTARGS;
|
||||
yylval.s = std::string(YYText());
|
||||
return ASM_T_INST; }
|
||||
<INITIAL>; {}
|
||||
<INITIAL>{endl} {yyline++;}
|
||||
|
||||
<EATCOLON>: { BEGIN INITIAL; }
|
||||
|
||||
|
||||
<INSTARGS>@p{num}{space}[,;]? { yylval.u = read_number(YYText());
|
||||
return ASM_T_PREG; }
|
||||
<INSTARGS>%r{num}{space}[,;]? { yylval.u = read_number(YYText());
|
||||
return ASM_T_REG; }
|
||||
<INSTARGS>#{num}{space}[,;]? { yylval.u = read_number(YYText());
|
||||
return ASM_T_LIT; }
|
||||
<INSTARGS>{sym} { yylval.s = std::string(YYText()); return ASM_T_SYM; }
|
||||
<INSTARGS>{parenexp} { yylval.s = std::string(YYText()); return ASM_T_PEXP; }
|
||||
|
||||
<INSTARGS>{space} {}
|
||||
<INSTARGS>; { BEGIN INITIAL; return ASM_T_DIR_END; }
|
||||
<INSTARGS>{endl} { BEGIN INITIAL; yyline++; return ASM_T_DIR_END; }
|
||||
|
||||
|
||||
<DEFARGS>{sym} { yylval.s = std::string(YYText());
|
||||
return ASM_T_DIR_ARG_SYM; }
|
||||
<DEFARGS>{num} { yylval.u = read_number(YYText());
|
||||
return ASM_T_DIR_ARG_NUM; }
|
||||
<DEFARGS>{endl} { yyline++; BEGIN INITIAL; }
|
||||
|
||||
|
||||
<PERMARGS>r { return ASM_T_DIR_ARG_R; }
|
||||
<PERMARGS>w { return ASM_T_DIR_ARG_W; }
|
||||
<PERMARGS>x { return ASM_T_DIR_ARG_X; }
|
||||
<PERMARGS>{endl} { BEGIN INITIAL; yyline++; return ASM_T_DIR_END; }
|
||||
|
||||
|
||||
<WORDARGS>{sym} { yylval.s = std::string(YYText());
|
||||
return ASM_T_DIR_ARG_SYM; }
|
||||
<WORDARGS>{num} { yylval.u = read_number(YYText());
|
||||
return ASM_T_DIR_ARG_NUM; }
|
||||
<WORDARGS>{endl} { BEGIN INITIAL; yyline++; return ASM_T_DIR_END; }
|
||||
|
||||
<STRINGARGS>{sym} { yylval.s = std::string(YYText());
|
||||
return ASM_T_DIR_ARG_SYM; }
|
||||
<STRINGARGS>\"([^\"]|\\\")*\" { BEGIN INITIAL;
|
||||
yylval.s = std::string(YYText());
|
||||
yylval.s = yylval.s.substr(1,
|
||||
yylval.s.length() - 2);
|
||||
return ASM_T_DIR_ARG_STRING; }
|
||||
|
||||
<ALIGNARGS>{num} { yylval.u = read_number(YYText());
|
||||
return ASM_T_DIR_ARG_NUM; }
|
||||
<ALIGNARGS>{endl} { yyline++; BEGIN INITIAL; }
|
||||
|
||||
|
||||
<EMPTYARGS>{endl} { yyline++; BEGIN INITIAL; }
|
||||
|
||||
{space} { /*Ignore inter-token whitespace.*/ }
|
||||
. { std::cout << "Unexpected character on line " << std::dec << yyline << '\n';
|
||||
exit(1); }
|
51
src/test/2thread.s
Normal file
51
src/test/2thread.s
Normal file
|
@ -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
|
32
src/test/Makefile
Normal file
32
src/test/Makefile
Normal file
|
@ -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 *~
|
41
src/test/boot.4w.s
Normal file
41
src/test/boot.4w.s
Normal file
|
@ -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
|
52
src/test/boot.s
Normal file
52
src/test/boot.s
Normal file
|
@ -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;
|
||||
|
||||
|
50
src/test/lib.s
Normal file
50
src/test/lib.s
Normal file
|
@ -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
|
81
src/test/sieve.s
Normal file
81
src/test/sieve.s
Normal file
|
@ -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. */
|
70
src/util.cpp
Normal file
70
src/util.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#include <vector>
|
||||
|
||||
#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<Byte> &b, Size &n) {
|
||||
if (b.size() <= n) throw OutOfBytes();
|
||||
return b[n++];
|
||||
}
|
||||
|
||||
Word_u Harp::readWord(const vector<Byte> &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<Byte> &p, Size &n, Byte b) {
|
||||
if (p.size() <= n) p.resize(n+1);
|
||||
p[n++] = b;
|
||||
}
|
||||
|
||||
void Harp::writeWord(vector<Byte> &p, Size &n, Size wordSize, Word w) {
|
||||
if (p.size() < (n+wordSize)) p.resize(n+wordSize);
|
||||
while (wordSize--) {
|
||||
p[n++] = w & 0xff;
|
||||
w >>= 8;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue