diff --git a/devices/ethernet/mace.cpp b/devices/ethernet/mace.cpp index 8c67d94..291a6a2 100644 --- a/devices/ethernet/mace.cpp +++ b/devices/ethernet/mace.cpp @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum +Copyright (C) 2018-24 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -32,11 +32,24 @@ using namespace MaceEnet; uint8_t MaceController::read(uint8_t reg_offset) { switch(reg_offset) { - case MaceReg::Interrupt: - LOG_F(INFO, "MACE: all interrupt flags cleared"); - return 0; + case MaceReg::Rcv_Frame_Ctrl: + return this->rcv_fc; + case MaceReg::Interrupt: { + uint8_t ret_val = this->int_stat; + this->int_stat = 0; + LOG_F(9, "%s: all interrupt flags cleared", this->name.c_str()); + return ret_val; + } + case MaceReg::Interrupt_Mask: + return this->int_mask; + case MaceReg::BIU_Config_Ctrl: + return this->biu_ctrl; + case MaceReg::Chip_ID_Lo: + return this->chip_id & 0xFFU; + case MaceReg::Chip_ID_Hi: + return (this->chip_id >> 8) & 0xFFU; default: - LOG_F(INFO, "Reading MACE register %d", reg_offset); + LOG_F(INFO, "%s: reading from register %d", this->name.c_str(), reg_offset); } return 0; @@ -45,15 +58,57 @@ uint8_t MaceController::read(uint8_t reg_offset) void MaceController::write(uint8_t reg_offset, uint8_t value) { switch(reg_offset) { + case MaceReg::Rcv_Frame_Ctrl: + this->rcv_fc = value; + break; + case MaceReg::Interrupt_Mask: + this->int_mask = value; + break; + case MaceReg::MAC_Config_Ctrl: + this->mac_cfg = value; + break; case MaceReg::BIU_Config_Ctrl: - if (value & 1) { - LOG_F(INFO, "MACE Reset issued"); - } else { - LOG_F(INFO, "MACE BIU Config set to 0x%X", value); + if (value & BIU_SWRST) { + LOG_F(INFO, "%s: soft reset asserted", this->name.c_str()); + value &= ~BIU_SWRST; // acknowledge soft reset + } + this->biu_ctrl = value; + break; + case MaceReg::PLS_Config_Ctrl: + if (value != 7) + LOG_F(WARNING, "%s: unsupported transceiver interface 0x%X in PLSCC", + this->name.c_str(), value); + break; + case MaceReg::Int_Addr_Config: + if ((value & IAC_LOGADDR) && (value & IAC_PHYADDR)) + value &= ~IAC_PHYADDR; + if (value & (IAC_LOGADDR | IAC_PHYADDR)) + this->addr_ptr = 0; + this->addr_cfg = value; + break; + case MaceReg::Log_Addr_Flt: + if (this->addr_cfg & IAC_LOGADDR) { + uint64_t mask = ~(0xFFULL << (this->addr_ptr * 8)); + this->log_addr = (this->log_addr & mask) | ((uint64_t)value << (this->addr_ptr * 8)); + if (++this->addr_ptr >= 8) { + this->addr_cfg &= ~IAC_LOGADDR; + this->addr_ptr = 0; + } + } + break; + case MaceReg::Phys_Addr: + if (this->addr_cfg & IAC_PHYADDR) { + uint64_t mask = ~(0xFFULL << (this->addr_ptr * 8)); + this->phys_addr = (this->phys_addr & mask) | ((uint64_t)value << (this->addr_ptr * 8)); + if (++this->addr_ptr >= 6) { + this->addr_cfg &= ~IAC_PHYADDR; + this->addr_ptr = 0; + } } break; default: - LOG_F(INFO, "Writing 0x%X to MACE register %d", value, reg_offset); + LOG_F(INFO, "%s: writing 0x%X to register %d", this->name.c_str(), + value, reg_offset); } } diff --git a/devices/ethernet/mace.h b/devices/ethernet/mace.h index a7c505e..5be621b 100644 --- a/devices/ethernet/mace.h +++ b/devices/ethernet/mace.h @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum +Copyright (C) 2018-24 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -24,58 +24,74 @@ along with this program. If not, see . #ifndef MACE_H #define MACE_H +#include #include #include #include -// MACE Chip ID from AMD datasheet -// TODO: compare with real HW -#define MACE_ID 0x3940 +/** Known MACE chip IDs. */ +#define MACE_ID_REV_B0 0x0940 // Darwin-0.3 source +#define MACE_ID_REV_A2 0x0941 // Darwin-0.3 source & Curio datasheet -// MACE registers offsets +/** MACE registers offsets. */ // Refer to the Am79C940 datasheet for details namespace MaceEnet { + enum MaceReg : uint8_t { + Rcv_FIFO = 0, + Xmit_FIFO = 1, + Xmit_Frame_Ctrl = 2, + Xmit_Frame_Stat = 3, + Xmit_Retry_Cnt = 4, + Rcv_Frame_Ctrl = 5, + Rcv_Frame_Stat = 6, + FIFO_Frame_Cnt = 7, + Interrupt = 8, + Interrupt_Mask = 9, + Poll = 10, + BIU_Config_Ctrl = 11, + FIFO_Config = 12, + MAC_Config_Ctrl = 13, + PLS_Config_Ctrl = 14, + PHY_Config_Ctrl = 15, + Chip_ID_Lo = 16, + Chip_ID_Hi = 17, + Int_Addr_Config = 18, + Log_Addr_Flt = 20, + Phys_Addr = 21, + Missed_Pkt_Cnt = 24, + Runt_Pkt_Cnt = 26, // not used in Macintosh? + Rcv_Collis_Cnt = 27, // not used in Macintosh? + User_Test = 29, + Rsrvd_Test_1 = 30, // not used in Macintosh? + Rsrvd_Test_2 = 31, // not used in Macintosh? + }; -enum MaceReg : uint8_t { - Rcv_FIFO = 0, - Xmit_FIFO = 1, - Xmit_Frame_Ctrl = 2, - Xmit_Frame_Stat = 3, - Xmit_Retry_Cnt = 4, - Rcv_Frame_Ctrl = 5, - Rcv_Frame_Stat = 6, - FIFO_Frame_Cnt = 7, - Interrupt = 8, - Interrupt_Mask = 9, - Poll = 0x0A, - BIU_Config_Ctrl = 0x0B, - FIFO_Config = 0x0C, - MAC_Config_Ctrl = 0x0D, - PLS_Config_Ctrl = 0x0E, - PHY_Config_Ctrl = 0x0F, - Chip_ID_Lo = 0x10, - Chip_ID_Hi = 0x11, - Addr_Config = 0x12, - Log_Addr_Flt = 0x14, - Phys_Addr = 0x15, - Missed_Pkt_Cnt = 0x18, - Runt_Pkt_Cnt = 0x1A, // not used in Macintosh? - Rcv_Collis_Cnt = 0x1B, // not used in Macintosh? - User_Test = 0x1D, - Rsrvd_Test_1 = 0x1E, // not used in Macintosh? - Rsrvd_Test_2 = 0x1F, // not used in Macintosh? -}; + /** Bit definitions for BIU_Config_Ctrl register. */ + enum { + BIU_SWRST = 1 << 0, + }; + + /** Bit definitions for the internal configuration register. */ + enum { + IAC_LOGADDR = 1 << 1, + IAC_PHYADDR = 1 << 2, + IAC_ADDRCHG = 1 << 7 + }; }; // namespace MaceEnet -class MaceController : public HWComponent { +class MaceController : public DmaDevice, public HWComponent { public: - MaceController(uint16_t id) { this->chip_id = id; }; + MaceController(uint16_t id) { + this->chip_id = id; + this->set_name("MACE"); + this->supports_types(HWCompType::MMIO_DEV | HWCompType::ETHER_MAC); + }; ~MaceController() = default; static std::unique_ptr create() { - return std::unique_ptr(new MaceController(MACE_ID)); + return std::unique_ptr(new MaceController(MACE_ID_REV_A2)); } // MACE registers access @@ -84,6 +100,17 @@ public: private: uint16_t chip_id; // per-instance MACE Chip ID + uint8_t addr_cfg = 0; + uint8_t addr_ptr = 0; + uint8_t rcv_fc = 1; + uint8_t biu_ctrl = 0; + uint8_t mac_cfg = 0; + uint64_t phys_addr = 0; + uint64_t log_addr = 0; + + // interrupt stuff + uint8_t int_stat = 0; + uint8_t int_mask = 0; }; #endif // MACE_H diff --git a/devices/ioctrl/grandcentral.cpp b/devices/ioctrl/grandcentral.cpp index afd9fb3..e7bd51d 100644 --- a/devices/ioctrl/grandcentral.cpp +++ b/devices/ioctrl/grandcentral.cpp @@ -129,6 +129,13 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl() // connect Ethernet HW this->mace = dynamic_cast(gMachineObj->get_comp_by_name("Mace")); + this->enet_tx_dma = std::unique_ptr (new DMAChannel("mace_enet_tx")); + this->enet_tx_dma->register_dma_int(this, this->register_dma_int(IntSrc::DMA_ETHERNET_Tx)); + this->enet_rx_dma = std::unique_ptr (new DMAChannel("mace_enet_rx")); + this->enet_rx_dma->register_dma_int(this, this->register_dma_int(IntSrc::DMA_ETHERNET_Rx)); + this->enet_tx_dma->connect(this->mace); + this->enet_rx_dma->connect(this->mace); + this->mace->connect(this->enet_rx_dma.get()); // connect floppy disk HW this->swim3 = dynamic_cast(gMachineObj->get_comp_by_name("Swim3")); @@ -221,6 +228,10 @@ uint32_t GrandCentral::read(uint32_t rgn_start, uint32_t offset, int size) return this->curio_dma->reg_read(offset & 0xFF, size); case MIO_GC_DMA_FLOPPY: return this->floppy_dma->reg_read(offset & 0xFF, size); + case MIO_GC_DMA_ETH_XMIT: + return this->enet_tx_dma->reg_read(offset & 0xFF, size); + case MIO_GC_DMA_ETH_RCV: + return this->enet_rx_dma->reg_read(offset & 0xFF, size); case MIO_GC_DMA_ESCC_A_XMIT: return this->escc_a_tx_dma->reg_read(offset & 0xFF, size); case MIO_GC_DMA_ESCC_A_RCV: @@ -337,6 +348,12 @@ void GrandCentral::write(uint32_t rgn_start, uint32_t offset, uint32_t value, in case MIO_GC_DMA_FLOPPY: this->floppy_dma->reg_write(offset & 0xFF, value, size); break; + case MIO_GC_DMA_ETH_XMIT: + this->enet_tx_dma->reg_write(offset & 0xFF, value, size); + break; + case MIO_GC_DMA_ETH_RCV: + this->enet_rx_dma->reg_write(offset & 0xFF, value, size); + break; case MIO_GC_DMA_ESCC_A_XMIT: this->escc_a_tx_dma->reg_write(offset & 0xFF, value, size); break; diff --git a/devices/ioctrl/macio.h b/devices/ioctrl/macio.h index 4234fb9..6235202 100644 --- a/devices/ioctrl/macio.h +++ b/devices/ioctrl/macio.h @@ -175,9 +175,9 @@ private: std::unique_ptr awacs; // AWACS audio codec instance std::unique_ptr mesh_stub = nullptr; - MaceController* mace; + MaceController* mace; // Ethernet cell within Curio ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it - EsccController* escc; // ESCC serial controller + EsccController* escc; // ESCC serial controller cell within Curio MeshBase* mesh; // internal SCSI (fast) Sc53C94* curio; // external SCSI (slow) Swim3::Swim3Ctrl* swim3; // floppy disk controller @@ -187,6 +187,8 @@ private: std::unique_ptr snd_out_dma; std::unique_ptr snd_in_dma; std::unique_ptr floppy_dma; + std::unique_ptr enet_tx_dma; + std::unique_ptr enet_rx_dma; std::unique_ptr escc_a_tx_dma; std::unique_ptr escc_a_rx_dma; std::unique_ptr escc_b_tx_dma;