/************************************************************************* * * This file is part of ACT dataflow neuro library * * Copyright (c) 2022 University of Groningen - Ole Richter * Copyright (c) 2022 University of Groningen - Michele Mastella * Copyright (c) 2022 University of Groningen - Hugh Greatorex * 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/cell_lib_async.act"; import "../../dataflow_neuro/cell_lib_std.act"; import "../../dataflow_neuro/treegates.act"; import "../../dataflow_neuro/primitives.act"; import "../../dataflow_neuro/registers.act"; import "../../dataflow_neuro/coders.act"; import "../../dataflow_neuro/interfaces.act"; // import tmpl::dataflow_neuro; // import tmpl::dataflow_neuro; import std::channel; open std::channel; namespace tmpl { namespace dataflow_neuro { export template defproc chip_texel (bd in, out; Mx1of2 reg_data[REG_M]; a1of1 synapses[N_SYN_X * N_SYN_Y]; a1of1 neurons[N_NRN_X * N_NRN_Y]; bool! nrn_mon_x[N_NRN_MON_X], nrn_mon_y[N_NRN_MON_Y]; bool! syn_mon_x[N_SYN_MON_X], syn_mon_y[N_SYN_MON_Y]; bool? syn_mon_AMZI[N_SYN_X * N_MON_AMZO_PER_SYN], nrn_mon_AMZI[N_NRN_X * N_MON_AMZO_PER_NRN]; bool! syn_mon_AMZO[N_MON_AMZO_PER_SYN], nrn_mon_AMZO[N_MON_AMZO_PER_NRN]; bool! syn_flags_EFO[N_FLAGS_PER_SYN], nrn_flags_EFO[N_FLAGS_PER_NRN]; bool? bd_dly_cfg[N_BD_DLY_CFG], bd_dly_cfg2[N_BD_DLY_CFG2]; bool? loopback_en; power supply; bool? reset_B){ pint index = 0; // Just useful bd2qdi _bd2qdi(.in = in, .dly_cfg = bd_dly_cfg, .dly_cfg2 = bd_dly_cfg2, .reset_B = reset_B, .supply = supply); fifo fifo_in2fork(.in = _bd2qdi.out, .reset_B = reset_B, .supply = supply); fork _fork(.in = fifo_in2fork.out, .reset_B = reset_B, .supply = supply); // Loopback fifo fifo_fork2drop(.in = _fork.out1, .reset_B = reset_B, .supply = supply); dropper_static _loopback_dropper(.in = fifo_fork2drop.out, .cond = loopback_en, .supply = supply); // Onwards fifo fifo_fork2dmx(.in = _fork.out2, .reset_B = reset_B, .supply = supply); demux_bit_msb _demux(.in = fifo_fork2dmx.out, .reset_B = reset_B, .supply = supply); // Register fifo fifo_dmx2reg(.in = _demux.out2, .reset_B = reset_B, .supply = supply); register_wr_array register(.in = fifo_dmx2reg.out, .data = reg_data, .supply = supply, .reset_B = reset_B); fifo fifo_reg2mrg(.in = register.out, .reset_B = reset_B, .supply = supply); // Spike Decoder pint NC_SYN; NC_SYN = NC_SYN_X + NC_SYN_Y; slice_data slice_pre_dec(.in = _demux.out1, .supply = supply); fifo fifo_dmx2dec(.in = slice_pre_dec.out, .reset_B = reset_B, .supply = supply); decoder_2d_hybrid decoder(.in = fifo_dmx2dec.out, .out = synapses, .hs_en = register.data[0].d[0].t, // Defaults to handshake disable .supply = supply, .reset_B = reset_B); (i:N_SYN_DLY_CFG: decoder.dly_cfg[i] = register.data[0].d[1 + i].f;) // Defaults to max delay // Neurons + encoder pint NC_NRN; NC_NRN = NC_NRN_X + NC_NRN_Y; nrn_hs_2d_array nrn_grid(.in = neurons, .supply = supply, .reset_B = reset_B); encoder2d_simple encoder( .inx = nrn_grid.outx, .iny = nrn_grid.outy, .reset_B = reset_B, .supply = supply ); fifo fifo_enc2mrg(.in = encoder.out, .reset_B = reset_B, .supply = supply); // Merge append append_enc(.in = fifo_enc2mrg.out, .supply = supply); append append_reg(.in = fifo_reg2mrg.out, .supply = supply); merge merge_enc8reg(.in1 = append_enc.out, .in2 = append_reg.out, .supply = supply, .reset_B = reset_B); merge merge_loop8mrg(.in1 = merge_enc8reg.out, .in2 = _loopback_dropper.out, .reset_B = reset_B, .supply = supply); // qdi2bd fifo fifo_mrg2bd(.in = merge_loop8mrg.out, .reset_B = reset_B, .supply = supply); qdi2bd _qdi2bd(.in = fifo_mrg2bd.out, .out = out, .dly_cfg = bd_dly_cfg, .reset_B = reset_B, .supply = supply); // Neuron/synapse monitor targeters pint NC_NRN_MON_X = std::ceil_log2(N_NRN_MON_X); pint NC_NRN_MON_Y = std::ceil_log2(N_NRN_MON_Y); pint NC_SYN_MON_X = std::ceil_log2(N_SYN_MON_X); pint NC_SYN_MON_Y = std::ceil_log2(N_SYN_MON_Y); decoder_dualrail_en nrn_mon_dec_x(.supply = supply); nrn_mon_dec_x.en = register.data[1].d[0].t; (i:NC_NRN_MON_X: nrn_mon_dec_x.in.d[i] = register.data[2].d[i]; ) sigbuf_boolarray nrn_mon_x_buf(.in = nrn_mon_dec_x.out, .out = nrn_mon_x, .supply = supply); decoder_dualrail_en nrn_mon_dec_y(.supply = supply); nrn_mon_dec_y.en = register.data[1].d[0].t; (i:NC_NRN_MON_Y: nrn_mon_dec_y.in.d[i] = register.data[2].d[i+NC_NRN_MON_X]; ) sigbuf_boolarray nrn_mon_y_buf(.in = nrn_mon_dec_y.out, .out = nrn_mon_y, .supply = supply); decoder_dualrail_en syn_mon_dec_x( .supply = supply); syn_mon_dec_x.en = register.data[1].d[1].t; (i:NC_SYN_MON_X: syn_mon_dec_x.in.d[i] = register.data[3].d[i]; ) sigbuf_boolarray syn_mon_x_buf(.out = syn_mon_x, .supply = supply); decoder_dualrail_en syn_mon_dec_y(.supply = supply); syn_mon_dec_y.en = register.data[1].d[1].t; (i:NC_SYN_MON_Y: syn_mon_dec_y.in.d[i] = register.data[3].d[i+NC_SYN_MON_X]; ) sigbuf_boolarray syn_mon_y_buf(.out = syn_mon_y, .in = syn_mon_dec_y.out, .supply = supply); // Device debug hard-wired safety (reg0, b05 = DEV_DEBUG) // Stops the possibility of dev_mon being high while some other sig is high. // Otherwise boom. bool DEV_DEBUG; pint NSMX4 = N_SYN_MON_X/4; // Self explanatory sigbuf sb_DEV_DEBUG(.in = register.data[0].d[5].t, .supply = supply); DEV_DEBUG = sb_DEV_DEBUG.out[0]; [NSMX4 >= 1 -> AND2_X1 ands_devmon[NSMX4]; (i:NSMX4: ands_devmon[i].a = syn_mon_dec_x.out[1+i*4]; ands_devmon[i].b = DEV_DEBUG; ands_devmon[i].y = syn_mon_x_buf.in[1+i*4]; ands_devmon[i].vdd = supply.vdd; ands_devmon[i].vss = supply.vss; ) // Wire up the non-ANDed lines. (i:N_SYN_MON_X: [~(i%4 = 1) -> syn_mon_x_buf.in[i] = syn_mon_dec_x.out[i]; ] ) ] // Create TBUFs for each synapse column, // ctrl wired to mon line (first in each 4). TBUF_X4 syn_x_AMZI_tbuf[N_SYN_X * N_MON_AMZO_PER_SYN]; sigbuf_boolarray syn_mon_AMZO_sb(.out = syn_mon_AMZO, .supply = supply); (j:N_MON_AMZO_PER_SYN: (i:N_SYN_X: index = i*N_MON_AMZO_PER_SYN + j; syn_x_AMZI_tbuf[index].a = syn_mon_AMZI[index]; syn_x_AMZI_tbuf[index].en = syn_mon_x[i*4]; syn_x_AMZI_tbuf[index].y = syn_mon_AMZO_sb.in[j]; ) ) // Create TBUFs for each neuron column, // ctrl wired to mon line (first in each 4). TBUF_X4 nrn_x_AMZI_tbuf[N_NRN_X * N_MON_AMZO_PER_NRN]; sigbuf_boolarray nrn_mon_AMZO_sb(.out = nrn_mon_AMZO, .supply = supply); (j:N_MON_AMZO_PER_NRN: (i:N_NRN_X: index = i*N_MON_AMZO_PER_NRN + j; nrn_x_AMZI_tbuf[index].a = nrn_mon_AMZI[index]; nrn_x_AMZI_tbuf[index].en = nrn_mon_x[i*2]; nrn_x_AMZI_tbuf[index].y = nrn_mon_AMZO_sb.in[j]; ) ) // Create NON buffered signals from register to nrns. (i:N_FLAGS_PER_NRN: nrn_flags_EFO[i] = register.data[5].d[i].t; ) // Create NON buffered signals from register to synapses. // Includes safety on the first 3 flags with dev mon. (i:3..N_FLAGS_PER_SYN-1: syn_flags_EFO[i] = register.data[4].d[i].t; ) AND2_X1 syn_flags_dev_safety[3]; BUF_X4 syn_flags_dev_safety_sb[3]; (i:0..2: syn_flags_dev_safety[i].a = register.data[4].d[i].t; // syn flag bit syn_flags_dev_safety[i].b = register.data[0].d[5].f; // no device is being monitored. syn_flags_dev_safety_sb[i].a = syn_flags_dev_safety[i].y; syn_flags_dev_safety_sb[i].y = syn_flags_EFO[i]; syn_flags_dev_safety[i].vdd = supply.vdd; syn_flags_dev_safety[i].vss = supply.vss; syn_flags_dev_safety_sb[i].vdd = supply.vdd; syn_flags_dev_safety_sb[i].vss = supply.vss; ) } } }