abstract regfile behind object
[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_ACK,
19 APP_CMD_NACK
20 };
21
22 #define APP_MAX_DATA_SIZE 1024U
23 #define HTIF_DATA_ALIGN 8U
24 struct packet
25 {
26 reg_t cmd : 4;
27 reg_t data_size : 12;
28 reg_t seqno : 8;
29 reg_t addr : 40;
30
31 uint64_t data[APP_MAX_DATA_SIZE/8];
32 };
33
34 htif_t::htif_t(int _tohost_fd, int _fromhost_fd)
35 : sim(NULL), tohost_fd(_tohost_fd), fromhost_fd(_fromhost_fd),
36 reset(true), seqno(1)
37 {
38 }
39
40 htif_t::~htif_t()
41 {
42 close(tohost_fd);
43 close(fromhost_fd);
44 }
45
46 void htif_t::init(sim_t* _sim)
47 {
48 sim = _sim;
49 }
50
51 void htif_t::wait_for_start()
52 {
53 while (reset)
54 wait_for_packet();
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 ssize_t bytes = read(fromhost_fd,&p,sizeof(p));
102 if(bytes < (ssize_t)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_READ_MEM:
120 assert(p.data_size <= APP_MAX_DATA_SIZE/HTIF_DATA_ALIGN);
121 assert(p.addr < sim->memsz/HTIF_DATA_ALIGN);
122 assert(p.addr+p.data_size <= sim->memsz/HTIF_DATA_ALIGN);
123 ackpacket.data_size = p.data_size;
124
125 assert(HTIF_DATA_ALIGN == sizeof(uint64_t));
126 for(size_t i = 0; i < p.data_size; i++)
127 ackpacket.data[i] = sim->mmu->load_uint64((p.addr+i)*HTIF_DATA_ALIGN);
128 break;
129 case APP_CMD_WRITE_MEM:
130 assert(p.data_size*HTIF_DATA_ALIGN <= bytes - offsetof(packet,data));
131 assert(p.addr < sim->memsz/HTIF_DATA_ALIGN);
132 assert(p.addr+p.data_size <= sim->memsz/HTIF_DATA_ALIGN);
133
134 for(size_t i = 0; i < p.data_size; i++)
135 sim->mmu->store_uint64((p.addr+i)*HTIF_DATA_ALIGN, p.data[i]);
136 break;
137 case APP_CMD_READ_CONTROL_REG:
138 assert(p.addr == 16);
139 assert(p.data_size == 1);
140 ackpacket.data_size = 1;
141 memcpy(ackpacket.data, &sim->tohost, sizeof(reg_t));
142 break;
143 case APP_CMD_WRITE_CONTROL_REG:
144 assert(p.addr == 17 || p.addr == 15);
145 assert(p.data_size == 1);
146 sim->tohost = 0;
147 if (p.addr == 17)
148 memcpy(&sim->fromhost, p.data, sizeof(reg_t));
149 else if (p.addr == 15)
150 {
151 bool next_reset = p.data[0] & 1;
152 if (!reset && next_reset)
153 sim->stop();
154 reset = next_reset;
155 }
156 break;
157 }
158
159 send_packet(&ackpacket);
160 seqno++;
161 return p.cmd;
162 }
163 }
164