From b49b9d98c3c943d6391b7ab21268759adf627d0b Mon Sep 17 00:00:00 2001 From: Michele Date: Wed, 2 Mar 2022 08:22:56 +0100 Subject: [PATCH 1/3] started arbiter tree --- dataflow_neuro/primitives.act | 101 ++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/dataflow_neuro/primitives.act b/dataflow_neuro/primitives.act index 7d3a97b..49497ee 100644 --- a/dataflow_neuro/primitives.act +++ b/dataflow_neuro/primitives.act @@ -507,6 +507,107 @@ namespace tmpl { BUF_X1 reset_buf(.a=reset_B, .y=_reset_BX,.vdd=supply.vdd,.vss=supply.vss); } + // A tree composed by arbiters. The first layer takes N signals + export template + defproc arbiter_tree(a1of1 in[N],a1of1 out; power supply) + { + + bool tout; + + { N > 0 : "What?" }; + + /* We calculate here how many elements we need to create the full tree */ + pint i, end, j; + i = 0; + end = N-1; + + pint lenTree2Count, lenTree3Count; + pint odd_one_idx = 0; + pbool odd_one_flag = 0; + lenTree2Count = 0; + *[ i != end -> + j = 0; + *[ i < end -> + j = j + 1; + [ i+1 >= end -> + i = end; + lenTree2Count = lenTree2Count +1; + + [] i >= end -> + i = end; + odd_one_idx = i; + odd_one_flag = 1; + [] else -> + i = i + 2; + lenTree2Count = lenTree2Count +1; + ] + ] + /*-- update range that has to be combined --*/ + i = end+1; + end = end+j+odd_one_flag; + ] + /* array that holds ALL the wires in the completion tree */ + a1of1 wire[end+1]; + // Connecting the first nodes to the input + (l:N: + wire[l] = in[l]; + ) + [lenTree2Count > 0 -> + arbiter_handshake arb_array[lenTree2Count]; + ] + (h:lenTree2Count:arb_array[h].vdd = supply.vdd;) + (h:lenTree2Count:arb_array[h].vss = supply.vss;) + + /* Reset the variables before the assigmnent of the nodes to the cells */ + i = 0; + end = N-1; + j = 0; + pint tree2Index = 0; + pint tree3Index = 0; + *[ i != end -> + /* + * Invariant: tmp[i..end] has the current signals that need to be + * combined together, and "isinv" specifies if they are the inverted + * sense or not + */ + j = 0; + *[ i < end -> + /*-- there are still signals that need to be combined --*/ + j = j + 1; + [ i+1 >= end -> + /*-- last piece: use either a 2 input C-element --*/ + C2Els[tree2Index].a = wire[i]; + C2Els[tree2Index].b = wire[i+1]; + C2Els[tree2Index].y = wire[end+j]; + tree2Index = tree2Index +1; + i = end; + [] i+2 >= end -> + /*-- last piece: use either a 3 input C-element --*/ + C3Els[tree3Index].a = tmp[i]; + C3Els[tree3Index].b = tmp[i+1]; + C3Els[tree3Index].c = tmp[i+2]; + C3Els[tree3Index].y = tmp[end+j]; + + tree3Index = tree3Index +1; + i = end; + [] else -> + /*-- more to come; so use a two input C-element --*/ + C2Els[tree2Index].a = tmp[i]; + C2Els[tree2Index].b = tmp[i+1]; + C2Els[tree2Index].y = tmp[end+j]; + tree2Index = tree2Index +1; + i = i + 2; + ] + ] + /*-- update range that has to be combined --*/ + i = end+1; + end = end+j; + j = 0; + ] + + out = tmp[end]; + + } export template defproc merge (avMx1of2 in1; avMx1of2 in2; avMx1of2 out ; bool? reset_B; power supply) { From 3e1b63c201d232fd79cd6b001052214abd9c5898 Mon Sep 17 00:00:00 2001 From: Michele Date: Wed, 2 Mar 2022 18:38:17 +0100 Subject: [PATCH 2/3] continued handshaking tree, not finished --- dataflow_neuro/primitives.act | 195 ++++++++++++++++++---------------- 1 file changed, 105 insertions(+), 90 deletions(-) diff --git a/dataflow_neuro/primitives.act b/dataflow_neuro/primitives.act index 49497ee..833a450 100644 --- a/dataflow_neuro/primitives.act +++ b/dataflow_neuro/primitives.act @@ -509,103 +509,118 @@ namespace tmpl { // A tree composed by arbiters. The first layer takes N signals export template - defproc arbiter_tree(a1of1 in[N],a1of1 out; power supply) + defproc arbiter_tree(a1of1 in[N]; a1of1 out; power supply) { - bool tout; + bool tout; - { N > 0 : "What?" }; + { N > 0 : "Invalid N, should be greater than 0" }; - /* We calculate here how many elements we need to create the full tree */ - pint i, end, j; - i = 0; - end = N-1; - - pint lenTree2Count, lenTree3Count; - pint odd_one_idx = 0; - pbool odd_one_flag = 0; - lenTree2Count = 0; - *[ i != end -> - j = 0; - *[ i < end -> - j = j + 1; - [ i+1 >= end -> - i = end; - lenTree2Count = lenTree2Count +1; - - [] i >= end -> - i = end; - odd_one_idx = i; - odd_one_flag = 1; - [] else -> - i = i + 2; - lenTree2Count = lenTree2Count +1; - ] - ] - /*-- update range that has to be combined --*/ - i = end+1; - end = end+j+odd_one_flag; - ] - /* array that holds ALL the wires in the completion tree */ - a1of1 wire[end+1]; - // Connecting the first nodes to the input - (l:N: - wire[l] = in[l]; - ) - [lenTree2Count > 0 -> - arbiter_handshake arb_array[lenTree2Count]; - ] - (h:lenTree2Count:arb_array[h].vdd = supply.vdd;) - (h:lenTree2Count:arb_array[h].vss = supply.vss;) - - /* Reset the variables before the assigmnent of the nodes to the cells */ - i = 0; + /* We calculate here how many arbiters we need to create for the full tree */ + pint inputs_in_layer, end, elements_in_layer; + pint odd_element_idx = 0; + pint odd_element_flag = 0; + inputs_in_layer = 0; end = N-1; - j = 0; - pint tree2Index = 0; - pint tree3Index = 0; - *[ i != end -> - /* - * Invariant: tmp[i..end] has the current signals that need to be - * combined together, and "isinv" specifies if they are the inverted - * sense or not - */ - j = 0; - *[ i < end -> - /*-- there are still signals that need to be combined --*/ - j = j + 1; - [ i+1 >= end -> - /*-- last piece: use either a 2 input C-element --*/ - C2Els[tree2Index].a = wire[i]; - C2Els[tree2Index].b = wire[i+1]; - C2Els[tree2Index].y = wire[end+j]; - tree2Index = tree2Index +1; - i = end; - [] i+2 >= end -> - /*-- last piece: use either a 3 input C-element --*/ - C3Els[tree3Index].a = tmp[i]; - C3Els[tree3Index].b = tmp[i+1]; - C3Els[tree3Index].c = tmp[i+2]; - C3Els[tree3Index].y = tmp[end+j]; - - tree3Index = tree3Index +1; - i = end; + pint element_counter = 0; + // Here we start a for loop to count the elements in the tree + // The loop iterates for every successive layer + // i is the variable used to iterate the inputs, + // j counts the elements in the layer + *[ inputs_in_layer != end -> + elements_in_layer = 0; // At every layer the counter of the elements is resetted + *[ inputs_in_layer < end -> + [ inputs_in_layer + 1 >= end -> + //In this case, the number of input is even: the layer finishes + inputs_in_layer = end; + odd_element_flag = 0; + [] inputs_in_layer + 2 >= end -> + //In this case, we arrived at the last input, this means the inputs are odd + //We need to save the odd input index and move it to the next layer, + //up to when the resulting number is even + odd_element_idx = end; + odd_element_flag = 1; + inputs_in_layer = end; [] else -> - /*-- more to come; so use a two input C-element --*/ - C2Els[tree2Index].a = tmp[i]; - C2Els[tree2Index].b = tmp[i+1]; - C2Els[tree2Index].y = tmp[end+j]; - tree2Index = tree2Index +1; - i = i + 2; + //If we are not close to the end, analyzes the next two inputs + inputs_in_layer = inputs_in_layer +2; ] - ] - /*-- update range that has to be combined --*/ - i = end+1; - end = end+j; - j = 0; - ] - - out = tmp[end]; + elements_in_layer = elements_in_layer + 1; //At every step the elements count is updated + + ] + //Move the inputs_in_layer to the next layer + //Increase the end to account for the next layer elements + //If there was an odd element, count it also in the end + inputs_in_layer = end + 1; + end = end + elements_in_layer + odd_element_flag; + element_counter = element_counter + elements_in_layer; + ] + + { element_counter = 4 : "Michele you did wrong" }; + + // Creating the elements of the tree + arbiter_handshake arb_array[element_counter]; + (i:element_counter:arb_array[i].supply = supply;) + // These are the wires that connect one element of the tree to the others + a1of1 channels[element_counter*2]; + + //Connecting the first channels to the inputs + (i:N:channels[i] = in[i];) + channels[element_counter*2-1] = out; + //Now we redo the for loop but here to assign the channels to the elements + odd_element_idx = 0; + odd_element_flag = 0; + inputs_in_layer = 0; + end = N-1; + { end=4 : "Michele you did wrong" }; + // Here we start a for loop to count the elements in the tree + // The loop iterates for every successive layer + // i is the variable used to iterate the inputs, + // j counts the elements in the layer + *[ inputs_in_layer != end -> + elements_in_layer = 0; // At every layer the counter of the elements is resetted + *[ inputs_in_layer < end -> + [ inputs_in_layer + 1 >= end -> + //In this case, the number of input is even: the layer finishes + [ odd_element_flag >= 1 -> + arb_array[elements_in_layer].in1 = channels[inputs_in_layer]; + arb_array[elements_in_layer].in2 = channels[odd_element_idx]; + [] else -> + arb_array[elements_in_layer].in1 = channels[inputs_in_layer]; + arb_array[elements_in_layer].in2 = channels[inputs_in_layer+1]; + ] + inputs_in_layer = end; + odd_element_flag = 0; + [] inputs_in_layer + 2 >= end -> + //In this case, we arrived at the last input, this means the inputs are odd + //We need to save the odd input index and move it to the next layer, + //up to when the resulting number is even + odd_element_idx = end; + odd_element_flag = 1; + { end<8 : "Michele you did wrong" }; + { odd_element_idx=4 : "Michele you did wrong" }; + arb_array[elements_in_layer].in1 = channels[inputs_in_layer]; + arb_array[elements_in_layer].in2 = channels[inputs_in_layer+1]; + inputs_in_layer = end; + [] else -> + //If we are not close to the end, analyzes the next two inputs + arb_array[elements_in_layer].in1 = channels[inputs_in_layer]; + arb_array[elements_in_layer].in2 = channels[inputs_in_layer+1]; + inputs_in_layer = inputs_in_layer +2; + + ] + elements_in_layer = elements_in_layer + 1; //At every step the elements count is updated + + ] + //Move the inputs_in_layer to the next layer + //Increase the end to account for the next layer elements + //If there was an odd element, count it also in the end + inputs_in_layer = end + 1; + end = end + elements_in_layer + odd_element_flag; + element_counter = element_counter + elements_in_layer; + ] + + } export template From f5859040d81245fb6dbadcd41de128bf18f7bf06 Mon Sep 17 00:00:00 2001 From: Michele Date: Thu, 3 Mar 2022 12:00:49 +0100 Subject: [PATCH 3/3] Arbiter tree test --- .../unit_tests/arbiter_tree_test/run/test.prs | 3 + test/unit_tests/arbiter_tree_test/test.act | 62 ++++++++++++++++++ test/unit_tests/arbiter_tree_test/test.prsim | 64 +++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 test/unit_tests/arbiter_tree_test/run/test.prs create mode 100644 test/unit_tests/arbiter_tree_test/test.act create mode 100644 test/unit_tests/arbiter_tree_test/test.prsim diff --git a/test/unit_tests/arbiter_tree_test/run/test.prs b/test/unit_tests/arbiter_tree_test/run/test.prs new file mode 100644 index 0000000..02d06ef --- /dev/null +++ b/test/unit_tests/arbiter_tree_test/run/test.prs @@ -0,0 +1,3 @@ += "GND" "GND" += "Vdd" "Vdd" += "Reset" "Reset" diff --git a/test/unit_tests/arbiter_tree_test/test.act b/test/unit_tests/arbiter_tree_test/test.act new file mode 100644 index 0000000..249aa2d --- /dev/null +++ b/test/unit_tests/arbiter_tree_test/test.act @@ -0,0 +1,62 @@ +/************************************************************************* + * + * This file is part of ACT dataflow neuro library. + * It's the testing facility for cell_lib_std.act + * + * Copyright (c) 2022 University of Groningen - Ole Richter + * Copyright (c) 2022 University of Groningen - Hugh Greatorex + * Copyright (c) 2022 University of Groningen - Michele Mastella + * Copyright (c) 2022 University of Groningen - Madison Cotteret + * + * This source describes Open Hardware and is licensed under the CERN-OHL-W v2 or later + * + * You may redistribute and modify this documentation and make products + * using it under the terms of the CERN-OHL-W v2 (https:/cern.ch/cern-ohl). + * This documentation is distributed WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY + * AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN-OHL-W v2 + * for applicable conditions. + * + * Source location: https://git.web.rug.nl/bics/actlib_dataflow_neuro + * + * As per CERN-OHL-W v2 section 4.1, should You produce hardware based on + * these sources, You must maintain the Source Location visible in its + * documentation. + * + ************************************************************************** + */ + +import "../../dataflow_neuro/primitives.act"; +import globals; + +open tmpl::dataflow_neuro; + + +defproc arbiter_treee (a1of1 in[5]; a1of1 out) +{ + a1of1 _in[5]; + power _supply + _supply.vdd = Vdd; + _supply.vss = GND; + + fifo_t<2> fifo_to_tree[5]; + (i:5: + fifo_to_tree[i].in = in[i]; + fifo_to_tree[i].out = _in[i]; + fifo_to_tree.supply = _supply; + fifo_to_tree.reset_B = _reset_B; + ) + + arbiter_tree<5> at_cell(.in=_in, .out = out); + + //Low active Reset + bool _reset_B; + prs { + Reset => _reset_B- + } + + at_cell.supply = _supply; + +} + +arbiter_treee my_tree; diff --git a/test/unit_tests/arbiter_tree_test/test.prsim b/test/unit_tests/arbiter_tree_test/test.prsim new file mode 100644 index 0000000..65294dd --- /dev/null +++ b/test/unit_tests/arbiter_tree_test/test.prsim @@ -0,0 +1,64 @@ + +watchall +set Reset 1 +set my_tree.in[0].r 0 +set my_tree.in[1].r 0 +set my_tree.in[2].r 0 +set my_tree.in[3].r 0 +set my_tree.in[4].r 0 +set my_tree.out.a 0 + +cycle + +assert my_tree.in[0].a 0 +assert my_tree.in[1].a 0 +assert my_tree.in[2].a 0 +assert my_tree.in[3].a 0 +assert my_tree.in[4].a 0 +assert my_tree.out.r 0 + +system "echo '-------------------------------------------------'" +system "echo '[0] System initialized'" + +set Reset 0 +cycle +system "echo '-------------------------------------------------'" +system "echo '[1] System reset completed'" + +set in[0].r 1 +set in[2].r 1 +set in[4].r 1 + +cycle + +assert out.r 1 +set out.a 1 +cycle + +assert out.r 0 +set out.a 0 + +cycle + +assert out.r 1 +set out.a 1 +cycle + +assert out.r 0 +set out.a 0 + +cycle + +assert out.r 1 +set out.a 1 +cycle + +assert out.r 0 +set out.a 0 + +cycle + + +system "echo '-------------------------------------------------'" +system "echo '[3] Sent three inputs, received 3 outputs'" +