diff --git a/devices/serial/escc.cpp b/devices/serial/escc.cpp
index 42a3736..e1967ac 100644
--- a/devices/serial/escc.cpp
+++ b/devices/serial/escc.cpp
@@ -21,6 +21,7 @@ along with this program. If not, see .
/** @file Enhanced Serial Communications Controller (ESCC) emulation. */
+#include
#include
#include
#include
@@ -324,6 +325,97 @@ uint8_t EsccChannel::receive_byte()
return c;
}
+void EsccChannel::dma_start_tx()
+{
+
+}
+
+void EsccChannel::dma_start_rx()
+{
+
+}
+
+void EsccChannel::dma_stop_tx()
+{
+ if (this->timer_id_tx) {
+ TimerManager::get_instance()->cancel_timer(this->timer_id_tx);
+ this->timer_id_tx = 0;
+ }
+}
+
+void EsccChannel::dma_stop_rx()
+{
+ if (this->timer_id_rx) {
+ TimerManager::get_instance()->cancel_timer(this->timer_id_rx);
+ this->timer_id_rx = 0;
+ }
+}
+
+void EsccChannel::dma_in_tx()
+{
+ LOG_F(ERROR, "%s: Unexpected DMA INPUT command for transmit.", this->name.c_str());
+}
+
+void EsccChannel::dma_in_rx()
+{
+ if (dma_ch[1]->get_push_data_remaining()) {
+ this->timer_id_rx = TimerManager::get_instance()->add_oneshot_timer(
+ 0,
+ [this]() {
+ this->timer_id_rx = 0;
+ char c = receive_byte();
+ int xx = dma_ch[1]->push_data(&c, 1);
+ this->dma_in_rx();
+ });
+ }
+}
+
+void EsccChannel::dma_out_tx()
+{
+ this->timer_id_tx = TimerManager::get_instance()->add_oneshot_timer(
+ 10,
+ [this]() {
+ this->timer_id_tx = 0;
+ uint8_t *data;
+ uint32_t avail_len;
+
+ if (dma_ch[1]->pull_data(256, &avail_len, &data) == MoreData) {
+ while(avail_len) {
+ this->send_byte(*data++);
+ avail_len--;
+ }
+ this->dma_out_tx();
+ }
+ });
+}
+
+void EsccChannel::dma_out_rx()
+{
+ LOG_F(ERROR, "%s: Unexpected DMA OUTPUT command for receive.", this->name.c_str());
+}
+
+void EsccChannel::dma_flush_tx()
+{
+ this->dma_stop_tx();
+ this->timer_id_tx = TimerManager::get_instance()->add_oneshot_timer(
+ 10,
+ [this]() {
+ this->timer_id_tx = 0;
+ dma_ch[1]->end_pull_data();
+ });
+}
+
+void EsccChannel::dma_flush_rx()
+{
+ this->dma_stop_rx();
+ this->timer_id_rx = TimerManager::get_instance()->add_oneshot_timer(
+ 10,
+ [this]() {
+ this->timer_id_rx = 0;
+ dma_ch[1]->end_push_data();
+ });
+}
+
static const vector CharIoBackends = {"null", "stdio", "socket"};
static const PropMap Escc_Properties = {
diff --git a/devices/serial/escc.h b/devices/serial/escc.h
index 190b10b..c92c6f0 100644
--- a/devices/serial/escc.h
+++ b/devices/serial/escc.h
@@ -25,6 +25,7 @@ along with this program. If not, see .
#define ESCC_H
#include
+#include
#include
#include
@@ -104,7 +105,55 @@ public:
void send_byte(uint8_t value);
uint8_t receive_byte();
+ void set_dma_channel(int dir_index, DmaBidirChannel *dma_ch) {
+ this->dma_ch[dir_index] = dma_ch;
+ auto dbdma_ch = dynamic_cast(dma_ch);
+ if (dbdma_ch) {
+ switch (dir_index) {
+ case 0:
+ dbdma_ch->set_callbacks(
+ std::bind(&EsccChannel::dma_start_tx, this),
+ std::bind(&EsccChannel::dma_stop_tx, this)
+ );
+ dbdma_ch->set_data_callbacks(
+ std::bind(&EsccChannel::dma_in_tx, this),
+ std::bind(&EsccChannel::dma_out_tx, this),
+ std::bind(&EsccChannel::dma_flush_tx, this)
+ );
+ break;
+ case 1:
+ dbdma_ch->set_callbacks(
+ std::bind(&EsccChannel::dma_start_rx, this),
+ std::bind(&EsccChannel::dma_stop_rx, this)
+ );
+ dbdma_ch->set_data_callbacks(
+ std::bind(&EsccChannel::dma_in_rx, this),
+ std::bind(&EsccChannel::dma_out_rx, this),
+ std::bind(&EsccChannel::dma_flush_rx, this)
+ );
+ break;
+ }
+ }
+ };
+
private:
+ uint32_t timer_id_tx = 0;
+ uint32_t timer_id_rx = 0;
+
+ void dma_start_tx();
+ void dma_stop_tx();
+ void dma_in_tx();
+ void dma_out_tx();
+ void dma_flush_tx();
+
+ void dma_start_rx();
+ void dma_stop_rx();
+ void dma_in_rx();
+ void dma_out_rx();
+ void dma_flush_rx();
+
+ DmaBidirChannel* dma_ch[2];
+
std::string name;
uint8_t read_regs[16];
uint8_t write_regs[16];
@@ -132,10 +181,11 @@ public:
uint8_t read(uint8_t reg_offset);
void write(uint8_t reg_offset, uint8_t value);
- void dma_start();
- void dma_stop();
- void set_dma_channel(int ch_index, DmaBidirChannel *dma_ch) {
- this->dma_ch[ch_index] = dma_ch;
+ void set_dma_channel(int ch_dir_index, DmaBidirChannel *dma_ch) {
+ switch (ch_dir_index >> 1) {
+ case 0: ch_a->set_dma_channel(ch_dir_index & 1, dma_ch); break;
+ case 1: ch_b->set_dma_channel(ch_dir_index & 1, dma_ch); break;
+ }
};
private:
@@ -149,8 +199,6 @@ private:
uint8_t master_int_cntrl;
uint8_t int_vec;
-
- DmaBidirChannel* dma_ch[4];
};
#endif // ESCC_H