--- /dev/null
+#include "applink.h"
+#include "common.h"
+#include "sim.h"
+#include <unistd.h>
+#include <stdexcept>
+
+enum
+{
+ APP_CMD_READ_MEM,
+ APP_CMD_WRITE_MEM,
+ APP_CMD_READ_CONTROL_REG,
+ APP_CMD_WRITE_CONTROL_REG,
+ APP_CMD_START,
+ APP_CMD_STOP,
+ APP_CMD_ACK,
+ APP_CMD_NACK
+};
+
+#define APP_DATA_ALIGN 8
+#define APP_MAX_DATA_SIZE 1024
+struct packet
+{
+ uint16_t cmd;
+ uint16_t seqno;
+ uint32_t data_size;
+ uint64_t addr;
+ uint8_t data[APP_MAX_DATA_SIZE];
+};
+
+class packet_error : public std::runtime_error
+{
+public:
+ packet_error(const std::string& s) : std::runtime_error(s) {}
+};
+class io_error : public packet_error
+{
+public:
+ io_error(const std::string& s) : packet_error(s) {}
+};
+
+appserver_link_t::appserver_link_t(int _tohost_fd, int _fromhost_fd)
+ : sim(NULL), tohost_fd(_tohost_fd), fromhost_fd(_fromhost_fd)
+{
+}
+
+void appserver_link_t::init(sim_t* _sim)
+{
+ sim = _sim;
+}
+
+void appserver_link_t::wait_for_start()
+{
+ while(wait_for_packet() != APP_CMD_START);
+}
+
+void appserver_link_t::send_packet(packet* p)
+{
+ while(1) try
+ {
+ int bytes = write(fromhost_fd,p,offsetof(packet,data)+p->data_size);
+ if(bytes == -1 || (size_t)bytes != offsetof(packet,data)+p->data_size)
+ throw io_error("write failed");
+ }
+ catch(io_error e)
+ {
+ fprintf(stderr,"warning: %s\n",e.what());
+ }
+}
+
+void appserver_link_t::nack(uint16_t nack_seqno)
+{
+ packet p = {APP_CMD_NACK,nack_seqno,0,0};
+ send_packet(&p);
+}
+
+int appserver_link_t::wait_for_packet()
+{
+ while(1) try
+ {
+ packet p;
+ int bytes = read(fromhost_fd,&p,sizeof(p));
+ if(bytes != offsetof(packet,data))
+ throw io_error("read failed");
+
+ if(p.seqno != seqno)
+ {
+ nack(p.seqno);
+ continue;
+ }
+
+ packet ackpacket = {APP_CMD_ACK,seqno,0,0};
+
+ switch(p.cmd)
+ {
+ case APP_CMD_START:
+ break;
+ case APP_CMD_STOP:
+ exit(0);
+ case APP_CMD_READ_MEM:
+ demand(p.addr % APP_DATA_ALIGN == 0, "misaligned address");
+ demand(p.data_size % APP_DATA_ALIGN == 0, "misaligned data");
+ demand(p.data_size <= APP_MAX_DATA_SIZE, "long read data");
+ demand(p.addr <= sim->memsz && p.addr+p.data_size <= sim->memsz, "out of bounds");
+ memcpy(ackpacket.data,sim->mem+p.addr,p.data_size);
+ ackpacket.data_size = p.data_size;
+ break;
+ case APP_CMD_WRITE_MEM:
+ demand(p.addr % APP_DATA_ALIGN == 0, "misaligned address");
+ demand(p.data_size % APP_DATA_ALIGN == 0, "misaligned data");
+ demand(p.data_size <= bytes - offsetof(packet,data), "short packet");
+ demand(p.addr <= sim->memsz && p.addr+p.data_size <= sim->memsz, "out of bounds");
+ memcpy(sim->mem+p.addr,p.data,p.data_size);
+ break;
+ case APP_CMD_READ_CONTROL_REG:
+ demand(p.addr == 16,"bad control reg");
+ demand(p.data_size == sizeof(reg_t),"bad control reg size");
+ ackpacket.data_size = sizeof(reg_t);
+ memcpy(ackpacket.data,&sim->tohost,sizeof(reg_t));
+ break;
+ case APP_CMD_WRITE_CONTROL_REG:
+ demand(p.addr == 17,"bad control reg");
+ demand(p.data_size == sizeof(reg_t),"bad control reg size");
+ sim->tohost = 0;
+ memcpy(&sim->fromhost,ackpacket.data,sizeof(reg_t));
+ break;
+ }
+
+ send_packet(&ackpacket);
+ seqno++;
+ return p.cmd;
+ }
+ catch(io_error e)
+ {
+ fprintf(stderr,"warning: %s\n",e.what());
+ }
+}
+
--- /dev/null
+#ifndef _APPLINK_H
+#define _APPLINK_H
+
+#include <stdint.h>
+
+class sim_t;
+struct packet;
+class appserver_link_t
+{
+public:
+ appserver_link_t(int _tohost_fd, int _fromhost_fd);
+ void init(sim_t* _sim);
+ void wait_for_start();
+ int wait_for_packet();
+
+private:
+ sim_t* sim;
+ int tohost_fd;
+ int fromhost_fd;
+ uint16_t seqno;
+
+ void nack(uint16_t seqno);
+ void send_packet(packet* p);
+};
+
+#endif
case 3:
RT = ebase;
break;
+
+ case 8:
+ RT = MEMSIZE >> 12;
+ break;
+
+ case 17:
+ RT = sim->get_fromhost();
+ break;
+
default:
RT = -1;
}
case 3:
ebase = RT & ~0xFFF;
break;
+
+ case 16:
+ sim->set_tohost(RT);
+ break;
}
case 3:
RT = sext32(ebase);
break;
+
+ case 8:
+ RT = sext32(MEMSIZE >> 12);
+ break;
+
+ case 17:
+ RT = sext32(sim->get_fromhost());
+ break;
+
default:
RT = -1;
}
case 9:
printf("%ld insns retired\n",counters[0]);
exit(0);
+
+ case 16:
+ sim->set_tohost(sext32(RT));
+ break;
}
#include "processor.h"
#include "common.h"
#include "config.h"
+#include "sim.h"
-processor_t::processor_t(int _id, char* _mem, size_t _memsz)
- : id(_id), mmu(_mem,_memsz)
+processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz)
+ : sim(_sim), mmu(_mem,_memsz)
{
memset(R,0,sizeof(R));
pc = 0;
memset(counters,0,sizeof(counters));
}
+void processor_t::init(uint32_t _id)
+{
+ id = _id;
+}
+
void processor_t::set_sr(uint32_t val)
{
sr = val & ~SR_ZERO;
#include "trap.h"
#include "mmu.h"
+class sim_t;
+
class processor_t
{
public:
- processor_t(int _id, char* _mem, size_t _memsz);
+ processor_t(sim_t* _sim, char* _mem, size_t _memsz);
+ void init(uint32_t _id);
void step(size_t n, bool noisy);
private:
+ sim_t* sim;
+
// architected state
reg_t R[NGPR];
reg_t pc;
#include <unistd.h>
+#include <fcntl.h>
#include "common.h"
#include "sim.h"
+#include "applink.h"
int main(int argc, char** argv)
{
- sim_t s(1,MEMSIZE);
-
bool debug = false;
+ int nprocs = 1;
+ int fromhost_fd = -1, tohost_fd = -1;
- for(int c; (c = getopt(argc,argv,"-d")) != -1; )
+ for(int c; (c = getopt(argc,argv,"dpf:t:")) != -1; )
{
switch(c)
{
- case '\1':
- s.load_elf(optarg);
- break;
case 'd':
debug = true;
break;
- case '?':
- demand(0,"unrecognized option %c",optopt);
+ case 'p':
+ nprocs = atoi(optarg);
+ break;
+ case 'f':
+ fromhost_fd = atoi(optarg);
+ break;
+ case 't':
+ tohost_fd = atoi(optarg);
+ break;
}
}
+ demand(fcntl(fromhost_fd,F_GETFD) >= 0, "fromhost file not open");
+ demand(fcntl(tohost_fd,F_GETFD) >= 0, "tohost file not open");
+
+ appserver_link_t applink(fromhost_fd,tohost_fd);
+
+ sim_t s(nprocs,MEMSIZE,&applink);
s.run(debug);
}
riscv_subproject_deps =
riscv_hdrs = \
+ applink.h \
common.h \
decode.h \
execute.h \
insns/*.h \
riscv_srcs = \
+ applink.cc \
load_elf.cc \
processor.cc \
sim.cc \
#include "sim.h"
+#include "applink.h"
#include "common.h"
#include "load_elf.h"
#include <sys/mman.h>
size_t size;
};
-sim_t::sim_t(int _nprocs, size_t _memsz)
- : nprocs(_nprocs), memsz(_memsz)
+sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink)
+ : applink(_applink),
+ memsz(_memsz),
+ mem((char*)mmap64(NULL, memsz, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)),
+ procs(std::vector<processor_t>(_nprocs,processor_t(this,mem,memsz)))
{
- mem = (char*)mmap(NULL, memsz, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
demand(mem != MAP_FAILED, "couldn't allocate target machine's memory");
- procs = (processor_t*)malloc(sizeof(*procs)*nprocs);
- for(int i = 0; i < nprocs; i++)
- new(&procs[i]) processor_t(i,mem,memsz);
+ for(int i = 0; i < (int)procs.size(); i++)
+ procs[i].init(i);
}
sim_t::~sim_t()
{
- free(procs);
}
void sim_t::load_elf(const char* fn)
memory_t loader(mem, memsz);
::load_elf(fn,&loader);
}
+void sim_t::set_tohost(reg_t val)
+{
+ fromhost = 0;
+ tohost = val;
+}
+
+reg_t sim_t::get_fromhost()
+{
+ while(fromhost == 0)
+ applink->wait_for_packet();
+ return fromhost;
+}
void sim_t::run(bool debug)
{
+ applink->wait_for_start();
+
while(1)
{
if(!debug)
void sim_t::step_all(size_t n, size_t interleave, bool noisy)
{
for(size_t j = 0; j < n; j+=interleave)
- for(int i = 0; i < nprocs; i++)
+ for(int i = 0; i < (int)procs.size(); i++)
procs[i].step(interleave,noisy);
}
return;
int p = atoi(a[0].c_str());
- if(p >= nprocs)
+ if(p >= (int)procs.size())
return;
if(a.size() == 2)
throw trap_illegal_instruction;
int p = atoi(args[0].c_str());
- if(p >= nprocs)
+ if(p >= (int)procs.size())
throw trap_illegal_instruction;
return procs[p].pc;
int p = atoi(args[0].c_str());
int r = atoi(args[1].c_str());
- if(p >= nprocs || r >= NGPR)
+ if(p >= (int)procs.size() || r >= NGPR)
throw trap_illegal_instruction;
return procs[p].R[r];
#include <string>
#include "processor.h"
-const int MEMSIZE = 0x7D000000;
+const long MEMSIZE = 0x100000000;
+
+class appserver_link_t;
class sim_t
{
public:
- sim_t(int _nprocs, size_t _memsz);
+ sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink);
~sim_t();
void load_elf(const char* fn);
void run(bool debug);
+ void set_tohost(reg_t val);
+ reg_t get_fromhost();
+
private:
- processor_t* procs;
- int nprocs;
+ // global architected state
+ reg_t tohost;
+ reg_t fromhost;
+
+ appserver_link_t* applink;
- char* mem;
size_t memsz;
+ char* mem;
+ std::vector<processor_t> procs;
void step_all(size_t n, size_t interleave, bool noisy);
reg_t get_reg(const std::vector<std::string>& args);
reg_t get_mem(const std::vector<std::string>& args);
reg_t get_pc(const std::vector<std::string>& args);
+
+ friend class appserver_link_t;
};
#endif