quic/qbox
Loading...
Searching...
No Matches
uart-ibex.h
1/*
2 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#pragma once
8
9#include <queue>
10#include <mutex>
11
12#include <systemc>
13#include <tlm.h>
14#include <tlm_utils/simple_target_socket.h>
15
16#include <async_event.h>
17#include <ports/biflow-socket.h>
18#include <module_factory_registery.h>
19#include <scp/report.h>
20
21class ibex_uart : public sc_core::sc_module
22{
23 SCP_LOGGER();
24
25public:
26 enum Reg {
27 REG_ITSTAT = 0x00,
28 REG_ITEN = 0x04,
29 REG_ITTEST = 0x08,
30 REG_CTRL = 0x0c,
31 REG_STATUS = 0x10,
32 REG_RDATA = 0x14,
33 REG_WDATA = 0x18,
34 };
35
36 enum {
37 FIELD_IT_RXWATERMARK = 0x2,
38 FIELD_CTRL_TXENABLE = 0x1,
39 FIELD_CTRL_RXENABLE = 0x2,
40 FIELD_STATUS_TXEMPTY = 0x04,
41 FIELD_STATUS_RXIDLE = 0x10,
42 FIELD_STATUS_RXEMPTY = 0x20,
43 };
44
45 sc_core::sc_out<bool> irq_rxwatermark;
46
47 uint32_t it_state;
48 uint32_t it_enable;
49 uint32_t ctrl;
50 uint32_t status;
51
52 uint8_t rdata;
53
54 void update_irqs(void)
55 {
56 uint32_t it = it_state & it_enable;
57 if (it & FIELD_IT_RXWATERMARK) {
58 irq_rxwatermark = true;
59 } else {
60 irq_rxwatermark = false;
61 }
62 }
63
64 void recv(uint32_t value)
65 {
66 if ((ctrl & FIELD_CTRL_RXENABLE) && (status & FIELD_STATUS_RXEMPTY)) {
67 rdata = value;
68 status &= ~(FIELD_STATUS_RXEMPTY | FIELD_STATUS_RXIDLE);
69 it_state |= FIELD_IT_RXWATERMARK;
70 update_event.notify();
71 } else {
72 SCP_ERR(()) << "ibex_uart: rx char overflow, ignoring chracter 0x" << (unsigned)value << " '" << value
73 << "'";
74 }
75 }
76
77 void receive(tlm::tlm_generic_payload& txn, sc_core::sc_time& t)
78 {
79 uint8_t* data = txn.get_data_ptr();
80 for (int i = 0; i < txn.get_streaming_width(); i++) {
81 recv(data[i]);
82 }
83 }
84
85public:
86 tlm_utils::simple_target_socket<ibex_uart> socket;
87
88 gs::biflow_socket<ibex_uart> backend_socket;
89
90 sc_core::sc_event update_event;
91
92 ibex_uart(sc_core::sc_module_name name)
93 : irq_rxwatermark("irq_rx_watermark"), socket("target_socket"), backend_socket("backend_socket")
94 {
95 ctrl = 0;
96 status = FIELD_STATUS_TXEMPTY | FIELD_STATUS_RXIDLE | FIELD_STATUS_RXEMPTY;
97 rdata = 0;
98 it_enable = 0;
99 it_state = 0;
100
101 SCP_TRACE(()) << "ibex_uart constructor";
102 socket.register_b_transport(this, &ibex_uart::b_transport);
103 backend_socket.register_b_transport(this, &ibex_uart::receive); // add the recive method
104
105 SC_METHOD(update_irqs);
106 sensitive << update_event;
107 }
108
109 void b_transport(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay)
110 {
111 unsigned char* ptr = trans.get_data_ptr();
112 uint64_t addr = trans.get_address();
113 unsigned int len = trans.get_data_length();
114
115 if (addr & 0x3) {
116 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
117 return;
118 }
119
120 switch (trans.get_command()) {
121 case tlm::TLM_WRITE_COMMAND:
122 switch (len) {
123 case 1:
124 reg_write(addr, *ptr);
125 break;
126 case 2:
127 reg_write(addr, *(uint16_t*)ptr);
128 break;
129 case 4:
130 reg_write(addr, *(uint32_t*)ptr);
131 break;
132 default:
133 SCP_FATAL(()) << "Incorrect transaction size";
134 break;
135 }
136 break;
137 case tlm::TLM_READ_COMMAND:
138 switch (len) {
139 case 1:
140 *ptr = (uint8_t)reg_read(addr);
141 break;
142 case 2:
143 *ptr = (uint16_t)reg_read(addr);
144 break;
145 case 4:
146 *(uint32_t*)ptr = reg_read(addr);
147 break;
148 default:
149 SCP_FATAL(()) << "Incorrect transaction size";
150 break;
151 }
152 break;
153 default:
154 break;
155 }
156
157 trans.set_dmi_allowed(false);
158 trans.set_response_status(tlm::TLM_OK_RESPONSE);
159 }
160
161 uint64_t reg_read(uint64_t addr)
162 {
163 uint64_t r = 0;
164
165 switch (addr) {
166 case REG_ITSTAT:
167 r = it_state;
168 break;
169 case REG_ITEN:
170 r = it_enable;
171 break;
172 case REG_CTRL:
173 r = ctrl;
174 break;
175 case REG_STATUS:
176 r = status;
177 break;
178 case REG_RDATA:
179 r = rdata;
180 if (ctrl & FIELD_CTRL_RXENABLE) {
181 status |= FIELD_STATUS_RXIDLE | FIELD_STATUS_RXEMPTY;
182 rdata = 0;
183 }
184 backend_socket.can_receive_more(1);
185 break;
186 }
187 return r;
188 }
189
190 void reg_write(uint64_t addr, uint32_t data)
191 {
192 switch (addr) {
193 case REG_ITSTAT:
194 it_state &= ~data;
195 update_event.notify();
196 break;
197 case REG_ITEN:
198 it_enable = data & FIELD_IT_RXWATERMARK;
199 backend_socket.can_receive_set(1);
200 update_event.notify();
201 break;
202 case REG_CTRL:
203 ctrl = data;
204 break;
205 case REG_STATUS:
206 break;
207 case REG_WDATA:
208 backend_socket.enqueue(data & 0xFF);
209 break;
210 }
211 }
212
213 void before_end_of_elaboration()
214 {
215 if (!irq_rxwatermark.get_interface()) {
216 sc_core::sc_signal<bool>* stub = new sc_core::sc_signal<bool>(sc_core::sc_gen_unique_name("stub"));
217 irq_rxwatermark.bind(*stub);
218 }
219 }
220};
221extern "C" void module_register();
Definition target.h:160
Definition biflow-socket.h:73
void enqueue(T data)
enqueue Enqueue data to be sent (unlimited queue size) NOTE: Thread safe.
Definition biflow-socket.h:277
void can_receive_set(int i)
can_receive_set
Definition biflow-socket.h:253
void register_b_transport(MODULE *mod, void(MODULE::*cb)(tlm::tlm_generic_payload &, sc_core::sc_time &))
Register b_transport to be called whenever data is received from the socket.
Definition biflow-socket.h:227
void can_receive_more(int i)
can_receive_more
Definition biflow-socket.h:237
Definition uart-ibex.h:22