d8fddaded421420c9e11b67be094d16b86a4a5e7
[riscv-isa-sim.git] / riscv / applink.cc
1 #include "applink.h"
2 #include "common.h"
3 #include "sim.h"
4 #include <unistd.h>
5 #include <stdexcept>
6
7 enum
8 {
9 APP_CMD_READ_MEM,
10 APP_CMD_WRITE_MEM,
11 APP_CMD_READ_CONTROL_REG,
12 APP_CMD_WRITE_CONTROL_REG,
13 APP_CMD_START,
14 APP_CMD_STOP,
15 APP_CMD_ACK,
16 APP_CMD_NACK
17 };
18
19 #define APP_DATA_ALIGN 8
20 #define APP_MAX_DATA_SIZE 1024
21 struct packet
22 {
23 uint16_t cmd;
24 uint16_t seqno;
25 uint32_t data_size;
26 uint64_t addr;
27 uint8_t data[APP_MAX_DATA_SIZE];
28 };
29
30 class packet_error : public std::runtime_error
31 {
32 public:
33 packet_error(const std::string& s) : std::runtime_error(s) {}
34 };
35 class io_error : public packet_error
36 {
37 public:
38 io_error(const std::string& s) : packet_error(s) {}
39 };
40
41 appserver_link_t::appserver_link_t(int _tohost_fd, int _fromhost_fd)
42 : sim(NULL), tohost_fd(_tohost_fd), fromhost_fd(_fromhost_fd), seqno(1)
43 {
44 }
45
46 void appserver_link_t::init(sim_t* _sim)
47 {
48 sim = _sim;
49 }
50
51 void appserver_link_t::wait_for_start()
52 {
53 while(wait_for_packet() != APP_CMD_START);
54 }
55
56 void appserver_link_t::send_packet(packet* p)
57 {
58 while(1) try
59 {
60 int bytes = write(tohost_fd,p,offsetof(packet,data)+p->data_size);
61 if(bytes == -1 || (size_t)bytes != offsetof(packet,data)+p->data_size)
62 throw io_error("write failed");
63 return;
64 }
65 catch(io_error e)
66 {
67 fprintf(stderr,"warning: %s\n",e.what());
68 }
69 }
70
71 void appserver_link_t::nack(uint16_t nack_seqno)
72 {
73 packet p = {APP_CMD_NACK,nack_seqno,0,0};
74 send_packet(&p);
75 }
76
77 int appserver_link_t::wait_for_packet()
78 {
79 while(1) try
80 {
81 packet p;
82 int bytes = read(fromhost_fd,&p,sizeof(p));
83 if(bytes < (signed)offsetof(packet,data))
84 throw io_error("read failed");
85
86 if(p.seqno != seqno)
87 {
88 nack(p.seqno);
89 continue;
90 }
91
92 packet ackpacket = {APP_CMD_ACK,seqno,0,0};
93
94 switch(p.cmd)
95 {
96 case APP_CMD_START:
97 break;
98 case APP_CMD_STOP:
99 send_packet(&ackpacket);
100 exit(0);
101 case APP_CMD_READ_MEM:
102 demand(p.addr % APP_DATA_ALIGN == 0, "misaligned address");
103 demand(p.data_size % APP_DATA_ALIGN == 0, "misaligned data");
104 demand(p.data_size <= APP_MAX_DATA_SIZE, "long read data");
105 demand(p.addr <= sim->memsz && p.addr+p.data_size <= sim->memsz, "out of bounds");
106 memcpy(ackpacket.data,sim->mem+p.addr,p.data_size);
107 ackpacket.data_size = p.data_size;
108 break;
109 case APP_CMD_WRITE_MEM:
110 demand(p.addr % APP_DATA_ALIGN == 0, "misaligned address");
111 demand(p.data_size % APP_DATA_ALIGN == 0, "misaligned data");
112 demand(p.data_size <= bytes - offsetof(packet,data), "short packet");
113 demand(p.addr <= sim->memsz && p.addr+p.data_size <= sim->memsz, "out of bounds");
114 memcpy(sim->mem+p.addr,p.data,p.data_size);
115 break;
116 case APP_CMD_READ_CONTROL_REG:
117 demand(p.addr == 16,"bad control reg");
118 demand(p.data_size == sizeof(reg_t),"bad control reg size");
119 ackpacket.data_size = sizeof(reg_t);
120 memcpy(ackpacket.data,&sim->tohost,sizeof(reg_t));
121 break;
122 case APP_CMD_WRITE_CONTROL_REG:
123 demand(p.addr == 17,"bad control reg");
124 demand(p.data_size == sizeof(reg_t),"bad control reg size");
125 sim->tohost = 0;
126 memcpy(&sim->fromhost,p.data,sizeof(reg_t));
127 break;
128 }
129
130 send_packet(&ackpacket);
131 seqno++;
132 return p.cmd;
133 }
134 catch(io_error e)
135 {
136 fprintf(stderr,"warning: %s\n",e.what());
137 }
138 }
139