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;