diff --git a/verif/cocotb/adp_cocotb_driver.py b/verif/cocotb/adp_cocotb_driver.py index 423a19e29f2903374c121ec4a8278396d34524ab..a0d02fe0b8f6ad38be1b99ba49048fe9767d504b 100644 --- a/verif/cocotb/adp_cocotb_driver.py +++ b/verif/cocotb/adp_cocotb_driver.py @@ -30,12 +30,42 @@ class ADP(): # Read Byte from ADP AXI Stream data = await self.recieve.read() return chr(data[0]) - + + #Reads the echo'ed response from the ADP, after sending a command + @cocotb.coroutine + async def readecho(self, debug = False): + received_str = "" + while True: + curr_char = await self.read8() + received_str += curr_char + if '\n\r]' in received_str: + break + if debug == True: + self.info(repr(received_str)) + return repr(received_str) + + #Write to the ADP, and read the echo'ed feedback from the ADP + @cocotb.coroutine + async def command(self, buf, debug = False): + #Writes the input string, buf, to the ADP + for i in buf: + await self.write8(ord(i)) + #Reads the echo'ed response from the ADP + received_str = "" + while True: + curr_char = await self.read8() + received_str += curr_char + if '\n\r]' in received_str: + break + if debug == True: + self.info(repr(received_str)) + return repr(received_str) + # Writes Byte from ADP AXI Stream @cocotb.coroutine async def write8(self, val): await self.send.write([val]) - + # Read ADP String @cocotb.coroutine async def readLine(self): @@ -49,22 +79,18 @@ class ADP(): # Return on Newline/Carrige Return return read_str - # Write ADP String @cocotb.coroutine async def write_bytes(self, buf): for i in buf: await self.write8(ord(i)) - # Append two additional newlines for reliability - await self.write8(0x0a) # Enter Monitor Mode @cocotb.coroutine async def monitorModeEnter(self): self.dut.log.info("Entering ADP Monitor Mode") await self.write8(0x1b) - # await self.write8(0x0a) - await self.wait_string("]", debug=True) + await self.readecho() self.monitor_mode = True # Exit Monitor Mode @@ -78,12 +104,12 @@ class ADP(): @cocotb.coroutine async def wait_response(self, debug=False): read_str = "" - while read_str in ["","]]"]: + while read_str in ["", "]]"]: read_str = await self.readLine() if debug == True: self.info(read_str) return read_str - + # Read Block from ADP @cocotb.coroutine async def wait_string(self, string, debug=False): @@ -103,6 +129,12 @@ class ADP(): # Ensure Address Read Back Matches that of what was sent assert resp.split()[1] == hex(address) self.info(f"ADP Address Pointer Set: {hex(address)}") + + # Write to the ADP + @cocotb.coroutine + async def w_command(self, message): + await self.write_bytes(message) + resp = await self.wait_response(debug = True) # Get ADP Current Address Pointer @cocotb.coroutine @@ -119,8 +151,7 @@ class ADP(): @cocotb.coroutine async def read_bytes(self, reads): read_string = f"R {str(int(reads))}\n" - self.info(read_string) - await self.write(read_string) + await self.write_bytes(read_string) for i in range(reads): resp = await self.wait_response() self.info(resp) @@ -142,4 +173,6 @@ class ADP(): await self.write8(int(str.strip(b),16)) await self.write8(0x0a) self.info(await self.wait_response()) - self.info("Finished Send Code") \ No newline at end of file + self.info("Finished Send Code") + + diff --git a/verif/cocotb/adp_tests.py b/verif/cocotb/adp_tests.py new file mode 100644 index 0000000000000000000000000000000000000000..bce3565c4e3c8cc6681b10c13a34873b23170ae5 --- /dev/null +++ b/verif/cocotb/adp_tests.py @@ -0,0 +1,226 @@ +import random +from collections.abc import Iterable +import os +import logging +import cocotb +from cocotb.clock import Clock +from cocotb.regression import TestFactory +from cocotb.result import TestFailure +from cocotb.triggers import ClockCycles, Combine, Join, RisingEdge + +from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamMonitor +from adp_cocotb_driver import ADP + +CLK_PERIOD = (10, "ns") + +# Control ADP AXI Stream bus and create ADP Driver Object +def setup_adp(dut): + logging.getLogger("cocotb.nanosoc_tb.rxd8").setLevel(logging.WARNING) + logging.getLogger("cocotb.nanosoc_tb.txd8").setLevel(logging.WARNING) + adp_sender = AxiStreamSource(AxiStreamBus.from_prefix(dut, "txd8"), dut.CLK, dut.NRST, reset_active_level=False) + adp_reciever = AxiStreamSink(AxiStreamBus.from_prefix(dut, "rxd8"), dut.CLK, dut.NRST, reset_active_level=False) + driver = ADP(dut, adp_sender, adp_reciever) + driver.write8(0x00) + return driver + +# Start Clocks and Reset System +@cocotb.coroutine +async def setup_dut(dut): + adp = setup_adp(dut) + cocotb.start_soon(Clock(dut.CLK, *CLK_PERIOD).start()) + dut.NRST.value = 0 + await ClockCycles(dut.CLK, 2) + dut.NRST.value = 1 + await ClockCycles(dut.CLK, 2) + return adp + +# Wait for bootcode to finish +@cocotb.coroutine +async def wait_bootcode(dut, driver): + bootcode_last = "** Remap->IMEM0" + received_str = "" + while True: + read_char = await driver.read8() + received_str += read_char + if bootcode_last in received_str: + break + dut.log.info(received_str) + +#Bit toggle Coverage, making sure each bit on the bus can toggle at the same time +@cocotb.test() +async def bit_toggle_address(dut): + adp = await setup_dut(dut) + dut.log.info("Setup Complete") + dut.log.info("Starting Test") + await wait_bootcode(dut, adp) + dut.log.info("Bootcode Finished") + await adp.monitorModeEnter() + + debug = True + random_value = random.getrandbits(32) + random_value_string = format(random_value, '08x') + + set_address = await adp.command('A' + random_value_string + '\n', debug) + read_address = await adp.command('A' + '\n', debug) + assert set_address == read_address, f'set_address: {set_address} not equal to read_address: {read_address}' + + random_value = random_value ^ ((1 << random_value.bit_length()) - 1) + random_value_string = format(random_value, '08x') + + set_address = await adp.command('A' + random_value_string + '\n', debug) + read_address = await adp.command('A' + '\n', debug) + assert set_address == read_address, f'set_address: {set_address} not equal to read_address: {read_address}' + + + +#Walking-1 Coverage, to measure activity covered by bus connectivity tests, and one-hot state or bus encoding coverage +@cocotb.test() +async def address_test_walking1(dut): + adp = await setup_dut(dut) + dut.log.info("Setup Complete") + dut.log.info("Starting Test") + await wait_bootcode(dut, adp) + dut.log.info("Bootcode Finished") + await adp.monitorModeEnter() + + debug = True + address = 0b00000000000000000000000000000001 + end_address = 0x9FFFFFFF + + while address <= end_address: + address_str = hex(address) + address_str = address_str[:2] + address_str[2:].rjust(8,'0') + set_address = await adp.command('A' + address_str + '\n', debug) + read_address = await adp.command('A' + '\n', debug) + assert set_address == read_address, f'set_address: {set_address} not equal to read_address: {read_address}' + address = address << 1 + +#Shifting the most significant bit to the left, with the bits below being randomized +@cocotb.test() +async def address_test_pof2(dut): + adp = await setup_dut(dut) + dut.log.info("Setup Complete") + dut.log.info("Starting Test") + await wait_bootcode(dut, adp) + dut.log.info("Bootcode Finished") + await adp.monitorModeEnter() + + debug = False + power = 2 + address = 0b00000000000000000000000000000010 + end_address = 0x9FFFFFFF + + set_address = await adp.command('A' + '0x00000001' + '\n', debug) + read_address = await adp.command('A' + '\n', debug) + assert set_address == read_address, f'set_address: {set_address} not equal to read_address: {read_address}' + + while address <= end_address: + dut.log.info(f"{bin(address)}") + address_str = hex(address) + address_str = address_str[:2] + address_str[2:].rjust(8,'0') + set_address = await adp.command('A' + address_str + '\n', debug) + read_address = await adp.command('A' + '\n', debug) + assert set_address == read_address, f'set_address: {set_address} not equal to read_address: {read_address}' + address = (2 ** power) + random.getrandbits(power - 1) + power += 1 + +#Write words, half words, bytes and read back as words, half words and bytes +@cocotb.test() +async def write_read_test(dut): + adp = await setup_dut(dut) + dut.log.info("Setup Complete") + dut.log.info("Starting Test") + await wait_bootcode(dut, adp) + dut.log.info("Bootcode Finished") + await adp.monitorModeEnter() + + debug = False + + #Write a word, and read it back as bytes, half words, and a word and see if they match up + + random_value = format(random.getrandbits(32), '08x') + read_word = "" + await adp.command('A' + '0x30000000' + '\n') + await adp.command('W'+ '0x' + str(random_value) + '\n', debug) + + await adp.command('A' + '0x30000000' + '\n') + for _ in range(4): + read_byte = await adp.command('R' + '0x01' + '\n', debug) + read_byte = read_byte[::-1] + read_word += read_byte[6:8] + read_word = read_word[::-1] + assert read_word == random_value,f'Read Word = {read_word}, Random Value = {random_value}' + + read_word = "" + await adp.command('A' + '0x30000000' + '\n') + for _ in range(2): + read_hw = await adp.command('R' + '0x0001' + '\n', debug) + read_hw = read_hw[::-1] + read_word += read_hw[6:10] + read_word = read_word[::-1] + assert read_word == random_value,f'Read Word = {read_word}, Random Value = {random_value}' + + await adp.command('A' + '0x30000000' + '\n', debug) + read_word = await adp.command('R' + '0x000000001' +'\n', debug) + assert read_word[5:13] == random_value,f'Read Word = {read_word[5:13]}, Random Value = {random_value}' + + #Write a word as half word, and read it back as bytes, half words, and a word and see if they match up + + random_value = format(random.getrandbits(32), '08x') + read_word = "" + await adp.command('A' + '0x30000000' + '\n') + await adp.command('W'+ '0x' + str(random_value[4:8]) + '\n', debug) + await adp.command('W'+ '0x' + str(random_value[0:4]) + '\n', debug) + + await adp.command('A' + '0x30000000' + '\n') + for _ in range(4): + read_byte = await adp.command('R' + '0x01' + '\n', debug) + read_byte = read_byte[::-1] + read_word += read_byte[6:8] + read_word = read_word[::-1] + assert read_word == random_value,f'Read Word = {read_word}, Random Value = {random_value}' + + read_word = "" + await adp.command('A' + '0x30000000' + '\n') + for _ in range(2): + read_hw = await adp.command('R' + '0x0001' + '\n', debug) + read_hw = read_hw[::-1] + read_word += read_hw[6:10] + read_word = read_word[::-1] + assert read_word == random_value,f'Read Word = {read_word}, Random Value = {random_value}' + + await adp.command('A' + '0x30000000' + '\n', debug) + read_word = await adp.command('R' + '0x000000001' +'\n', debug) + assert read_word[5:13] == random_value,f'Read Word = {read_word[5:13]}, Random Value = {random_value}' + + #Write a word as bytes, and read it back as bytes, half words, and a word and see if they match up + + random_value = format(random.getrandbits(32), '08x') + read_word = "" + await adp.command('A' + '0x30000000' + '\n') + await adp.command('W'+ '0x' + str(random_value[6:8]) + '\n', debug) + await adp.command('W'+ '0x' + str(random_value[4:6]) + '\n', debug) + await adp.command('W'+ '0x' + str(random_value[2:4]) + '\n', debug) + await adp.command('W'+ '0x' + str(random_value[0:2]) + '\n', debug) + + await adp.command('A' + '0x30000000' + '\n') + for _ in range(4): + read_byte = await adp.command('R' + '0x01' + '\n', debug) + read_byte = read_byte[::-1] + read_word += read_byte[6:8] + read_word = read_word[::-1] + assert read_word == random_value,f'Read Word = {read_word}, Random Value = {random_value}' + + read_word = "" + await adp.command('A' + '0x30000000' + '\n') + for _ in range(2): + read_hw = await adp.command('R' + '0x0001' + '\n', debug) + read_hw = read_hw[::-1] + read_word += read_hw[6:10] + read_word = read_word[::-1] + assert read_word == random_value,f'Read Word = {read_word}, Random Value = {random_value}' + + await adp.command('A' + '0x30000000' + '\n', debug) + read_word = await adp.command('R' + '0x000000001' +'\n', debug) + assert read_word[5:13] == random_value,f'Read Word = {read_word[5:13]}, Random Value = {random_value}' + diff --git a/verif/cocotb/fill_test_dmem.py b/verif/cocotb/fill_test_dmem.py new file mode 100644 index 0000000000000000000000000000000000000000..1db6b9b08418d18aae137d76133fffd2b30569da --- /dev/null +++ b/verif/cocotb/fill_test_dmem.py @@ -0,0 +1,86 @@ +import random +from collections.abc import Iterable +import os +import logging +import cocotb +from cocotb.clock import Clock +from cocotb.regression import TestFactory +from cocotb.result import TestFailure +from cocotb.triggers import ClockCycles, Combine, Join, RisingEdge + +from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamMonitor +from adp_cocotb_driver import ADP + +CLK_PERIOD = (10, "ns") + +# Control ADP AXI Stream bus and create ADP Driver Object +def setup_adp(dut): + logging.getLogger("cocotb.nanosoc_tb.rxd8").setLevel(logging.WARNING) + logging.getLogger("cocotb.nanosoc_tb.txd8").setLevel(logging.WARNING) + adp_sender = AxiStreamSource(AxiStreamBus.from_prefix(dut, "txd8"), dut.CLK, dut.NRST, reset_active_level=False) + adp_reciever = AxiStreamSink(AxiStreamBus.from_prefix(dut, "rxd8"), dut.CLK, dut.NRST, reset_active_level=False) + driver = ADP(dut, adp_sender, adp_reciever) + driver.write8(0x00) + return driver + +# Start Clocks and Reset System +@cocotb.coroutine +async def setup_dut(dut): + adp = setup_adp(dut) + cocotb.start_soon(Clock(dut.CLK, *CLK_PERIOD).start()) + dut.NRST.value = 0 + await ClockCycles(dut.CLK, 2) + dut.NRST.value = 1 + await ClockCycles(dut.CLK, 2) + return adp + +# Wait for bootcode to finish +@cocotb.coroutine +async def wait_bootcode(dut, driver): + bootcode_last = "** Remap->IMEM0" + received_str = "" + while True: + read_char = await driver.read8() + received_str += read_char + if bootcode_last in received_str: + break + dut.log.info(received_str) + +@cocotb.test() +async def test_fill(dut): + adp = await setup_dut(dut) + dut.log.info("Setup Complete") + dut.log.info("Starting Test") + await wait_bootcode(dut, adp) + dut.log.info("Bootcode Finished") + await adp.monitorModeEnter() + + #setup complete, can interface with the design + + def count_substring_occurrences(full_string, substring): + return full_string.count(substring) + + address = 0x30000000 + address_increment = 0x4 + iteration = 1 + fill_value = random.randint(0, 0xFFFFFFFF) + + while address <= (0x30000000 + 4*address_increment): + fill_value = hex(random.randint(0, 0xFFFFFFFF)) + fill_value = fill_value[:2] + fill_value[2:].rjust(8, '0') + + v = await adp.command('V' + fill_value + '\n', debug = True) + + a = await adp.command('A'+ hex(address) + '\n', debug = True) + + f = await adp.command('F' + repr(address_increment) + '\n', debug = True) + + a = await adp.command('A'+ hex(address) + '\n', debug = True) + + r = await adp.command('R'+ '0x00000000'+ repr(address_increment) +'\n', debug = True) + + c = count_substring_occurrences(r, f"R {fill_value}") + + assert hex(c) == hex(address_increment), f'range {hex(address + address_increment)} to {hex(address)} failed the test, count = {c} ' + address += address_increment + iteration += 1 diff --git a/verif/cocotb/read_write_test.py b/verif/cocotb/read_write_test.py new file mode 100644 index 0000000000000000000000000000000000000000..017807da5a0085dbc9d02285a93c43d4015f8255 --- /dev/null +++ b/verif/cocotb/read_write_test.py @@ -0,0 +1,85 @@ +from random import randint, randrange, getrandbits, shuffle +from collections.abc import Iterable + +import numpy as np +import os +import logging +import cocotb +from cocotb.clock import Clock +from cocotb.regression import TestFactory +from cocotb.result import TestFailure +from cocotb.triggers import ClockCycles, Combine, Join, RisingEdge + +from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamMonitor +from adp_cocotb_driver import ADP + +CLK_PERIOD = (10, "ns") + +# Control ADP AXI Stream bus and create ADP Driver Object +def setup_adp(dut): + logging.getLogger("cocotb.nanosoc_tb.rxd8").setLevel(logging.WARNING) + logging.getLogger("cocotb.nanosoc_tb.txd8").setLevel(logging.WARNING) + adp_sender = AxiStreamSource(AxiStreamBus.from_prefix(dut, "txd8"), dut.CLK, dut.NRST, reset_active_level=False) + adp_reciever = AxiStreamSink(AxiStreamBus.from_prefix(dut, "rxd8"), dut.CLK, dut.NRST, reset_active_level=False) + driver = ADP(dut, adp_sender, adp_reciever) + driver.write8(0x00) + return driver + +# Start Clocks and Reset System +@cocotb.coroutine +async def setup_dut(dut): + adp = setup_adp(dut) + cocotb.start_soon(Clock(dut.CLK, *CLK_PERIOD).start()) + dut.NRST.value = 0 + await ClockCycles(dut.CLK, 2) + dut.NRST.value = 1 + await ClockCycles(dut.CLK, 2) + return adp + +# Wait for bootcode to finish +@cocotb.coroutine +async def wait_bootcode(dut, driver): + bootcode_last = "** Remap->IMEM0" + received_str = "" + while True: + read_char = await driver.read8() + received_str += read_char + if bootcode_last in received_str: + break + dut.log.info(received_str) + +@cocotb.test() +async def random_address_read_write(dut): + adp = await setup_dut(dut) + dut.log.info("Setup Complete") + dut.log.info("Starting Test") + await wait_bootcode(dut, adp) + dut.log.info("Bootcode Finished") + await adp.monitorModeEnter() + + #setup complete, can interface with the design + + length = 0xF + + test_vector_data = np.random.randint(0, 0xFFFFFFFF, size = length) + test_vector_address = np.random.randint(0x30000000, 0x3FFFFFFF, size = length) + + read_values = [] + i = 1 + + for address, data in zip(test_vector_address, test_vector_data): + await adp.command('A'+ hex(address) + '\n',debug = True) #Set base address + await adp.command('W' + hex(data) + '\n', debug = True) #Write to the specified address + + dut.log.info("Writing Complete") + + for address, data in zip(test_vector_address, test_vector_data): + await adp.command('A'+ hex(address) + '\n', debug = True) + b = await adp.command('R\n', debug = True) #Start reading the data starting from the base address + read_values.append(b[2:13]) + + dut.log.info("Reading Complete") + + for data1, data2 in zip(test_vector_data, read_values): + assert data1 == int(data2,16) , f"Assertion failed: {hex(data1)} is not equal to {data2} on iteration {i}" + i += 1 diff --git a/verif/cocotb/test_adp.py b/verif/cocotb/test_adp.py index 3113dd533e2e20791d2699bd8409166d2d276165..87a1c49bb15742d7a1da51fff0b6645102df33d2 100644 --- a/verif/cocotb/test_adp.py +++ b/verif/cocotb/test_adp.py @@ -47,11 +47,23 @@ async def setup_dut(dut): @cocotb.coroutine async def wait_bootcode(dut, driver): bootcode_last = "** Remap->IMEM0" + received_str = "" + while True: + read_char = await driver.read8() + received_str += read_char + if bootcode_last in received_str: + break + dut.log.info(received_str) + +@cocotb.coroutine +async def wait_prompt(dut, driver): + bootcode_last = "]" while True: read_str = await driver.readLine() dut.log.info(read_str) - if read_str == bootcode_last: + if read_str == "bootcode_last": break + # Wait for bootcode to finish @cocotb.coroutine @@ -79,7 +91,20 @@ async def test_adp_read(dut): dut.log.info("Starting Test") await wait_bootcode(dut, adp_driver) dut.log.info("ADP Read Test Complete") - + +@cocotb.test() +async def test_address_pointer(dut): + adp_driver = await setup_dut(dut) + dut.log.info("Setup Complete") + dut.log.info("Starting Test") + await wait_bootcode(dut, adp_driver) + dut.log.info("Bootcode Finished") + await adp_driver.monitorModeEnter() + await adp_driver.write_bytes("A" + "0x30000000" "\n") + await adp_driver.readecho(debug = True) + await adp_driver.write_bytes("W" + "0x11" +"\n") + await adp_driver.readecho(debug = True) + # Basic Test Write to ADP @cocotb.test() async def test_adp_write(dut): @@ -95,20 +120,20 @@ async def test_adp_write(dut): read_str += await adp_driver.read8() dut.log.info(repr(read_str)) - # dut.log.info(await adp_driver.wait_response()) - # dut.log.info("Setting Address") - # await adp_driver.set_address(0x10000000) - # await adp_driver.get_address() - # await adp_driver.set_address(0x10000000) - # await adp_driver.read_bytes(4) - # adp_driver.info(await adp_driver.wait_response()) - # await adp_driver.write_bytes('A 0x10000000\n') - # adp_driver.info(await adp_driver.wait_response()) - # await adp_driver.write_bytes('A\n') - # adp_driver.info(await adp_driver.wait_response()) - # await adp_driver.write('R 4\n') - # for i in range(2): - # dut.log.info(await adp_driver.readLine()) + dut.log.info(await adp_driver.wait_response()) + dut.log.info("Setting Address") + await adp_driver.set_address(0x10000000) + await adp_driver.get_address() + await adp_driver.set_address(0x10000000) + await adp_driver.read_bytes(4) + adp_driver.info(await adp_driver.wait_response()) + await adp_driver.write_bytes('A 0x10000000\n') + adp_driver.info(await adp_driver.wait_response()) + await adp_driver.write_bytes('A\n') + adp_driver.info(await adp_driver.wait_response()) + await adp_driver.write('R 4\n') + for i in range(2): + dut.log.info(await adp_driver.readLine()) dut.log.info("ADP Write Test Complete") # Basic Software Load Test