diff --git a/devices/ioctrl/amic.cpp b/devices/ioctrl/amic.cpp index e240526..e8ed2f6 100644 --- a/devices/ioctrl/amic.cpp +++ b/devices/ioctrl/amic.cpp @@ -114,7 +114,7 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size) case AMICReg::Snd_Stat_0: case AMICReg::Snd_Stat_1: case AMICReg::Snd_Stat_2: - return (this->awacs->read_stat() >> (offset & 3 * 8)) & 0xFF; + return (this->awacs->read_stat() >> (offset & 3) * 8) & 0xFF; case AMICReg::Snd_Phase0: case AMICReg::Snd_Phase1: case AMICReg::Snd_Phase2: @@ -153,8 +153,20 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size) return (this->int_ctrl & 0xC0) | (this->dev_irq_lines & 0x3F); case AMICReg::Diag_Reg: return 0xFFU; // this value allows the machine to boot normally + case AMICReg::DMA_Base_Addr_0: + 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; 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; + case AMICReg::Floppy_DMA_Ctrl: + return this->floppy_dma_cs; default: LOG_F(WARNING, "Unknown AMIC register read, offset=%x", offset); } @@ -197,9 +209,7 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) return; case AMICReg::Snd_Buf_Size_Hi: case AMICReg::Snd_Buf_Size_Lo: - mask = 0xFF00U >> (8 * (offset & 1)); - this->snd_buf_size = (this->snd_buf_size & ~mask) | - ((value & 0xFF) << (8 * ((offset & 1) ^1))); + SET_SIZE_BYTE(this->snd_buf_size, offset, value); this->snd_buf_size &= ~3; // sound buffer size is always a multiple of 4 LOG_F(9, "AMIC: Sound buffer size set to 0x%X", this->snd_buf_size); return; @@ -286,9 +296,8 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) case AMICReg::DMA_Base_Addr_1: case AMICReg::DMA_Base_Addr_2: case AMICReg::DMA_Base_Addr_3: - mask = 0xFF000000UL >> (8 * (offset & 3)); - this->dma_base = (this->dma_base & ~mask) | - ((value & 0xFF) << (8 * (3 - (offset & 3)))); + SET_ADDR_BYTE(this->dma_base, offset, value); + this->dma_base &= 0xFFFC0000UL; LOG_F(9, "AMIC: DMA base address set to 0x%X", this->dma_base); break; case AMICReg::Enet_DMA_Xmt_Ctrl: @@ -301,8 +310,28 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) case AMICReg::Enet_DMA_Rcv_Ctrl: LOG_F(INFO, "AMIC Ethernet Receive DMA Ctrl updated, val=%x", value); break; - case AMICReg::SWIM3_DMA_Ctrl: + case AMICReg::Floppy_Addr_Ptr_2: + case AMICReg::Floppy_Addr_Ptr_3: + SET_ADDR_BYTE(this->floppy_addr_ptr, offset, value); + break; + case AMICReg::Floppy_Byte_Cnt_Hi: + case AMICReg::Floppy_Byte_Cnt_Lo: + 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; + } + } break; case AMICReg::SCC_DMA_Xmt_A_Ctrl: LOG_F(INFO, "AMIC SCC Transmit Ch A DMA Ctrl updated, val=%x", value); @@ -460,3 +489,11 @@ DmaPullResult AmicSndOutDma::pull_data(uint32_t req_len, uint32_t *avail_len, *avail_len = len; return DmaPullResult::MoreData; } + +// =========================== Floppy DMA stuff ============================== +void AMIC::reset_floppy_dma() +{ + 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; +} diff --git a/devices/ioctrl/amic.h b/devices/ioctrl/amic.h index 79c55b1..1109474 100644 --- a/devices/ioctrl/amic.h +++ b/devices/ioctrl/amic.h @@ -82,6 +82,16 @@ private: uint32_t cur_buf_pos; }; +// macro for byte wise updating of AMIC DMA address registers +#define SET_ADDR_BYTE(reg, offset, value) \ + mask = 0xFF000000UL >> (8 * ((offset) & 3)); \ + (reg) = ((reg) & ~mask) | (((value) & 0xFF) << (8 * (3 - ((offset) & 3)))); + +// macro for byte wise updating of AMIC DMA size registers +#define SET_SIZE_BYTE(reg, offset, value) \ + mask = 0xFF00U >> (8 * ((offset) & 1)); \ + (reg) = ((reg) & ~mask) | (((value) & 0xFF) << (8 * (((offset) & 1) ^ 1))); + /* AMIC registers offsets from AMIC base (0x50F00000). */ enum AMICReg : uint32_t { // Sound control registers @@ -132,7 +142,16 @@ enum AMICReg : uint32_t { Enet_DMA_Xmt_Ctrl = 0x31C20, SCSI_DMA_Ctrl = 0x32008, Enet_DMA_Rcv_Ctrl = 0x32028, - SWIM3_DMA_Ctrl = 0x32068, + + // Floppy (SWIM3) DMA registers + Floppy_Addr_Ptr_0 = 0x32060, + Floppy_Addr_Ptr_1 = 0x32061, + Floppy_Addr_Ptr_2 = 0x32062, + Floppy_Addr_Ptr_3 = 0x32063, + Floppy_Byte_Cnt_Hi = 0x32064, + Floppy_Byte_Cnt_Lo = 0x32065, + Floppy_DMA_Ctrl = 0x32068, + SCC_DMA_Xmt_A_Ctrl = 0x32088, SCC_DMA_Rcv_A_Ctrl = 0x32098, SCC_DMA_Xmt_B_Ctrl = 0x320A8, @@ -161,15 +180,21 @@ 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 - uint32_t dma_base = 0; // DMA physical base address - uint16_t snd_buf_size = 0; // sound buffer size in bytes + 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; - uint8_t scsi_dma_cs = 0; // SCSI DMA control/status register value + // 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 uint8_t int_ctrl = 0; uint8_t dev_irq_lines = 0; // state of the IRQ lines