e3e979d86cccded8a197312b3b04229b798a2792
[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: 0x%llx",(unsigned long long)p.addr);
116 ackpacket.data_size = p.data_size;
117
118 static_assert(APP_DATA_ALIGN >= sizeof(uint64_t))
119 for(size_t i = 0; i < p.data_size/8; i++)
120 ((uint64_t*)ackpacket.data)[i] = sim->mmu->load_uint64(p.addr+i*8);
121 break;
122 case APP_CMD_WRITE_MEM:
123 demand(p.addr % APP_DATA_ALIGN == 0, "misaligned address");
124 demand(p.data_size % APP_DATA_ALIGN == 0, "misaligned data");
125 demand(p.data_size <= bytes - offsetof(packet,data), "short packet");
126 demand(p.addr <= sim->memsz && p.addr+p.data_size <= sim->memsz, "out of bounds: 0x%llx",(unsigned long long)p.addr);
127
128 for(size_t i = 0; i < p.data_size/8; i++)
129 sim->mmu->store_uint64(p.addr+i*8, ((uint64_t*)p.data)[i]);
130 break;
131 case APP_CMD_READ_CONTROL_REG:
132 demand(p.addr == 16,"bad control reg");
133 demand(p.data_size == sizeof(reg_t),"bad control reg size");
134 ackpacket.data_size = sizeof(reg_t);
135 memcpy(ackpacket.data,&sim->tohost,sizeof(reg_t));
136 break;
137 case APP_CMD_WRITE_CONTROL_REG:
138 demand(p.addr == 17,"bad control reg");
139 demand(p.data_size == sizeof(reg_t),"bad control reg size");
140 sim->tohost = 0;
141 memcpy(&sim->fromhost,p.data,sizeof(reg_t));
142 break;
143 }
144
145 send_packet(&ackpacket);
146 seqno++;
147 return p.cmd;
148 }
149 catch(io_error e)
150 {
151 fprintf(stderr,"warning: %s\n",e.what());
152 }
153 }
154