Source code for NetworkSim.system_verilog.transmitter

__author__ = ['Hongyi Yang']
__all__ = [
    'print_delay_lut',
    'generate_testvector'
]

import os

from NetworkSim.simulation.simulator.base import BaseSimulator





[docs]def generate_testvector( simulator, transmitter_id=1, id_width=7, address_width=8, data_width=128, output_dir=None, ): """ Testvector generation for transmitters. Parameters ---------- simulator : BaseSimulator The simulator used for testvector generation. transmitter_id : int, optional The ID of the transmitter of choice, by default ``1`` address_width : int, optional The bit width of transmitter RAM address, by default ``8`` data_width : int, optional The bit width of the transmitter RAM data, by default ``128`` output_dir : str, optional Output directory for the testvectors, by default ``None`` \ (the `testvectors` directory under Digital-Design). bidirectional : bool, optional If bi-directional transmission scheme is carried out. Default is ``False``. Returns ------- ram_content_tv, data_out_tv : list Two lists (or four lists in the case of bi-directional transmission) \ containing RAM content and output data signal to be checked against. """ # Mapping SystemVerilog ID to NetworkSim ID mapped_transmitter_id = transmitter_id - 1 file_dir = os.path.dirname(os.path.realpath(__file__)) output_dir = os.path.join(file_dir, '../../../Digital-Design/SystemVerilog-Project/testvectors') if not simulator.bidirectional: ram_filename = os.path.join(output_dir, 'transmitter_ram.tv') data_out_assert_filename = os.path.join(output_dir, 'transmitter_data_out_assert.tv') else: cw_ram_filename = os.path.join(output_dir, 'transmitter_ram_cw.tv') cw_data_out_assert_filename = os.path.join(output_dir, 'transmitter_data_out_assert_cw.tv') acw_ram_filename = os.path.join(output_dir, 'transmitter_ram_acw.tv') acw_data_out_assert_filename = os.path.join(output_dir, 'transmitter_data_out_assert_acw.tv') def update_ram_address(ram_address): """ Function to update RAM address during iterations. Parameters ---------- ram_address : int The RAM address to be updated. Returns ------- new_ram_address : int The updated RAM address. """ if ram_address + 1 == 2 ** address_width: return 0 else: return ram_address + 1 def is_upstream(destination_id): """ Check if the destination node is an upstream node. Parameters ---------- destination_id : int ID of the destination node. Returns ------- is_upstream : bool ``True`` if the destination is upstream, ``False`` if downstream. """ _difference = destination_id - mapped_transmitter_id if _difference < 0: _difference += simulator.model.network.num_nodes if _difference <= simulator.model.network.num_nodes / 2: return False else: return True def generate_ram_tv(): """ Function to generate RAM content testvector input. Returns ------- ram_content : list List of RAM content testvectors, including address and data. """ time_counter = 0 if simulator.bidirectional: cw_ram_address = 0 acw_ram_address = 0 cw_ram_content = [] acw_ram_content = [] else: ram_address = 0 ram_content = [] last_packet_time = simulator.RAM[mapped_transmitter_id].generated_data_packet[-1][0] for data_packet in simulator.RAM[mapped_transmitter_id].generated_data_packet: if simulator.bidirectional: if is_upstream(destination_id=data_packet[3]): upstream = True else: upstream = False # Time period with no data while time_counter < int(data_packet[0]): if simulator.bidirectional: cw_content = [time_counter, cw_ram_address, str(bin(0)[2:].zfill(data_width))] acw_content = [time_counter, acw_ram_address, str(bin(0)[2:].zfill(data_width))] cw_ram_content.append(cw_content) acw_ram_content.append(acw_content) else: content = [time_counter, ram_address, str(bin(0)[2:].zfill(data_width))] ram_content.append(content) time_counter += 1 # Clock cycle with source and destination ID if time_counter == int(data_packet[0]): # Mapping NetworkSim ID to SystemVerilog ID mapped_destination_id = data_packet[3] + 1 # Append destination ID packet_content = str(bin(mapped_destination_id)[2:].zfill(data_width)) # Insert source ID packet_content = str(bin(transmitter_id)[2:].zfill(id_width)) + packet_content[id_width:] if simulator.bidirectional: if upstream: cw_content = content = [time_counter, cw_ram_address, str(bin(0)[2:].zfill(data_width))] acw_content = [time_counter, acw_ram_address, packet_content] acw_ram_address = update_ram_address(acw_ram_address) else: cw_content = [time_counter, cw_ram_address, packet_content] acw_content = content = [time_counter, acw_ram_address, str(bin(0)[2:].zfill(data_width))] cw_ram_address = update_ram_address(cw_ram_address) cw_ram_content.append(cw_content) acw_ram_content.append(acw_content) else: content = [time_counter, ram_address, packet_content] ram_content.append(content) ram_address = update_ram_address(ram_address) time_counter += 1 # Time period with data packet_length = len(data_packet[2]) num_clock_cycle = -(-packet_length // data_width) bit_counter = 0 for i in range(num_clock_cycle): if i == num_clock_cycle - 1: data = data_packet[2][bit_counter:].ljust(data_width, '0') else: data = data_packet[2][bit_counter:bit_counter + data_width] if simulator.bidirectional: if upstream: cw_content = [time_counter, cw_ram_address, str(bin(0)[2:].zfill(data_width))] acw_content = [time_counter, acw_ram_address, data] acw_ram_address = update_ram_address(acw_ram_address) else: cw_content = [time_counter, cw_ram_address, data] acw_content = [time_counter, acw_ram_address, str(bin(0)[2:].zfill(data_width))] cw_ram_address = update_ram_address(cw_ram_address) cw_ram_content.append(cw_content) acw_ram_content.append(acw_content) else: content = [time_counter, ram_address, data] ram_content.append(content) ram_address = update_ram_address(ram_address) bit_counter += data_width time_counter += 1 # Time period with no data after all packets if time_counter > last_packet_time: while time_counter < simulator.until: if simulator.bidirectional: cw_content = [time_counter, cw_ram_address, str(bin(0)[2:].zfill(data_width))] acw_content = [time_counter, acw_ram_address, str(bin(0)[2:].zfill(data_width))] cw_ram_content.append(cw_content) acw_ram_content.append(acw_content) else: content = [time_counter, ram_address, str(bin(0)[2:].zfill(data_width))] ram_content.append(content) time_counter += 1 if simulator.bidirectional: return cw_ram_content, acw_ram_content else: return ram_content def generate_data_out_tv(): """ Function to generate transmitter data output testvectors. Returns ------- data_out : list The list of data output testvectors, including empty slot check flag and output data. """ def generate_data_output(data_packet_record): time_counter = 0 data_out = [] last_packet_time = data_packet_record[-1][0] for data_packet in data_packet_record: # Time period with no data while time_counter < int(data_packet[0]): data_out.append([time_counter, 0, str(bin(0)[2:].zfill(data_width))]) time_counter += 1 # Clock cycle with destination ID if time_counter == int(data_packet[0]): # Mapping NetworkSim ID to SystemVerilog ID mapped_destination_id = data_packet[2] + 1 # Append destination ID packet_content = str(bin(mapped_destination_id)[2:].zfill(data_width)) # Insert source ID packet_content = str(bin(transmitter_id)[2:].zfill(id_width)) + packet_content[id_width:] data_out.append([time_counter, 1, packet_content]) time_counter += 1 # Time period with data packet_length = len(data_packet[1]) num_clock_cycle = -(-packet_length // data_width) bit_counter = 0 for i in range(num_clock_cycle): if i == num_clock_cycle - 1: data = data_packet[1][bit_counter:].ljust(data_width, '0') else: data = data_packet[1][bit_counter:bit_counter + data_width] data_out.append([time_counter, 0, data]) bit_counter += data_width time_counter += 1 # Time period with no data after all packets if time_counter > last_packet_time: while time_counter < simulator.until: data_out.append([time_counter, 0, str(bin(0)[2:].zfill(data_width))]) time_counter += 1 return data_out if simulator.bidirectional: cw_data_packet_record = simulator.downstream_transmitter[mapped_transmitter_id].transmitted_data_packet acw_data_packet_record = simulator.upstream_transmitter[mapped_transmitter_id].transmitted_data_packet return generate_data_output(data_packet_record=cw_data_packet_record), \ generate_data_output(data_packet_record=acw_data_packet_record) else: data_packet_record = simulator.transmitter[mapped_transmitter_id].transmitted_data_packet return generate_data_output(data_packet_record=data_packet_record) if simulator.bidirectional: cw_ram_content_tv, acw_ram_content_tv = generate_ram_tv() cw_data_out_tv, acw_data_out_tv = generate_data_out_tv() else: ram_content_tv = generate_ram_tv() data_out_tv = generate_data_out_tv() if not simulator.bidirectional: # Write to test vector files with open(ram_filename, 'w') as f_ram: for i in range(len(ram_content_tv)): print( str(bin(ram_content_tv[i][1])[2:].zfill(address_width)) + '_' + ram_content_tv[i][2], file=f_ram ) with open(data_out_assert_filename, 'w') as f_data_out_assert: for i in range(len(data_out_tv)): print( str(bin(data_out_tv[i][1])[2:].zfill(1)) + '_' + data_out_tv[i][2], file=f_data_out_assert ) else: # Write to test vector files with open(cw_ram_filename, 'w') as f_ram_cw: for i in range(len(cw_ram_content_tv)): print( str(bin(cw_ram_content_tv[i][1])[2:].zfill(address_width)) + '_' + cw_ram_content_tv[i][2], file=f_ram_cw ) with open(cw_data_out_assert_filename, 'w') as f_data_out_assert_cw: for i in range(len(cw_data_out_tv)): print( str(bin(cw_data_out_tv[i][1])[2:].zfill(1)) + '_' + cw_data_out_tv[i][2], file=f_data_out_assert_cw ) with open(acw_ram_filename, 'w') as f_ram_acw: for i in range(len(acw_ram_content_tv)): print( str(bin(acw_ram_content_tv[i][1])[2:].zfill(address_width)) + '_' + acw_ram_content_tv[i][2], file=f_ram_acw ) with open(acw_data_out_assert_filename, 'w') as f_data_out_assert_acw: for i in range(len(acw_data_out_tv)): print( str(bin(acw_data_out_tv[i][1])[2:].zfill(1)) + '_' + acw_data_out_tv[i][2], file=f_data_out_assert_acw ) if simulator.bidirectional: return cw_ram_content_tv, acw_ram_content_tv, cw_data_out_tv, acw_data_out_tv else: return ram_content_tv, data_out_tv