Skip to content

Commit bcbadfc

Browse files
Crossbar latency
1 parent a10550e commit bcbadfc

2 files changed

Lines changed: 44 additions & 23 deletions

File tree

hwcomponents_neurosim/main.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,9 @@ class FlipFlop(_NeurosimPlugInComponent):
750750
_get_stats_func = staticmethod(neurointerface.flip_flop_stats)
751751
_params = ["tech_node", "cycle_period", "n_bits"]
752752

753-
def __init__(self, tech_node: float, cycle_period: float, n_bits: int, n_instances: int = 1):
753+
def __init__(
754+
self, tech_node: float, cycle_period: float, n_bits: int, n_instances: int = 1
755+
):
754756
super().__init__(
755757
tech_node=tech_node,
756758
cycle_period=cycle_period,
@@ -860,7 +862,9 @@ class Adder(_NeurosimPlugInComponent):
860862
_get_stats_func = staticmethod(neurointerface.adder_stats)
861863
_params = ["tech_node", "cycle_period", "n_bits"]
862864

863-
def __init__(self, tech_node: float, cycle_period: float, n_bits: int, n_instances: int = 1):
865+
def __init__(
866+
self, tech_node: float, cycle_period: float, n_bits: int, n_instances: int = 1
867+
):
864868
super().__init__(
865869
tech_node=tech_node,
866870
cycle_period=cycle_period,
@@ -999,7 +1003,12 @@ class MaxPool(_NeurosimPlugInComponent):
9991003
_params = ["tech_node", "cycle_period", "n_bits", "pool_window"]
10001004

10011005
def __init__(
1002-
self, tech_node: float, cycle_period: float, n_bits: int, pool_window: int, n_instances: int = 1
1006+
self,
1007+
tech_node: float,
1008+
cycle_period: float,
1009+
n_bits: int,
1010+
pool_window: int,
1011+
n_instances: int = 1,
10031012
):
10041013
super().__init__(
10051014
tech_node=tech_node,

hwcomponents_neurosim/neurointerface.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ def __init__(
354354
self.n_adder_tree_inputs = n_adder_tree_inputs
355355
self.n_mux_inputs = n_mux_inputs
356356
self.max_activation_time = 2**self.temporal_dac_bits - 1
357+
self.min_latency = None
358+
self.cols_active_at_once = None
357359

358360
def run_neurosim(
359361
self,
@@ -438,6 +440,25 @@ def read_pipe_thread(pipe, write_to: list):
438440
self.comps = [
439441
Component(line) for line in results.split("\n") if "<COMPONENT>" in line
440442
]
443+
444+
columns_at_once = nvsimget("Columns read at once:", results, False)
445+
min_latency = nvsimget("Minimum latency per read:", results, False)
446+
logger.info(
447+
"Crossbar minimum latency is %s ns to read %s columns at once.",
448+
min_latency,
449+
columns_at_once,
450+
)
451+
if min_latency < self.cycle_period * 1e9:
452+
logger.warning(
453+
"Minimum crossbar latency of %s ns is less than the cycle "
454+
"time of %s ns.",
455+
min_latency,
456+
self.cycle_period * 1e9,
457+
)
458+
459+
self.min_latency = min_latency
460+
self.cols_active_at_once = columns_at_once
461+
441462
for c in self.comps:
442463
if "adc" in c.name:
443464
c.area *= self.adc_area_scale
@@ -449,28 +470,12 @@ def read_pipe_thread(pipe, write_to: list):
449470
logger.error("NeuroSIM returned no components. NeuroSIM output below.")
450471
logger.error("\n\nNeuroSIM returned no components. NeuroSIM output below.")
451472
logger.error("| " + results.replace("\n", "\n| ") + " ")
452-
if err:
453-
logger.error("| " + err.decode("utf-8").replace("\n", "\n| ") + " ")
454473
logger.error("NeuroSIM returned no components. NeuroSIM output above.")
455474
raise ValueError(
456475
"NeuroSIM returned no components. Check the generated Neurosim input"
457476
" config and make sure all values are populated."
458477
)
459478

460-
columns_at_once = nvsimget("Columns read at once:", results, False)
461-
min_latency = nvsimget("Minimum latency per read:", results, False)
462-
logger.info(
463-
"Crossbar minimum latency is %s ns to read %s columns at once.",
464-
min_latency,
465-
columns_at_once,
466-
)
467-
if min_latency < self.cycle_period * 1e9:
468-
logger.warning(
469-
"Minimum crossbar latency of %s ns is less than the cycle "
470-
"time of %s ns.",
471-
min_latency,
472-
self.cycle_period * 1e9,
473-
)
474479
# Remove the config file
475480
os.remove(inputpath)
476481

@@ -596,7 +601,13 @@ def rowcol_stats(
596601
read = read_off + (read_on - read_off) * avg_input
597602
write = write_on # Can't gate writes becasuse we still have to reset cells
598603

599-
latency = crossbar.latency(kind)
604+
latency = max(
605+
crossbar.min_latency, crossbar.read_pulse_width * crossbar.max_activation_time
606+
)
607+
if kind == "row": # Latency per row
608+
latency /= crossbar.rows
609+
if kind == "col": # Latency per column
610+
latency /= crossbar.cols_active_at_once
600611

601612
return stats2dict(read, write, area, leakage * crossbar.cycle_period, latency)
602613

@@ -618,8 +629,6 @@ def row_stats(
618629
dac_scale = 2 ** (crossbar.voltage_dac_bits - 1) - 1
619630
stats["Area"] = stats["Area"] + stats_dac["Area"] * dac_scale
620631
stats["Leakage"] = stats["Leakage"] + stats_dac["Leakage"] * dac_scale
621-
stats["Latency"] = max(stats["Latency"], crossbar.read_pulse_width)
622-
stats["Latency"] *= crossbar.max_activation_time
623632
return stats
624633

625634

@@ -649,12 +658,15 @@ def cell_stats(
649658
rlscale = crossbar.cell_read_leak_energy_scale
650659
act_time = crossbar.max_activation_time
651660
wscale = crossbar.cell_write_energy_scale
661+
latency = max(
662+
crossbar.min_latency, crossbar.read_pulse_width * crossbar.max_activation_time
663+
)
652664
return stats2dict(
653665
read_memcell_energy * act_time,
654666
write_memcell_energy * wscale,
655667
crossbar.area_per_cell(),
656668
crossbar.leakage_per_cell() * rlscale,
657-
crossbar.max_activation_time * crossbar.read_pulse_width,
669+
latency,
658670
)
659671

660672

0 commit comments

Comments
 (0)