OpenOCD does a dmi read and gets dummy value back.
[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
62 void remote_bitbang_t::accept()
63 {
64 client_fd = ::accept(socket_fd, NULL, NULL);
65 if (client_fd == -1) {
66 if (errno == EAGAIN) {
67 // No client waiting to connect right now.
68 } else {
69 fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
70 errno);
71 abort();
72 }
73 } else {
74 fcntl(client_fd, F_SETFL, O_NONBLOCK);
75 }
76 }
77
78 void remote_bitbang_t::tick()
79 {
80 if (client_fd > 0) {
81 execute_commands();
82 } else {
83 this->accept();
84 }
85 }
86
87 void remote_bitbang_t::execute_commands()
88 {
89 const unsigned buf_size = 64 * 1024;
90 char recv_buf[buf_size];
91 char send_buf[buf_size];
92 unsigned total_received = 0;
93 ssize_t bytes = read(client_fd, recv_buf, buf_size);
94 bool quit = false;
95 while (bytes > 0) {
96 total_received += bytes;
97 unsigned send_offset = 0;
98 for (unsigned i = 0; i < bytes; i++) {
99 uint8_t command = recv_buf[i];
100
101 switch (command) {
102 case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
103 case 'b': /* fprintf(stderr, "_______\n"); */ break;
104 case 'r': tap->reset(); break;
105 case '0': tap->set_pins(0, 0, 0); break;
106 case '1': tap->set_pins(0, 0, 1); break;
107 case '2': tap->set_pins(0, 1, 0); break;
108 case '3': tap->set_pins(0, 1, 1); break;
109 case '4': tap->set_pins(1, 0, 0); break;
110 case '5': tap->set_pins(1, 0, 1); break;
111 case '6': tap->set_pins(1, 1, 0); break;
112 case '7': tap->set_pins(1, 1, 1); break;
113 case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
114 case 'Q': quit = true; break;
115 default:
116 fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
117 command);
118 }
119 }
120 unsigned sent = 0;
121 while (sent < send_offset) {
122 bytes = write(client_fd, send_buf + sent, send_offset);
123 if (bytes == -1) {
124 fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
125 abort();
126 }
127 sent += bytes;
128 }
129
130 if (total_received > buf_size || quit) {
131 // Don't go forever, because that could starve the main simulation.
132 break;
133 }
134 bytes = read(client_fd, recv_buf, buf_size);
135 }
136
137 if (bytes == -1) {
138 if (errno == EAGAIN) {
139 // We'll try again the next call.
140 } else {
141 fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
142 strerror(errno), errno);
143 abort();
144 }
145 }
146 if (bytes == 0 || quit) {
147 // The remote disconnected.
148 close(client_fd);
149 client_fd = 0;
150 }
151 }