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:
chad 2011-06-13 20:27:18 +00:00
commit 25377e4c03
29 changed files with 5463 additions and 0 deletions

22
src/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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> &reg(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))&reg[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

File diff suppressed because it is too large Load diff

209
src/mem.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}
}