#define __STDC_FORMAT_MACROS
#include <algorithm>
#include <cstring>
#include <cinttypes>
#include <iostream>
#include <cassert>
#include <cstdio>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <iostream>
struct RAM
{
char
operator()(uint64_t address) const
{
return data[address];
}
char &
operator()(uint64_t address)
{
return data[address];
}
void
print(int from, int to) const
{
for (int i=from; i<=to; ++i) {
std::printf("---");
}
std::printf("\n");
for (int i=from; i<=to; ++i) {
std::printf("%02x ", 0xFF & data[i]);
}
std::printf("\n");
for (int i=from; i<=to; ++i) {
std::printf("---");
}
std::printf("\n");
for (int i=from; i<=to; ++i) {
if (i % 8 == 0) {
std::printf("|%-23d", i);
}
}
std::printf("\n");
for (int i=from; i<=to; ++i) {
if (i % 8 == 0) {
std::printf("|0x%-21x", i);
}
}
std::printf("\n\n");
}
mutable std::unordered_map<uint64_t,char> data;
};
struct CpuRegister
{
CpuRegister()
: zero(0)
{
}
const uint64_t &
operator()(unsigned char id) const
{
return (id!=0) ? r[id] : zero;
}
uint64_t &
operator()(unsigned char id)
{
return (id!=0) ? r[id] : zero;
}
void
print(unsigned char from,
unsigned char to,
const std::string &IR_asmCode) const
{
for (unsigned char i=from; i<=to; ++i) {
std::printf("Reg%-2d 0x%016" PRIx64, i, (i!=0) ? r[i] : zero);
if (i==1) {
std::printf(" IP: %" PRIu64, r[1]);
} else if (i==2) {
std::printf(" IR: %-s", IR_asmCode.c_str());
}
std::printf("\n");
}
std::printf("\n\n");
}
uint64_t r[256];
uint64_t zero;
};
struct DataBus
{
DataBus(RAM &ram, CpuRegister &cpuRegister)
: ram(ram), cpuRegister(cpuRegister)
{
}
template <unsigned int bytes, bool asSigned=true>
void
fetch(uint64_t address, int reg)
{
assert(bytes==1 || bytes==2 || bytes==4 || bytes==8);
assert(address % bytes == 0);
cpuRegister(reg) = 0;
if (asSigned && (0x80 & ram(address))) {
cpuRegister(reg) = -1;
}
for (unsigned int i=0; i<bytes; ++i) {
cpuRegister(reg) = cpuRegister(reg) << 8;
cpuRegister(reg) = cpuRegister(reg) | (0xFF & ram(address+i));
}
}
template <unsigned int bytes>
void
store(int reg, uint64_t address)
{
assert(bytes==1 || bytes==2 || bytes==4 || bytes==8);
assert(address % bytes == 0);
uint64_t value = cpuRegister(reg);
for (unsigned int i=0; i<bytes; ++i) {
char byte = value & 0xFF;
ram(address+bytes-i-1) = byte;
value = value >> 8;
}
}
RAM &ram;
CpuRegister &cpuRegister;
};
struct ALU
{
ALU(CpuRegister &cpuRegister)
: cpuRegister(cpuRegister), zf(0), of(0), sf(0), cf(0)
{
}
void
setWord(uint16_t valueXY, int regZ)
{
cpuRegister(regZ) = valueXY;
}
void
bitwiseOR(unsigned char regX, unsigned char regY, unsigned char regZ)
{
uint64_t valueX = cpuRegister(regX);
uint64_t valueY = cpuRegister(regY);
cpuRegister(regZ) = valueX | valueY;
}
void
bitwiseOR(uint64_t valueX, unsigned char regY, unsigned char regZ)
{
uint64_t valueY = cpuRegister(regY);
cpuRegister(regZ) = valueX | valueY;
}
void
bitwiseAND(unsigned char regX, unsigned char regY, unsigned char regZ)
{
uint64_t valueX = cpuRegister(regX);
uint64_t valueY = cpuRegister(regY);
cpuRegister(regZ) = valueX & valueY;
}
void
bitwiseAND(uint64_t valueX, unsigned char regY, unsigned char regZ)
{
uint64_t valueY = cpuRegister(regY);
cpuRegister(regZ) = valueX & valueY;
}
void
add(unsigned char regX, unsigned char regY, unsigned char regZ)
{
uint64_t valueX = cpuRegister(regX);
uint64_t valueY = cpuRegister(regY);
zf = of = sf = cf = 0;
cpuRegister(regZ) = valueX + valueY;
if ((cpuRegister(regZ) < valueX) || (cpuRegister(regZ) < valueY)) {
cf = 1;
}
if (cpuRegister(regZ)==0) {
zf = 1;
}
bool signX = (valueX>>63);
bool signY = (valueY>>63);
bool signZ = (cpuRegister(regZ)>>63);
if ((signX==signY) && (signX!=signZ)) {
of = 1;
}
sf = signZ;
}
void
add(uint64_t valueX, unsigned char regY, unsigned char regZ)
{
uint64_t valueY = cpuRegister(regY);
zf = of = sf = cf = 0;
cpuRegister(regZ) = valueX + valueY;
if ((cpuRegister(regZ) < valueX) || (cpuRegister(regZ) < valueY)) {
cf = 1;
}
if (cpuRegister(regZ)==0) {
zf = 1;
}
bool signX = (valueX>>63);
bool signY = (valueY>>63);
bool signZ = (cpuRegister(regZ)>>63);
if ((signX==signY) && (signX!=signZ)) {
of = 1;
}
sf = signZ;
}
void
sub(unsigned char regX, unsigned char regY, unsigned char regZ)
{
add(-cpuRegister(regX), regY, regZ);
}
void
sub(uint64_t valueX, unsigned char regY, unsigned char regZ)
{
add(-valueX, regY, regZ);
}
void
unsignedMul(unsigned char regX, unsigned char regY, int regZ)
{
cpuRegister(regZ) = cpuRegister(regX) * cpuRegister(regY);
}
void
unsignedMul(uint64_t valueX, unsigned char regY, int regZ)
{
cpuRegister(regZ) = valueX * cpuRegister(regY);
}
void
print()
{
std::printf("ZF = %1d, OF = %1d, SF = %1d, CF = %1d\n", zf, of, sf, cf);
}
CpuRegister &cpuRegister;
int zf, of, sf, cf;
};
struct CPU
{
CPU(RAM &ram)
: alu(cpuRegister), dataBus(ram, cpuRegister)
{
cpuRegister(1) = 0;
cpuRegister(2) = 0;
IR_asm = "halt";
}
void
print()
{
cpuRegister.print(0,15,IR_asm);
alu.print();
}
bool
cycle()
{
char asmBuffer[101];
bool run = true;
dataBus.fetch<4, false>(cpuRegister(1), 2);
uint32_t instruction = cpuRegister(2);
unsigned char Z = instruction & 0xFF;
unsigned char Y = (instruction>> 8) & 0xFF;
unsigned char X = (instruction>>16) & 0xFF;
unsigned char op = (instruction>>24) & 0xFF;
signed char Xs = X;
signed char Ys = Y;
signed char Zs = Z;
bool jump = false;
uint16_t XY = X;
XY = (XY<<8) | Y;
uint32_t XYZ = XY;
XYZ = (XYZ<<8) | Z;
int32_t XYZs = Zs;
switch (op) {
case 0x00:
std::snprintf(asmBuffer, 100, "halt");
run = false;
break;
case 0x10:
std::snprintf(asmBuffer, 100,
"movq (%%%d, %%%d), %%%d", X, Y, Z);
dataBus.fetch<8>(cpuRegister(X)+cpuRegister(Y), Z);
break;
case 0x11:
std::snprintf(asmBuffer, 100,
"movq %d(%%%d), %%%d", Ys, X, Z);
dataBus.fetch<8>(cpuRegister(X)+Ys, Z);
break;
case 0x40:
std::snprintf(asmBuffer, 100,
"movq %%%d, (%%%d, %%%d)", X, Y, Z);
dataBus.store<8>(X, cpuRegister(Y)+cpuRegister(Z));
break;
case 0x41:
std::snprintf(asmBuffer, 100,
"movq %%%d, %d(%%%d)", X, Zs, Y);
dataBus.store<8>(X, cpuRegister(Y)+Zs);
break;
case 0x80:
std::snprintf(asmBuffer, 100,
"orq %%%d, %%%d, %%%d", X, Y, Z);
alu.bitwiseOR(X, Y, Z);
break;
case 0x81:
std::snprintf(asmBuffer, 100,
"orq $%d, %%%d, %%%d", X, Y, Z);
alu.bitwiseOR(uint64_t(X), Y, Z);
break;
case 0x82:
std::snprintf(asmBuffer, 100,
"andq %%%d, %%%d, %%%d", X, Y, Z);
alu.bitwiseAND(X, Y, Z);
break;
case 0x83:
std::snprintf(asmBuffer, 100,
"andq $%d, %%%d, %%%d", X, Y, Z);
alu.bitwiseAND(uint64_t(X), Y, Z);
break;
case 0x60:
std::snprintf(asmBuffer, 100,
"addq %%%d, %%%d, %%%d", X, Y, Z);
alu.add(X, Y, Z);
break;
case 0x61:
std::snprintf(asmBuffer, 100,
"addq $%d, %%%d, %%%d", Xs, Y, Z);
alu.add(uint64_t(Xs), Y, Z);
break;
case 0x62:
std::snprintf(asmBuffer, 100,
"subq %%%d, %%%d, %%%d", X, Y, Z);
alu.sub(X, Y, Z);
break;
case 0x63:
std::snprintf(asmBuffer, 100,
"subq $%d, %%%d, %%%d", Xs, Y, Z);
alu.sub(uint64_t(Xs), Y, Z);
break;
case 0x70:
std::snprintf(asmBuffer, 100,
"mulq %%%d, %%%d, %%%d", X, Y, Z);
alu.unsignedMul(X, Y, Z);
break;
case 0x71:
std::snprintf(asmBuffer, 100,
"mulq $%d, %%%d, %%%d", X, Y, Z);
alu.unsignedMul(uint64_t(X), Y, Z);
break;
case 0x90:
std::snprintf(asmBuffer, 100,
"jmp @+$%d", XYZs);
jump = true;
cpuRegister(1) = int64_t(cpuRegister(1))+ 4*int64_t(XYZs);
break;
case 0x91:
std::snprintf(asmBuffer, 100,
"jz @+$%d", XYZs);
if (alu.zf) {
jump = true;
cpuRegister(1) = int64_t(cpuRegister(1))+ 4*int64_t(XYZs);
}
break;
case 0x92:
std::snprintf(asmBuffer, 100,
"jnz @+$%d", XYZs);
if (!alu.zf) {
jump = true;
cpuRegister(1) = int64_t(cpuRegister(1))+ 4*int64_t(XYZs);
}
break;
case 0x93:
std::snprintf(asmBuffer, 100,
"jnz @+$%d", XYZs);
if (alu.sf != alu.of) {
jump = true;
cpuRegister(1) = int64_t(cpuRegister(1))+ 4*int64_t(XYZs);
}
break;
default:
std::fprintf(stderr, "Illegal instruction or instruction not "
"implemented\n");
assert(0);
}
if (!jump) {
cpuRegister(1) += 4;
}
IR_asm = std::string(asmBuffer);
return run;
}
CpuRegister cpuRegister;
ALU alu;
DataBus dataBus;
std::string IR_asm;
};
struct Computer
{
Computer(const char *filename, bool interactive=true)
: cpu(ram), cycle(0), interactive(interactive)
{
if (!load(filename)) {
std::fprintf(stderr, "Code in %s corrupted\n", filename);
assert(0);
}
}
void
run()
{
do {
print();
++cycle;
if (interactive) {
std::getchar();
}
} while (cpu.cycle());
print();
}
bool
load(const char *filename)
{
std::ifstream infile(filename);
std::string line;
std::uint64_t code;
std::uint64_t addr = 0;
while (std::getline(infile, line))
{
remove_if(line.begin(), line.end(), isspace);
std::istringstream in(line);
if (! (in >> std::hex >> code)) {
return false;
}
addr += 4;
ram(addr-1) = 0xFF & (code >> 0*8);
ram(addr-2) = 0xFF & (code >> 1*8);
ram(addr-3) = 0xFF & (code >> 2*8);
ram(addr-4) = 0xFF & (code >> 3*8);
}
return true;
}
void
print()
{
std::printf("CPU cycles done %4d\n\n", cycle);
ram.print(0,60);
cpu.print();
std::printf("\n\n");
}
RAM ram;
CPU cpu;
int cycle;
bool interactive;
};
int
main(int argc, const char **argv)
{
const char *code;
bool interactive = true;
if (argc<2) {
std::fprintf(stderr, "usage: [-r] %s code-file\n", argv[0]);
return 1;
}
for (int i=1; i<argc; ++i) {
if (!strcmp(argv[i], "-r")) {
interactive = false;
} else {
code = argv[i];
}
}
Computer computer(code, interactive);
computer.run();
}