5ced3203cb0b669c326009f3afcd98429e55929d
[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::wait_for_tohost()
57 {
58 while(wait_for_packet() != APP_CMD_READ_CONTROL_REG);
59 }
60
61 void appserver_link_t::wait_for_fromhost()
62 {
63 while(wait_for_packet() != APP_CMD_WRITE_CONTROL_REG);
64 }
65
66 void appserver_link_t::send_packet(packet* p)
67 {
68 while(1) try
69 {
70 int bytes = write(tohost_fd,p,offsetof(packet,data)+p->data_size);
71 if(bytes == -1 || (size_t)bytes != offsetof(packet,data)+p->data_size)
72 throw io_error("write failed");
73 return;
74 }
75 catch(io_error e)
76 {
77 fprintf(stderr,"warning: %s\n",e.what());
78 }
79 }
80
81 void appserver_link_t::nack(uint16_t nack_seqno)
82 {
83 packet p = {APP_CMD_NACK,nack_seqno,0,0};
84 send_packet(&p);
85 }
86
87 int appserver_link_t::wait_for_packet()
88 {
89 while(1) try
90 {
91 packet p;
92 int bytes = read(fromhost_fd,&p,sizeof(p));
93 if(bytes < (signed)offsetof(packet,data))
94 throw io_error("read failed");
95
96 if(p.seqno != seqno)
97 {
98 nack(p.seqno);
99 continue;
100 }
101
102 packet ackpacket = {APP_CMD_ACK,seqno,0,0};
103
104 switch(p.cmd)
105 {
106 case APP_CMD_START:
107 break;
108 case APP_CMD_STOP:
109 send_packet(&ackpacket);
110 throw quit_sim();
111 case APP_CMD_READ_MEM:
112 demand(p.addr % APP_DATA_ALIGN == 0, "misaligned address");
113 demand(p.data_size % APP_DATA_ALIGN == 0, "misaligned data");
114 demand(p.data_size <= APP_MAX_DATA_SIZE, "long read data");
115 demand(p.addr <= sim->memsz && p.addr+p.data_size <= sim->memsz, "out of bounds");
116 memcpy(ackpacket.data,sim->mem+p.addr,p.data_size);
117 ackpacket.data_size = p.data_size;
118 break;
119 case APP_CMD_WRITE_MEM:
120 demand(p.addr % APP_DATA_ALIGN == 0, "misaligned address");
121 demand(p.data_size % APP_DATA_ALIGN == 0, "misaligned data");
122 demand(p.data_size <= bytes - offsetof(packet,data), "short packet");
123 demand(p.addr <= sim->memsz && p.addr+p.data_size <= sim->memsz, "out of bounds");
124 memcpy(sim->mem+p.addr,p.data,p.data_size);
125 break;
126 case APP_CMD_READ_CONTROL_REG:
127 demand(p.addr == 16,"bad control reg");
128 demand(p.data_size == sizeof(reg_t),"bad control reg size");
129 ackpacket.data_size = sizeof(reg_t);
130 memcpy(ackpacket.data,&sim->tohost,sizeof(reg_t));
131 break;
132 case APP_CMD_WRITE_CONTROL_REG:
133 demand(p.addr == 17,"bad control reg");
134 demand(p.data_size == sizeof(reg_t),"bad control reg size");
135 sim->tohost = 0;
136 memcpy(&sim->fromhost,p.data,sizeof(reg_t));
137 break;
138 }
139
140 send_packet(&ackpacket);
141 seqno++;
142 return p.cmd;
143 }
144 catch(io_error e)
145 {
146 fprintf(stderr,"warning: %s\n",e.what());
147 }
148 }
149