amic: implement SCSI DMA.

This commit is contained in:
Maxim Poliakovski 2022-11-07 12:32:34 +01:00
parent a00b87790b
commit c87fc10376
2 changed files with 101 additions and 8 deletions

View File

@ -53,6 +53,8 @@ AMIC::AMIC() : MMIODevice()
// connect internal SCSI controller
this->scsi = dynamic_cast<Sc53C94*>(gMachineObj->get_comp_by_name("Sc53C94"));
this->scsi_dma = std::unique_ptr<AmicScsiDma> (new AmicScsiDma());
this->scsi->set_dma_channel(this->scsi_dma.get());
// connect serial HW
this->escc = dynamic_cast<EsccController*>(gMachineObj->get_comp_by_name("Escc"));
@ -170,7 +172,7 @@ uint32_t AMIC::read(uint32_t rgn_start, uint32_t offset, int size)
case AMICReg::DMA_Base_Addr_3:
return (this->dma_base >> (3 - (offset & 3)) * 8) & 0xFF;
case AMICReg::SCSI_DMA_Ctrl:
return this->scsi_dma_cs;
return this->scsi_dma->read_stat();
case AMICReg::Floppy_Addr_Ptr_0:
case AMICReg::Floppy_Addr_Ptr_1:
case AMICReg::Floppy_Addr_Ptr_2:
@ -324,9 +326,24 @@ void AMIC::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
case AMICReg::Enet_DMA_Xmt_Ctrl:
LOG_F(INFO, "AMIC Ethernet Transmit DMA Ctrl updated, val=%x", value);
break;
case AMICReg::SCSI_DMA_Base_0:
case AMICReg::SCSI_DMA_Base_1:
case AMICReg::SCSI_DMA_Base_2:
case AMICReg::SCSI_DMA_Base_3:
SET_ADDR_BYTE(this->scsi_dma_base, offset, value);
this->scsi_dma_base &= 0xFFFFFFF8UL;
LOG_F(9, "AMIC: SCSI DMA base address set to 0x%X", this->scsi_dma_base);
break;
case AMICReg::SCSI_DMA_Ctrl:
LOG_F(INFO, "AMIC SCSI DMA Ctrl updated, val=%x", value);
this->scsi_dma_cs = value;
if (value & 1) { // RST bit set?
this->scsi_addr_ptr = this->scsi_dma_base;
this->scsi_dma->reset(this->scsi_addr_ptr);
}
if (value & 2) { // RUN bit set?
this->scsi_dma->reinit(this->scsi_dma_base);
this->scsi->real_dma_xfer((value >> 6) & 1);
}
this->scsi_dma->write_ctrl(value);
break;
case AMICReg::Enet_DMA_Rcv_Ctrl:
LOG_F(INFO, "AMIC Ethernet Receive DMA Ctrl updated, val=%x", value);
@ -554,6 +571,50 @@ DmaPullResult AmicFloppyDma::pull_data(uint32_t req_len, uint32_t *avail_len,
return DmaPullResult::NoMoreData;
}
// ============================ SCSI DMA stuff ================================
void AmicScsiDma::reset(const uint32_t addr_ptr)
{
this->stat &= 0x48; // clear interrupt flag, RUN and RST bits
this->addr_ptr = addr_ptr;
this->byte_count = 0;
}
void AmicScsiDma::reinit(const uint32_t addr_ptr)
{
this->addr_ptr = addr_ptr;
this->byte_count = 0;
}
void AmicScsiDma::write_ctrl(uint8_t value)
{
// copy over DIR, IE and RUN bits
this->stat = (this->stat & 0x81) | (value & 0x4A);
// clear interrupt flag if requested
if (value & 0x80) {
this->stat &= 0x7F;
}
}
int AmicScsiDma::push_data(const char* src_ptr, int len)
{
uint8_t *p_data = mmu_get_dma_mem(this->addr_ptr, len);
std::memcpy(p_data, src_ptr, len);
this->addr_ptr += len;
return 0;
}
DmaPullResult AmicScsiDma::pull_data(uint32_t req_len, uint32_t *avail_len,
uint8_t **p_data)
{
*p_data = mmu_get_dma_mem(this->addr_ptr, req_len);
this->addr_ptr += req_len;
*avail_len = req_len;
return DmaPullResult::MoreData;
}
static vector<string> Amic_Subdevices = {
"Sc53C94", "Escc", "Mace", "ViaCuda", "Swim3"
};

View File

@ -102,6 +102,27 @@ private:
uint8_t stat;
};
/** AMIC-specific SCSI DMA implementation. */
class AmicScsiDma : public DmaBidirChannel {
public:
AmicScsiDma() = default;
~AmicScsiDma() = default;
void reinit(const uint32_t addr_ptr);
void reset(const uint32_t addr_ptr);
void write_ctrl(const uint8_t value);
uint8_t read_stat() { return this->stat; };
int push_data(const char* src_ptr, int len);
DmaPullResult pull_data(uint32_t req_len, uint32_t *avail_len,
uint8_t **p_data);
private:
uint32_t addr_ptr;
uint16_t byte_count;
uint8_t stat;
};
// macro for byte wise updating of AMIC DMA address registers
#define SET_ADDR_BYTE(reg, offset, value) \
mask = 0xFF000000UL >> (8 * ((offset) & 3)); \
@ -164,9 +185,15 @@ enum AMICReg : uint32_t {
DMA_Base_Addr_2 = 0x31002,
DMA_Base_Addr_3 = 0x31003,
Enet_DMA_Xmt_Ctrl = 0x31C20,
SCSI_DMA_Ctrl = 0x32008,
Enet_DMA_Rcv_Ctrl = 0x32028,
// SCSI DMA registers
SCSI_DMA_Base_0 = 0x32000,
SCSI_DMA_Base_1 = 0x32001,
SCSI_DMA_Base_2 = 0x32002,
SCSI_DMA_Base_3 = 0x32003,
SCSI_DMA_Ctrl = 0x32008,
// Floppy (SWIM3) DMA registers
Floppy_Addr_Ptr_0 = 0x32060,
Floppy_Addr_Ptr_1 = 0x32061,
@ -214,15 +241,19 @@ private:
uint8_t emmo_pin; // EMMO aka factory tester pin status, active low
uint32_t dma_base = 0; // DMA physical base address
uint16_t snd_buf_size = 0; // sound buffer size in bytes
uint8_t snd_out_ctrl = 0;
uint32_t dma_base = 0; // DMA physical base address
uint32_t scsi_dma_base = 0; // physical base address for SCSI DMA
uint16_t snd_buf_size = 0; // sound buffer size in bytes
uint8_t snd_out_ctrl = 0;
// floppy DMA state
uint32_t floppy_addr_ptr;
uint16_t floppy_byte_cnt;
uint8_t scsi_dma_cs = 0; // SCSI DMA control/status register value
// SCSI DMA state
uint32_t scsi_addr_ptr;
//uint8_t scsi_dma_cs = 0; // SCSI DMA control/status register value
// interrupt state
uint8_t int_ctrl = 0;
@ -245,6 +276,7 @@ private:
std::unique_ptr<AwacDevicePdm> awacs;
std::unique_ptr<AmicSndOutDma> snd_out_dma;
std::unique_ptr<AmicFloppyDma> floppy_dma;
std::unique_ptr<AmicScsiDma> scsi_dma;
// on-board video
std::unique_ptr<DisplayID> disp_id;