From 579a56f7495dd9dcc01ef123b2937d7e29e320cd Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Tue, 15 Feb 2022 15:54:21 +0100 Subject: [PATCH] AMIC: implement floppy DMA channel. --- devices/ioctrl/amic.cpp | 83 ++++++++++++++++++++++++++++------------- devices/ioctrl/amic.h | 25 +++++++++++-- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/devices/ioctrl/amic.cpp b/devices/ioctrl/amic.cpp index e8ed2f6..124a791 100644 --- a/devices/ioctrl/amic.cpp +++ b/devices/ioctrl/amic.cpp @@ -70,6 +70,8 @@ AMIC::AMIC() : MMIODevice() // intialize floppy disk HW this->swim3 = std::unique_ptr (new Swim3::Swim3Ctrl()); + this->floppy_dma = std::unique_ptr (new AmicFloppyDma()); + this->swim3->set_dma_channel(this->floppy_dma.get()); gMachineObj->add_subdevice("SWIM3", this->swim3.get()); } @@ -157,16 +159,16 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size) case AMICReg::DMA_Base_Addr_1: case AMICReg::DMA_Base_Addr_2: case AMICReg::DMA_Base_Addr_3: - return (this->dma_base >> (offset & 3) * 8) & 0xFF; + return (this->dma_base >> (3 - (offset & 3)) * 8) & 0xFF; case AMICReg::SCSI_DMA_Ctrl: return this->scsi_dma_cs; case AMICReg::Floppy_Addr_Ptr_0: case AMICReg::Floppy_Addr_Ptr_1: case AMICReg::Floppy_Addr_Ptr_2: case AMICReg::Floppy_Addr_Ptr_3: - return (this->floppy_addr_ptr >> (offset & 3) * 8) & 0xFF; + return (this->floppy_addr_ptr >> (3 - (offset & 3)) * 8) & 0xFF; case AMICReg::Floppy_DMA_Ctrl: - return this->floppy_dma_cs; + return this->floppy_dma->read_stat(); default: LOG_F(WARNING, "Unknown AMIC register read, offset=%x", offset); } @@ -319,19 +321,14 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) SET_SIZE_BYTE(this->floppy_byte_cnt, offset, value); break; case AMICReg::Floppy_DMA_Ctrl: - LOG_F(INFO, "AMIC SWIM3 DMA Ctrl updated, val=%x", value); - // copy over DIR and IE bits - this->floppy_dma_cs = (floppy_dma_cs & 0x83) | (value & 0x48); - if (value & 1) { - this->reset_floppy_dma(); - } else { - // copy over RUN bit - this->floppy_dma_cs = (floppy_dma_cs & 0xC8) | (value & 2); - // clear interrupt flag if requested - if (value & 0x80) { - this->floppy_dma_cs &= 0x7F; - } + if (value & 1) { // RST bit set? + this->floppy_addr_ptr = this->dma_base + 0x15000; + this->floppy_dma->reset(this->floppy_addr_ptr); } + if (value & 2) { // RUN bit set? + this->floppy_dma->reinit(this->floppy_addr_ptr, this->floppy_byte_cnt); + } + this->floppy_dma->write_ctrl(value); break; case AMICReg::SCC_DMA_Xmt_A_Ctrl: LOG_F(INFO, "AMIC SCC Transmit Ch A DMA Ctrl updated, val=%x", value); @@ -414,18 +411,13 @@ void AMIC::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) { ABORT_F("AMIC: ack_dma_int() not implemented"); } -// =========================== DMA related stuff ============================= +// ============================ Sound DMA stuff ================================ AmicSndOutDma::AmicSndOutDma() { this->dma_out_ctrl = 0; this->enabled = false; } -bool AmicSndOutDma::is_active() -{ - return true; -} - void AmicSndOutDma::init(uint32_t buf_base, uint32_t buf_samples) { this->out_buf0 = buf_base + AMIC_SND_BUF0_OFFS; @@ -490,10 +482,49 @@ DmaPullResult AmicSndOutDma::pull_data(uint32_t req_len, uint32_t *avail_len, return DmaPullResult::MoreData; } -// =========================== Floppy DMA stuff ============================== -void AMIC::reset_floppy_dma() +// ============================ Floppy DMA stuff =============================== +void AmicFloppyDma::reset(const uint32_t addr_ptr) { - this->floppy_dma_cs &= 0x48; // clear interrupt flang, RUN and RST bits - this->floppy_addr_ptr = this->dma_base + 0x15000; - this->floppy_byte_cnt = 0; + this->stat &= 0x48; // clear interrupt flag, RUN and RST bits + this->addr_ptr = addr_ptr; + this->byte_count = 0; +} + +void AmicFloppyDma::reinit(const uint32_t addr_ptr, const uint16_t byte_cnt) +{ + this->addr_ptr = addr_ptr; + this->byte_count = byte_cnt; +} + +void AmicFloppyDma::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 AmicFloppyDma::push_data(const char* src_ptr, int len) +{ + len = std::min((int)this->byte_count, len); + + uint8_t *p_data = mmu_get_dma_mem(this->addr_ptr, len); + std::memcpy(p_data, src_ptr, len); + + this->addr_ptr += len; + this->byte_count -= len; + if (!this->byte_count) { + LOG_F(WARNING, "AMIC: DMA interrupts not implemented yet"); + } + + return 0; +} + +DmaPullResult AmicFloppyDma::pull_data(uint32_t req_len, uint32_t *avail_len, + uint8_t **p_data) +{ + return DmaPullResult::NoMoreData; } diff --git a/devices/ioctrl/amic.h b/devices/ioctrl/amic.h index 1109474..8616919 100644 --- a/devices/ioctrl/amic.h +++ b/devices/ioctrl/amic.h @@ -61,7 +61,6 @@ public: AmicSndOutDma(); ~AmicSndOutDma() = default; - bool is_active(); void init(uint32_t buf_base, uint32_t buf_samples); void enable() { this->enabled = true; }; void disable() { this->enabled = false; }; @@ -82,6 +81,27 @@ private: uint32_t cur_buf_pos; }; +/** AMIC-specific floppy DMA implementation. */ +class AmicFloppyDma : public DmaBidirChannel { +public: + AmicFloppyDma() = default; + ~AmicFloppyDma() = default; + + void reinit(const uint32_t addr_ptr, const uint16_t byte_cnt); + 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)); \ @@ -180,7 +200,6 @@ public: protected: void ack_via2_int(uint32_t irq_id, uint8_t irq_line_state); void ack_cpu_int(uint32_t irq_id, uint8_t irq_line_state); - void reset_floppy_dma(); private: uint8_t imm_snd_regs[4]; // temporary storage for sound control registers @@ -192,7 +211,6 @@ private: // floppy DMA state uint32_t floppy_addr_ptr; uint16_t floppy_byte_cnt; - uint8_t floppy_dma_cs; // floppy DMA control/status value uint8_t scsi_dma_cs = 0; // SCSI DMA control/status register value @@ -214,6 +232,7 @@ private: std::unique_ptr awacs; std::unique_ptr snd_out_dma; + std::unique_ptr floppy_dma; // on-board video std::unique_ptr disp_id;