11 #include <util/log_fmt.h>
18 : fd(posix_openpt(O_RDWR
| O_NOCTTY
)) {
20 throw std::runtime_error(fmt_errno("posix_openpt"));
28 void prepare() const {
30 throw std::runtime_error(fmt_errno("grantpt"));
33 throw std::runtime_error(fmt_errno("unlockpt"));
36 if (tcgetattr(fd
, &raw
)) {
37 throw std::runtime_error(fmt_errno("tcgetattr"));
39 raw
.c_cflag
= (raw
.c_cflag
& ~CSIZE
) | CS8
;
40 raw
.c_lflag
&= ~(ECHO
| ICANON
);
41 if (tcsetattr(fd
, TCSANOW
, &raw
)) {
42 throw std::runtime_error(fmt_errno("tcsetattr"));
46 bool readable() const {
47 pollfd pfd
= {fd
, POLLIN
, 0};
48 poll(&pfd
, /*nfds=*/1, /*timeout=*/0);
49 return (pfd
.revents
& POLLIN
);
52 bool writable() const {
53 pollfd pfd
= {fd
, POLLOUT
, 0};
54 poll(&pfd
, /*nfds=*/1, /*timeout=*/0);
55 return (pfd
.revents
& POLLOUT
);
58 unsigned char read_char() const {
60 ssize_t nread
= read(fd
, &c
, /*count=*/1);
62 throw std::runtime_error(fmt_errno("read"));
67 void write_char(unsigned char c
) const {
68 ssize_t nwrite
= write(fd
, &c
, /*count=*/1);
70 throw std::runtime_error(fmt_errno("write"));
76 static std::map
<const std::string
, std::weak_ptr
<serial_pty
>> serial_pty_map
;
87 serial_pty(const std::string
&id
)
95 serial_pty() = delete;
96 serial_pty(const serial_pty
&) = delete;
97 serial_pty
&operator=(const serial_pty
&) = delete;
100 if (serial_pty_map
.count(id
)) {
101 serial_pty_map
.erase(id
);
105 static std::shared_ptr
<serial_pty
> get(const std::string
&id
) {
106 std::shared_ptr
<serial_pty
> desc
;
107 if (!serial_pty_map
.count(id
)) {
108 desc
= std::make_shared
<serial_pty
>(id
);
109 serial_pty_map
[id
] = desc
;
111 desc
= serial_pty_map
[id
].lock();
124 bool has_rx() const {
127 bool has_tx() const {
132 namespace cxxrtl_design
{
136 struct serial_pty_rx
: public bb_p_serial__rx
</*DATA_BITS=*/8> {
137 std::shared_ptr
<serial_pty
> desc
;
138 std::vector
<unsigned char> buffer
;
140 serial_pty_rx(const std::shared_ptr
<serial_pty
> &desc
)
142 if (desc
->has_rx()) {
143 throw std::invalid_argument(fmt_msg("RX port collision"));
148 void reset() override
{}
150 bool eval() override
{
151 if (posedge_p_clk()) {
152 if (p_ack
.get
<bool>() & p_rdy
.curr
.get
<bool>()) {
153 assert(!buffer
.empty());
154 buffer
.erase(buffer
.begin());
155 p_rdy
.next
.set
<bool>(false);
157 if (desc
->pty
.readable()) {
158 buffer
.insert(buffer
.end(), desc
->pty
.read_char());
160 if (!buffer
.empty()) {
161 p_rdy
.next
.set
<bool>(true);
162 p_data
.next
.set
<unsigned char>(buffer
.front());
165 return bb_p_serial__rx
</*DATA_BITS=*/8>::eval();
170 std::unique_ptr
<bb_p_serial__rx
</*DATA_BITS=*/8>>
171 bb_p_serial__rx
</*DATA_BITS=*/8>::create(std::string name
, cxxrtl::metadata_map parameters
,
172 cxxrtl::metadata_map attributes
) {
173 assert(parameters
.count("ID"));
174 const std::string
&id
= parameters
["ID"].as_string();
176 std::shared_ptr
<serial_pty
> desc
= serial_pty::get(id
);
177 std::cout
<< "Assigning '" << name
<< "' to " << ptsname(desc
->pty
.fd
) << "\n";
179 return std::make_unique
<serial_pty_rx
>(desc
);
184 struct serial_pty_tx
: public bb_p_serial__tx
</*DATA_BITS=*/8> {
185 const std::shared_ptr
<serial_pty
> desc
;
187 serial_pty_tx(const std::shared_ptr
<serial_pty
> &desc
)
189 if (desc
->has_tx()) {
190 throw std::invalid_argument(fmt_msg("TX port collision"));
195 void reset() override
{}
197 bool eval() override
{
198 if (posedge_p_clk()) {
199 if (p_ack
.get
<bool>() & p_rdy
.curr
.get
<bool>()) {
200 desc
->pty
.write_char(p_data
.get
<unsigned char>());
202 p_rdy
.next
.set
<bool>(desc
->pty
.writable());
204 return bb_p_serial__tx
</*DATA_BITS=*/8>::eval();
209 std::unique_ptr
<bb_p_serial__tx
</*DATA_BITS=*/8>>
210 bb_p_serial__tx
</*DATA_BITS=*/8>::create(std::string name
, cxxrtl::metadata_map parameters
,
211 cxxrtl::metadata_map attributes
) {
212 assert(parameters
.count("ID"));
213 const std::string
&id
= parameters
["ID"].as_string();
215 std::shared_ptr
<serial_pty
> desc
= serial_pty::get(id
);
216 std::cout
<< "Assigning '" << name
<< "' to " << ptsname(desc
->pty
.fd
) << "\n";
218 return std::make_unique
<serial_pty_tx
>(desc
);
221 } // namespace cxxrtl_design