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.
Files changed (99) hide show
  1. _switchboard.cpython-314-darwin.so +0 -0
  2. switchboard/__init__.py +24 -0
  3. switchboard/ams.py +668 -0
  4. switchboard/apb.py +278 -0
  5. switchboard/autowrap.py +1000 -0
  6. switchboard/axi.py +571 -0
  7. switchboard/axil.py +348 -0
  8. switchboard/bitvector.py +112 -0
  9. switchboard/cmdline.py +142 -0
  10. switchboard/cpp/Makefile +13 -0
  11. switchboard/cpp/bitutil.h +39 -0
  12. switchboard/cpp/pagemap.h +91 -0
  13. switchboard/cpp/pciedev.h +86 -0
  14. switchboard/cpp/router.cc +89 -0
  15. switchboard/cpp/spsc_queue.h +267 -0
  16. switchboard/cpp/switchboard.hpp +257 -0
  17. switchboard/cpp/switchboard_pcie.hpp +234 -0
  18. switchboard/cpp/switchboard_tlm.hpp +98 -0
  19. switchboard/cpp/umilib.h +144 -0
  20. switchboard/cpp/umilib.hpp +113 -0
  21. switchboard/cpp/umisb.hpp +364 -0
  22. switchboard/cpp/xyce.hpp +90 -0
  23. switchboard/deps/__init__.py +0 -0
  24. switchboard/deps/verilog_axi.py +23 -0
  25. switchboard/dpi/__init__.py +0 -0
  26. switchboard/dpi/switchboard_dpi.cc +119 -0
  27. switchboard/dpi/switchboard_dpi.py +13 -0
  28. switchboard/dpi/xyce_dpi.cc +43 -0
  29. switchboard/gpio.py +108 -0
  30. switchboard/icarus.py +85 -0
  31. switchboard/loopback.py +157 -0
  32. switchboard/network.py +714 -0
  33. switchboard/pytest_plugin.py +11 -0
  34. switchboard/sbdesign.py +55 -0
  35. switchboard/sbdut.py +744 -0
  36. switchboard/sbtcp.py +345 -0
  37. switchboard/sc/__init__.py +0 -0
  38. switchboard/sc/morty/__init__.py +0 -0
  39. switchboard/sc/morty/uniquify.py +67 -0
  40. switchboard/sc/sed/__init__.py +0 -0
  41. switchboard/sc/sed/sed_remove.py +47 -0
  42. switchboard/sc/standalone_netlist_flow.py +25 -0
  43. switchboard/switchboard.py +53 -0
  44. switchboard/test_util.py +46 -0
  45. switchboard/uart_xactor.py +66 -0
  46. switchboard/umi.py +793 -0
  47. switchboard/util.py +131 -0
  48. switchboard/verilator/__init__.py +0 -0
  49. switchboard/verilator/config.vlt +13 -0
  50. switchboard/verilator/testbench.cc +143 -0
  51. switchboard/verilator/verilator.py +13 -0
  52. switchboard/verilator_run.py +31 -0
  53. switchboard/verilog/__init__.py +0 -0
  54. switchboard/verilog/common/__init__.py +0 -0
  55. switchboard/verilog/common/common.py +26 -0
  56. switchboard/verilog/common/switchboard.vh +429 -0
  57. switchboard/verilog/common/uart_xactor.sv +247 -0
  58. switchboard/verilog/common/umi_gpio.v +236 -0
  59. switchboard/verilog/fpga/__init__.py +0 -0
  60. switchboard/verilog/fpga/axi_reader.sv +82 -0
  61. switchboard/verilog/fpga/axi_writer.sv +111 -0
  62. switchboard/verilog/fpga/config_registers.sv +249 -0
  63. switchboard/verilog/fpga/fpga.py +21 -0
  64. switchboard/verilog/fpga/include/sb_queue_regmap.vh +21 -0
  65. switchboard/verilog/fpga/include/spsc_queue.vh +7 -0
  66. switchboard/verilog/fpga/memory_fault.sv +40 -0
  67. switchboard/verilog/fpga/sb_fpga_queues.sv +416 -0
  68. switchboard/verilog/fpga/sb_rx_fpga.sv +303 -0
  69. switchboard/verilog/fpga/sb_tx_fpga.sv +294 -0
  70. switchboard/verilog/fpga/umi_fpga_queues.sv +146 -0
  71. switchboard/verilog/sim/__init__.py +0 -0
  72. switchboard/verilog/sim/auto_stop_sim.sv +25 -0
  73. switchboard/verilog/sim/perf_meas_sim.sv +97 -0
  74. switchboard/verilog/sim/queue_to_sb_sim.sv +176 -0
  75. switchboard/verilog/sim/queue_to_umi_sim.sv +66 -0
  76. switchboard/verilog/sim/sb_apb_m.sv +146 -0
  77. switchboard/verilog/sim/sb_axi_m.sv +199 -0
  78. switchboard/verilog/sim/sb_axil_m.sv +180 -0
  79. switchboard/verilog/sim/sb_axil_s.sv +180 -0
  80. switchboard/verilog/sim/sb_clk_gen.sv +89 -0
  81. switchboard/verilog/sim/sb_jtag_rbb_sim.sv +148 -0
  82. switchboard/verilog/sim/sb_rx_sim.sv +55 -0
  83. switchboard/verilog/sim/sb_to_queue_sim.sv +196 -0
  84. switchboard/verilog/sim/sb_tx_sim.sv +55 -0
  85. switchboard/verilog/sim/switchboard_sim.py +49 -0
  86. switchboard/verilog/sim/umi_rx_sim.sv +61 -0
  87. switchboard/verilog/sim/umi_to_queue_sim.sv +66 -0
  88. switchboard/verilog/sim/umi_tx_sim.sv +61 -0
  89. switchboard/verilog/sim/xyce_intf.sv +67 -0
  90. switchboard/vpi/switchboard_vpi.cc +431 -0
  91. switchboard/vpi/xyce_vpi.cc +200 -0
  92. switchboard/warn.py +14 -0
  93. switchboard/xyce.py +27 -0
  94. switchboard_hw-0.3.0.dist-info/METADATA +303 -0
  95. switchboard_hw-0.3.0.dist-info/RECORD +99 -0
  96. switchboard_hw-0.3.0.dist-info/WHEEL +6 -0
  97. switchboard_hw-0.3.0.dist-info/entry_points.txt +6 -0
  98. switchboard_hw-0.3.0.dist-info/licenses/LICENSE +190 -0
  99. switchboard_hw-0.3.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,144 @@
1
+ // C-based subset of umilib
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 __UMILIB_H__
7
+ #define __UMILIB_H__
8
+
9
+ #include <assert.h>
10
+ #include <string.h>
11
+ #include <unistd.h>
12
+
13
+ // ref: umi/rtl/umi_messages.vh
14
+ enum UMI_CMD {
15
+ UMI_INVALID = 0x00,
16
+
17
+ // Requests (host -> device)
18
+ UMI_REQ_READ = 0x01,
19
+ UMI_REQ_WRITE = 0x03,
20
+ UMI_REQ_POSTED = 0x05,
21
+ UMI_REQ_RDMA = 0x07,
22
+ UMI_REQ_ATOMIC = 0x09,
23
+ UMI_REQ_USER0 = 0x0B,
24
+ UMI_REQ_FUTURE0 = 0x0D,
25
+ UMI_REQ_ERROR = 0x0F,
26
+ UMI_REQ_LINK = 0x2F,
27
+
28
+ // Response (device -> host)
29
+ UMI_RESP_READ = 0x02,
30
+ UMI_RESP_WRITE = 0x04,
31
+ UMI_RESP_USER0 = 0x06,
32
+ UMI_RESP_USER1 = 0x08,
33
+ UMI_RESP_FUTURE0 = 0x0A,
34
+ UMI_RESP_FUTURE1 = 0x0C,
35
+ UMI_RESP_LINK = 0x0E
36
+ };
37
+
38
+ enum UMI_ATOMIC {
39
+ UMI_REQ_ATOMICADD = 0x00,
40
+ UMI_REQ_ATOMICAND = 0x01,
41
+ UMI_REQ_ATOMICOR = 0x02,
42
+ UMI_REQ_ATOMICXOR = 0x03,
43
+ UMI_REQ_ATOMICMAX = 0x04,
44
+ UMI_REQ_ATOMICMIN = 0x05,
45
+ UMI_REQ_ATOMICMAXU = 0x06,
46
+ UMI_REQ_ATOMICMINU = 0x07,
47
+ UMI_REQ_ATOMICSWAP = 0x08
48
+ };
49
+
50
+ // TODO: make this flexible
51
+ #define UMI_PACKET_DATA_BYTES 32
52
+
53
+ typedef struct umi_packet {
54
+ uint32_t cmd;
55
+ uint64_t dstaddr;
56
+ uint64_t srcaddr;
57
+ uint8_t data[UMI_PACKET_DATA_BYTES];
58
+ } __attribute__((packed)) umi_packet;
59
+
60
+ static inline bool has_umi_resp(uint32_t opcode) {
61
+ return ((opcode == UMI_REQ_READ) || (opcode == UMI_REQ_WRITE) || (opcode == UMI_REQ_ATOMIC));
62
+ }
63
+
64
+ static inline bool has_umi_data(uint32_t opcode) {
65
+ return ((opcode == UMI_REQ_WRITE) || (opcode == UMI_REQ_POSTED) || (opcode == UMI_REQ_ATOMIC) ||
66
+ (opcode == UMI_REQ_USER0) || (opcode == UMI_REQ_FUTURE0) || (opcode == UMI_RESP_READ) ||
67
+ (opcode == UMI_RESP_USER1) || (opcode == UMI_RESP_FUTURE1));
68
+ }
69
+
70
+ static inline bool allows_umi_merge(uint32_t opcode) {
71
+ return ((opcode == UMI_REQ_READ) || (opcode == UMI_REQ_WRITE) || (opcode == UMI_REQ_POSTED) ||
72
+ (opcode == UMI_REQ_RDMA) || (opcode == UMI_RESP_READ) || (opcode == UMI_RESP_WRITE));
73
+ }
74
+
75
+ static inline bool is_umi_invalid(uint32_t opcode) {
76
+ return opcode == 0;
77
+ }
78
+
79
+ static inline bool is_umi_req(uint32_t opcode) {
80
+ return (opcode & 0b1) == 0b1;
81
+ }
82
+
83
+ static inline bool is_umi_resp(uint32_t opcode) {
84
+ return (opcode != 0) && ((opcode & 0b1) == 0b0);
85
+ }
86
+
87
+ static inline bool is_umi_user(uint32_t opcode) {
88
+ return ((opcode == UMI_REQ_USER0) | (opcode == UMI_RESP_USER0) | (opcode == UMI_RESP_USER1));
89
+ }
90
+
91
+ static inline bool is_umi_future(uint32_t opcode) {
92
+ return (
93
+ (opcode == UMI_REQ_FUTURE0) | (opcode == UMI_RESP_FUTURE0) | (opcode == UMI_RESP_FUTURE1));
94
+ }
95
+
96
+ static inline uint32_t get_umi_bits(uint32_t cmd, uint32_t offset, uint32_t width) {
97
+ uint32_t mask = (1 << width) - 1;
98
+ return ((cmd >> offset) & mask);
99
+ }
100
+
101
+ static inline void set_umi_bits(uint32_t* cmd, uint32_t bits, uint32_t offset, uint32_t width) {
102
+
103
+ uint32_t mask = (1 << width) - 1;
104
+
105
+ *cmd = *cmd & (~(mask << offset));
106
+ *cmd = *cmd | (((bits & mask) << offset));
107
+ }
108
+
109
+ #define DECL_UMI_GETTER(FIELD, OFFSET, WIDTH) \
110
+ static inline uint32_t umi_##FIELD(uint32_t cmd) { \
111
+ return get_umi_bits(cmd, OFFSET, WIDTH); \
112
+ }
113
+
114
+ #define DECL_UMI_SETTER(FIELD, OFFSET, WIDTH) \
115
+ static inline void set_umi_##FIELD(uint32_t* cmd, uint32_t FIELD) { \
116
+ set_umi_bits(cmd, FIELD, OFFSET, WIDTH); \
117
+ }
118
+
119
+ #define DECL_UMI_FIELD(FIELD, OFFSET, WIDTH) \
120
+ DECL_UMI_GETTER(FIELD, OFFSET, WIDTH) \
121
+ DECL_UMI_SETTER(FIELD, OFFSET, WIDTH)
122
+
123
+ DECL_UMI_FIELD(opcode, 0, 5)
124
+ DECL_UMI_FIELD(size, 5, 3)
125
+ static inline uint32_t umi_len(uint32_t cmd) {
126
+ if (umi_opcode(cmd) == UMI_REQ_ATOMIC) {
127
+ return 0;
128
+ } else {
129
+ return get_umi_bits(cmd, 8, 8);
130
+ }
131
+ }
132
+ DECL_UMI_SETTER(len, 8, 8)
133
+ DECL_UMI_FIELD(atype, 8, 8)
134
+ DECL_UMI_FIELD(qos, 16, 4)
135
+ DECL_UMI_FIELD(prot, 20, 2)
136
+ DECL_UMI_FIELD(eom, 22, 1)
137
+ DECL_UMI_FIELD(eof, 23, 1)
138
+ DECL_UMI_FIELD(ex, 24, 1)
139
+
140
+ static inline bool umi_packets_match(umi_packet* a, umi_packet* b) {
141
+ return (memcmp(a, b, 52) == 0);
142
+ }
143
+
144
+ #endif // __UMILIB_H__
@@ -0,0 +1,113 @@
1
+ // Copyright (c) 2024 Zero ASIC Corporation
2
+ // This code is licensed under Apache License 2.0 (see LICENSE for details)
3
+
4
+ #ifndef __UMILIB_HPP__
5
+ #define __UMILIB_HPP__
6
+
7
+ #include "umilib.h"
8
+ #include <string>
9
+
10
+ static inline uint32_t umi_pack(uint32_t opcode, uint32_t atype, uint32_t size, uint32_t len,
11
+ uint32_t eom, uint32_t eof, uint32_t qos = 0, uint32_t prot = 0, uint32_t ex = 0) {
12
+
13
+ uint32_t cmd = 0;
14
+
15
+ set_umi_opcode(&cmd, opcode);
16
+ set_umi_size(&cmd, size);
17
+ if (opcode != UMI_REQ_ATOMIC) {
18
+ set_umi_len(&cmd, len);
19
+ } else {
20
+ set_umi_atype(&cmd, atype);
21
+ }
22
+ set_umi_qos(&cmd, qos);
23
+ set_umi_prot(&cmd, prot);
24
+ set_umi_eom(&cmd, eom);
25
+ set_umi_eof(&cmd, eof);
26
+ set_umi_ex(&cmd, ex);
27
+
28
+ return cmd;
29
+ }
30
+
31
+ static inline void umi_unpack(uint32_t cmd, uint32_t& opcode, uint32_t& atype, uint32_t& size,
32
+ uint32_t& len, uint32_t& eom, uint32_t& eof, uint32_t& qos, uint32_t& prot, uint32_t& ex) {
33
+
34
+ opcode = umi_opcode(cmd);
35
+ size = umi_size(cmd);
36
+ len = umi_len(cmd);
37
+ atype = umi_atype(cmd);
38
+ qos = umi_qos(cmd);
39
+ prot = umi_prot(cmd);
40
+ eom = umi_eom(cmd);
41
+ eof = umi_eof(cmd);
42
+ ex = umi_ex(cmd);
43
+ }
44
+
45
+ static inline void umi_unpack(uint32_t cmd, uint32_t& opcode, uint32_t& atype, uint32_t& size,
46
+ uint32_t& len, uint32_t& eom, uint32_t& eof) {
47
+ uint32_t qos, prot, ex;
48
+ umi_unpack(cmd, opcode, atype, size, len, eom, eof, qos, prot, ex);
49
+ }
50
+
51
+ static inline void umi_unpack(uint32_t cmd, uint32_t& opcode, uint32_t& atype, uint32_t& size,
52
+ uint32_t& len, uint32_t& eom, uint32_t& eof, uint32_t& qos) {
53
+ uint32_t prot, ex;
54
+ umi_unpack(cmd, opcode, atype, size, len, eom, eof, qos, prot, ex);
55
+ }
56
+
57
+ static inline void umi_unpack(uint32_t cmd, uint32_t& opcode, uint32_t& atype, uint32_t& size,
58
+ uint32_t& len, uint32_t& eom, uint32_t& eof, uint32_t& qos, uint32_t& prot) {
59
+ uint32_t ex;
60
+ umi_unpack(cmd, opcode, atype, size, len, eom, eof, qos, prot, ex);
61
+ }
62
+
63
+ static inline std::string umi_opcode_to_str(uint32_t cmd) {
64
+ uint32_t opcode = umi_opcode(cmd);
65
+ if (opcode == UMI_INVALID) {
66
+ return "UMI_INVALID";
67
+ } else if (opcode == UMI_REQ_READ) {
68
+ return "UMI_REQ_READ";
69
+ } else if (opcode == UMI_REQ_RDMA) {
70
+ return "UMI_REQ_RDMA";
71
+ } else if (opcode == UMI_REQ_WRITE) {
72
+ return "UMI_REQ_WRITE";
73
+ } else if (opcode == UMI_REQ_POSTED) {
74
+ return "UMI_REQ_POSTED";
75
+ } else if (opcode == UMI_REQ_ATOMIC) {
76
+ return "UMI_REQ_ATOMIC";
77
+ } else if (opcode == UMI_RESP_READ) {
78
+ return "UMI_RESP_READ";
79
+ } else if (opcode == UMI_RESP_WRITE) {
80
+ return "UMI_RESP_WRITE";
81
+ } else if (opcode == UMI_REQ_ATOMIC) {
82
+ uint32_t atomic = umi_atype(cmd);
83
+ if (atomic == UMI_REQ_ATOMICADD) {
84
+ return "UMI_REQ_ATOMICADD";
85
+ } else if (atomic == UMI_REQ_ATOMICAND) {
86
+ return "UMI_REQ_ATOMICAND";
87
+ } else if (atomic == UMI_REQ_ATOMICOR) {
88
+ return "UMI_REQ_ATOMICOR";
89
+ } else if (atomic == UMI_REQ_ATOMICXOR) {
90
+ return "UMI_REQ_ATOMICXOR";
91
+ } else if (atomic == UMI_REQ_ATOMICMAX) {
92
+ return "UMI_REQ_ATOMICMAX";
93
+ } else if (atomic == UMI_REQ_ATOMICMIN) {
94
+ return "UMI_REQ_ATOMICMIN";
95
+ } else if (atomic == UMI_REQ_ATOMICMAXU) {
96
+ return "UMI_REQ_ATOMICMAXU";
97
+ } else if (atomic == UMI_REQ_ATOMICMINU) {
98
+ return "UMI_REQ_ATOMICMINU";
99
+ } else if (atomic == UMI_REQ_ATOMICSWAP) {
100
+ return "UMI_REQ_ATOMICSWAP";
101
+ } else {
102
+ return "UMI_REQ_ATOMIC";
103
+ }
104
+ } else if (is_umi_user(opcode)) {
105
+ return "UMI_USER";
106
+ } else if (is_umi_future(opcode)) {
107
+ return "UMI_FUTURE";
108
+ } else {
109
+ return "UMI_UNKNOWN";
110
+ }
111
+ }
112
+
113
+ #endif // __UMILIB_HPP__
@@ -0,0 +1,364 @@
1
+ // Copyright (c) 2024 Zero ASIC Corporation
2
+ // This code is licensed under Apache License 2.0 (see LICENSE for details)
3
+
4
+ #ifndef __UMISB_HPP__
5
+ #define __UMISB_HPP__
6
+
7
+ #include <functional>
8
+ #include <iostream>
9
+ #include <memory>
10
+ #include <sstream>
11
+ #include <stdexcept>
12
+
13
+ #include "switchboard.hpp"
14
+ #include "umilib.h"
15
+ #include "umilib.hpp"
16
+
17
+ // generic formatting methods
18
+
19
+ template <typename T> std::string umi_data_as_str(T& x) {
20
+ // get the data representation
21
+ uint8_t* ptr = x.ptr();
22
+ size_t nbytes = x.nbytes();
23
+
24
+ uint32_t opcode = umi_opcode(x.cmd);
25
+
26
+ // create a formatted representation
27
+ std::stringstream stream;
28
+ stream << "[";
29
+ if (has_umi_data(opcode)) {
30
+
31
+ uint32_t size = umi_size(x.cmd);
32
+ uint32_t len = umi_len(x.cmd) + 1;
33
+
34
+ for (size_t i = 0; i < len; i++) {
35
+ if ((i + 1) * (1 << size) <= nbytes) {
36
+ if (size == 0) {
37
+ // uint8_t needs to be cast to an integer to print correctly
38
+ // with std::hex: https://stackoverflow.com/a/23575509
39
+ stream << "0x" << std::hex << static_cast<int>(ptr[i]);
40
+ } else if (size == 1) {
41
+ stream << "0x" << std::hex << ((uint16_t*)ptr)[i];
42
+ } else if (size == 2) {
43
+ stream << "0x" << std::hex << ((uint32_t*)ptr)[i];
44
+ } else if (size == 3) {
45
+ stream << "0x" << std::hex << ((uint64_t*)ptr)[i];
46
+ } else {
47
+ stream << "X";
48
+ }
49
+ } else {
50
+ stream << "X";
51
+ }
52
+ if (i != (len - 1)) {
53
+ stream << ", ";
54
+ }
55
+ }
56
+ }
57
+
58
+ stream << "]";
59
+
60
+ // return the result
61
+ return stream.str();
62
+ }
63
+
64
+ template <typename T> std::string umi_transaction_as_str(T& x) {
65
+ std::stringstream stream;
66
+
67
+ uint32_t opcode = umi_opcode(x.cmd);
68
+
69
+ stream << "opcode: " << umi_opcode_to_str(opcode);
70
+
71
+ stream << std::endl << "dstaddr: 0x" << std::hex << x.dstaddr;
72
+
73
+ // print out the source address if this is a request, as long
74
+ // as it isn't a posted write, since that doesn't have a source
75
+ // address.
76
+ if (is_umi_req(opcode) && (opcode != UMI_REQ_POSTED)) {
77
+ stream << std::endl << "srcaddr: 0x" << std::hex << x.srcaddr;
78
+ }
79
+
80
+ stream << std::endl << "size: " << umi_size(x.cmd);
81
+ stream << std::endl << "len: " << umi_len(x.cmd);
82
+ stream << std::endl << "eom: " << umi_eom(x.cmd);
83
+ stream << std::endl << "eof: " << umi_eof(x.cmd);
84
+
85
+ // print out the data as long as this isn't a read request, since
86
+ // that doesn't have data
87
+ if (!((opcode == UMI_REQ_READ) || (opcode == UMI_REQ_RDMA))) {
88
+ stream << std::endl << "data: " << umi_data_as_str<T>(x);
89
+ }
90
+
91
+ // return the result, noting that it does not contain a final newline
92
+ return stream.str();
93
+ }
94
+
95
+ // function to print a warning or throw an error
96
+
97
+ static inline void umisb_error_or_warn(std::string const& msg, bool error = true) {
98
+ if (error) {
99
+ throw std::runtime_error(msg);
100
+ } else {
101
+ std::cerr << "Warning: " << msg << std::endl;
102
+ }
103
+ }
104
+
105
+ // function for checking if requests and replies match up as expected
106
+
107
+ template <typename T>
108
+ void umisb_check_resp(T& resp, uint32_t opcode, uint32_t size, uint32_t to_ack,
109
+ uint64_t expected_addr, bool error = true) {
110
+
111
+ uint32_t resp_opcode = umi_opcode(resp.cmd);
112
+ uint32_t resp_size = umi_size(resp.cmd);
113
+ uint32_t resp_len = umi_len(resp.cmd);
114
+
115
+ // check that the response makes sense
116
+
117
+ if (resp_opcode != opcode) {
118
+ std::ostringstream oss;
119
+ oss << "Got " << umi_opcode_to_str(resp_opcode) << " (expected "
120
+ << umi_opcode_to_str(opcode) << ")";
121
+ umisb_error_or_warn(oss.str(), error);
122
+ }
123
+
124
+ if (resp_size != size) {
125
+ std::ostringstream oss;
126
+ oss << umi_opcode_to_str(resp_opcode) << " response SIZE is " << std::to_string(resp_size)
127
+ << " (expected " << std::to_string(size) << ")";
128
+ umisb_error_or_warn(oss.str(), error);
129
+ }
130
+
131
+ if ((resp_len + 1) > to_ack) {
132
+ std::ostringstream oss;
133
+ oss << umi_opcode_to_str(resp_opcode) << " response LEN is " << std::to_string(resp_len)
134
+ << " (expected no more than " << std::to_string(to_ack - 1) << ")";
135
+ umisb_error_or_warn(oss.str(), error);
136
+ }
137
+
138
+ if (resp.dstaddr != expected_addr) {
139
+ std::ostringstream oss;
140
+ oss << "dstaddr in " << umi_opcode_to_str(resp_opcode) << " response is "
141
+ << std::to_string(resp.dstaddr) << " (expected " << std::to_string(expected_addr)
142
+ << ")";
143
+ umisb_error_or_warn(oss.str(), error);
144
+ }
145
+ }
146
+
147
+ // basic class for representing a UMI transaction, which may span
148
+ // multiple packets.
149
+
150
+ struct UmiTransaction {
151
+ UmiTransaction(uint32_t cmd = 0, uint64_t dstaddr = 0, uint64_t srcaddr = 0,
152
+ uint8_t* data = NULL, size_t nbytes = 0)
153
+ : cmd(cmd), dstaddr(dstaddr), srcaddr(srcaddr) {
154
+
155
+ m_storage = false;
156
+ m_allocated = false;
157
+ m_nbytes = 0;
158
+
159
+ if (data != NULL) {
160
+ this->data = data;
161
+ m_storage = true;
162
+ m_nbytes = nbytes;
163
+ } else if (nbytes > 0) {
164
+ allocate(0, nbytes - 1);
165
+ } else {
166
+ this->data = NULL;
167
+ }
168
+ }
169
+
170
+ ~UmiTransaction() {
171
+ if (m_allocated) {
172
+ delete[] data;
173
+ }
174
+ }
175
+
176
+ std::string toString() {
177
+ return umi_transaction_as_str<UmiTransaction>(*this);
178
+ }
179
+
180
+ void allocate(size_t size, size_t len) {
181
+ // check that we can perform this operation
182
+
183
+ if (m_storage) {
184
+ throw std::runtime_error(
185
+ "There is already storage for this UMI transaction, no need to allocate.");
186
+ }
187
+
188
+ if (m_allocated) {
189
+ throw std::runtime_error("Memory has already been allocated for this UMI transaction.");
190
+ }
191
+
192
+ // allocate the memory
193
+
194
+ size_t nbytes = (len + 1) << size;
195
+ data = new uint8_t[nbytes];
196
+
197
+ // indicate that storage is now available for this transaction,
198
+ // and that we allocated memory to make it available
199
+
200
+ m_storage = true;
201
+ m_allocated = true;
202
+ m_nbytes = nbytes;
203
+ }
204
+
205
+ bool storage() {
206
+ return m_storage;
207
+ }
208
+
209
+ size_t nbytes() {
210
+ return m_nbytes;
211
+ }
212
+
213
+ uint8_t* ptr() {
214
+ return data;
215
+ }
216
+
217
+ uint32_t cmd;
218
+ uint64_t dstaddr;
219
+ uint64_t srcaddr;
220
+ uint8_t* data;
221
+
222
+ private:
223
+ size_t m_nbytes;
224
+ bool m_allocated;
225
+ bool m_storage;
226
+ };
227
+
228
+ // higher-level functions for UMI transactions
229
+
230
+ template <typename T>
231
+ static inline bool umisb_send(T& x, SBTX& tx, bool blocking = true, void (*loop)(void) = NULL) {
232
+
233
+ // sends (or tries to send, if blocking=false) a single UMI transaction
234
+
235
+ if (!tx.is_active()) {
236
+ return false;
237
+ }
238
+
239
+ // load fields into an SB packet
240
+
241
+ sb_packet p;
242
+ umi_packet* up = (umi_packet*)p.data;
243
+
244
+ up->cmd = x.cmd;
245
+ up->dstaddr = x.dstaddr;
246
+ up->srcaddr = x.srcaddr;
247
+
248
+ uint32_t opcode = umi_opcode(x.cmd);
249
+
250
+ if ((opcode == UMI_REQ_READ) || (opcode == UMI_REQ_RDMA) || (opcode == UMI_RESP_WRITE)) {
251
+ // do nothing, since there isn't data to copy
252
+ } else {
253
+ uint32_t size = umi_size(x.cmd);
254
+ uint32_t len = umi_len(x.cmd);
255
+
256
+ size_t nbytes = (len + 1) << size;
257
+
258
+ if (nbytes > sizeof(up->data)) {
259
+ throw std::runtime_error(
260
+ "umisb_send: (len+1)<<size cannot exceed the data size of a umi_packet.");
261
+ }
262
+
263
+ if (nbytes > x.nbytes()) {
264
+ throw std::runtime_error(
265
+ "umisb_send: (len+1)<<size cannot exceed the data size of a UmiTransaction.");
266
+ }
267
+
268
+ memcpy(up->data, x.ptr(), nbytes);
269
+ }
270
+
271
+ bool header_sent = tx.send(p);
272
+ if ((!blocking) && (!header_sent)) {
273
+ return false;
274
+ }
275
+
276
+ // if we reach this point, we're committed to send out the whole UMI
277
+ // transaction, which may span multiple packets
278
+
279
+ // finish sending the header packet
280
+ if (!header_sent) {
281
+ bool success = false;
282
+
283
+ while (!success) {
284
+ success = tx.send(p);
285
+
286
+ if (loop) {
287
+ loop();
288
+ }
289
+ }
290
+ }
291
+
292
+ // if we reach this point, we succeeded in sending the packet
293
+ return true;
294
+ }
295
+
296
+ template <typename T>
297
+ static inline bool umisb_recv(T& x, SBRX& rx, bool blocking = true, void (*loop)(void) = NULL) {
298
+
299
+ // if the receive side isn't active, there is nothing to receive
300
+ if (!rx.is_active()) {
301
+ return false;
302
+ }
303
+
304
+ // get a response
305
+
306
+ sb_packet p;
307
+
308
+ if (!blocking) {
309
+ if (!rx.recv(p)) {
310
+ return false;
311
+ }
312
+ } else {
313
+ bool success = false;
314
+
315
+ while (!success) {
316
+ success = rx.recv(p);
317
+
318
+ if (loop) {
319
+ loop();
320
+ }
321
+ }
322
+ }
323
+
324
+ // if we get to this point, there is valid data in "p"
325
+
326
+ umi_packet* up = (umi_packet*)p.data;
327
+
328
+ // read information from the packet
329
+
330
+ x.cmd = up->cmd;
331
+ x.dstaddr = up->dstaddr;
332
+ x.srcaddr = up->srcaddr;
333
+
334
+ uint32_t opcode = umi_opcode(up->cmd);
335
+
336
+ if ((opcode == UMI_REQ_READ) || (opcode == UMI_REQ_RDMA) || (opcode == UMI_RESP_WRITE)) {
337
+ // do nothing, since there isn't data to copy
338
+ } else {
339
+ uint32_t size = umi_size(x.cmd);
340
+ uint32_t len = umi_len(x.cmd);
341
+
342
+ if (!x.storage()) {
343
+ x.allocate(size, len);
344
+ }
345
+
346
+ size_t nbytes = (len + 1) << size;
347
+
348
+ if (nbytes > sizeof(up->data)) {
349
+ throw std::runtime_error(
350
+ "umisb_recv: (len+1)<<size cannot exceed the data size of a umi_packet.");
351
+ }
352
+
353
+ if (nbytes > x.nbytes()) {
354
+ throw std::runtime_error(
355
+ "umisb_recv: (len+1)<<size cannot exceed the data size of a UmiTransaction.");
356
+ }
357
+
358
+ memcpy(x.ptr(), up->data, nbytes);
359
+ }
360
+
361
+ return true;
362
+ }
363
+
364
+ #endif // __UMISB_HPP__
@@ -0,0 +1,90 @@
1
+ // Copyright (c) 2024 Zero ASIC Corporation
2
+ // This code is licensed under Apache License 2.0 (see LICENSE for details)
3
+
4
+ #include <map>
5
+ #include <string>
6
+ #include <vector>
7
+
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+
11
+ #include <N_CIR_XyceCInterface.h>
12
+
13
+ class XyceIntf {
14
+ public:
15
+ XyceIntf() {}
16
+
17
+ ~XyceIntf() {
18
+ if (m_opened) {
19
+ xyce_close(m_xyceObj);
20
+ }
21
+
22
+ if (m_xyceObj) {
23
+ free(m_xyceObj);
24
+ }
25
+ }
26
+
27
+ void init(std::string file) {
28
+ // pointer to N_CIR_Xyce object
29
+ m_xyceObj = (void**)malloc(sizeof(void* [1]));
30
+
31
+ // xyce command
32
+ char* argList[] = {(char*)("Xyce"), (char*)("-quiet"), (char*)file.c_str()};
33
+ int argc = sizeof(argList) / sizeof(argList[0]);
34
+ char** argv = argList;
35
+
36
+ // Open N_CIR_Xyce object
37
+ xyce_open(m_xyceObj);
38
+ m_opened = true;
39
+
40
+ // Initialize N_CIR_Xyce object
41
+ xyce_initialize(m_xyceObj, argc, argv);
42
+ m_initialized = true;
43
+
44
+ // Simulate for a small amount of time
45
+ xyce_simulateUntil(m_xyceObj, 1e-10, &m_simTime);
46
+ }
47
+
48
+ void put(std::string name, double time, double value) {
49
+ if (!m_time.count(name)) {
50
+ m_time[name] = std::vector<double>();
51
+ }
52
+
53
+ m_time[name].push_back(time);
54
+
55
+ if (!m_value.count(name)) {
56
+ m_value[name] = std::vector<double>();
57
+ }
58
+
59
+ m_value[name].push_back(value);
60
+
61
+ // TODO: prune old values for higher performance?
62
+
63
+ if (m_initialized) {
64
+ std::string fullName = "YDAC!" + name;
65
+
66
+ xyce_updateTimeVoltagePairs(m_xyceObj, (char*)fullName.c_str(), m_time[name].size(),
67
+ m_time[name].data(), m_value[name].data());
68
+ }
69
+ }
70
+
71
+ void get(std::string name, double time, double* value) {
72
+ if (m_initialized) {
73
+ // advance simulation if necessary
74
+ if (time > m_simTime) {
75
+ int status = xyce_simulateUntil(m_xyceObj, time, &m_simTime);
76
+ }
77
+
78
+ // read out the value
79
+ xyce_obtainResponse(m_xyceObj, (char*)name.c_str(), value);
80
+ }
81
+ }
82
+
83
+ private:
84
+ void** m_xyceObj;
85
+ double m_simTime;
86
+ bool m_opened;
87
+ bool m_initialized;
88
+ std::map<std::string, std::vector<double>> m_time;
89
+ std::map<std::string, std::vector<double>> m_value;
90
+ };
File without changes