diff --git a/pynn_spinnaker/spinnaker/runtime/common/arm_intrinsics.h b/pynn_spinnaker/spinnaker/runtime/common/arm_intrinsics.h index d11161c..0ad1fad 100644 --- a/pynn_spinnaker/spinnaker/runtime/common/arm_intrinsics.h +++ b/pynn_spinnaker/spinnaker/runtime/common/arm_intrinsics.h @@ -48,7 +48,7 @@ inline int64_t __smlal(int64_t acc, int32_t x, int32_t y) //! \param[in] y second argument. //! \return signed result. -static inline int32_t __smulbb (int32_t x, int32_t y) +inline int32_t __smulbb (int32_t x, int32_t y) { register int32_t r; @@ -63,7 +63,7 @@ static inline int32_t __smulbb (int32_t x, int32_t y) //! \param[in] y second argument. //! \return signed result. -static inline int32_t __smulbt (int32_t x, int32_t y) +inline int32_t __smulbt (int32_t x, int32_t y) { register int32_t r; @@ -78,7 +78,7 @@ static inline int32_t __smulbt (int32_t x, int32_t y) //! \param[in] y second argument. //! \return signed result. -static inline int32_t __smultb (int32_t x, int32_t y) +inline int32_t __smultb (int32_t x, int32_t y) { register int32_t r; @@ -93,7 +93,7 @@ static inline int32_t __smultb (int32_t x, int32_t y) //! \param[in] y second argument. //! \return signed result. -static inline int32_t __smultt (int32_t x, int32_t y) +inline int32_t __smultt (int32_t x, int32_t y) { register int32_t r; @@ -110,7 +110,7 @@ static inline int32_t __smultt (int32_t x, int32_t y) //! \param[in] y second argument. //! \return signed result. -static inline int32_t __smulwb (int32_t x, int32_t y) +inline int32_t __smulwb (int32_t x, int32_t y) { register int32_t r; @@ -127,7 +127,7 @@ static inline int32_t __smulwb (int32_t x, int32_t y) //! \param[in] y second argument. //! \return signed result. -static inline int32_t __smulwt (int32_t x, int32_t y) +inline int32_t __smulwt (int32_t x, int32_t y) { register int32_t r; @@ -150,7 +150,7 @@ static inline int32_t __smulwt (int32_t x, int32_t y) //! \param[in] acc accumulation argument. //! \return x*y+acc. -static inline int32_t __smlabb (int32_t x, int32_t y, int32_t acc) +inline int32_t __smlabb (int32_t x, int32_t y, int32_t acc) { register int32_t r; @@ -171,7 +171,7 @@ static inline int32_t __smlabb (int32_t x, int32_t y, int32_t acc) //! \param[in] acc accumulation argument. //! \return x*y+acc. -static inline int32_t __smlabt (int32_t x, int32_t y, int32_t acc) +inline int32_t __smlabt (int32_t x, int32_t y, int32_t acc) { register int32_t r; @@ -191,7 +191,7 @@ static inline int32_t __smlabt (int32_t x, int32_t y, int32_t acc) //! \param[in] acc accumulation argument. //! \return x*y+acc. -static inline int32_t __smlatb (int32_t x, int32_t y, int32_t acc) +inline int32_t __smlatb (int32_t x, int32_t y, int32_t acc) { register int32_t r; @@ -211,7 +211,7 @@ static inline int32_t __smlatb (int32_t x, int32_t y, int32_t acc) //! \param[in] acc accumulation argument. //! \return x*y+acc. -static inline int32_t __smlatt (int32_t x, int32_t y, int32_t acc) +inline int32_t __smlatt (int32_t x, int32_t y, int32_t acc) { register int32_t r; @@ -233,7 +233,7 @@ static inline int32_t __smlatt (int32_t x, int32_t y, int32_t acc) //! \param[in] acc accumulation argument. //! \return x*y+acc. -static inline int32_t __smlawb (int32_t x, int32_t y, int32_t acc) +inline int32_t __smlawb (int32_t x, int32_t y, int32_t acc) { register int32_t r; @@ -254,7 +254,7 @@ static inline int32_t __smlawb (int32_t x, int32_t y, int32_t acc) //! \param[in] acc accumulation argument. //! \return x*y+acc. -static inline int32_t __smlawt (int32_t x, int32_t y, int32_t acc) +inline int32_t __smlawt (int32_t x, int32_t y, int32_t acc) { register int32_t r; diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/Makefile b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/Makefile index 25669c2..1b1b3e1 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/Makefile +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/Makefile @@ -5,7 +5,9 @@ SOURCES = ../../../common/config.cpp \ ../../../common/bit_field.cpp \ ../../../common/profiler.cpp \ ../../neuron_processor.cpp \ - ../../neuron_models/if_cond.cpp \ + ../../neuron_dynamics_models/if.cpp \ + ../../neuron_input_models/cond.cpp \ + ../../neuron_threshold_models/constant.cpp \ ../../synapse_models/exp.cpp CFLAGS += -I $(CURDIR) diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/config.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/config.h index 03683d5..7795b9a 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/config.h +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_cond_exp/config.h @@ -3,7 +3,11 @@ // Model includes #include "../../input_buffer.h" #include "../../intrinsic_plasticity_models/stub.h" -#include "../../neuron_models/if_cond.h" +#include "../../modular_neuron.h" +#include "../../neuron_dynamics_models/if.h" +#include "../../neuron_input_models/cond.h" +#include "../../neuron_threshold_models/constant.h" +#include "../../neuron_extra_input_models/stub.h" #include "../../synapse_models/exp.h" namespace NeuronProcessor @@ -11,7 +15,9 @@ namespace NeuronProcessor //----------------------------------------------------------------------------- // Typedefines //----------------------------------------------------------------------------- -typedef NeuronModels::IFCond Neuron; +typedef ModularNeuron Neuron; typedef SynapseModels::Exp Synapse; typedef IntrinsicPlasticityModels::Stub IntrinsicPlasticity; diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/Makefile b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/Makefile index 64d9420..15f3eb2 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/Makefile +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/Makefile @@ -5,7 +5,9 @@ SOURCES = ../../../common/config.cpp \ ../../../common/bit_field.cpp \ ../../../common/profiler.cpp \ ../../neuron_processor.cpp \ - ../../neuron_models/if_curr.cpp \ + ../../neuron_dynamics_models/if.cpp \ + ../../neuron_input_models/curr.cpp \ + ../../neuron_threshold_models/constant.cpp \ ../../synapse_models/exp.cpp CFLAGS += -I $(CURDIR) diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/config.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/config.h index d1036bd..16d2c55 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/config.h +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/build/if_curr_exp/config.h @@ -3,7 +3,11 @@ // Model includes #include "../../input_buffer.h" #include "../../intrinsic_plasticity_models/stub.h" -#include "../../neuron_models/if_curr.h" +#include "../../modular_neuron.h" +#include "../../neuron_dynamics_models/if.h" +#include "../../neuron_input_models/curr.h" +#include "../../neuron_threshold_models/constant.h" +#include "../../neuron_extra_input_models/stub.h" #include "../../synapse_models/exp.h" namespace NeuronProcessor @@ -11,7 +15,9 @@ namespace NeuronProcessor //----------------------------------------------------------------------------- // Typedefines //----------------------------------------------------------------------------- -typedef NeuronModels::IFCurr Neuron; +typedef ModularNeuron Neuron; typedef SynapseModels::Exp Synapse; typedef IntrinsicPlasticityModels::Stub IntrinsicPlasticity; diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/modular_neuron.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/modular_neuron.h new file mode 100644 index 0000000..6f31b1b --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/modular_neuron.h @@ -0,0 +1,130 @@ +#pragma once + +// Common includes +#include "../common/fixed_point_number.h" +#include "../common/log.h" + +// Namespaces +using namespace Common::FixedPointNumber; + +//----------------------------------------------------------------------------- +// NeuronProcessor::ModularNeuron +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +template +class ModularNeuron +{ +public: + //----------------------------------------------------------------------------- + // Constants + //----------------------------------------------------------------------------- + enum RecordingChannel + { + RecordingChannelInputMax = (Dynamics::RecordingChannelMax + Input::RecordingChannelMax), + RecordingChannelThresholdMax = (RecordingChannelInputMax + Threshold::RecordingChannelMax), + RecordingChannelMax = (RecordingChannelThresholdMax + ExtraInput::RecordingChannelMax), + }; + + //----------------------------------------------------------------------------- + // MutableState + //----------------------------------------------------------------------------- + struct MutableState : Dynamics::MutableState, Input::MutableState, + Threshold::MutableState, ExtraInput::MutableState + { + }; + + //----------------------------------------------------------------------------- + // ImmutableState + //----------------------------------------------------------------------------- + struct ImmutableState : Dynamics::ImmutableState, Input::ImmutableState, + Threshold::ImmutableState, ExtraInput::ImmutableState + { + }; + + //----------------------------------------------------------------------------- + // Static methods + //----------------------------------------------------------------------------- + static bool Update(MutableState &mutableState, const ImmutableState &immutableState, + S1615 excInput, S1615 inhInput, S1615 extCurrent) + { + // Get membrane voltage from dynamics + const S1615 membraneVoltage = Dynamics::GetMembraneVoltage(mutableState, immutableState); + + // Convert the excitatory and inhibitory inputs into a suitable input current + const S1615 synapticInputCurrent = Input::GetInputCurrent(mutableState, immutableState, + excInput, inhInput, membraneVoltage); + + // Get any extra input current + const S1615 extraInputCurrent = ExtraInput::GetInputCurrent(mutableState, immutableState, + membraneVoltage); + + // Add together all sources of input current + const S1615 totalInputCurrent = synapticInputCurrent + extraInputCurrent + extCurrent; + + // Update membrane dynamics to get new membrane voltage + const S1615 newMembraneVoltage = Dynamics::Update(mutableState, immutableState, + totalInputCurrent); + + // Has this new membrane voltage crossed the threshold? + const bool spike = Threshold::HasCrossed(mutableState, immutableState, + newMembraneVoltage); + + // If a spike occurs, notify dynamics and extra input + if(spike) + { + Dynamics::SetSpiked(mutableState, immutableState); + ExtraInput::SetSpiked(mutableState, immutableState); + } + + return spike; + + } + + static S1615 GetRecordable(unsigned int c, + const MutableState &mutableState, const ImmutableState &immutableState, + S1615 excInput, S1615 inhInput) + { + // If recording channel comes from neuron dynamics + if(c < Dynamics::RecordingChannelMax) + { + return Dynamics::GetRecordable((typename Dynamics::RecordingChannel)c, + mutableState, immutableState); + } + // Otherwise, if recording channel comes from neuron input + else if(c < RecordingChannelInputMax) + { + return Input::GetRecordable((typename Input::RecordingChannel)(c - Dynamics::RecordingChannelMax), + mutableState, immutableState, + excInput, inhInput); + } + // Otherwise, if recording channel comes from spiking threshold + else if(c < RecordingChannelThresholdMax) + { + return Threshold::GetRecordable((typename Threshold::RecordingChannel)(c - RecordingChannelInputMax), + mutableState, immutableState); + } + // Otherwise, if recording channel comes from extra input + else if(c < RecordingChannelMax) + { + return ExtraInput::GetRecordable((typename ExtraInput::RecordingChannel)(c - RecordingChannelThresholdMax), + mutableState, immutableState); + } + // Otherwise + else + { + LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant recording channel %u", c); + return 0; + } + } + + static void Print(char *stream, const MutableState &mutableState, const ImmutableState &immutableState) + { + // Print from all modules of neuron + Dynamics::Print(stream, mutableState, immutableState); + Input::Print(stream, mutableState, immutableState); + Threshold::Print(stream, mutableState, immutableState); + ExtraInput::Print(stream, mutableState, immutableState); + } +}; +} // NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_curr.cpp b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_dynamics_models/if.cpp similarity index 79% rename from pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_curr.cpp rename to pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_dynamics_models/if.cpp index b53d883..5252fef 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_curr.cpp +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_dynamics_models/if.cpp @@ -1,22 +1,23 @@ -#include "if_curr.h" +#include "if.h" +// Common includes #include "../../common/spinnaker.h" //----------------------------------------------------------------------------- -// NeuronProcessor::NeuronModels::IFCurr +// NeuronProcessor::NeuronDynamicsModels::IF //----------------------------------------------------------------------------- namespace NeuronProcessor { -namespace NeuronModels +namespace NeuronDynamicsModels { -void IFCurr::Print(char *stream, const MutableState &mutableState, const ImmutableState &immutableState) +void IF::Print(char *stream, const MutableState &mutableState, const ImmutableState &immutableState) { + io_printf(stream, "Integrate-and-fire dynamics\n"); io_printf(stream, "\tMutable state:\n"); io_printf(stream, "\t\tV_Membrane = %11.4k [mV]\n", mutableState.m_V_Membrane); io_printf(stream, "\t\tRefractoryTimer = %10d [timesteps]\n", mutableState.m_RefractoryTimer); io_printf(stream, "\tImmutable state:\n"); - io_printf(stream, "\t\tV_Threshold = %11.4k [mV]\n", immutableState.m_V_Threshold); io_printf(stream, "\t\tV_Reset = %11.4k [mV]\n", immutableState.m_V_Reset); io_printf(stream, "\t\tV_Rest = %11.4k [mV]\n", immutableState.m_V_Rest); io_printf(stream, "\t\tI_Offset = %11.4k [nA]\n", immutableState.m_I_Offset); diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_curr.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_dynamics_models/if.h similarity index 78% rename from pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_curr.h rename to pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_dynamics_models/if.h index 239cf33..28720e8 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_curr.h +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_dynamics_models/if.h @@ -8,16 +8,16 @@ using namespace Common::FixedPointNumber; //----------------------------------------------------------------------------- -// NeuronModels +// NeuronDynamicsModels //----------------------------------------------------------------------------- namespace NeuronProcessor { -namespace NeuronModels +namespace NeuronDynamicsModels { //----------------------------------------------------------------------------- -// IFCurr +// IF //----------------------------------------------------------------------------- -class IFCurr +class IF { public: //----------------------------------------------------------------------------- @@ -46,9 +46,6 @@ class IFCurr //----------------------------------------------------------------------------- struct ImmutableState { - // Membrane voltage threshold at which neuron spikes [mV] - S1615 m_V_Threshold; - // Post-spike reset membrane voltage [mV] S1615 m_V_Reset; @@ -73,15 +70,14 @@ class IFCurr //----------------------------------------------------------------------------- // Static methods //----------------------------------------------------------------------------- - static inline bool Update(MutableState &mutableState, const ImmutableState &immutableState, - S1615 excInput, S1615 inhInput, S1615 extCurrent) + static S1615 Update(MutableState &mutableState, const ImmutableState &immutableState, + S1615 inputCurrent) { // If outside of the refractory period if (mutableState.m_RefractoryTimer <= 0) { // Get the input in nA - S1615 inputThisTimestep = excInput - inhInput - + extCurrent + immutableState.m_I_Offset; + S1615 inputThisTimestep = inputCurrent + immutableState.m_I_Offset; LOG_PRINT(LOG_LEVEL_TRACE, "\t\tInput this timestep:%.4knA", inputThisTimestep); @@ -95,18 +91,6 @@ class IFCurr alpha - mutableState.m_V_Membrane); LOG_PRINT(LOG_LEVEL_TRACE, "\t\tMembrane voltage:%.4knA", mutableState.m_V_Membrane); - - // Neuron spikes if membrane voltage has crossed threshold - if (mutableState.m_V_Membrane >= immutableState.m_V_Threshold) - { - // Reset membrane voltage - mutableState.m_V_Membrane = immutableState.m_V_Reset; - - // Reset refractory timer - mutableState.m_RefractoryTimer = immutableState.m_T_Refractory; - - return true; - } } // Otherwise, count down refractory timer else @@ -114,12 +98,26 @@ class IFCurr mutableState.m_RefractoryTimer--; } - return false; + // Return membrane voltage + return mutableState.m_V_Membrane; + } + + static void SetSpiked(MutableState &mutableState, const ImmutableState &immutableState) + { + // Reset membrane voltage + mutableState.m_V_Membrane = immutableState.m_V_Reset; + + // Reset refractory timer + mutableState.m_RefractoryTimer = immutableState.m_T_Refractory; + } + + static S1615 GetMembraneVoltage(const MutableState &mutableState, const ImmutableState &) + { + return mutableState.m_V_Membrane; } static S1615 GetRecordable(RecordingChannel c, - const MutableState &mutableState, const ImmutableState &, - S1615, S1615, S1615) + const MutableState &mutableState, const ImmutableState &) { switch(c) { @@ -127,12 +125,12 @@ class IFCurr return mutableState.m_V_Membrane; default: - LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant recording channel %u", c); + LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant dynamics recording channel %u", c); return 0; } } static void Print(char *stream, const MutableState &mutableState, const ImmutableState &immutableState); }; -}; // namespace NeuronModels +}; // namespace NeuronDynamicsModels }; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_extra_input_models/stub.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_extra_input_models/stub.h new file mode 100644 index 0000000..1c13b5d --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_extra_input_models/stub.h @@ -0,0 +1,67 @@ +#pragma once + +// Common includes +#include "../../common/fixed_point_number.h" +#include "../../common/log.h" + +// Namespaces +using namespace Common::FixedPointNumber; + +//----------------------------------------------------------------------------- +// NeuronProcessor::NeuronExtraInputModels::Stub +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +namespace NeuronExtraInputModels +{ +class Stub +{ +public: + //----------------------------------------------------------------------------- + // Constants + //----------------------------------------------------------------------------- + enum RecordingChannel + { + RecordingChannelMax, + }; + + //----------------------------------------------------------------------------- + // MutableState + //----------------------------------------------------------------------------- + struct MutableState + { + }; + + //----------------------------------------------------------------------------- + // ImmutableState + //----------------------------------------------------------------------------- + struct ImmutableState + { + }; + + //----------------------------------------------------------------------------- + // Static methods + //----------------------------------------------------------------------------- + static S1615 GetInputCurrent(MutableState &, const ImmutableState &, + S1615) + { + return 0; + } + + static void SetSpiked(MutableState &, const ImmutableState &) + { + } + + static S1615 GetRecordable(RecordingChannel c, + const MutableState &, const ImmutableState &) + { + LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant extra input recording channel %u", c); + return 0; + } + + static void Print(char *, const MutableState &, const ImmutableState &) + { + } +}; +} // NeuronExtraInputModels +} // NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/cond.cpp b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/cond.cpp new file mode 100644 index 0000000..825901d --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/cond.cpp @@ -0,0 +1,21 @@ +#include "cond.h" + +// Common includes +#include "../../common/spinnaker.h" + +//----------------------------------------------------------------------------- +// NeuronProcessor::NeuronInputModels::Curr +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +namespace NeuronInputModels +{ +void Cond::Print(char *stream, const MutableState &, const ImmutableState &immutableState) +{ + io_printf(stream, "Conductance input\n"); + io_printf(stream, "\tImmutable state:\n"); + io_printf(stream, "\t\tV_RevExc = %11.4k [mV]\n", immutableState.m_V_RevExc); + io_printf(stream, "\t\tV_RevInh = %11.4k [mV]\n", immutableState.m_V_RevInh); +} +}; // namespace NeuronInputModels +}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/cond.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/cond.h new file mode 100644 index 0000000..2b9b490 --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/cond.h @@ -0,0 +1,81 @@ +#pragma once + +// Common includes +#include "../../common/fixed_point_number.h" +#include "../../common/log.h" + +// Namespaces +using namespace Common::FixedPointNumber; + +//----------------------------------------------------------------------------- +// NeuronProcessor::NeuronInputModels::Cond +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +namespace NeuronInputModels +{ +class Cond +{ +public: + //----------------------------------------------------------------------------- + // Constants + //----------------------------------------------------------------------------- + enum RecordingChannel + { + RecordingChannelGSynExc, + RecordingChannelGSynInh, + RecordingChannelMax, + }; + + //----------------------------------------------------------------------------- + // MutableState + //----------------------------------------------------------------------------- + struct MutableState + { + }; + + //----------------------------------------------------------------------------- + // ImmutableState + //----------------------------------------------------------------------------- + struct ImmutableState + { + // Excitatory reversal voltage [mV] + S1615 m_V_RevExc; + + // Inhibitory reversal voltage [mV] + S1615 m_V_RevInh; + }; + + //----------------------------------------------------------------------------- + // Static methods + //----------------------------------------------------------------------------- + static S1615 GetInputCurrent(MutableState &, const ImmutableState &immutableState, + S1615 excInput, S1615 inhInput, + S1615 membraneVoltage) + { + return MulS1615(excInput, immutableState.m_V_RevExc - membraneVoltage) + + MulS1615(inhInput, immutableState.m_V_RevInh - membraneVoltage); + } + + static S1615 GetRecordable(RecordingChannel c, + const MutableState &, const ImmutableState &, + S1615 excInput, S1615 inhInput) + { + switch(c) + { + case RecordingChannelGSynExc: + return excInput; + + case RecordingChannelGSynInh: + return inhInput; + + default: + LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant input recording channel %u", c); + return 0; + } + } + + static void Print(char *stream, const MutableState &, const ImmutableState &); +}; +}; // namespace NeuronInputModels +}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/curr.cpp b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/curr.cpp new file mode 100644 index 0000000..42adb6b --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/curr.cpp @@ -0,0 +1,18 @@ +#include "curr.h" + +// Common includes +#include "../../common/spinnaker.h" + +//----------------------------------------------------------------------------- +// NeuronProcessor::NeuronInputModels::Curr +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +namespace NeuronInputModels +{ +void Curr::Print(char *stream, const MutableState &, const ImmutableState &) +{ + io_printf(stream, "Current input\n"); +} +}; // namespace NeuronInputModels +}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/curr.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/curr.h new file mode 100644 index 0000000..a0cfa74 --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_input_models/curr.h @@ -0,0 +1,63 @@ +#pragma once + +// Common includes +#include "../../common/fixed_point_number.h" +#include "../../common/log.h" + +// Namespaces +using namespace Common::FixedPointNumber; + +//----------------------------------------------------------------------------- +// NeuronProcessor::NeuronInputModels::Curr +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +namespace NeuronInputModels +{ +class Curr +{ +public: + //----------------------------------------------------------------------------- + // Constants + //----------------------------------------------------------------------------- + enum RecordingChannel + { + RecordingChannelMax, + }; + + //----------------------------------------------------------------------------- + // MutableState + //----------------------------------------------------------------------------- + struct MutableState + { + }; + + //----------------------------------------------------------------------------- + // ImmutableState + //----------------------------------------------------------------------------- + struct ImmutableState + { + }; + + //----------------------------------------------------------------------------- + // Static methods + //----------------------------------------------------------------------------- + static S1615 GetInputCurrent(MutableState &, const ImmutableState &, + S1615 excInput, S1615 inhInput, + S1615) + { + return (excInput - inhInput); + } + + static S1615 GetRecordable(RecordingChannel c, + const MutableState &, const ImmutableState &, + S1615, S1615) + { + LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant input recording channel %u", c); + return 0; + } + + static void Print(char *stream, const MutableState &, const ImmutableState &); +}; +}; // namespace NeuronInputModels +}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_cond.cpp b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_cond.cpp deleted file mode 100644 index d8c216f..0000000 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_cond.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "if_cond.h" - -#include "../../common/spinnaker.h" - -//----------------------------------------------------------------------------- -// NeuronProcessor::NeuronModels::IFCond -//----------------------------------------------------------------------------- -namespace NeuronProcessor -{ -namespace NeuronModels -{ -void IFCond::Print(char *stream, const MutableState &mutableState, const ImmutableState &immutableState) -{ - io_printf(stream, "\tMutable state:\n"); - io_printf(stream, "\t\tV_Membrane = %11.4k [mV]\n", mutableState.m_V_Membrane); - io_printf(stream, "\t\tRefractoryTimer = %10d [timesteps]\n", mutableState.m_RefractoryTimer); - - io_printf(stream, "\tImmutable state:\n"); - io_printf(stream, "\t\tV_Threshold = %11.4k [mV]\n", immutableState.m_V_Threshold); - io_printf(stream, "\t\tV_Reset = %11.4k [mV]\n", immutableState.m_V_Reset); - io_printf(stream, "\t\tV_Rest = %11.4k [mV]\n", immutableState.m_V_Rest); - io_printf(stream, "\t\tV_RevExc = %11.4k [mV]\n", immutableState.m_V_RevExc); - io_printf(stream, "\t\tV_RevInh = %11.4k [mV]\n", immutableState.m_V_RevInh); - io_printf(stream, "\t\tI_Offset = %11.4k [nA]\n", immutableState.m_I_Offset); - io_printf(stream, "\t\tR_Membrane = %11.4k [MegaOhm]\n", immutableState.m_R_Membrane); - io_printf(stream, "\t\tExpTC = %11.4k\n", immutableState.m_ExpTC); - io_printf(stream, "\t\tT_Refractory = %10d [timesteps]\n", immutableState.m_T_Refractory); -} -}; // namespace NeuronModels -}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_cond.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_cond.h deleted file mode 100644 index 8e3cf01..0000000 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_models/if_cond.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -// Common includes -#include "../../common/fixed_point_number.h" -#include "../../common/log.h" - -// Namespaces -using namespace Common::FixedPointNumber; - -//----------------------------------------------------------------------------- -// NeuronModels -//----------------------------------------------------------------------------- -namespace NeuronProcessor -{ -namespace NeuronModels -{ -//----------------------------------------------------------------------------- -// IFCond -//----------------------------------------------------------------------------- -class IFCond -{ -public: - //----------------------------------------------------------------------------- - // Constants - //----------------------------------------------------------------------------- - enum RecordingChannel - { - RecordingChannelV, - RecordingChannelGSynExc, - RecordingChannelGSynInh, - RecordingChannelMax, - }; - - //----------------------------------------------------------------------------- - // MutableState - //----------------------------------------------------------------------------- - struct MutableState - { - // Membrane voltage [mV] - S1615 m_V_Membrane; - - // Countdown to end of next refractory period [machine timesteps] - int32_t m_RefractoryTimer; - }; - - //----------------------------------------------------------------------------- - // ImmutableState - //----------------------------------------------------------------------------- - struct ImmutableState - { - // Membrane voltage threshold at which neuron spikes [mV] - S1615 m_V_Threshold; - - // Post-spike reset membrane voltage [mV] - S1615 m_V_Reset; - - // Membrane resting voltage [mV] - S1615 m_V_Rest; - - // Excitatory reversal voltage [mV] - S1615 m_V_RevExc; - - // Inhibitory reversal voltage [mV] - S1615 m_V_RevInh; - - // Offset current [nA] but take care because actually 'per timestep charge' - S1615 m_I_Offset; - - // Membrane resistance [MegaOhm] - S1615 m_R_Membrane; - - // 'Fixed' computation parameter - time constant multiplier for - // Closed-form solution - // exp( -(machine time step in ms)/(R * C) ) [.] - S1615 m_ExpTC; - - // Refractory time of neuron [machine timesteps] - int32_t m_T_Refractory; - }; - - //----------------------------------------------------------------------------- - // Static methods - //----------------------------------------------------------------------------- - static inline bool Update(MutableState &mutableState, const ImmutableState &immutableState, - S1615 excInput, S1615 inhInput, S1615 extCurrent) - { - // If outside of the refractory period - if (mutableState.m_RefractoryTimer <= 0) - { - // Get the input in nA - S1615 inputThisTimestep = MulS1615(excInput, immutableState.m_V_RevExc - mutableState.m_V_Membrane) + - MulS1615(inhInput, immutableState.m_V_RevInh - mutableState.m_V_Membrane) + - extCurrent + immutableState.m_I_Offset; - - LOG_PRINT(LOG_LEVEL_TRACE, "\t\tInput this timestep:%.4knA", inputThisTimestep); - - // Convert input from current to voltage - S1615 alpha = MulS1615(inputThisTimestep, immutableState.m_R_Membrane) + immutableState.m_V_Rest; - - LOG_PRINT(LOG_LEVEL_TRACE, "\t\tAlpha:%.4kmV", alpha); - - // Perform closed form update - mutableState.m_V_Membrane = alpha - MulS1615(immutableState.m_ExpTC, - alpha - mutableState.m_V_Membrane); - - LOG_PRINT(LOG_LEVEL_TRACE, "\t\tMembrane voltage:%.4knA", mutableState.m_V_Membrane); - - // Neuron spikes if membrane voltage has crossed threshold - if (mutableState.m_V_Membrane >= immutableState.m_V_Threshold) - { - // Reset membrane voltage - mutableState.m_V_Membrane = immutableState.m_V_Reset; - - // Reset refractory timer - mutableState.m_RefractoryTimer = immutableState.m_T_Refractory; - - return true; - } - } - // Otherwise, count down refractory timer - else - { - mutableState.m_RefractoryTimer--; - } - - return false; - } - - static S1615 GetRecordable(RecordingChannel c, - const MutableState &mutableState, const ImmutableState &, - S1615 excInput, S1615 inhInput, S1615) - { - switch(c) - { - case RecordingChannelV: - return mutableState.m_V_Membrane; - - case RecordingChannelGSynExc: - return excInput; - - case RecordingChannelGSynInh: - return inhInput; - - default: - LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant recording channel %u", c); - return 0; - } - } - - static void Print(char *stream, const MutableState &mutableState, const ImmutableState &immutableState); -}; -}; // namespace NeuronModels -}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_processor.cpp b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_processor.cpp index b68b32e..a211486 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_processor.cpp +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_processor.cpp @@ -338,9 +338,7 @@ void UpdateNeurons() { // Record the value from each one g_AnalogueRecording[r].RecordValue(n, - Neuron::GetRecordable((Neuron::RecordingChannel)r, - neuronMutable, neuronImmutable, - excInput, inhInput, extCurrent) + Neuron::GetRecordable(r, neuronMutable, neuronImmutable, excInput, inhInput) ); } diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_threshold_models/constant.cpp b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_threshold_models/constant.cpp new file mode 100644 index 0000000..4bfd8b0 --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_threshold_models/constant.cpp @@ -0,0 +1,20 @@ +#include "constant.h" + +// Common includes +#include "../../common/spinnaker.h" + +//----------------------------------------------------------------------------- +// NeuronProcessor::NeuronThresholdModels::Curr +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +namespace NeuronThresholdModels +{ +void Constant::Print(char *stream, const MutableState &, const ImmutableState &immutableState) +{ + io_printf(stream, "Constant threshold\n"); + io_printf(stream, "\tImmutable state:\n"); + io_printf(stream, "\t\tV_Threshold = %11.4k [mV]\n", immutableState.m_V_Threshold); +} +}; // namespace NeuronThresholdModels +}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_threshold_models/constant.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_threshold_models/constant.h new file mode 100644 index 0000000..0a8b518 --- /dev/null +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/neuron_threshold_models/constant.h @@ -0,0 +1,63 @@ +#pragma once + +// Common includes +#include "../../common/fixed_point_number.h" +#include "../../common/log.h" + +// Namespaces +using namespace Common::FixedPointNumber; + +//----------------------------------------------------------------------------- +// NeuronProcessor::NeuronThresholdModels::Constant +//----------------------------------------------------------------------------- +namespace NeuronProcessor +{ +namespace NeuronThresholdModels +{ +class Constant +{ +public: + //----------------------------------------------------------------------------- + // Constants + //----------------------------------------------------------------------------- + enum RecordingChannel + { + RecordingChannelMax, + }; + + //----------------------------------------------------------------------------- + // MutableState + //----------------------------------------------------------------------------- + struct MutableState + { + }; + + //----------------------------------------------------------------------------- + // ImmutableState + //----------------------------------------------------------------------------- + struct ImmutableState + { + // Membrane voltage threshold at which neuron spikes [mV] + S1615 m_V_Threshold; + }; + + //----------------------------------------------------------------------------- + // Static methods + //----------------------------------------------------------------------------- + static bool HasCrossed(const MutableState &, const ImmutableState &immutableState, + S1615 membraneVoltage) + { + return (membraneVoltage >= immutableState.m_V_Threshold); + } + + static S1615 GetRecordable(RecordingChannel c, + const MutableState &, const ImmutableState &) + { + LOG_PRINT(LOG_LEVEL_WARN, "Attempting to get data from non-existant threshold recording channel %u", c); + return 0; + } + + static void Print(char *stream, const MutableState &, const ImmutableState &immutableState); +}; +}; // namespace NeuronModels +}; // namespace NeuronProcessor \ No newline at end of file diff --git a/pynn_spinnaker/spinnaker/runtime/neuron_processor/synapse_models/exp.h b/pynn_spinnaker/spinnaker/runtime/neuron_processor/synapse_models/exp.h index 559eab9..bc65578 100644 --- a/pynn_spinnaker/spinnaker/runtime/neuron_processor/synapse_models/exp.h +++ b/pynn_spinnaker/spinnaker/runtime/neuron_processor/synapse_models/exp.h @@ -50,7 +50,7 @@ class Exp //----------------------------------------------------------------------------- // Static methods //----------------------------------------------------------------------------- - static inline void ApplyInput(MutableState &mutableState, const ImmutableState &, S1615 input, unsigned int receptorType) + static void ApplyInput(MutableState &mutableState, const ImmutableState &, S1615 input, unsigned int receptorType) { // Apply input to correct receptor if(receptorType == 0) @@ -63,17 +63,17 @@ class Exp } } - static inline S1615 GetExcInput(const MutableState &mutableState, const ImmutableState &immutableState) + static S1615 GetExcInput(const MutableState &mutableState, const ImmutableState &immutableState) { return MulS1615(mutableState.m_ISynExc, immutableState.m_InitExc); } - static inline S1615 GetInhInput(const MutableState &mutableState, const ImmutableState &immutableState) + static S1615 GetInhInput(const MutableState &mutableState, const ImmutableState &immutableState) { return MulS1615(mutableState.m_ISynInh, immutableState.m_InitInh); } - static inline void Shape(MutableState &mutableState, const ImmutableState &immutableState) + static void Shape(MutableState &mutableState, const ImmutableState &immutableState) { // Decay both currents mutableState.m_ISynExc = MulS1615U032(mutableState.m_ISynExc, immutableState.m_ExpTauSynExc); diff --git a/pynn_spinnaker/standardmodels/cells.py b/pynn_spinnaker/standardmodels/cells.py index d73c907..6dc9f88 100644 --- a/pynn_spinnaker/standardmodels/cells.py +++ b/pynn_spinnaker/standardmodels/cells.py @@ -70,8 +70,7 @@ def _poisson_slow_model(values, sim_timestep_ms, **kwargs): # Neuron region maps # ---------------------------------------------------------------------------- # Build maps of where and how parameters need to be written into neuron regions -if_curr_neuron_immutable_param_map = [ - ("v_thresh", "i4", lazy_param_map.s1615), +if_dynamics_immutable_param_map = [ ("v_reset", "i4", lazy_param_map.s1615), ("v_rest", "i4", lazy_param_map.s1615), ("i_offset", "i4", lazy_param_map.s1615), @@ -80,24 +79,16 @@ def _poisson_slow_model(values, sim_timestep_ms, **kwargs): ("tau_refrac", "u4", lazy_param_map.integer_time_divide), ] -if_curr_neuron_mutable_param_map = [ - ("v", "i4", lazy_param_map.s1615), - (0, "i4"), +cond_input_immutable_param_map = [ + ("e_rev_e", "i4", lazy_param_map.s1615), + ("e_rev_i", "i4", lazy_param_map.s1615), ] -if_cond_neuron_immutable_param_map = [ +constant_threshold_immutable_param_map = [ ("v_thresh", "i4", lazy_param_map.s1615), - ("v_reset", "i4", lazy_param_map.s1615), - ("v_rest", "i4", lazy_param_map.s1615), - ("e_rev_e", "i4", lazy_param_map.s1615), - ("e_rev_i", "i4", lazy_param_map.s1615), - ("i_offset", "i4", lazy_param_map.s1615), - ("r_membrane", "i4", lazy_param_map.s1615), - ("tau_m", "i4", lazy_param_map.s1615_exp_decay), - ("tau_refrac", "u4", lazy_param_map.integer_time_divide), ] -if_cond_neuron_mutable_param_map = [ +if_dynamics_mutable_param_map = [ ("v", "i4", lazy_param_map.s1615), (0, "i4"), ] @@ -143,8 +134,9 @@ class IF_curr_exp(cells.IF_curr_exp): _directly_connectable = False - _neuron_immutable_param_map = if_curr_neuron_immutable_param_map - _neuron_mutable_param_map = if_curr_neuron_mutable_param_map + _neuron_immutable_param_map = (if_dynamics_immutable_param_map + + constant_threshold_immutable_param_map) + _neuron_mutable_param_map = if_dynamics_mutable_param_map _synapse_immutable_param_map = exp_synapse_immutable_param_map _synapse_mutable_param_map = exp_synapse_curr_mutable_param_map @@ -167,8 +159,10 @@ class IF_cond_exp(cells.IF_cond_exp): _directly_connectable = False - _neuron_immutable_param_map = if_cond_neuron_immutable_param_map - _neuron_mutable_param_map = if_cond_neuron_mutable_param_map + _neuron_immutable_param_map = (if_dynamics_immutable_param_map + + cond_input_immutable_param_map + + constant_threshold_immutable_param_map) + _neuron_mutable_param_map = if_dynamics_mutable_param_map _synapse_immutable_param_map = exp_synapse_immutable_param_map _synapse_mutable_param_map = exp_synapse_cond_mutable_param_map