511 lines
No EOL
18 KiB
Python
511 lines
No EOL
18 KiB
Python
########################################################################################
|
|
# This library creates the task needed to establish a circuit switched transmission and
|
|
# the configuration data that these task need to send
|
|
########################################################################################
|
|
|
|
import math
|
|
import os
|
|
import random
|
|
import numpy as np
|
|
import svgwrite
|
|
|
|
from lib_vhdl_gen import *
|
|
|
|
def bit_length(n):
|
|
if n == 1:
|
|
return 1
|
|
elif n > 1:
|
|
return math.ceil(math.log(n) / math.log(2))
|
|
|
|
def int2binary(w, z):
|
|
return bin(w)[2:].zfill(z)
|
|
|
|
|
|
#function to count the number of ports of a router with dimensions as input
|
|
def port_num_def(port,x_dim,y_dim,z_dim):
|
|
port_num=7
|
|
if port[1]==y_dim-1:
|
|
port_num-=1
|
|
if port[2]==x_dim-1:
|
|
port_num-=1
|
|
if port[1]==0:
|
|
port_num-=1
|
|
if port[2]==0:
|
|
port_num-=1
|
|
if port[0]==z_dim-1:
|
|
port_num-=1
|
|
if port[0]==0:
|
|
port_num-=1
|
|
return(port_num)
|
|
|
|
# Function to add zeros to the beginning of a string
|
|
def zeros(str,n):
|
|
for i in range(n):
|
|
str='0'+str
|
|
return(str)
|
|
|
|
|
|
#calculates the coordinates from the router number
|
|
def int_to_coordinates(router_num, x_dim=4, y_dim=4, z_dim=3):
|
|
coordinateZYX = [0, 0, 0]
|
|
coordinateZ = math.floor(router_num / (x_dim * y_dim))
|
|
coordinateY = math.floor((router_num - coordinateZ * x_dim * y_dim) / x_dim)
|
|
coordinateX = router_num - coordinateZ * x_dim * y_dim - coordinateY * x_dim
|
|
coordinateZYX[0] = coordinateZ
|
|
coordinateZYX[1] = coordinateY
|
|
coordinateZYX[2] = coordinateX
|
|
return coordinateZYX
|
|
|
|
def coordinates_to_int(coordinateZYX, x_dim=4, y_dim=4, z_dim=3):
|
|
coordinateZ, coordinateY, coordinateX = coordinateZYX
|
|
router_num = coordinateZ * x_dim * y_dim + coordinateY * x_dim + coordinateX
|
|
return router_num
|
|
|
|
|
|
|
|
#doing XYZ routing takin the source and destination router in int form as input
|
|
def xyz_routing(src_router, dest_router, x_dim=4, y_dim=4, z_dim=3):
|
|
# Convert router numbers to coordinates
|
|
src_coord = int_to_coordinates(src_router, x_dim, y_dim, z_dim)
|
|
dest_coord = int_to_coordinates(dest_router, x_dim, y_dim, z_dim)
|
|
|
|
# Initialize the route list with the source coordinate
|
|
route=list()
|
|
route.append(src_coord[:])
|
|
|
|
# XYZ Routing Logic [0]=Z [1]=Y [2]=X
|
|
while src_coord != dest_coord:
|
|
if src_coord[2] < dest_coord[2]:
|
|
src_coord[2] += 1
|
|
elif src_coord[2] > dest_coord[2]:
|
|
src_coord[2] -= 1
|
|
elif src_coord[1] < dest_coord[1]:
|
|
src_coord[1] += 1
|
|
elif src_coord[1] > dest_coord[1]:
|
|
src_coord[1] -= 1
|
|
elif src_coord[0] < dest_coord[0]:
|
|
src_coord[0] += 1
|
|
elif src_coord[0] > dest_coord[0]:
|
|
src_coord[0] -= 1
|
|
route.append(src_coord[:])
|
|
return route
|
|
|
|
# requirements not needed as this will always be a start task
|
|
config_task_template="""
|
|
<task id="{id}">
|
|
<start min="0" max="0"/>
|
|
<duration min="1" max="1"/>
|
|
<repeat min="1" max="1"/>
|
|
<generates>
|
|
<possibility id="0">
|
|
<probability value="1"/>
|
|
<destinations>
|
|
<destination id="0">
|
|
<delay min="-1" max="-1"/>
|
|
<interval min="20" max="20"/>
|
|
<count min="2" max="2"/>
|
|
<type value="{id}"/>
|
|
<task value="{dest}"/>
|
|
</destination>
|
|
</destinations>
|
|
</possibility>
|
|
</generates>
|
|
</task>
|
|
"""
|
|
|
|
config_map_template="""
|
|
<bind>
|
|
<task value="{id}"/>
|
|
<node value="{PE}"/>
|
|
</bind>
|
|
|
|
"""
|
|
from collections import Counter
|
|
|
|
def count_consecutive_pairs(data):
|
|
# Initialize a Counter to track occurrences of pairs
|
|
pair_counts = Counter()
|
|
pair_counter=0
|
|
|
|
# Iterate through each sublist in the data
|
|
for sublist in data:
|
|
# Extract consecutive pairs from the sublist
|
|
for i in range(len(sublist) - 1):
|
|
pair = (sublist[i], sublist[i + 1])
|
|
pair_counts[pair] += 1
|
|
pair_counter+=1
|
|
|
|
# Print results for pairs that occur multiple times
|
|
filename = "/home/sfischer/Documents/projects/wk_hybridNoC_VHDL/Python/gen_vhdl_from_task/simlog.txt"
|
|
|
|
write_to_file(filename, f"Paths {data}")
|
|
for pair, count in pair_counts.items():
|
|
if count > 1:
|
|
write_to_file(filename, f"Hop {pair} occurs {count} times")
|
|
|
|
write_to_file(filename, f"Total number of hops {pair_counter}")
|
|
|
|
|
|
|
|
def count_consecutive_pairs_no_file(data):
|
|
# Initialize a Counter to track occurrences of pairs
|
|
pair_counts = Counter()
|
|
pair_list=[]
|
|
|
|
# Iterate through each sublist in the data
|
|
for idx,sublist in enumerate(data):
|
|
# Extract consecutive pairs from the sublist
|
|
for i in range(len(sublist) - 1):
|
|
pair = (sublist[i], sublist[i + 1])
|
|
pair_counts[pair] += 1
|
|
# if pair_counts[pair]>1:
|
|
# print(idx,i,pair)
|
|
|
|
|
|
# write_to_file(filename, f"Paths {data}")
|
|
for pair, count in pair_counts.items():
|
|
if count > 1:
|
|
# print(f"Hop {pair} occurs {count} times")
|
|
pair_list.append(pair)
|
|
|
|
# print(pair_list)
|
|
return(pair_list)
|
|
|
|
def find_pair_indices(pair, lists):
|
|
indices = []
|
|
for i, sublist in enumerate(lists):
|
|
for j in range(len(sublist) - 1):
|
|
if sublist[j] == pair[0] and sublist[j + 1] == pair[1]:
|
|
indices.append(i)
|
|
break # No need to check further in this sublist
|
|
return indices
|
|
|
|
def cs_tasks(
|
|
source_destination = [],
|
|
start_task=21,
|
|
start_PE=30,
|
|
x_dim = 4, #async noc dimensions
|
|
y_dim = 4,
|
|
z_dim = 3
|
|
):
|
|
"""
|
|
Generates configuration and data for tasks in a 3D asynchronous NoC (Network-on-Chip).
|
|
This function creates configuration tasks, mapping tasks, and data for routing packets
|
|
in a 3D asynchronous NoC. It calculates routing paths, determines input/output ports,
|
|
and generates XML-like data for tasks and mappings.
|
|
Args:
|
|
source_destination (list): A list of tuples where each tuple contains source and
|
|
destination coordinates for routing tasks.
|
|
start_task (int): The starting task ID for generating unique task IDs.
|
|
start_PE (int): The starting processing element (PE) ID for mapping tasks.
|
|
x_dim (int): The X dimension of the NoC.
|
|
y_dim (int): The Y dimension of the NoC.
|
|
z_dim (int): The Z dimension of the NoC.
|
|
Returns:
|
|
tuple: A tuple containing:
|
|
- data_xml (str): The generated data for routing tasks in XML-like format.
|
|
- task_xml (str): The configuration tasks in XML-like format.
|
|
- map_xml (str): The mapping tasks in XML-like format.
|
|
- dest_address_list_int (list): A list of destination addresses as integers.
|
|
"""
|
|
|
|
|
|
|
|
# ----------------------------------------------header---------------------------------------------------
|
|
# | | | | | | | | | | |
|
|
# |config Flag| Flit_num | Packet_id | Z_src | Y_src | X_src | Z_dest | Y_dest | X_dest | Packet_length |
|
|
# | 1b | 2b | 13b | 2b | 2b | 2b | 2b | 2b | 2b | 5b |
|
|
# | | | | | | | | | | |
|
|
# -------------------------------------------------------------------------------------------------------
|
|
|
|
# -------------------------data----------------------------
|
|
# | | | | | |
|
|
# |config Flag| Flit_num | Filler | write_clk | direction |
|
|
# | 1b | 2b | 2b | 7b | 21b |
|
|
# | | | | | |
|
|
# ---------------------------------------------------------
|
|
|
|
max_x_dim = 4 # starting from 1 // Must be the same in both files + VHDL files
|
|
max_y_dim = 4 # starting from 1 // Must be the same in both files + VHDL files
|
|
max_z_dim = 4 # starting from 1 // Must be the same in both files + VHDL files
|
|
flit_width = 32 # Must be the same in both files + VHDL files
|
|
max_packet_len = 31 # (number of flits + header_included) in a packet // Must be the same in both files + VHDL files normal 31
|
|
|
|
max_tasks_per_pe=50
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# start_task=21 # the max task of the normal file so that we can create more tasks with unique IDs
|
|
start_task_temp=start_task
|
|
# start_PE=30 # as we can have a max of 50 tasks per PE, we need to split the config task on multiple PEs
|
|
|
|
|
|
dest_address_list_coord=list()
|
|
for i in range(len(source_destination)):
|
|
|
|
dest_address_list_coord.append(xyz_routing(source_destination[i][0],source_destination[i][1]))
|
|
|
|
dest_address_list_int=list()
|
|
for i, liste in enumerate(dest_address_list_coord):
|
|
dest_address_list_int.append([])
|
|
for n, coord in enumerate(liste):
|
|
dest_address_list_int[i].append(coordinates_to_int(coord))
|
|
|
|
|
|
count_consecutive_pairs_no_file(dest_address_list_int)
|
|
# print(dest_address_list_int)
|
|
task_xml=""
|
|
map_xml=""
|
|
counter_PE=0
|
|
for m in dest_address_list_int:
|
|
for idx,k in enumerate(m):
|
|
|
|
task_xml += config_task_template.format(id=start_task, dest=k)
|
|
map_xml += config_map_template.format(id=start_task, PE=start_PE)
|
|
counter_PE+=1
|
|
start_task+=1
|
|
if counter_PE==max_tasks_per_pe:
|
|
counter_PE=0
|
|
start_PE+=1
|
|
|
|
|
|
|
|
# Define source address in the synchronous NoC
|
|
# src_address = (0, 2, 1)
|
|
|
|
# Dimensions of asynchronous NoC
|
|
|
|
# Port constants
|
|
local = 0
|
|
north = 1
|
|
east = 2
|
|
south = 3
|
|
west = 4
|
|
up = 5
|
|
down = 6
|
|
|
|
# print(int_to_coordinates(17))
|
|
|
|
#convert the adress list with the router as int to the adress list with the routes as coordinated
|
|
counter=0
|
|
dest_address_list=list()
|
|
for i in dest_address_list_int:
|
|
dest_address_list.append([])
|
|
for n in i:
|
|
|
|
dest_address_list[counter].append(int_to_coordinates(n))
|
|
counter+=1
|
|
|
|
|
|
|
|
|
|
|
|
input_port=0
|
|
output_port=0
|
|
|
|
packet_id=0
|
|
|
|
packet_len=2 #packet length without header
|
|
|
|
|
|
|
|
data_xml=""
|
|
|
|
task_num_counter=0
|
|
# print(dest_address_list)
|
|
|
|
for j in range(len(dest_address_list)):
|
|
|
|
for i in range(len(dest_address_list[j])):
|
|
dest_address = dest_address_list[j][i]
|
|
|
|
#########################################################################
|
|
# calculate port numbers of async noc
|
|
#########################################################################
|
|
|
|
#what direction is what port
|
|
north=math.nan
|
|
east=math.nan
|
|
south=math.nan
|
|
west=math.nan
|
|
up=math.nan
|
|
down=math.nan
|
|
port_index=0
|
|
|
|
if (dest_address[1]==y_dim-1): #north doesnt exist
|
|
north=math.nan
|
|
else:
|
|
port_index+=1
|
|
north=port_index
|
|
|
|
if (dest_address[2]==x_dim-1): #east doesnt exist
|
|
east=math.nan
|
|
else:
|
|
port_index+=1
|
|
east=port_index
|
|
|
|
if (dest_address[1]==0): #south doesnt exist
|
|
south=math.nan
|
|
else:
|
|
port_index+=1
|
|
south=port_index
|
|
|
|
if (dest_address[2]==0): #west doesnt exist
|
|
west=math.nan
|
|
else:
|
|
port_index+=1
|
|
west=port_index
|
|
|
|
if (dest_address[0]==z_dim-1): #up doesnt exist
|
|
up=math.nan
|
|
else:
|
|
port_index+=1
|
|
up=port_index
|
|
|
|
if (dest_address[0]==0): #down doesnt exist
|
|
down=math.nan
|
|
else:
|
|
port_index+=1
|
|
down=port_index
|
|
|
|
###############################################################################
|
|
#what number is input port and output port
|
|
|
|
if i==0: #first router always has local as input port
|
|
input_port=0
|
|
else:
|
|
|
|
if dest_address_list[j][i][0] <dest_address_list[j][i-1][0]: #Z of previous router is higher ->comming from up
|
|
input_port=up
|
|
if dest_address_list[j][i][0] >dest_address_list[j][i-1][0]: #Z of previous router is lower ->comming from down
|
|
input_port=down
|
|
|
|
if dest_address_list[j][i][1] <dest_address_list[j][i-1][1]: #Y of previous router is higher ->comming from north
|
|
input_port=north
|
|
if dest_address_list[j][i][1] >dest_address_list[j][i-1][1]: #Y of previous router is lower ->comming from south
|
|
input_port=south
|
|
|
|
if dest_address_list[j][i][2] <dest_address_list[j][i-1][2]: #X of previous router is higher ->comming from east
|
|
input_port=east
|
|
if dest_address_list[j][i][2] >dest_address_list[j][i-1][2]: #X of previous router is lower ->comming from west
|
|
input_port=west
|
|
|
|
|
|
if i==len(dest_address_list[j])-1: #last router alway has local as output port
|
|
output_port=0
|
|
else:
|
|
|
|
if dest_address_list[j][i][0] <dest_address_list[j][i+1][0]: #Z of next router is higher ->going to up
|
|
output_port=up
|
|
if dest_address_list[j][i][0] >dest_address_list[j][i+1][0]: #Z of next router is lower ->going to down
|
|
output_port=down
|
|
|
|
if dest_address_list[j][i][1] <dest_address_list[j][i+1][1]: #Y of next router is higher ->going to north
|
|
output_port=north
|
|
if dest_address_list[j][i][1] >dest_address_list[j][i+1][1]: #Y of next router is lower ->going to south
|
|
output_port=south
|
|
|
|
if dest_address_list[j][i][2] <dest_address_list[j][i+1][2]: #X of next router is higher ->going to east
|
|
output_port=east
|
|
if dest_address_list[j][i][2] >dest_address_list[j][i+1][2]: #X of next router is lower ->going to west
|
|
output_port=west
|
|
|
|
|
|
#########################################################################
|
|
# create header and data - Not using the header. It gets created in vhdl
|
|
#########################################################################
|
|
flit_num=0
|
|
|
|
flit_num+=1
|
|
packet_id+=1
|
|
|
|
|
|
######################direction data output##############
|
|
data_output=''
|
|
|
|
data_output=zeros(data_output,bit_length(port_num_def(dest_address,x_dim,y_dim,z_dim))*output_port) #how many bits do we need for one direction signal* outputport num (zeros until the right direction must be set)
|
|
data_output= int2binary(input_port,bit_length(port_num_def(dest_address,x_dim,y_dim,z_dim)))+ data_output
|
|
data_output=zeros(data_output,flit_width-len(data_output)-11)
|
|
|
|
#write_clk
|
|
data_output=zeros(data_output,output_port)
|
|
data_output='1' +data_output #write_clk
|
|
data_output=zeros(data_output,6-output_port)
|
|
|
|
#filler
|
|
data_output=zeros(data_output,1)
|
|
|
|
#flit number in packet
|
|
data_output=int2binary(flit_num,2) +data_output
|
|
|
|
#config flag
|
|
data_output='1'+data_output
|
|
|
|
task_num=0
|
|
fixed_length = 10
|
|
# if j>0:
|
|
# # task_num=len(dest_address_list[j-1])*j+start_task_temp+i
|
|
# task_num=start_task_temp+task_num_counter
|
|
# print(f"start_task_temp {start_task_temp}")
|
|
# print(f"len(dest_address_list[j-1])) {len(dest_address_list[j-1])}")
|
|
# print(f"j {j}")
|
|
# print(f"i {i}")
|
|
# print(f"task_num {task_num}")
|
|
|
|
# task_num_counter+=1
|
|
|
|
|
|
# else:
|
|
# task_num=start_task_temp+task_num_counter
|
|
# # task_num=start_task_temp+i
|
|
# task_num_counter+=1
|
|
# # print(task_num)
|
|
task_num=start_task_temp+task_num_counter
|
|
task_num_counter+=1
|
|
# print(task_num)
|
|
task_num=format(task_num, f'0{fixed_length}b')
|
|
|
|
data_output=task_num+data_output + "\n"
|
|
|
|
data_xml=data_xml+data_output
|
|
|
|
flit_num+=1
|
|
##################direction data input########################
|
|
data_input=''
|
|
|
|
data_input=zeros(data_input,bit_length(port_num_def(dest_address,x_dim,y_dim,z_dim))*input_port)
|
|
|
|
data_input= int2binary(output_port,bit_length(port_num_def(dest_address,x_dim,y_dim,z_dim)))+ data_input
|
|
data_input=zeros(data_input,flit_width-len(data_input)-11)
|
|
|
|
#write clk
|
|
data_input=zeros(data_input,input_port)
|
|
data_input='1' +data_input
|
|
data_input=zeros(data_input,6-input_port)
|
|
|
|
#fillter
|
|
data_input=zeros(data_input,1)
|
|
|
|
#flit number in packet
|
|
data_input=int2binary(flit_num,2) +data_input
|
|
|
|
#config flag
|
|
data_input='1'+data_input
|
|
|
|
data_input=task_num+data_input + "\n"
|
|
|
|
|
|
data_xml=data_xml+data_input
|
|
|
|
|
|
|
|
# print(data_xml)
|
|
# print(task_xml)
|
|
# print(map_xml)
|
|
return (data_xml,task_xml,map_xml,dest_address_list_int)
|
|
|
|
|
|
# cs_tasks() |