Skip to content

Commit 991572f

Browse files
committedMar 3, 2015
mibuild/sim: create server.py and server_tb (Proof of concept OK with flterm)
Using a server allow us to create a virtual UART (and ethernet TAP in the future). 1) start the server 2) start flterm on the virtual serial port created by the server 3) run the simulation This will enable us to do serialboot and netboot in simulation. This will also enable prototyping ethernet for ARTIQ in simulation.
1 parent f154c2e commit 991572f

File tree

4 files changed

+313
-9
lines changed

4 files changed

+313
-9
lines changed
 
File renamed without changes.

Diff for: ‎mibuild/sim/server.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
2+
# License: BSD
3+
4+
import socket
5+
import os
6+
import pty
7+
import time
8+
import threading
9+
10+
messages= {
11+
"EXIT": 0,
12+
"ACK": 1,
13+
"ERROR": 2,
14+
"UART": 3
15+
}
16+
17+
class PacketTooLarge(Exception):
18+
pass
19+
20+
class VerilatorServer:
21+
def __init__(self, sockaddr="simsocket"):
22+
self.sockaddr = sockaddr
23+
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
24+
self._cleanup_file()
25+
self.socket.bind(self.sockaddr)
26+
self.socket.listen(1)
27+
28+
master, slave = pty.openpty()
29+
self.serial = master
30+
self.serial_name = os.ttyname(slave)
31+
32+
self.ack = False
33+
34+
self._print_banner()
35+
36+
def _print_banner(self):
37+
print("Mibuild simulation server")
38+
print("sockaddr: {}".format(self.sockaddr))
39+
print("serial: {}".format(self.serial_name))
40+
41+
def _cleanup_file(self):
42+
try:
43+
os.remove(self.sockaddr)
44+
except OSError:
45+
pass
46+
47+
def accept(self):
48+
self.conn, addr = self.socket.accept()
49+
50+
def send(self, packet):
51+
self.conn.send(packet)
52+
53+
def recv(self):
54+
maxlen = 2048
55+
packet = self.conn.recv(maxlen)
56+
if len(packet) < 1:
57+
return None
58+
if len(packet) >= maxlen:
59+
raise PacketTooLarge
60+
return packet
61+
62+
def close(self):
63+
if hasattr(self, "conn"):
64+
self.conn.shutdown(socket.SHUT_RDWR)
65+
self.conn.close()
66+
if hasattr(self, "socket"):
67+
self.socket.shutdown(socket.SHUT_RDWR)
68+
self.socket.close()
69+
self._cleanup_file()
70+
71+
# XXX proof of concept
72+
server = VerilatorServer()
73+
server.accept()
74+
print("Connection accepted")
75+
76+
def read():
77+
while True:
78+
packet = server.recv()
79+
if packet is not None:
80+
if packet[0] == messages["UART"]:
81+
c = bytes(chr(packet[1]).encode('utf-8'))
82+
os.write(server.serial, c)
83+
84+
elif packet[0] == messages["ACK"]:
85+
server.ack = True
86+
87+
def write():
88+
while True:
89+
for c in list(os.read(server.serial, 100)):
90+
packet = [messages["UART"], c]
91+
server.send(bytes(packet))
92+
while not server.ack:
93+
pass
94+
server.ack = False
95+
96+
readthread = threading.Thread(target=read, daemon=True)
97+
readthread.start()
98+
99+
writethread = threading.Thread(target=write, daemon=True)
100+
writethread.start()
101+
102+
while True:
103+
time.sleep(1)

Diff for: ‎mibuild/sim/server_tb.cpp

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
2+
// License: BSD
3+
4+
#include <time.h>
5+
6+
#include "Vdut.h"
7+
#include "verilated.h"
8+
#include "verilated_vcd_c.h"
9+
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <string.h>
13+
#include <unistd.h>
14+
#include <sys/types.h>
15+
#include <sys/select.h>
16+
#include <sys/socket.h>
17+
#include <netinet/in.h>
18+
#include <sys/un.h>
19+
#include <netdb.h>
20+
#include <pthread.h>
21+
22+
int trace = 0;
23+
24+
vluint64_t main_time = 0;
25+
double sc_time_stamp()
26+
{
27+
return main_time;
28+
}
29+
30+
Vdut* dut;
31+
VerilatedVcdC* tfp;
32+
33+
/* ios */
34+
35+
#define MAX_LEN 2048
36+
37+
enum {
38+
MESSAGE_EXIT = 0,
39+
MESSAGE_ACK,
40+
MESSAGE_ERROR,
41+
MESSAGE_UART
42+
};
43+
44+
struct sim {
45+
int socket;
46+
bool run;
47+
48+
unsigned int tick;
49+
clock_t start;
50+
clock_t end;
51+
float speed;
52+
53+
char txbuffer[MAX_LEN];
54+
char rxbuffer[MAX_LEN];
55+
56+
char rx_serial_stb;
57+
char rx_serial_data;
58+
char rx_serial_presented;
59+
};
60+
61+
int sim_connect(struct sim *s, const char *sockaddr)
62+
{
63+
struct sockaddr_un addr;
64+
65+
s->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
66+
if(s->socket < 0) {
67+
return -1;
68+
}
69+
70+
addr.sun_family = AF_UNIX;
71+
strcpy(addr.sun_path, sockaddr);
72+
if(connect(s->socket, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
73+
close(s->socket);
74+
return -1;
75+
}
76+
77+
return 0;
78+
}
79+
80+
int sim_send(struct sim *s, char *buffer, int len)
81+
{
82+
send(s->socket, s->txbuffer, len, 0);
83+
return 0;
84+
}
85+
86+
void sim_receive_process(struct sim *s, char * buffer, int len) {
87+
int i;
88+
switch(buffer[0]) {
89+
case MESSAGE_EXIT:
90+
s->run = false;
91+
break;
92+
case MESSAGE_UART:
93+
i = 0;
94+
for(i=0; i<len-1; i++) {
95+
s->rx_serial_stb = 1;
96+
s->rx_serial_data = buffer[i+1];
97+
while (s->rx_serial_presented == 0);
98+
s->rx_serial_presented = 0;
99+
}
100+
s->rx_serial_stb = 0;
101+
break;
102+
default:
103+
break;
104+
}
105+
}
106+
107+
void *sim_receive(void *s_void)
108+
{
109+
struct sim *s = (sim *) s_void;
110+
int rxlen;
111+
while(1)
112+
{
113+
rxlen = recv(s->socket, s->rxbuffer, MAX_LEN, 0);
114+
if (rxlen > 0)
115+
sim_receive_process(s, s->rxbuffer, rxlen);
116+
s->txbuffer[0] = MESSAGE_ACK;
117+
sim_send(s, s->txbuffer, 1);
118+
}
119+
}
120+
121+
void sim_destroy(struct sim *s)
122+
{
123+
close(s->socket);
124+
free(s);
125+
}
126+
127+
int console_service(struct sim *s)
128+
{
129+
/* fpga --> console */
130+
SERIAL_SOURCE_ACK = 1;
131+
if(SERIAL_SOURCE_STB == 1) {
132+
s->txbuffer[0] = MESSAGE_UART;
133+
s->txbuffer[1] = SERIAL_SOURCE_DATA;
134+
sim_send(s, s->txbuffer, 2);
135+
}
136+
137+
/* console --> fpga */
138+
SERIAL_SINK_STB = s->rx_serial_stb;
139+
SERIAL_SINK_DATA = s->rx_serial_data;
140+
if (s->rx_serial_stb)
141+
s->rx_serial_presented = 1;
142+
143+
return 0;
144+
}
145+
146+
void sim_tick(struct sim *s)
147+
{
148+
SYS_CLK = s->tick%2;
149+
dut->eval();
150+
if (trace)
151+
tfp->dump(s->tick);
152+
s->tick++;
153+
s->end = clock();
154+
}
155+
156+
void sim_init(struct sim *s)
157+
{
158+
int i;
159+
s->tick = 0;
160+
#ifdef SYS_RST
161+
SYS_RST = 1;
162+
SYS_CLK = 0;
163+
for (i=0; i<8; i++)
164+
sim_tick(s);
165+
SYS_RST = 0;
166+
#endif
167+
s->start = clock();
168+
}
169+
170+
int main(int argc, char **argv, char **env)
171+
{
172+
Verilated::commandArgs(argc, argv);
173+
dut = new Vdut;
174+
175+
Verilated::traceEverOn(true);
176+
tfp = new VerilatedVcdC;
177+
dut->trace(tfp, 99);
178+
tfp->open("dut.vcd");
179+
180+
struct sim s;
181+
sim_init(&s);
182+
sim_connect(&s, "../../migen/mibuild/sim/simsocket"); // XXX use args
Has a conversation. Original line has a conversation.
183+
184+
pthread_t sim_receive_thread;
185+
186+
pthread_create(&sim_receive_thread, NULL, sim_receive, &s);
187+
188+
s.run = true;
189+
while(s.run) {
190+
sim_tick(&s);
191+
if (SYS_CLK) {
192+
if (console_service(&s) != 0)
193+
s.run = false;
194+
}
195+
}
196+
197+
tfp->close();
198+
pthread_cancel(sim_receive_thread);
199+
sim_destroy(&s);
200+
201+
exit(0);
202+
}

Diff for: ‎mibuild/sim/verilator.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -49,24 +49,23 @@ def io_name(ressource, subsignal=None):
4949
f.close()
5050
tools.write_to_file("dut_tb.cpp", content)
5151

52-
def _build_sim(platform, build_name, include_paths, template_file, trace, verbose):
52+
def _build_sim(platform, build_name, include_paths, sim_path, dut, verbose):
5353
include = ""
5454
for path in include_paths:
5555
include += "-I"+path+" "
5656

5757
build_script_contents = """# Autogenerated by mibuild
5858
rm -rf obj_dir/
59-
verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp {trace} {include}
59+
verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp -LDFLAGS "-lpthread" -trace {include}
6060
make -j -C obj_dir/ -f Vdut.mk Vdut
6161
6262
""".format(
6363
disable_warnings="-Wno-fatal",
64-
trace="-trace" if trace else "",
6564
include=include)
6665
build_script_file = "build_" + build_name + ".sh"
6766
tools.write_to_file(build_script_file, build_script_contents, force_unix=True)
6867

69-
_build_tb(platform, os.path.join("../", template_file)) # XXX
68+
_build_tb(platform, os.path.join("../", sim_path, dut + ".cpp")) # XXX
7069
if verbose:
7170
r = subprocess.call(["bash", build_script_file])
7271
else:
@@ -84,10 +83,10 @@ def _run_sim(build_name):
8483
raise OSError("Subprocess failed")
8584

8685
class VerilatorPlatform(GenericPlatform):
87-
# XXX fix template_file
88-
def build(self, soc, build_dir="build", build_name="top", run=True, trace=True,
89-
template_file="../migen/mibuild/sim/dut_tb.cpp",
90-
verbose=False):
86+
# XXX fir sim_path
87+
def build(self, soc, build_dir="build", build_name="top",
88+
sim_path="../migen/mibuild/sim/", dut="console_tb",
89+
run=True, verbose=False):
9190
tools.mkdir_noerror(build_dir)
9291
os.chdir(build_dir)
9392

@@ -106,7 +105,7 @@ def build(self, soc, build_dir="build", build_name="top", run=True, trace=True,
106105
if path not in include_paths:
107106
include_paths.append(path)
108107
include_paths += self.verilog_include_paths
109-
_build_sim(self, build_name, include_paths, template_file, trace, verbose)
108+
_build_sim(self, build_name, include_paths, sim_path, dut, verbose)
110109

111110
if run:
112111
_run_sim(build_name)

0 commit comments

Comments
 (0)
Please sign in to comment.