AMIC: implement floppy DMA channel.

This commit is contained in:
Maxim Poliakovski 2022-02-15 15:54:21 +01:00
parent 2525398b6e
commit 579a56f749
2 changed files with 79 additions and 29 deletions

View File

@ -70,6 +70,8 @@ AMIC::AMIC() : MMIODevice()
// intialize floppy disk HW
this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl());
this->floppy_dma = std::unique_ptr<AmicFloppyDma> (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;
}

View File

@ -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<AwacDevicePdm> awacs;
std::unique_ptr<AmicSndOutDma> snd_out_dma;
std::unique_ptr<AmicFloppyDma> floppy_dma;
// on-board video
std::unique_ptr<DisplayID> disp_id;