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 // intialize floppy disk HW
this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl()); 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()); 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_1:
case AMICReg::DMA_Base_Addr_2: case AMICReg::DMA_Base_Addr_2:
case AMICReg::DMA_Base_Addr_3: 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: case AMICReg::SCSI_DMA_Ctrl:
return this->scsi_dma_cs; return this->scsi_dma_cs;
case AMICReg::Floppy_Addr_Ptr_0: case AMICReg::Floppy_Addr_Ptr_0:
case AMICReg::Floppy_Addr_Ptr_1: case AMICReg::Floppy_Addr_Ptr_1:
case AMICReg::Floppy_Addr_Ptr_2: case AMICReg::Floppy_Addr_Ptr_2:
case AMICReg::Floppy_Addr_Ptr_3: 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: case AMICReg::Floppy_DMA_Ctrl:
return this->floppy_dma_cs; return this->floppy_dma->read_stat();
default: default:
LOG_F(WARNING, "Unknown AMIC register read, offset=%x", offset); 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); SET_SIZE_BYTE(this->floppy_byte_cnt, offset, value);
break; break;
case AMICReg::Floppy_DMA_Ctrl: case AMICReg::Floppy_DMA_Ctrl:
LOG_F(INFO, "AMIC SWIM3 DMA Ctrl updated, val=%x", value); if (value & 1) { // RST bit set?
// copy over DIR and IE bits this->floppy_addr_ptr = this->dma_base + 0x15000;
this->floppy_dma_cs = (floppy_dma_cs & 0x83) | (value & 0x48); this->floppy_dma->reset(this->floppy_addr_ptr);
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 & 2) { // RUN bit set?
this->floppy_dma->reinit(this->floppy_addr_ptr, this->floppy_byte_cnt);
}
this->floppy_dma->write_ctrl(value);
break; break;
case AMICReg::SCC_DMA_Xmt_A_Ctrl: case AMICReg::SCC_DMA_Xmt_A_Ctrl:
LOG_F(INFO, "AMIC SCC Transmit Ch A DMA Ctrl updated, val=%x", value); 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"); ABORT_F("AMIC: ack_dma_int() not implemented");
} }
// =========================== DMA related stuff ============================= // ============================ Sound DMA stuff ================================
AmicSndOutDma::AmicSndOutDma() AmicSndOutDma::AmicSndOutDma()
{ {
this->dma_out_ctrl = 0; this->dma_out_ctrl = 0;
this->enabled = false; this->enabled = false;
} }
bool AmicSndOutDma::is_active()
{
return true;
}
void AmicSndOutDma::init(uint32_t buf_base, uint32_t buf_samples) void AmicSndOutDma::init(uint32_t buf_base, uint32_t buf_samples)
{ {
this->out_buf0 = buf_base + AMIC_SND_BUF0_OFFS; 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; return DmaPullResult::MoreData;
} }
// =========================== Floppy DMA stuff ============================== // ============================ Floppy DMA stuff ===============================
void AMIC::reset_floppy_dma() void AmicFloppyDma::reset(const uint32_t addr_ptr)
{ {
this->floppy_dma_cs &= 0x48; // clear interrupt flang, RUN and RST bits this->stat &= 0x48; // clear interrupt flag, RUN and RST bits
this->floppy_addr_ptr = this->dma_base + 0x15000; this->addr_ptr = addr_ptr;
this->floppy_byte_cnt = 0; 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();
~AmicSndOutDma() = default; ~AmicSndOutDma() = default;
bool is_active();
void init(uint32_t buf_base, uint32_t buf_samples); void init(uint32_t buf_base, uint32_t buf_samples);
void enable() { this->enabled = true; }; void enable() { this->enabled = true; };
void disable() { this->enabled = false; }; void disable() { this->enabled = false; };
@@ -82,6 +81,27 @@ private:
uint32_t cur_buf_pos; 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 // macro for byte wise updating of AMIC DMA address registers
#define SET_ADDR_BYTE(reg, offset, value) \ #define SET_ADDR_BYTE(reg, offset, value) \
mask = 0xFF000000UL >> (8 * ((offset) & 3)); \ mask = 0xFF000000UL >> (8 * ((offset) & 3)); \
@@ -180,7 +200,6 @@ public:
protected: protected:
void ack_via2_int(uint32_t irq_id, uint8_t irq_line_state); 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 ack_cpu_int(uint32_t irq_id, uint8_t irq_line_state);
void reset_floppy_dma();
private: private:
uint8_t imm_snd_regs[4]; // temporary storage for sound control registers uint8_t imm_snd_regs[4]; // temporary storage for sound control registers
@@ -192,7 +211,6 @@ private:
// floppy DMA state // floppy DMA state
uint32_t floppy_addr_ptr; uint32_t floppy_addr_ptr;
uint16_t floppy_byte_cnt; 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 scsi_dma_cs = 0; // SCSI DMA control/status register value
@@ -214,6 +232,7 @@ private:
std::unique_ptr<AwacDevicePdm> awacs; std::unique_ptr<AwacDevicePdm> awacs;
std::unique_ptr<AmicSndOutDma> snd_out_dma; std::unique_ptr<AmicSndOutDma> snd_out_dma;
std::unique_ptr<AmicFloppyDma> floppy_dma;
// on-board video // on-board video
std::unique_ptr<DisplayID> disp_id; std::unique_ptr<DisplayID> disp_id;