implement lighter-weight htif packet header
[riscv-isa-sim.git] / riscv / htif.cc
1 #include "htif.h"
2 #include "common.h"
3 #include "sim.h"
4 #include <unistd.h>
5 #include <stdexcept>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <assert.h>
9 #include <stddef.h>
10 #include <poll.h>
11
12 enum
13 {
14 APP_CMD_READ_MEM,
15 APP_CMD_WRITE_MEM,
16 APP_CMD_READ_CONTROL_REG,
17 APP_CMD_WRITE_CONTROL_REG,
18 APP_CMD_START,
19 APP_CMD_STOP,
20 APP_CMD_ACK,
21 APP_CMD_NACK
22 };
23
24 #define APP_MAX_DATA_SIZE 1024
25 #define HTIF_DATA_ALIGN 8
26 struct packet
27 {
28 reg_t cmd : 4;
29 reg_t data_size : 12;
30 reg_t seqno : 8;
31 reg_t addr : 40;
32
33 uint8_t data[APP_MAX_DATA_SIZE];
34 };
35
36 htif_t::htif_t(int _tohost_fd, int _fromhost_fd)
37 : sim(NULL), tohost_fd(_tohost_fd), fromhost_fd(_fromhost_fd), seqno(1)
38 {
39 }
40
41 htif_t::~htif_t()
42 {
43 close(tohost_fd);
44 close(fromhost_fd);
45 }
46
47 void htif_t::init(sim_t* _sim)
48 {
49 sim = _sim;
50 }
51
52 void htif_t::wait_for_start()
53 {
54 while(wait_for_packet() != APP_CMD_START);
55 }
56
57 void htif_t::wait_for_tohost_write()
58 {
59 while(wait_for_packet() != APP_CMD_READ_CONTROL_REG);
60 }
61
62 void htif_t::wait_for_fromhost_write()
63 {
64 while(wait_for_packet() != APP_CMD_WRITE_CONTROL_REG);
65 }
66
67 void htif_t::send_packet(packet* p)
68 {
69 size_t data_size = p->data_size*HTIF_DATA_ALIGN;
70 size_t bytes = write(tohost_fd, p, offsetof(packet,data) + data_size);
71 if(bytes != offsetof(packet,data) + data_size)
72 {
73 const char* error = (ssize_t)bytes == -1 ? strerror(errno) : "not all bytes sent";
74 fprintf(stderr,"HTIF error: %s\n", error);
75 exit(-1);
76 }
77 }
78
79 void htif_t::nack(uint8_t nack_seqno)
80 {
81 packet p = {APP_CMD_NACK,0,nack_seqno,0};
82 send_packet(&p);
83 }
84
85 void htif_t::poll()
86 {
87 struct pollfd pfd;
88 pfd.fd = fromhost_fd;
89 pfd.events = POLLIN;
90 pfd.revents = 0;
91
92 if (::poll(&pfd, 1, 0) > 0)
93 wait_for_packet();
94 }
95
96 int htif_t::wait_for_packet()
97 {
98 while(1)
99 {
100 packet p;
101 int bytes = read(fromhost_fd,&p,sizeof(p));
102 if(bytes < (int)offsetof(packet,data))
103 {
104 const char* error = bytes == -1 ? strerror(errno) : "too few bytes read";
105 fprintf(stderr,"HTIF error: %s\n", error);
106 exit(-1);
107 }
108
109 if(p.seqno != seqno)
110 {
111 nack(p.seqno);
112 continue;
113 }
114
115 packet ackpacket = {APP_CMD_ACK,0,seqno,0};
116
117 switch(p.cmd)
118 {
119 case APP_CMD_START:
120 break;
121 case APP_CMD_STOP:
122 sim->stop();
123 break;
124 case APP_CMD_READ_MEM:
125 assert(p.data_size <= APP_MAX_DATA_SIZE/HTIF_DATA_ALIGN);
126 assert(p.addr < sim->memsz/HTIF_DATA_ALIGN);
127 assert(p.addr+p.data_size <= sim->memsz/HTIF_DATA_ALIGN);
128 ackpacket.data_size = p.data_size;
129
130 assert(HTIF_DATA_ALIGN == sizeof(uint64_t));
131 for(size_t i = 0; i < p.data_size; i++)
132 ((uint64_t*)ackpacket.data)[i] = sim->mmu->load_uint64((p.addr+i)*HTIF_DATA_ALIGN);
133 break;
134 case APP_CMD_WRITE_MEM:
135 assert(p.data_size*HTIF_DATA_ALIGN <= bytes - offsetof(packet,data));
136 assert(p.addr < sim->memsz/HTIF_DATA_ALIGN);
137 assert(p.addr+p.data_size <= sim->memsz/HTIF_DATA_ALIGN);
138
139 for(size_t i = 0; i < p.data_size; i++)
140 sim->mmu->store_uint64((p.addr+i)*HTIF_DATA_ALIGN, ((uint64_t*)p.data)[i]);
141 break;
142 case APP_CMD_READ_CONTROL_REG:
143 assert(p.addr == 16);
144 assert(p.data_size == 1);
145 ackpacket.data_size = 1;
146 memcpy(ackpacket.data,&sim->tohost,sizeof(reg_t));
147 break;
148 case APP_CMD_WRITE_CONTROL_REG:
149 assert(p.addr == 17);
150 assert(p.data_size == 1);
151 sim->tohost = 0;
152 memcpy(&sim->fromhost,p.data,sizeof(reg_t));
153 break;
154 }
155
156 send_packet(&ackpacket);
157 seqno++;
158 return p.cmd;
159 }
160 }
161