Don't spin on the remote bitbang reads
[riscv-isa-sim.git] / remote_bitbang.cc
1 #include <arpa/inet.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7
8 #include <algorithm>
9 #include <cassert>
10 #include <cstdio>
11
12 #include "remote_bitbang.h"
13
14 #if 1
15 # define D(x) x
16 #else
17 # define D(x)
18 #endif
19
20 /////////// remote_bitbang_t
21
22 remote_bitbang_t::remote_bitbang_t(uint16_t port, jtag_dtm_t *tap) :
23 tap(tap),
24 socket_fd(0),
25 client_fd(0),
26 recv_start(0),
27 recv_end(0)
28 {
29 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
30 if (socket_fd == -1) {
31 fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
32 strerror(errno), errno);
33 abort();
34 }
35
36 fcntl(socket_fd, F_SETFL, O_NONBLOCK);
37 int reuseaddr = 1;
38 if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
39 sizeof(int)) == -1) {
40 fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
41 strerror(errno), errno);
42 abort();
43 }
44
45 struct sockaddr_in addr;
46 memset(&addr, 0, sizeof(addr));
47 addr.sin_family = AF_INET;
48 addr.sin_addr.s_addr = INADDR_ANY;
49 addr.sin_port = htons(port);
50
51 if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
52 fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
53 strerror(errno), errno);
54 abort();
55 }
56
57 if (listen(socket_fd, 1) == -1) {
58 fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
59 strerror(errno), errno);
60 abort();
61 }
62
63 socklen_t addrlen = sizeof(addr);
64 if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
65 fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
66 strerror(errno), errno);
67 abort();
68 }
69
70 printf("Listening for remote bitbang connection on port %d.\n",
71 ntohs(addr.sin_port));
72 fflush(stdout);
73 }
74
75 void remote_bitbang_t::accept()
76 {
77 client_fd = ::accept(socket_fd, NULL, NULL);
78 if (client_fd == -1) {
79 if (errno == EAGAIN) {
80 // No client waiting to connect right now.
81 } else {
82 fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
83 errno);
84 abort();
85 }
86 } else {
87 fcntl(client_fd, F_SETFL, O_NONBLOCK);
88 }
89 }
90
91 void remote_bitbang_t::tick()
92 {
93 if (client_fd > 0) {
94 execute_commands();
95 } else {
96 this->accept();
97 }
98 }
99
100 void remote_bitbang_t::execute_commands()
101 {
102 static char send_buf[buf_size];
103 unsigned total_processed = 0;
104 bool quit = false;
105 bool in_rti = tap->state() == RUN_TEST_IDLE;
106 bool entered_rti = false;
107 while (1) {
108 if (recv_start < recv_end) {
109 unsigned send_offset = 0;
110 while (recv_start < recv_end) {
111 uint8_t command = recv_buf[recv_start];
112
113 switch (command) {
114 case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
115 case 'b': /* fprintf(stderr, "_______\n"); */ break;
116 case 'r': tap->reset(); break;
117 case '0': tap->set_pins(0, 0, 0); break;
118 case '1': tap->set_pins(0, 0, 1); break;
119 case '2': tap->set_pins(0, 1, 0); break;
120 case '3': tap->set_pins(0, 1, 1); break;
121 case '4': tap->set_pins(1, 0, 0); break;
122 case '5': tap->set_pins(1, 0, 1); break;
123 case '6': tap->set_pins(1, 1, 0); break;
124 case '7': tap->set_pins(1, 1, 1); break;
125 case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
126 case 'Q': quit = true; break;
127 default:
128 fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
129 command);
130 }
131 recv_start++;
132 total_processed++;
133 if (!in_rti && tap->state() == RUN_TEST_IDLE) {
134 entered_rti = true;
135 break;
136 }
137 in_rti = false;
138 }
139 unsigned sent = 0;
140 while (sent < send_offset) {
141 ssize_t bytes = write(client_fd, send_buf + sent, send_offset);
142 if (bytes == -1) {
143 fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
144 abort();
145 }
146 sent += bytes;
147 }
148 }
149
150 if (total_processed > buf_size || quit || entered_rti) {
151 // Don't go forever, because that could starve the main simulation.
152 break;
153 }
154
155 recv_start = 0;
156 recv_end = read(client_fd, recv_buf, buf_size);
157
158 if (recv_end == -1) {
159 if (errno == EAGAIN) {
160 // We'll try again the next call.
161 } else {
162 fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
163 strerror(errno), errno);
164 abort();
165 }
166 }
167 if (recv_end == 0 || quit) {
168 // The remote disconnected.
169 close(client_fd);
170 client_fd = 0;
171 break;
172 }
173 }
174 }