From c87fc103760dc186121e1ece27c68247341a41ae Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Mon, 7 Nov 2022 12:32:34 +0100 Subject: [PATCH] amic: implement SCSI DMA. --- devices/ioctrl/amic.cpp | 67 +++++++++++++++++++++++++++++++++++++++-- devices/ioctrl/amic.h | 42 +++++++++++++++++++++++--- 2 files changed, 101 insertions(+), 8 deletions(-) diff --git a/devices/ioctrl/amic.cpp b/devices/ioctrl/amic.cpp index 7a9b7e9..adc348a 100644 --- a/devices/ioctrl/amic.cpp +++ b/devices/ioctrl/amic.cpp @@ -53,6 +53,8 @@ AMIC::AMIC() : MMIODevice() // connect internal SCSI controller this->scsi = dynamic_cast(gMachineObj->get_comp_by_name("Sc53C94")); + this->scsi_dma = std::unique_ptr (new AmicScsiDma()); + this->scsi->set_dma_channel(this->scsi_dma.get()); // connect serial HW this->escc = dynamic_cast(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 Amic_Subdevices = { "Sc53C94", "Escc", "Mace", "ViaCuda", "Swim3" }; diff --git a/devices/ioctrl/amic.h b/devices/ioctrl/amic.h index fb91587..141589b 100644 --- a/devices/ioctrl/amic.h +++ b/devices/ioctrl/amic.h @@ -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 awacs; std::unique_ptr snd_out_dma; std::unique_ptr floppy_dma; + std::unique_ptr scsi_dma; // on-board video std::unique_ptr disp_id;