switchboard-hw 0.3.0__cp314-cp314-macosx_10_15_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _switchboard.cpython-314-darwin.so +0 -0
- switchboard/__init__.py +24 -0
- switchboard/ams.py +668 -0
- switchboard/apb.py +278 -0
- switchboard/autowrap.py +1000 -0
- switchboard/axi.py +571 -0
- switchboard/axil.py +348 -0
- switchboard/bitvector.py +112 -0
- switchboard/cmdline.py +142 -0
- switchboard/cpp/Makefile +13 -0
- switchboard/cpp/bitutil.h +39 -0
- switchboard/cpp/pagemap.h +91 -0
- switchboard/cpp/pciedev.h +86 -0
- switchboard/cpp/router.cc +89 -0
- switchboard/cpp/spsc_queue.h +267 -0
- switchboard/cpp/switchboard.hpp +257 -0
- switchboard/cpp/switchboard_pcie.hpp +234 -0
- switchboard/cpp/switchboard_tlm.hpp +98 -0
- switchboard/cpp/umilib.h +144 -0
- switchboard/cpp/umilib.hpp +113 -0
- switchboard/cpp/umisb.hpp +364 -0
- switchboard/cpp/xyce.hpp +90 -0
- switchboard/deps/__init__.py +0 -0
- switchboard/deps/verilog_axi.py +23 -0
- switchboard/dpi/__init__.py +0 -0
- switchboard/dpi/switchboard_dpi.cc +119 -0
- switchboard/dpi/switchboard_dpi.py +13 -0
- switchboard/dpi/xyce_dpi.cc +43 -0
- switchboard/gpio.py +108 -0
- switchboard/icarus.py +85 -0
- switchboard/loopback.py +157 -0
- switchboard/network.py +714 -0
- switchboard/pytest_plugin.py +11 -0
- switchboard/sbdesign.py +55 -0
- switchboard/sbdut.py +744 -0
- switchboard/sbtcp.py +345 -0
- switchboard/sc/__init__.py +0 -0
- switchboard/sc/morty/__init__.py +0 -0
- switchboard/sc/morty/uniquify.py +67 -0
- switchboard/sc/sed/__init__.py +0 -0
- switchboard/sc/sed/sed_remove.py +47 -0
- switchboard/sc/standalone_netlist_flow.py +25 -0
- switchboard/switchboard.py +53 -0
- switchboard/test_util.py +46 -0
- switchboard/uart_xactor.py +66 -0
- switchboard/umi.py +793 -0
- switchboard/util.py +131 -0
- switchboard/verilator/__init__.py +0 -0
- switchboard/verilator/config.vlt +13 -0
- switchboard/verilator/testbench.cc +143 -0
- switchboard/verilator/verilator.py +13 -0
- switchboard/verilator_run.py +31 -0
- switchboard/verilog/__init__.py +0 -0
- switchboard/verilog/common/__init__.py +0 -0
- switchboard/verilog/common/common.py +26 -0
- switchboard/verilog/common/switchboard.vh +429 -0
- switchboard/verilog/common/uart_xactor.sv +247 -0
- switchboard/verilog/common/umi_gpio.v +236 -0
- switchboard/verilog/fpga/__init__.py +0 -0
- switchboard/verilog/fpga/axi_reader.sv +82 -0
- switchboard/verilog/fpga/axi_writer.sv +111 -0
- switchboard/verilog/fpga/config_registers.sv +249 -0
- switchboard/verilog/fpga/fpga.py +21 -0
- switchboard/verilog/fpga/include/sb_queue_regmap.vh +21 -0
- switchboard/verilog/fpga/include/spsc_queue.vh +7 -0
- switchboard/verilog/fpga/memory_fault.sv +40 -0
- switchboard/verilog/fpga/sb_fpga_queues.sv +416 -0
- switchboard/verilog/fpga/sb_rx_fpga.sv +303 -0
- switchboard/verilog/fpga/sb_tx_fpga.sv +294 -0
- switchboard/verilog/fpga/umi_fpga_queues.sv +146 -0
- switchboard/verilog/sim/__init__.py +0 -0
- switchboard/verilog/sim/auto_stop_sim.sv +25 -0
- switchboard/verilog/sim/perf_meas_sim.sv +97 -0
- switchboard/verilog/sim/queue_to_sb_sim.sv +176 -0
- switchboard/verilog/sim/queue_to_umi_sim.sv +66 -0
- switchboard/verilog/sim/sb_apb_m.sv +146 -0
- switchboard/verilog/sim/sb_axi_m.sv +199 -0
- switchboard/verilog/sim/sb_axil_m.sv +180 -0
- switchboard/verilog/sim/sb_axil_s.sv +180 -0
- switchboard/verilog/sim/sb_clk_gen.sv +89 -0
- switchboard/verilog/sim/sb_jtag_rbb_sim.sv +148 -0
- switchboard/verilog/sim/sb_rx_sim.sv +55 -0
- switchboard/verilog/sim/sb_to_queue_sim.sv +196 -0
- switchboard/verilog/sim/sb_tx_sim.sv +55 -0
- switchboard/verilog/sim/switchboard_sim.py +49 -0
- switchboard/verilog/sim/umi_rx_sim.sv +61 -0
- switchboard/verilog/sim/umi_to_queue_sim.sv +66 -0
- switchboard/verilog/sim/umi_tx_sim.sv +61 -0
- switchboard/verilog/sim/xyce_intf.sv +67 -0
- switchboard/vpi/switchboard_vpi.cc +431 -0
- switchboard/vpi/xyce_vpi.cc +200 -0
- switchboard/warn.py +14 -0
- switchboard/xyce.py +27 -0
- switchboard_hw-0.3.0.dist-info/METADATA +303 -0
- switchboard_hw-0.3.0.dist-info/RECORD +99 -0
- switchboard_hw-0.3.0.dist-info/WHEEL +6 -0
- switchboard_hw-0.3.0.dist-info/entry_points.txt +6 -0
- switchboard_hw-0.3.0.dist-info/licenses/LICENSE +190 -0
- switchboard_hw-0.3.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// Copyright (c) 2024 Zero ASIC Corporation
|
|
2
|
+
// This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
#ifndef __SWITCHBOARD_HPP__
|
|
5
|
+
#define __SWITCHBOARD_HPP__
|
|
6
|
+
|
|
7
|
+
#include <array>
|
|
8
|
+
#include <chrono>
|
|
9
|
+
#include <cstdio>
|
|
10
|
+
#include <stdexcept>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <thread>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
#include "spsc_queue.h"
|
|
16
|
+
|
|
17
|
+
// packet type
|
|
18
|
+
// TODO: make size runtime programmable
|
|
19
|
+
#define SB_DATA_SIZE 52
|
|
20
|
+
struct sb_packet {
|
|
21
|
+
uint32_t destination;
|
|
22
|
+
union {
|
|
23
|
+
struct {
|
|
24
|
+
unsigned int last : 1;
|
|
25
|
+
};
|
|
26
|
+
uint32_t flags;
|
|
27
|
+
};
|
|
28
|
+
uint8_t data[SB_DATA_SIZE];
|
|
29
|
+
} __attribute__((packed));
|
|
30
|
+
|
|
31
|
+
static inline long max_rate_timestamp_us() {
|
|
32
|
+
return std::chrono::duration_cast<std::chrono::microseconds>(
|
|
33
|
+
std::chrono::high_resolution_clock::now().time_since_epoch())
|
|
34
|
+
.count();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static inline void max_rate_tick(long& last_us, long min_period_us) {
|
|
38
|
+
if (min_period_us > 0) {
|
|
39
|
+
// measure the time now
|
|
40
|
+
|
|
41
|
+
long now_us = max_rate_timestamp_us();
|
|
42
|
+
|
|
43
|
+
// sleep if needed
|
|
44
|
+
|
|
45
|
+
if (last_us != -1) {
|
|
46
|
+
long dt_us = now_us - last_us;
|
|
47
|
+
|
|
48
|
+
if (dt_us < min_period_us) {
|
|
49
|
+
long sleep_us = min_period_us - dt_us;
|
|
50
|
+
std::this_thread::sleep_for(std::chrono::microseconds(sleep_us));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// update the time stamp. it is not enough to set last_us = now_us,
|
|
55
|
+
// due to the sleep_for invocation
|
|
56
|
+
|
|
57
|
+
last_us = max_rate_timestamp_us();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static inline void start_delay(double value) {
|
|
62
|
+
if (value > 0) {
|
|
63
|
+
int value_us = (value * 1.0e6) + 0.5;
|
|
64
|
+
std::this_thread::sleep_for(std::chrono::microseconds(value_us));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class SB_base {
|
|
69
|
+
public:
|
|
70
|
+
SB_base() : m_active(false), m_q(NULL) {}
|
|
71
|
+
|
|
72
|
+
virtual ~SB_base() {
|
|
73
|
+
deinit();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
void init(std::string uri, size_t capacity = 0, bool fresh = false, double max_rate = -1) {
|
|
77
|
+
init(uri.c_str(), capacity, fresh, max_rate);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
void init(const char* uri, size_t capacity = 0, bool fresh = false, double max_rate = -1) {
|
|
81
|
+
// Default to one page of capacity
|
|
82
|
+
if (capacity == 0) {
|
|
83
|
+
capacity = spsc_capacity(getpagesize());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// delete old queue if "fresh" is set
|
|
87
|
+
if (fresh) {
|
|
88
|
+
spsc_remove_shmfile(uri);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
m_q = spsc_open(uri, capacity);
|
|
92
|
+
m_active = true;
|
|
93
|
+
m_timestamp_us = -1;
|
|
94
|
+
|
|
95
|
+
set_max_rate(max_rate);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
void deinit(void) {
|
|
99
|
+
spsc_close(m_q);
|
|
100
|
+
m_active = false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
bool is_active() {
|
|
104
|
+
return m_active;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
int mlock(void) {
|
|
108
|
+
check_active();
|
|
109
|
+
assert(m_q);
|
|
110
|
+
return spsc_mlock(m_q);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
int get_capacity(void) {
|
|
114
|
+
check_active();
|
|
115
|
+
return m_q->capacity;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
void* get_shm_handle(void) {
|
|
119
|
+
check_active();
|
|
120
|
+
return m_q->shm;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void set_max_rate(double max_rate) {
|
|
124
|
+
if (max_rate > 0) {
|
|
125
|
+
m_min_period_us = (1.0e6 / max_rate) + 0.5;
|
|
126
|
+
} else {
|
|
127
|
+
m_min_period_us = -1;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
protected:
|
|
132
|
+
void check_active(void) {
|
|
133
|
+
if (!m_active) {
|
|
134
|
+
throw std::runtime_error("Using an uninitialized SB queue!");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
bool m_auto_deinit;
|
|
139
|
+
bool m_active;
|
|
140
|
+
long m_min_period_us;
|
|
141
|
+
long m_timestamp_us;
|
|
142
|
+
spsc_queue* m_q;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
class SBTX : public SB_base {
|
|
146
|
+
public:
|
|
147
|
+
SBTX() {}
|
|
148
|
+
|
|
149
|
+
bool send(sb_packet& p) {
|
|
150
|
+
check_active();
|
|
151
|
+
max_rate_tick(m_timestamp_us, m_min_period_us);
|
|
152
|
+
return spsc_send(m_q, &p, sizeof p);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
void send_blocking(sb_packet& p) {
|
|
156
|
+
bool success = false;
|
|
157
|
+
|
|
158
|
+
while (!success) {
|
|
159
|
+
success = send(p);
|
|
160
|
+
|
|
161
|
+
if ((!success) && (m_min_period_us == -1)) {
|
|
162
|
+
// maintain old behavior if max_rate isn't specified,
|
|
163
|
+
// i.e. yield on every iteration that the send isn't
|
|
164
|
+
// successful
|
|
165
|
+
std::this_thread::yield();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
bool all_read() {
|
|
171
|
+
check_active();
|
|
172
|
+
return spsc_size(m_q) == 0;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
class SBRX : public SB_base {
|
|
177
|
+
public:
|
|
178
|
+
SBRX() {}
|
|
179
|
+
|
|
180
|
+
bool recv(sb_packet& p) {
|
|
181
|
+
check_active();
|
|
182
|
+
max_rate_tick(m_timestamp_us, m_min_period_us);
|
|
183
|
+
return spsc_recv(m_q, &p, sizeof p);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
bool recv() {
|
|
187
|
+
check_active();
|
|
188
|
+
sb_packet dummy_p;
|
|
189
|
+
max_rate_tick(m_timestamp_us, m_min_period_us);
|
|
190
|
+
return spsc_recv(m_q, &dummy_p, sizeof dummy_p);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
void recv_blocking(sb_packet& p) {
|
|
194
|
+
bool success = false;
|
|
195
|
+
|
|
196
|
+
while (!success) {
|
|
197
|
+
success = recv(p);
|
|
198
|
+
|
|
199
|
+
if ((!success) && (m_min_period_us == -1)) {
|
|
200
|
+
// maintain old behavior if max_rate isn't specified,
|
|
201
|
+
// i.e. yield on every iteration that the send isn't
|
|
202
|
+
// successful
|
|
203
|
+
std::this_thread::yield();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
bool recv_peek(sb_packet& p) {
|
|
209
|
+
check_active();
|
|
210
|
+
max_rate_tick(m_timestamp_us, m_min_period_us);
|
|
211
|
+
return spsc_recv_peek(m_q, &p, sizeof p);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
static inline void delete_shared_queue(const char* name) {
|
|
216
|
+
spsc_remove_shmfile(name);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static inline void delete_shared_queue(std::string name) {
|
|
220
|
+
delete_shared_queue(name.c_str());
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static inline std::string sb_packet_to_str(sb_packet p, ssize_t nbytes = -1) {
|
|
224
|
+
// determine how many bytes to print
|
|
225
|
+
size_t max_idx;
|
|
226
|
+
if (nbytes < 0) {
|
|
227
|
+
max_idx = sizeof(p.data);
|
|
228
|
+
} else {
|
|
229
|
+
max_idx = nbytes;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// used for convenient formatting with sprintf
|
|
233
|
+
char buf[128];
|
|
234
|
+
|
|
235
|
+
// build up return value
|
|
236
|
+
std::string retval;
|
|
237
|
+
retval = "";
|
|
238
|
+
|
|
239
|
+
// format control information
|
|
240
|
+
sprintf(buf, "dest: %08x, last: %d, data: {", p.destination, p.last);
|
|
241
|
+
retval += buf;
|
|
242
|
+
|
|
243
|
+
// format data
|
|
244
|
+
for (size_t i = 0; i < max_idx; i++) {
|
|
245
|
+
sprintf(buf, "%02x", p.data[i]);
|
|
246
|
+
retval += buf;
|
|
247
|
+
if (i != (max_idx - 1)) {
|
|
248
|
+
retval += ", ";
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
retval += "}";
|
|
253
|
+
|
|
254
|
+
return retval;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#endif // __SWITCHBOARD_HPP__
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// Switchboard FPGA/PCIe transactor driver
|
|
2
|
+
|
|
3
|
+
// Copyright (c) 2024 Zero ASIC Corporation
|
|
4
|
+
// This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
5
|
+
|
|
6
|
+
#ifndef __SWITCHBOARD_PCIE_HPP__
|
|
7
|
+
#define __SWITCHBOARD_PCIE_HPP__
|
|
8
|
+
|
|
9
|
+
#include <array>
|
|
10
|
+
#include <cstdio>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <thread>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
#include "pagemap.h"
|
|
16
|
+
#include "pciedev.h"
|
|
17
|
+
#include "spsc_queue.h"
|
|
18
|
+
#include "switchboard.hpp"
|
|
19
|
+
|
|
20
|
+
#undef D
|
|
21
|
+
#define D(x)
|
|
22
|
+
|
|
23
|
+
#define REG_ID 0x000
|
|
24
|
+
#define REG_ID_FPGA 0x1234
|
|
25
|
+
|
|
26
|
+
#define REG_CAP 0x004
|
|
27
|
+
|
|
28
|
+
#define REG_ENABLE 0x100
|
|
29
|
+
#define REG_RESET 0x104
|
|
30
|
+
#define REG_STATUS 0x108
|
|
31
|
+
#define REG_QUEUE_ADDRESS_LO 0x10c
|
|
32
|
+
#define REG_QUEUE_ADDRESS_HI 0x110
|
|
33
|
+
#define REG_QUEUE_CAPACITY 0x114
|
|
34
|
+
|
|
35
|
+
#define REG_QUEUE_ADDR_SIZE 0x100 // size of addr space dedicated to each queue
|
|
36
|
+
|
|
37
|
+
// Map enough space to configure 256 queues + global config.
|
|
38
|
+
#define PCIE_BAR_MAP_SIZE (REG_QUEUE_ADDR_SIZE * 256 + REG_ENABLE)
|
|
39
|
+
|
|
40
|
+
// Max nr of retries when resetting or disabling queue's.
|
|
41
|
+
#define MAX_RETRY 3
|
|
42
|
+
|
|
43
|
+
template <typename T> static inline void sb_pcie_deinit(T* s) {
|
|
44
|
+
|
|
45
|
+
// Needs to be done in reverse order.
|
|
46
|
+
s->deinit_dev();
|
|
47
|
+
s->deinit_host();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class SB_pcie {
|
|
51
|
+
public:
|
|
52
|
+
SB_pcie(int queue_id) : m_queue_id(queue_id), m_map(NULL), m_addr(0) {}
|
|
53
|
+
|
|
54
|
+
~SB_pcie() {
|
|
55
|
+
sb_pcie_deinit(this);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
virtual bool init_host(const char* uri, const char* bdf, int bar_num, void* handle) {
|
|
59
|
+
m_addr = pagemap_virt_to_phys(handle);
|
|
60
|
+
m_map = (char*)pcie_bar_map(bdf, bar_num, 0, PCIE_BAR_MAP_SIZE);
|
|
61
|
+
if (m_map == MAP_FAILED) {
|
|
62
|
+
m_map = NULL;
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
virtual void deinit_host(void) {
|
|
69
|
+
if (m_map) {
|
|
70
|
+
pcie_bar_unmap(m_map, PCIE_BAR_MAP_SIZE);
|
|
71
|
+
m_map = NULL;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
bool init_dev(int capacity) {
|
|
76
|
+
int qoffset = m_queue_id * REG_QUEUE_ADDR_SIZE;
|
|
77
|
+
int reset_retry = 0;
|
|
78
|
+
uint32_t r;
|
|
79
|
+
|
|
80
|
+
r = dev_read32(REG_ID);
|
|
81
|
+
D(printf("SB pcie ID=%x\n", r));
|
|
82
|
+
if (r >> 16 != REG_ID_FPGA) {
|
|
83
|
+
printf("%s: Incompatible REG_ID=%x\n", __func__, r);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
r = dev_read32(REG_CAP);
|
|
88
|
+
D(printf("SB pcie CAP=%x\n", r));
|
|
89
|
+
|
|
90
|
+
// Reset the device.
|
|
91
|
+
dev_write32(qoffset + REG_RESET, 0x1);
|
|
92
|
+
D(printf("Read reset state\n"));
|
|
93
|
+
while (dev_read32(qoffset + REG_STATUS) != 0x1) {
|
|
94
|
+
if (reset_retry++ >= MAX_RETRY) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
usleep(100 * 1000);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
dev_write32(qoffset + REG_QUEUE_ADDRESS_LO, m_addr);
|
|
101
|
+
dev_write32(qoffset + REG_QUEUE_ADDRESS_HI, m_addr >> 32);
|
|
102
|
+
D(printf("SB QUEUE_ADDR=%lx\n", m_addr));
|
|
103
|
+
|
|
104
|
+
dev_write32(qoffset + REG_QUEUE_CAPACITY, capacity);
|
|
105
|
+
D(printf("SB CAPACITY=%d\n", capacity));
|
|
106
|
+
|
|
107
|
+
dev_write32_strong(qoffset + REG_ENABLE, 0x1);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
void deinit_dev() {
|
|
112
|
+
int disable_retry = 0;
|
|
113
|
+
|
|
114
|
+
if (!m_map) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
int qoffset = m_queue_id * REG_QUEUE_ADDR_SIZE;
|
|
118
|
+
|
|
119
|
+
// Must disable queue and wait for it to quiesce before unmapping
|
|
120
|
+
// queue shared memory, otherwise FPGA may read from/write to memory
|
|
121
|
+
// that gets reallocated to another process.
|
|
122
|
+
dev_write32_strong(qoffset + REG_ENABLE, 0x0);
|
|
123
|
+
while (dev_read32(qoffset + REG_STATUS) != 0x1) {
|
|
124
|
+
if (disable_retry++ >= MAX_RETRY) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
usleep(100 * 1000);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
virtual uint32_t dev_read32(uint64_t offset) {
|
|
132
|
+
assert(m_map);
|
|
133
|
+
assert(offset <= PCIE_BAR_MAP_SIZE - 4);
|
|
134
|
+
return pcie_read32(m_map + offset);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
virtual void dev_write32(uint64_t offset, uint32_t v) {
|
|
138
|
+
assert(m_map);
|
|
139
|
+
assert(offset <= PCIE_BAR_MAP_SIZE - 4);
|
|
140
|
+
pcie_write32(m_map + offset, v);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
virtual void dev_write32_strong(uint64_t offset, uint32_t v) {
|
|
144
|
+
assert(m_map);
|
|
145
|
+
assert(offset <= PCIE_BAR_MAP_SIZE - 4);
|
|
146
|
+
pcie_write32_strong(m_map + offset, v);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
protected:
|
|
150
|
+
// Queue index.
|
|
151
|
+
int m_queue_id;
|
|
152
|
+
|
|
153
|
+
// m_map holds a pointer to a mapped memory area that can be
|
|
154
|
+
// used for register accesses. Not all implementations will use it.
|
|
155
|
+
char* m_map;
|
|
156
|
+
|
|
157
|
+
// m_addr holds an address to the SPSC queue's SHM area. For some
|
|
158
|
+
// implementations this will simply be a user-space virtual address
|
|
159
|
+
// and for others it may be a physical address for HW DMA implementations
|
|
160
|
+
// to access.
|
|
161
|
+
uint64_t m_addr;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
static inline bool sb_init_queue(SB_base* s, const char* uri) {
|
|
165
|
+
int capacity;
|
|
166
|
+
|
|
167
|
+
// Create queue's that fit into a single page.
|
|
168
|
+
capacity = spsc_capacity(getpagesize());
|
|
169
|
+
s->init(uri, capacity);
|
|
170
|
+
|
|
171
|
+
// Lock pages into RAM (avoid ondemand allocation or swapping).
|
|
172
|
+
if (s->mlock()) {
|
|
173
|
+
perror("mlock");
|
|
174
|
+
s->deinit();
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
template <typename T>
|
|
181
|
+
static inline bool sb_pcie_init(T* s, const char* uri, const char* bdf, int bar_num) {
|
|
182
|
+
sb_init_queue(s, uri);
|
|
183
|
+
|
|
184
|
+
if (!s->init_host(uri, bdf, bar_num, s->get_shm_handle())) {
|
|
185
|
+
s->deinit();
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!s->init_dev(s->get_capacity())) {
|
|
190
|
+
s->deinit();
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
class SBTX_pcie : public SBTX, public SB_pcie {
|
|
197
|
+
public:
|
|
198
|
+
SBTX_pcie(int queue_id) : SB_pcie(queue_id) {}
|
|
199
|
+
|
|
200
|
+
bool init(std::string uri, std::string bdf, int bar_num) {
|
|
201
|
+
return init(uri.c_str(), bdf.c_str(), bar_num);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
bool init(const char* uri, const char* bdf, int bar_num) {
|
|
205
|
+
return sb_pcie_init(this, uri, bdf, bar_num);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
void deinit(void) {
|
|
209
|
+
sb_pcie_deinit(this);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private:
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
class SBRX_pcie : public SBRX, public SB_pcie {
|
|
216
|
+
public:
|
|
217
|
+
SBRX_pcie(int queue_id) : SB_pcie(queue_id) {}
|
|
218
|
+
|
|
219
|
+
bool init(std::string uri, std::string bdf, int bar_num) {
|
|
220
|
+
return init(uri.c_str(), bdf.c_str(), bar_num);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
bool init(const char* uri, const char* bdf, int bar_num) {
|
|
224
|
+
return sb_pcie_init(this, uri, bdf, bar_num);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
void deinit(void) {
|
|
228
|
+
sb_pcie_deinit(this);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private:
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
#endif // __SWITCHBOARD_PCIE_HPP__
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Switchboard TLM transactor driver
|
|
2
|
+
|
|
3
|
+
// Copyright (c) 2024 Zero ASIC Corporation
|
|
4
|
+
// This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
5
|
+
|
|
6
|
+
#ifndef __SWITCHBOARD_TLM_HPP__
|
|
7
|
+
#define __SWITCHBOARD_TLM_HPP__
|
|
8
|
+
|
|
9
|
+
#include <array>
|
|
10
|
+
#include <cstdio>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <thread>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
#include "spsc_queue.h"
|
|
16
|
+
#include "switchboard.hpp"
|
|
17
|
+
#include "switchboard_pcie.hpp"
|
|
18
|
+
|
|
19
|
+
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
|
20
|
+
|
|
21
|
+
#include "systemc"
|
|
22
|
+
using namespace sc_core;
|
|
23
|
+
using namespace sc_dt;
|
|
24
|
+
using namespace std;
|
|
25
|
+
|
|
26
|
+
#include "tlm.h"
|
|
27
|
+
#include "tlm_utils/simple_initiator_socket.h"
|
|
28
|
+
#include "tlm_utils/simple_target_socket.h"
|
|
29
|
+
|
|
30
|
+
class SB_tlm : public SB_pcie {
|
|
31
|
+
public:
|
|
32
|
+
tlm_utils::simple_initiator_socket<SB_tlm> socket;
|
|
33
|
+
|
|
34
|
+
SB_tlm(int queue_id) : SB_pcie(queue_id) {}
|
|
35
|
+
|
|
36
|
+
bool init_host(const char* uri, const char* bdf, int bar_num, void* handle) {
|
|
37
|
+
assert(handle);
|
|
38
|
+
m_addr = (uintptr_t)handle;
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
void dev_access(tlm::tlm_command cmd, uint64_t offset, void* buf, unsigned int len) {
|
|
43
|
+
unsigned char* buf8 = (unsigned char*)buf;
|
|
44
|
+
sc_time delay = SC_ZERO_TIME;
|
|
45
|
+
tlm::tlm_generic_payload tr;
|
|
46
|
+
|
|
47
|
+
tr.set_command(cmd);
|
|
48
|
+
tr.set_address(offset);
|
|
49
|
+
tr.set_data_ptr(buf8);
|
|
50
|
+
tr.set_data_length(len);
|
|
51
|
+
tr.set_streaming_width(len);
|
|
52
|
+
tr.set_dmi_allowed(false);
|
|
53
|
+
tr.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
|
|
54
|
+
|
|
55
|
+
socket->b_transport(tr, delay);
|
|
56
|
+
assert(tr.get_response_status() == tlm::TLM_OK_RESPONSE);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
uint32_t dev_read32(uint64_t offset) {
|
|
60
|
+
uint32_t r;
|
|
61
|
+
assert((offset & 3) == 0);
|
|
62
|
+
dev_access(tlm::TLM_READ_COMMAND, offset, &r, sizeof(r));
|
|
63
|
+
return r;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void dev_write32(uint64_t offset, uint32_t v) {
|
|
67
|
+
assert((offset & 3) == 0);
|
|
68
|
+
dev_access(tlm::TLM_WRITE_COMMAND, offset, &v, sizeof(v));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void dev_write32_strong(uint64_t offset, uint32_t v) {
|
|
72
|
+
uint32_t dummy;
|
|
73
|
+
|
|
74
|
+
dev_write32(offset, v);
|
|
75
|
+
// Enforce PCIe ordering.
|
|
76
|
+
dummy = dev_read32(offset);
|
|
77
|
+
dummy = dummy;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
class SBTX_tlm : public SBTX, public SB_tlm {
|
|
82
|
+
public:
|
|
83
|
+
SBTX_tlm(int queue_id) : SB_tlm(queue_id) {}
|
|
84
|
+
|
|
85
|
+
bool init(const char* uri) {
|
|
86
|
+
return sb_pcie_init(this, uri, NULL, -1);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
class SBRX_tlm : public SBRX, public SB_tlm {
|
|
91
|
+
public:
|
|
92
|
+
SBRX_tlm(int queue_id) : SB_tlm(queue_id) {}
|
|
93
|
+
|
|
94
|
+
bool init(const char* uri) {
|
|
95
|
+
return sb_pcie_init(this, uri, NULL, -1);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
#endif
|