diff --git a/sim/hwdbg/communication/DebuggerPacketReceiver/Makefile b/sim/hwdbg/communication/DebuggerPacketReceiver/Makefile new file mode 100644 index 0000000..1bfc1a0 --- /dev/null +++ b/sim/hwdbg/communication/DebuggerPacketReceiver/Makefile @@ -0,0 +1,8 @@ +# Makefile + +TOPLEVEL_LANG = verilog +VERILOG_SOURCES = $(shell pwd)/../../../../generated/DebuggerPacketReceiver.sv +TOPLEVEL = DebuggerPacketReceiver +MODULE = test_DebuggerPacketReceiver + +include $(shell cocotb-config --makefiles)/Makefile.sim diff --git a/sim/hwdbg/communication/DebuggerPacketReceiver/test.sh b/sim/hwdbg/communication/DebuggerPacketReceiver/test.sh new file mode 100755 index 0000000..a83ca69 --- /dev/null +++ b/sim/hwdbg/communication/DebuggerPacketReceiver/test.sh @@ -0,0 +1 @@ +make SIM=icarus WAVES=1 diff --git a/sim/hwdbg/communication/DebuggerPacketReceiver/test_DebuggerPacketReceiver.py b/sim/hwdbg/communication/DebuggerPacketReceiver/test_DebuggerPacketReceiver.py new file mode 100644 index 0000000..9371c28 --- /dev/null +++ b/sim/hwdbg/communication/DebuggerPacketReceiver/test_DebuggerPacketReceiver.py @@ -0,0 +1,125 @@ +## +# @file test_DebuggerPacketReceiver.py +# +# @author Sina Karvandi (sina@hyperdbg.org) +# +# @brief Testing module for DebuggerPacketReceiver +# +# @details +# +# @version 0.1 +# +# @date 2024-04-22 +# +# @copyright This project is released under the GNU Public License v3. +# + +import random + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge +from cocotb.types import LogicArray + +''' + input clock, + reset, + io_en, + io_plInSignal, + output [12:0] io_rdWrAddr, + input [31:0] io_rdData, + output [31:0] io_requestedActionOfThePacketOutput, + output io_requestedActionOfThePacketOutputValid, + input io_noNewDataReceiver, + io_readNextData, + output io_dataValidOutput, + output [31:0] io_receivingData, + output io_finishedReceivingBuffer +''' + +@cocotb.test() +async def DebuggerPacketReceiver_test(dut): + """Test DebuggerPacketReceiver module""" + + # + # Assert initial output is unknown + # + assert LogicArray(dut.io_rdWrAddr.value) == LogicArray("XXXXXXXXXXXXX") + assert LogicArray(dut.io_requestedActionOfThePacketOutput.value) == LogicArray("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") + assert LogicArray(dut.io_requestedActionOfThePacketOutputValid.value) == LogicArray("X") + assert LogicArray(dut.io_dataValidOutput.value) == LogicArray("X") + assert LogicArray(dut.io_receivingData.value) == LogicArray("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") + assert LogicArray(dut.io_finishedReceivingBuffer.value) == LogicArray("X") + + clock = Clock(dut.clock, 10, units="ns") # Create a 10ns period clock on port clock + + # + # Start the clock. Start it low to avoid issues on the first RisingEdge + # + cocotb.start_soon(clock.start(start_high=False)) + + dut._log.info("Initialize and reset module") + + # + # Initial values + # + dut.io_en.value = 0 + dut.io_plInSignal.value = 0 + + # + # Reset DUT + # + dut.reset.value = 1 + for _ in range(10): + await RisingEdge(dut.clock) + dut.reset.value = 0 + + dut._log.info("Enabling chip") + + # + # Enable chip + # + dut.io_en.value = 1 + + for test_number in range(10): + + dut._log.info("Enable receiving data on the chip (" + str(test_number) + ")") + + # + # Tell the receiver to start receiving data (This mainly operates based on + # a rising-edge detector, so we'll need to make it low) + # + dut.io_plInSignal.value = 1 + await RisingEdge(dut.clock) + dut.io_plInSignal.value = 0 + + # + # Wait until the data is received + # + for _ in range(1000): + if (dut.io_dataValidOutput.value == 1): + break + else: + match dut.io_rdWrAddr.value: + case 0x0: # checksum + dut.io_rdData.value = 0x00001234 + case 0x8: # indicator + dut.io_rdData.value = 0x88888888 + case 0x10: # type + dut.io_rdData.value = 0x10101010 + case 0x14: # requested action + dut.io_rdData.value = 0x14141414 + case _: + assert "invalid address in the address line" + await RisingEdge(dut.clock) + + # + # Run extra waiting clocks + # + for _ in range(10): + await RisingEdge(dut.clock) + + # + # Check the final input on the next clock + # + await RisingEdge(dut.clock) diff --git a/sim/hwdbg/communication/DebuggerPacketSender/test_DebuggerPacketSender.py b/sim/hwdbg/communication/DebuggerPacketSender/test_DebuggerPacketSender.py index d9c18ad..96bb544 100644 --- a/sim/hwdbg/communication/DebuggerPacketSender/test_DebuggerPacketSender.py +++ b/sim/hwdbg/communication/DebuggerPacketSender/test_DebuggerPacketSender.py @@ -39,7 +39,7 @@ ''' @cocotb.test() -async def DebuggerModuleTestingBRAM_test(dut): +async def DebuggerPacketSender_test(dut): """Test DebuggerPacketSender module""" # @@ -84,7 +84,7 @@ async def DebuggerModuleTestingBRAM_test(dut): for test_number in range(10): - dut._log.info("Enable sending data chip (" + str(test_number) + ")") + dut._log.info("Enable sending data on the chip (" + str(test_number) + ")") # # Still there is data to send diff --git a/src/main/scala/hwdbg/communication/receiver.scala b/src/main/scala/hwdbg/communication/receiver.scala index 00a8a63..2689b91 100644 --- a/src/main/scala/hwdbg/communication/receiver.scala +++ b/src/main/scala/hwdbg/communication/receiver.scala @@ -86,14 +86,15 @@ class DebuggerPacketReceiver( val state = RegInit(sIdle) // - // Output pins (registers) + // Output pins // + val rdWrAddr = WireInit(0.U(bramAddrWidth.W)) val regRdWrAddr = RegInit(0.U(bramAddrWidth.W)) - val regRequestedActionOfThePacketOutput = RegInit(0.U(new DebuggerRemotePacket().RequestedActionOfThePacket.getWidth.W)) - val regRequestedActionOfThePacketOutputValid = RegInit(false.B) - val regDataValidOutput = RegInit(false.B) - val regReceivingData = RegInit(0.U(bramDataWidth.W)) - val regFinishedReceivingBuffer = RegInit(false.B) + val finishedReceivingBuffer = WireInit(false.B) + val requestedActionOfThePacketOutput = WireInit(0.U(new DebuggerRemotePacket().RequestedActionOfThePacket.getWidth.W)) + val requestedActionOfThePacketOutputValid = WireInit(false.B) + val dataValidOutput = WireInit(false.B) + val receivingData = WireInit(0.U(bramDataWidth.W)) // // Rising-edge detector for start receiving signal @@ -135,14 +136,14 @@ class DebuggerPacketReceiver( } // - // Configure the registers in case of sIdle + // Configure the output pins in case of sIdle // - regRdWrAddr := 0.U - regRequestedActionOfThePacketOutput := 0.U - regRequestedActionOfThePacketOutputValid := false.B - regDataValidOutput := false.B - regReceivingData := 0.U - regFinishedReceivingBuffer := false.B + rdWrAddr := 0.U + requestedActionOfThePacketOutput := 0.U + requestedActionOfThePacketOutputValid := false.B + dataValidOutput := false.B + receivingData := 0.U + finishedReceivingBuffer := false.B } is(sReadChecksum) { @@ -150,7 +151,7 @@ class DebuggerPacketReceiver( // // Adjust address to read Checksum from BRAM (Not Used) // - regRdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.checksum).U + rdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.checksum).U // // Goes to the next section @@ -162,7 +163,7 @@ class DebuggerPacketReceiver( // // Adjust address to read Indicator from BRAM // - regRdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.indicator).U + rdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.indicator).U // // Goes to the next section @@ -174,12 +175,15 @@ class DebuggerPacketReceiver( // // Adjust address to read TypeOfThePacket from BRAM // - regRdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.typeOfThePacket).U + rdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.typeOfThePacket).U // // Check whether the indicator is valid or not // - when(io.rdData === HyperDbgSharedConstants.INDICATOR_OF_HYPERDBG_PACKET.U) { + LogInfo(debug)( + f"Comparing first 0x${BitwiseFunction.printFirstNBits(HyperDbgSharedConstants.INDICATOR_OF_HYPERDBG_PACKET, bramDataWidth)}%x bits of the indicator" + ) + when(io.rdData === BitwiseFunction.printFirstNBits(HyperDbgSharedConstants.INDICATOR_OF_HYPERDBG_PACKET, bramDataWidth).U) { // // Indicator of packet is valid @@ -190,7 +194,7 @@ class DebuggerPacketReceiver( }.otherwise { // - // Type of packet is not valid + // Indicator of packet is not valid // (Receiving was done but not found a valid packet, // so, go to the idle state) // @@ -202,7 +206,12 @@ class DebuggerPacketReceiver( // // Adjust address to read RequestedActionOfThePacket from BRAM // - regRdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.requestedActionOfThePacket).U + rdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.requestedActionOfThePacket).U + + // + // Save the address into a register + // + regRdWrAddr := (MemoryCommunicationConfigurations.BASE_ADDRESS_OF_PS_TO_PL_COMMUNICATION + receivedPacketBuffer.Offset.requestedActionOfThePacket + (bramDataWidth >> 3)).U // // Check whether the type of the packet is valid or not @@ -232,12 +241,12 @@ class DebuggerPacketReceiver( // // Read the RequestedActionOfThePacket // - regRequestedActionOfThePacketOutput := io.rdData + requestedActionOfThePacketOutput := io.rdData // // The RequestedActionOfThePacketOutput is valid from now // - regRequestedActionOfThePacketOutputValid := true.B + requestedActionOfThePacketOutputValid := true.B // // Check if the caller needs to read the next part of @@ -248,7 +257,8 @@ class DebuggerPacketReceiver( // // Adjust address to read next data to BRAM // - regRdWrAddr := regRdWrAddr + bramDataWidth.U + rdWrAddr := regRdWrAddr + regRdWrAddr := regRdWrAddr + (bramDataWidth >> 3).U // // Read the next offset of the buffer @@ -276,12 +286,12 @@ class DebuggerPacketReceiver( // // Data outputs are now valid // - regDataValidOutput := true.B + dataValidOutput := true.B // // Adjust the read buffer data // - regReceivingData := io.rdData + receivingData := io.rdData // // Return to the previous state of action @@ -291,13 +301,18 @@ class DebuggerPacketReceiver( } is(sDone) { + // + // Reset the temporary address holder + // + regRdWrAddr := 0.U + // // The receiving is done at this stage, either // was successful of unsucessful, we'll release the // sharing bram resource by indicating that the receiving // module is no longer using the bram line // - regFinishedReceivingBuffer := true.B + finishedReceivingBuffer := true.B // // Go to the idle state @@ -310,14 +325,14 @@ class DebuggerPacketReceiver( // --------------------------------------------------------------------- // - // Connect output pins to internal registers + // Connect output pins // - io.rdWrAddr := regRdWrAddr - io.requestedActionOfThePacketOutput := regRequestedActionOfThePacketOutput - io.requestedActionOfThePacketOutputValid := regRequestedActionOfThePacketOutputValid - io.dataValidOutput := regDataValidOutput - io.receivingData := regReceivingData - io.finishedReceivingBuffer := regFinishedReceivingBuffer + io.rdWrAddr := rdWrAddr + io.requestedActionOfThePacketOutput := requestedActionOfThePacketOutput + io.requestedActionOfThePacketOutputValid := requestedActionOfThePacketOutputValid + io.dataValidOutput := dataValidOutput + io.receivingData := receivingData + io.finishedReceivingBuffer := finishedReceivingBuffer } @@ -386,3 +401,27 @@ object DebuggerPacketReceiver { ) } } + +object ReceiverModule extends App { + + // + // Generate hwdbg verilog files + // + println( + ChiselStage.emitSystemVerilog( + new DebuggerPacketReceiver( + DebuggerConfigurations.ENABLE_DEBUG, + DebuggerConfigurations.BLOCK_RAM_ADDR_WIDTH, + DebuggerConfigurations.BLOCK_RAM_DATA_WIDTH + ), + firtoolOpts = Array( + "-disable-all-randomization", + "--lowering-options=disallowLocalVariables", // because icarus doesn't support 'automatic logic', this option prevents such logics + "-strip-debug-info", + "--split-verilog", // The intention for this argument (and next argument) is to separate generated files. + "-o", + "generated/" + ) + ) + ) +} diff --git a/src/main/scala/hwdbg/communication/sender.scala b/src/main/scala/hwdbg/communication/sender.scala index 27e7475..4d39579 100644 --- a/src/main/scala/hwdbg/communication/sender.scala +++ b/src/main/scala/hwdbg/communication/sender.scala @@ -113,7 +113,7 @@ class DebuggerPacketSender( // // Used to hold the transferred length of the indicator // - val lengthOfIndicator: Int = new DebuggerRemotePacket().Indicator.getWidth; + val lengthOfIndicator: Int = new DebuggerRemotePacket().Indicator.getWidth val regTransferredIndicatorLength = RegInit(0.U((log2Ceil(lengthOfIndicator) + 1).W)) // @@ -495,27 +495,3 @@ object DebuggerPacketSender { (psOutInterrupt, rdWrAddr, wrEna, wrData, sendWaitForBuffer, finishedSendingBuffer) } } - -object SenderModule extends App { - - // - // Generate hwdbg verilog files - // - println( - ChiselStage.emitSystemVerilog( - new DebuggerPacketSender( - DebuggerConfigurations.ENABLE_DEBUG, - DebuggerConfigurations.BLOCK_RAM_ADDR_WIDTH, - DebuggerConfigurations.BLOCK_RAM_DATA_WIDTH - ), - firtoolOpts = Array( - "-disable-all-randomization", - "--lowering-options=disallowLocalVariables", // because icarus doesn't support 'automatic logic', this option prevents such logics - "-strip-debug-info", - "--split-verilog", // The intention for this argument (and next argument) is to separate generated files. - "-o", - "generated/" - ) - ) - ) -} diff --git a/src/main/scala/hwdbg/utils/utils.scala b/src/main/scala/hwdbg/utils/utils.scala index f290671..f5f6cf7 100644 --- a/src/main/scala/hwdbg/utils/utils.scala +++ b/src/main/scala/hwdbg/utils/utils.scala @@ -28,3 +28,15 @@ object LogInfo { println("[*] debug msg: " + message) } } + +object BitwiseFunction { + + def printFirstNBits(num: Long, n: Int): Long = { + + val mask = (1L << n) - 1 // Create a bitmask with the first 'n' bits set to 1 + val shifted = num >>> (java.lang.Long.SIZE - n) // Shift the bits to the right to keep the first 'n' bits + val firstNBits = shifted & mask // Extract the first 'n' bits by performing a bitwise AND operation + + firstNBits + } +}