mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 20:29:46 +00:00
escc: Attempt to add DBDMA support.
Move dma channels from EsccController to EsccChannel. Add DBDMA callbacks.
This commit is contained in:
parent
6adba32238
commit
159fe8d48e
@ -21,6 +21,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file Enhanced Serial Communications Controller (ESCC) emulation. */
|
||||
|
||||
#include <core/timermanager.h>
|
||||
#include <devices/deviceregistry.h>
|
||||
#include <devices/serial/chario.h>
|
||||
#include <devices/serial/escc.h>
|
||||
@ -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<string> CharIoBackends = {"null", "stdio", "socket"};
|
||||
|
||||
static const PropMap Escc_Properties = {
|
||||
|
@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#define ESCC_H
|
||||
|
||||
#include <devices/common/hwcomponent.h>
|
||||
#include <devices/common/dbdma.h>
|
||||
#include <devices/serial/chario.h>
|
||||
|
||||
#include <cinttypes>
|
||||
@ -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<DMAChannel*>(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
|
||||
|
Loading…
x
Reference in New Issue
Block a user