mirror of https://github.com/VLSIDA/OpenRAM.git
PEP8 formatting
This commit is contained in:
parent
69f5621245
commit
403ea17039
|
|
@ -5,23 +5,18 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
import sys,re,shutil
|
|
||||||
import copy
|
|
||||||
import collections
|
import collections
|
||||||
from design import design
|
|
||||||
import debug
|
import debug
|
||||||
import math
|
|
||||||
import tech
|
|
||||||
import random
|
import random
|
||||||
from .stimuli import *
|
from .stimuli import *
|
||||||
from .charutils import *
|
from .charutils import *
|
||||||
import utils
|
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from .simulation import simulation
|
from .simulation import simulation
|
||||||
# from .delay import delay
|
# from .delay import delay
|
||||||
import graph_util
|
import graph_util
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
|
|
||||||
class functional(simulation):
|
class functional(simulation):
|
||||||
"""
|
"""
|
||||||
Functions to write random data values to a random address then read them back and check
|
Functions to write random data values to a random address then read them back and check
|
||||||
|
|
@ -60,7 +55,6 @@ class functional(simulation):
|
||||||
self.read_check = []
|
self.read_check = []
|
||||||
self.read_results = []
|
self.read_results = []
|
||||||
|
|
||||||
|
|
||||||
def run(self, feasible_period=None):
|
def run(self, feasible_period=None):
|
||||||
if feasible_period: #period defaults to tech.py feasible period otherwise.
|
if feasible_period: #period defaults to tech.py feasible period otherwise.
|
||||||
self.period = feasible_period
|
self.period = feasible_period
|
||||||
|
|
@ -85,11 +79,11 @@ class functional(simulation):
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
checks = []
|
checks = []
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
checks.append((self.addr_value[port],"addr"))
|
checks.append((self.addr_value[port], "addr"))
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
checks.append((self.data_value[port],"data"))
|
checks.append((self.data_value[port], "data"))
|
||||||
checks.append((self.wmask_value[port],"wmask"))
|
checks.append((self.wmask_value[port], "wmask"))
|
||||||
checks.append((self.spare_wen_value[port],"spare_wen"))
|
checks.append((self.spare_wen_value[port], "spare_wen"))
|
||||||
|
|
||||||
for (val, name) in checks:
|
for (val, name) in checks:
|
||||||
debug.check(len(self.cycle_times)==len(val),
|
debug.check(len(self.cycle_times)==len(val),
|
||||||
|
|
@ -108,15 +102,15 @@ class functional(simulation):
|
||||||
r_ops = ["noop", "read"]
|
r_ops = ["noop", "read"]
|
||||||
|
|
||||||
# First cycle idle is always an idle cycle
|
# First cycle idle is always an idle cycle
|
||||||
comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, "0"*self.num_wmasks, 0, self.t_current)
|
comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.addr_size, "0" * self.num_wmasks, 0, self.t_current)
|
||||||
self.add_noop_all_ports(comment)
|
self.add_noop_all_ports(comment)
|
||||||
|
|
||||||
# 1. Write all the write ports first to seed a bunch of locations.
|
# 1. Write all the write ports first to seed a bunch of locations.
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
addr = self.gen_addr()
|
addr = self.gen_addr()
|
||||||
word = self.gen_data()
|
word = self.gen_data()
|
||||||
comment = self.gen_cycle_comment("write", word, addr, "1"*self.num_wmasks, port, self.t_current)
|
comment = self.gen_cycle_comment("write", word, addr, "1" * self.num_wmasks, port, self.t_current)
|
||||||
self.add_write_one_port(comment, addr, word, "1"*self.num_wmasks, port)
|
self.add_write_one_port(comment, addr, word, "1" * self.num_wmasks, port)
|
||||||
self.stored_words[addr] = word
|
self.stored_words[addr] = word
|
||||||
|
|
||||||
# All other read-only ports are noops.
|
# All other read-only ports are noops.
|
||||||
|
|
@ -135,7 +129,7 @@ class functional(simulation):
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
self.add_noop_one_port(port)
|
self.add_noop_one_port(port)
|
||||||
else:
|
else:
|
||||||
comment = self.gen_cycle_comment("read", word, addr, "0"*self.num_wmasks, port, self.t_current)
|
comment = self.gen_cycle_comment("read", word, addr, "0" * self.num_wmasks, port, self.t_current)
|
||||||
self.add_read_one_port(comment, addr, port)
|
self.add_read_one_port(comment, addr, port)
|
||||||
self.add_read_check(word, port)
|
self.add_read_check(word, port)
|
||||||
self.cycle_times.append(self.t_current)
|
self.cycle_times.append(self.t_current)
|
||||||
|
|
@ -164,13 +158,13 @@ class functional(simulation):
|
||||||
self.add_noop_one_port(port)
|
self.add_noop_one_port(port)
|
||||||
else:
|
else:
|
||||||
word = self.gen_data()
|
word = self.gen_data()
|
||||||
comment = self.gen_cycle_comment("write", word, addr, "1"*self.num_wmasks, port, self.t_current)
|
comment = self.gen_cycle_comment("write", word, addr, "1" * self.num_wmasks, port, self.t_current)
|
||||||
self.add_write_one_port(comment, addr, word, "1"*self.num_wmasks, port)
|
self.add_write_one_port(comment, addr, word, "1" * self.num_wmasks, port)
|
||||||
self.stored_words[addr] = word
|
self.stored_words[addr] = word
|
||||||
w_addrs.append(addr)
|
w_addrs.append(addr)
|
||||||
elif op == "partial_write":
|
elif op == "partial_write":
|
||||||
# write only to a word that's been written to
|
# write only to a word that's been written to
|
||||||
(addr,old_word) = self.get_data()
|
(addr, old_word) = self.get_data()
|
||||||
# two ports cannot write to the same address
|
# two ports cannot write to the same address
|
||||||
if addr in w_addrs:
|
if addr in w_addrs:
|
||||||
self.add_noop_one_port(port)
|
self.add_noop_one_port(port)
|
||||||
|
|
@ -183,7 +177,7 @@ class functional(simulation):
|
||||||
self.stored_words[addr] = new_word
|
self.stored_words[addr] = new_word
|
||||||
w_addrs.append(addr)
|
w_addrs.append(addr)
|
||||||
else:
|
else:
|
||||||
(addr,word) = random.choice(list(self.stored_words.items()))
|
(addr, word) = random.choice(list(self.stored_words.items()))
|
||||||
# The write driver is not sized sufficiently to drive through the two
|
# The write driver is not sized sufficiently to drive through the two
|
||||||
# bitcell access transistors to the read port. So, for now, we do not allow
|
# bitcell access transistors to the read port. So, for now, we do not allow
|
||||||
# a simultaneous write and read to the same address on different ports. This
|
# a simultaneous write and read to the same address on different ports. This
|
||||||
|
|
@ -191,7 +185,7 @@ class functional(simulation):
|
||||||
if addr in w_addrs:
|
if addr in w_addrs:
|
||||||
self.add_noop_one_port(port)
|
self.add_noop_one_port(port)
|
||||||
else:
|
else:
|
||||||
comment = self.gen_cycle_comment("read", word, addr, "0"*self.num_wmasks, port, self.t_current)
|
comment = self.gen_cycle_comment("read", word, addr, "0" * self.num_wmasks, port, self.t_current)
|
||||||
self.add_read_one_port(comment, addr, port)
|
self.add_read_one_port(comment, addr, port)
|
||||||
self.add_read_check(word, port)
|
self.add_read_check(word, port)
|
||||||
|
|
||||||
|
|
@ -199,7 +193,7 @@ class functional(simulation):
|
||||||
self.t_current += self.period
|
self.t_current += self.period
|
||||||
|
|
||||||
# Last cycle idle needed to correctly measure the value on the second to last clock edge
|
# Last cycle idle needed to correctly measure the value on the second to last clock edge
|
||||||
comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, "0"*self.num_wmasks, 0, self.t_current)
|
comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.addr_size, "0" * self.num_wmasks, 0, self.t_current)
|
||||||
self.add_noop_all_ports(comment)
|
self.add_noop_all_ports(comment)
|
||||||
|
|
||||||
def gen_masked_data(self, old_word, word, wmask):
|
def gen_masked_data(self, old_word, word, wmask):
|
||||||
|
|
@ -213,7 +207,7 @@ class functional(simulation):
|
||||||
if wmask[bit] == "0":
|
if wmask[bit] == "0":
|
||||||
lower = bit * self.write_size
|
lower = bit * self.write_size
|
||||||
upper = lower + self.write_size - 1
|
upper = lower + self.write_size - 1
|
||||||
new_word = new_word[:lower] + old_word[lower:upper+1] + new_word[upper + 1:]
|
new_word = new_word[:lower] + old_word[lower:upper + 1] + new_word[upper + 1:]
|
||||||
|
|
||||||
return new_word
|
return new_word
|
||||||
|
|
||||||
|
|
@ -223,7 +217,7 @@ class functional(simulation):
|
||||||
self.check
|
self.check
|
||||||
except:
|
except:
|
||||||
self.check = 0
|
self.check = 0
|
||||||
self.read_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, self.check])
|
self.read_check.append([word, "{0}{1}".format(self.dout_name, port), self.t_current + self.period, self.check])
|
||||||
self.check += 1
|
self.check += 1
|
||||||
|
|
||||||
def read_stim_results(self):
|
def read_stim_results(self):
|
||||||
|
|
@ -231,7 +225,7 @@ class functional(simulation):
|
||||||
for (word, dout_port, eo_period, check) in self.read_check:
|
for (word, dout_port, eo_period, check) in self.read_check:
|
||||||
sp_read_value = ""
|
sp_read_value = ""
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
value = parse_spice_list("timing", "v{0}.{1}ck{2}".format(dout_port.lower(),bit,check))
|
value = parse_spice_list("timing", "v{0}.{1}ck{2}".format(dout_port.lower(), bit, check))
|
||||||
if value > self.v_high:
|
if value > self.v_high:
|
||||||
sp_read_value = "1" + sp_read_value
|
sp_read_value = "1" + sp_read_value
|
||||||
elif value < self.v_low:
|
elif value < self.v_low:
|
||||||
|
|
@ -282,25 +276,24 @@ class functional(simulation):
|
||||||
# wmask must be reversed since a python list goes right to left and sram bits go left to right.
|
# wmask must be reversed since a python list goes right to left and sram bits go left to right.
|
||||||
return wmask[::-1]
|
return wmask[::-1]
|
||||||
|
|
||||||
|
|
||||||
def gen_data(self):
|
def gen_data(self):
|
||||||
""" Generates a random word to write. """
|
""" Generates a random word to write. """
|
||||||
if not self.num_spare_cols:
|
if not self.num_spare_cols:
|
||||||
random_value = random.randint(0,(2**(self.word_size))-1)
|
random_value = random.randint(0, (2 ** self.word_size) - 1)
|
||||||
else:
|
else:
|
||||||
random_value1 = random.randint(0,(2**(self.word_size))-1)
|
random_value1 = random.randint(0, (2 ** self.word_size) - 1)
|
||||||
random_value2 = random.randint(0,(2**(self.num_spare_cols))-1)
|
random_value2 = random.randint(0, (2 ** self.num_spare_cols) - 1)
|
||||||
random_value = random_value1 + random_value2
|
random_value = random_value1 + random_value2
|
||||||
data_bits = self.convert_to_bin(random_value,False)
|
data_bits = self.convert_to_bin(random_value, False)
|
||||||
return data_bits
|
return data_bits
|
||||||
|
|
||||||
def gen_addr(self):
|
def gen_addr(self):
|
||||||
""" Generates a random address value to write to. """
|
""" Generates a random address value to write to. """
|
||||||
if self.num_spare_rows==0:
|
if self.num_spare_rows==0:
|
||||||
random_value = random.randint(0,(2**self.addr_size)-1)
|
random_value = random.randint(0, (2 ** self.addr_size) - 1)
|
||||||
else:
|
else:
|
||||||
random_value = random.randint(0,((2**(self.addr_size-1)-1))+(self.num_spare_rows * self.words_per_row))
|
random_value = random.randint(0, ((2 ** (self.addr_size - 1) - 1)) + (self.num_spare_rows * self.words_per_row))
|
||||||
addr_bits = self.convert_to_bin(random_value,True)
|
addr_bits = self.convert_to_bin(random_value, True)
|
||||||
return addr_bits
|
return addr_bits
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
|
|
@ -308,36 +301,36 @@ class functional(simulation):
|
||||||
# Used for write masks since they should be writing to previously written addresses
|
# Used for write masks since they should be writing to previously written addresses
|
||||||
addr = random.choice(list(self.stored_words.keys()))
|
addr = random.choice(list(self.stored_words.keys()))
|
||||||
word = self.stored_words[addr]
|
word = self.stored_words[addr]
|
||||||
return (addr,word)
|
return (addr, word)
|
||||||
|
|
||||||
def convert_to_bin(self,value,is_addr):
|
def convert_to_bin(self, value, is_addr):
|
||||||
""" Converts addr & word to usable binary values. """
|
""" Converts addr & word to usable binary values. """
|
||||||
new_value = str.replace(bin(value),"0b","")
|
new_value = str.replace(bin(value), "0b", "")
|
||||||
if(is_addr):
|
if(is_addr):
|
||||||
expected_value = self.addr_size
|
expected_value = self.addr_size
|
||||||
else:
|
else:
|
||||||
expected_value = self.word_size + self.num_spare_cols
|
expected_value = self.word_size + self.num_spare_cols
|
||||||
for i in range (expected_value - len(new_value)):
|
for i in range(expected_value - len(new_value)):
|
||||||
new_value = "0" + new_value
|
new_value = "0" + new_value
|
||||||
|
|
||||||
#print("Binary Conversion: {} to {}".format(value, new_value))
|
# print("Binary Conversion: {} to {}".format(value, new_value))
|
||||||
return new_value
|
return new_value
|
||||||
|
|
||||||
def write_functional_stimulus(self):
|
def write_functional_stimulus(self):
|
||||||
""" Writes SPICE stimulus. """
|
""" Writes SPICE stimulus. """
|
||||||
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
|
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
|
||||||
self.sf = open(temp_stim,"w")
|
self.sf = open(temp_stim, "w")
|
||||||
self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period))
|
self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period))
|
||||||
self.stim = stimuli(self.sf,self.corner)
|
self.stim = stimuli(self.sf, self.corner)
|
||||||
|
|
||||||
#Write include statements
|
# Write include statements
|
||||||
self.stim.write_include(self.sp_file)
|
self.stim.write_include(self.sp_file)
|
||||||
|
|
||||||
#Write Vdd/Gnd statements
|
# Write Vdd/Gnd statements
|
||||||
self.sf.write("\n* Global Power Supplies\n")
|
self.sf.write("\n* Global Power Supplies\n")
|
||||||
self.stim.write_supply()
|
self.stim.write_supply()
|
||||||
|
|
||||||
#Instantiate the SRAM
|
# Instantiate the SRAM
|
||||||
self.sf.write("\n* Instantiation of the SRAM\n")
|
self.sf.write("\n* Instantiation of the SRAM\n")
|
||||||
self.stim.inst_model(pins=self.pins,
|
self.stim.inst_model(pins=self.pins,
|
||||||
model_name=self.sram.name)
|
model_name=self.sram.name)
|
||||||
|
|
@ -378,10 +371,10 @@ class functional(simulation):
|
||||||
# Generate control signals
|
# Generate control signals
|
||||||
self.sf.write("\n * Generation of control signals\n")
|
self.sf.write("\n * Generation of control signals\n")
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.stim.gen_pwl("CSB{}".format(port), self.cycle_times , self.csb_values[port], self.period, self.slew, 0.05)
|
self.stim.gen_pwl("CSB{}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
|
||||||
|
|
||||||
for port in self.readwrite_ports:
|
for port in self.readwrite_ports:
|
||||||
self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05)
|
self.stim.gen_pwl("WEB{}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05)
|
||||||
|
|
||||||
# Generate wmask bits
|
# Generate wmask bits
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
|
|
@ -416,11 +409,11 @@ class functional(simulation):
|
||||||
# Generate dout value measurements
|
# Generate dout value measurements
|
||||||
self.sf.write("\n * Generation of dout measurements\n")
|
self.sf.write("\n * Generation of dout measurements\n")
|
||||||
for (word, dout_port, eo_period, check) in self.read_check:
|
for (word, dout_port, eo_period, check) in self.read_check:
|
||||||
t_intital = eo_period - 0.01*self.period
|
t_intital = eo_period - 0.01 * self.period
|
||||||
t_final = eo_period + 0.01*self.period
|
t_final = eo_period + 0.01 * self.period
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
self.stim.gen_meas_value(meas_name="V{0}_{1}ck{2}".format(dout_port,bit,check),
|
self.stim.gen_meas_value(meas_name="V{0}_{1}ck{2}".format(dout_port, bit, check),
|
||||||
dout="{0}_{1}".format(dout_port,bit),
|
dout="{0}_{1}".format(dout_port, bit),
|
||||||
t_intital=t_intital,
|
t_intital=t_intital,
|
||||||
t_final=t_final)
|
t_final=t_final)
|
||||||
|
|
||||||
|
|
@ -450,7 +443,7 @@ class functional(simulation):
|
||||||
# Generate new graph every analysis as edges might change depending on test bit
|
# Generate new graph every analysis as edges might change depending on test bit
|
||||||
self.graph = graph_util.timing_graph()
|
self.graph = graph_util.timing_graph()
|
||||||
self.sram_spc_name = "X{}".format(self.sram.name)
|
self.sram_spc_name = "X{}".format(self.sram.name)
|
||||||
self.sram.build_graph(self.graph,self.sram_spc_name,self.pins)
|
self.sram.build_graph(self.graph, self.sram_spc_name, self.pins)
|
||||||
|
|
||||||
# FIXME: refactor to share with delay.py
|
# FIXME: refactor to share with delay.py
|
||||||
def set_internal_spice_names(self):
|
def set_internal_spice_names(self):
|
||||||
|
|
@ -462,13 +455,13 @@ class functional(simulation):
|
||||||
'{}{}_{}'.format(self.dout_name, port, 0).lower())
|
'{}{}_{}'.format(self.dout_name, port, 0).lower())
|
||||||
|
|
||||||
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
||||||
debug.info(2,"s_en name = {}".format(self.sen_name))
|
debug.info(2, "s_en name = {}".format(self.sen_name))
|
||||||
|
|
||||||
self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths, port)
|
self.bl_name, self.br_name = self.get_bl_name(self.graph.all_paths, port)
|
||||||
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name))
|
||||||
|
|
||||||
self.q_name,self.qbar_name = self.get_bit_name()
|
self.q_name, self.qbar_name = self.get_bit_name()
|
||||||
debug.info(2,"q name={}\nqbar name={}".format(self.q_name,self.qbar_name))
|
debug.info(2, "q name={}\nqbar name={}".format(self.q_name, self.qbar_name))
|
||||||
|
|
||||||
def get_bit_name(self):
|
def get_bit_name(self):
|
||||||
""" Get a bit cell name """
|
""" Get a bit cell name """
|
||||||
|
|
@ -476,10 +469,10 @@ class functional(simulation):
|
||||||
storage_names = cell_inst.mod.get_storage_net_names()
|
storage_names = cell_inst.mod.get_storage_net_names()
|
||||||
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
|
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
|
||||||
"supported for characterization. Storage nets={}").format(storage_names))
|
"supported for characterization. Storage nets={}").format(storage_names))
|
||||||
q_name = cell_name+'.'+str(storage_names[0])
|
q_name = cell_name + '.' + str(storage_names[0])
|
||||||
qbar_name = cell_name+'.'+str(storage_names[1])
|
qbar_name = cell_name + '.' + str(storage_names[1])
|
||||||
|
|
||||||
return (q_name,qbar_name)
|
return (q_name, qbar_name)
|
||||||
|
|
||||||
# FIXME: refactor to share with delay.py
|
# FIXME: refactor to share with delay.py
|
||||||
def get_sen_name(self, paths):
|
def get_sen_name(self, paths):
|
||||||
|
|
@ -504,7 +497,6 @@ class functional(simulation):
|
||||||
cell_bl = cell_mod.get_bl_name(port)
|
cell_bl = cell_mod.get_bl_name(port)
|
||||||
cell_br = cell_mod.get_br_name(port)
|
cell_br = cell_mod.get_br_name(port)
|
||||||
|
|
||||||
bl_found = False
|
|
||||||
# Only a single path should contain a single s_en name. Anything else is an error.
|
# Only a single path should contain a single s_en name. Anything else is an error.
|
||||||
bl_names = []
|
bl_names = []
|
||||||
exclude_set = self.get_bl_name_search_exclusions()
|
exclude_set = self.get_bl_name_search_exclusions()
|
||||||
|
|
@ -530,14 +522,14 @@ class functional(simulation):
|
||||||
for path in paths:
|
for path in paths:
|
||||||
aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set)
|
aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set)
|
||||||
if net_found and len(aliases) >= 1:
|
if net_found and len(aliases) >= 1:
|
||||||
debug.error('Found multiple paths with {} net.'.format(int_net),1)
|
debug.error('Found multiple paths with {} net.'.format(int_net), 1)
|
||||||
elif len(aliases) > 1:
|
elif len(aliases) > 1:
|
||||||
debug.error('Found multiple {} nets in single path.'.format(int_net),1)
|
debug.error('Found multiple {} nets in single path.'.format(int_net), 1)
|
||||||
elif not net_found and len(aliases) == 1:
|
elif not net_found and len(aliases) == 1:
|
||||||
path_net_name = aliases[0]
|
path_net_name = aliases[0]
|
||||||
net_found = True
|
net_found = True
|
||||||
if not net_found:
|
if not net_found:
|
||||||
debug.error("Could not find {} net in timing paths.".format(int_net),1)
|
debug.error("Could not find {} net in timing paths.".format(int_net), 1)
|
||||||
|
|
||||||
return path_net_name
|
return path_net_name
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue