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