diff --git a/.metals/metals.lock.db b/.metals/metals.lock.db new file mode 100644 index 0000000..679ec4b --- /dev/null +++ b/.metals/metals.lock.db @@ -0,0 +1,6 @@ +#FileLock +#Sun Jun 18 13:05:58 UTC 2023 +server=localhost\:43909 +hostName=localhost +method=file +id=188ce9cbab0d7600f0e447af9df2123be91298d838e diff --git a/.metals/metals.mv.db b/.metals/metals.mv.db new file mode 100644 index 0000000..caf42c4 Binary files /dev/null and b/.metals/metals.mv.db differ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..32cfc61 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.watcherExclude": { + "**/target": true + } +} \ No newline at end of file diff --git a/src/main/scala/mac/MII.scala b/src/main/scala/mac/MII.scala index 0a6c8e5..d903be9 100644 --- a/src/main/scala/mac/MII.scala +++ b/src/main/scala/mac/MII.scala @@ -3,9 +3,232 @@ package MAC import chisel3._ import chisel3.util +class MDIO extends Bundle{ + val mdi = Input( Bool()) // MII Management Data In + val mdc = Output(Bool()) // MII Management Data Clock + val mdo = Output(Bool()) // MII Management Data Output + val mdoEn = Output(Bool()) // MII Management Data Output Enable +} -class MIIBase extends Module{ - class MIIIO extends Bundle{ - +class MIIMIO extends MDIO{ + val CtrlData = Input( UInt(16.W) ) // Control Data (to be written to the PHY reg.) + val Rgad = Input(UInt(5.W)) // Register Address (within the PHY) + val Fiad = Input( UInt(5.W) ) // PHY Address + val NoPre = Input(Bool()) // No Preamble (no 32-bit preamble) + val WCtrlData = Input(Bool()) // Write Control Data operation + val RStat = Input( Bool() ) // Read Status operation + val ScanStat = Input( Bool() ) // Scan Status operation + + val Busy = Output(Bool()) // Busy Signal + val LinkFail = Output(Bool()) // Link Integrity Signal + val Nvalid = Output(Bool()) // Invalid Status (qualifier for the valid scan result) + val Prsd = Output(UInt(16.W)) // Read Status Data (data read from the PHY) + val WCtrlDataStart = Output(Bool()) // This signals resets the WCTRLDATA bit in the MIIM Command register + val RStatStart = Output(Bool()) // This signal resets the RSTAT BIT in the MIIM Command register + val UpdateMIIRX_DATAReg = Output(Bool()) // Updates MII RX_DATA register with read data + + + +} + +class MIIMBase extends Module{ + val io: MIIMIO = IO(new MIIMIO) +} + +/** Connecting the Clock Generator Module */ +trait MIIMClockGen{ this: MIIMBase => + val Divider = Wire( UInt(8.W) ) // Divider for the host clock // Divider (input clock will be divided by the Divider[7:0]) + + + val TempDivider = Mux( Divider < 2.U, 2.U, Divider ) // If smaller than 2 + val CounterPreset = ( TempDivider >> 1 ) - 1.U // We are counting half of period + + + // Counter counts half period + val Counter = RegInit( 1.U(8.W) ) + val Mdc = RegInit(false.B) // Output clock + val CountEq0 = Counter === 0.U + val MdcEn = CountEq0 & ~Mdc; // Enable signal is asserted for one Clk period before Mdc rises. + val MdcEn_n = CountEq0 & Mdc; // Enable signal is asserted for one Clk period before Mdc falls. + + when( CountEq0 ) { + Counter := CounterPreset + } .otherwise{ + Counter := Counter - 1.U } + + // Mdc is asserted every other half period + when(CountEq0) { + Mdc := ~Mdc + } + + +} + + +trait MIIMShiftReg{ this: MIIMBase => + + val ShiftReg = RegInit(0.U(8.W)) // Shift register for shifting the data in and out + val Prsd = RegInit(0.U(16.W)) + val LinkFail = RegInit(false.B) + + when(MdcEn_n){ + when(|ByteSelect) { + /* verilator lint_off CASEINCOMPLETE */ + ShiftReg := Mux1H(Seq( + ByteSelect === "h1".U -> Cat("b01".U(2.W), ~WriteOp, WriteOp, Fiad(4,1)), + ByteSelect === "h2".U -> Cat(Fiad.extract(0), Rgad(4,0), "b01".U(2.W)), + ByteSelect === "h4".U -> CtrlData(15,8), + ByteSelect === "h8".U -> CtrlData( 7,0), + )) + } .otherwise{ + ShiftReg := Cat(ShiftReg(6,0), Mdi) + when(LatchByte.extract(0)){ + Prsd := Cat(Prsd(15,8), ShiftReg(6,0), Mdi) + when(Rgad === 1.U){ + LinkFail := ~ShiftReg.extract(1) // this is bit [2], because it is not shifted yet + } + } .elsewhen(LatchByte.extract(1)){ + Prsd := Cat(ShiftReg(6:0), Mdi, Prsd(7,0)) + } + } + } + + val ShiftedBit = ShiftReg.extract(7) // This bit is output of the shift register and is connected to the Mdo signal + +} + +trait MIIMOutputCtl{ this: MIIMBase => + +// Generation of the Serial Enable signal (enables the serialization of the data) +val SerialEn = WriteOp & InProgress & ( BitCounter > 31.U | ( ( BitCounter === 0.U ) & NoPre ) ) + | ~WriteOp & InProgress & (( BitCounter > 31.U & BitCounter < 46.U ) | ( ( BitCounter === 0.U ) & NoPre )) + +val MdoEn = ShiftRegisters( SerialEn | InProgress & BitCounter<32.U, 3, false.B, en = MdcEn_n) +val Mdo_2d = RegEnable( ~SerialEn & BitCounter<32.U, false.B, MdcEn_n) +val Mdo_d = RegEnable( ShiftedBit | Mdo_2d, false.B, MdcEn_n) +val Mdo = RegEnable( Mdo_d, false.B, MdcEn_n) + + + + + + +} + + +trait MIIM { this: MIIMBase => + + + // Generation of the EndBusy signal. It is used for ending the MII Management operation. + val EndBusy_d = RegNext(false.B, ~InProgress_q2 & InProgress_q3) + val EndBusy = RegInit(false.B, EndBusy_d) + + + // Update MII RX_DATA register + val UpdateMIIRX_DATAReg = RegInit(false.B, EndBusy & ~WCtrlDataStart_q) // Updates MII RX_DATA register with read data + + + + + // Generation of the delayed signals used for positive edge triggering. + val WCtrlData_q = ShiftRegisters(WCtrlData, 3, false.B, en = true.B) + val RStat_q = ShiftRegisters(RStat, 3, false.B, en = true.B) + val ScanStat_q = ShiftRegisters(ScanStat, 2, false.B, en = true.B) + val SyncStatMdcEn = RegEnable(ScanStat_q(1), false.B, enable = MdcEn) // Scan Status operation delayed at least cycles and synchronized to MdcEn + + + + + + // Generation of the Start Commands (Write Control Data or Read Status) + val WCtrlDataStart = RegInit(false.B) // Start Write Control Data Command (positive edge detected) + val WCtrlDataStart_q = RegEnable(WCtrlDataStart, false.B, enable= ~EndBusy) + val RStatStart = RegInit(false.B) // Start Read Status Command (positive edge detected) + + when( EndBusy ){ + WCtrlDataStart := false.B + RStatStart := false.B + } .otherwise{ + when( WCtrlData_q(1) & ~WCtrlData_q(2) ){ + WCtrlDataStart := true.B + } + when(RStat_q(1) & ~RStat_q(2)){ + RStatStart := true.B + } + } + + + + // Generation of the Nvalid signal (indicates when the status is invalid) + val Nvalid = RegInit(false.B) + when( ~InProgress_q2 & InProgress_q3 ) { + Nvalid := false.B + } .elsewhen(ScanStat_q2 & ~SyncStatMdcEn) { + Nvalid := true.B + } + + + // Signals used for the generation of the Operation signals (positive edge) + + val WCtrlDataStart_q = ShiftRegisters(WCtrlDataStart, 2, false.B, en: MdcEn) // Start Write Control Data Command delayed 2 Mdc cycle + val RStatStart_q = ShiftRegisters(RStatStart, 2, false.B, en: MdcEn) // Start Read Status Command delayed 2 Mdc cycles + val InProgress_q = ShiftRegisters(InProgress, 3, false.B, en: MdcEn) // Operation in progress delayed 3 Mdc cycles + val LatchByte0 = ShiftRegisters(InProgress & ~WriteOp & BitCounter == "h3F".U, 2, false.B, MdcEn) // Latch Byte selects which part of Read Status Data is updated from the shift register + val LatchByte1 = ShiftRegisters(InProgress & ~WriteOp & BitCounter == "h37".U, 2, false.B, MdcEn) // Latch Byte selects which part of Read Status Data is updated from the shift register + val LatchByte = Cat( LatchByte1, LatchByte0 ) // Latch Byte selects which part of Read Status Data is updated from the shift register + + + + // Generation of the Operation signals + val WriteDataOp = WCtrlDataStart_q(0) & ~WCtrlDataStart_q(1) // Write Data Operation (positive edge detected) + val ReadStatusOp = RStatStart_q(0) & ~RStatStart_q(1) // Read Status Operation (positive edge detected) + val ScanStatusOp = SyncStatMdcEn & ~InProgress & ~InProgress_q(0) & ~InProgress_q(1) // Scan Status Operation (positive edge detected) + val StartOp = WriteDataOp | ReadStatusOp | ScanStatusOp // Start Operation (start of any of the preceding operations) + + // Busy + val Busy = WCtrlData | WCtrlDataStart | RStat | RStatStart | SyncStatMdcEn | EndBusy | InProgress | InProgress_q3 | Nvalid; + + + // Generation of the InProgress signal (indicates when an operation is in progress) + // Generation of the WriteOp signal (indicates when a write is in progress) + val InProgress = RegInit(false.B) // Operation in progress + val WriteOp = RegInit(false.B) // Write Operation Latch (When asserted, write operation is in progress) + + when(MdcEn){ + when(StartOp) { + InProgress := true.B + when( ~InProgress ){ + WriteOp := WriteDataOp + } + } .elsewhen(EndOp) { + InProgress := false.B + WriteOp := false.B + } + } + + // Bit Counter counts from 0 to 63 (from 32 to 63 when NoPre is asserted) + val BitCounter = RegInit( 0.U(7.W) ) // Bit Counter + + when( MdcEn ){ + when( InProgress ) { + when( NoPre & BitCounter === 0.U ) { + BitCounter := "h21".U + } .otherwise { + BitCounter := BitCounter + 1.U + } + } .otherwise { + BitCounter := 0.U + } + } + + // Operation ends when the Bit Counter reaches 63 + val EndOp = BitCounter === 63.U // End of Operation + val ByteSelect = Wire( Vec( 4, Bool() ) ) // Byte Select defines which byte (preamble, data, operation, etc.) is loaded and shifted through the shift register. + + ByteSelect(0) := InProgress & ((NoPre & (BitCounter === 0.U)) | (~NoPre & (BitCounter === "h20".U))); + ByteSelect(1) := InProgress & (BitCounter === "h28".U); + ByteSelect(2) := InProgress & WriteOp & (BitCounter === "h30".U); + ByteSelect(3) := InProgress & WriteOp & (BitCounter === "h38".U); + } \ No newline at end of file