{"id":13774930,"url":"https://github.com/sgherbst/msdsl","last_synced_at":"2026-01-18T00:29:42.505Z","repository":{"id":48388545,"uuid":"143658506","full_name":"sgherbst/msdsl","owner":"sgherbst","description":"Automatic generation of real number models from analog circuits","archived":false,"fork":false,"pushed_at":"2024-04-02T17:26:11.000Z","size":542,"stargazers_count":39,"open_issues_count":13,"forks_count":11,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-15T17:46:45.903Z","etag":null,"topics":["ams","analog","analog-circuits","generator","mixed-signal","model","python","real-number-modeling","rnm","simulation","synthesis","synthesizable"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sgherbst.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-06T00:42:23.000Z","updated_at":"2025-03-12T16:17:06.000Z","dependencies_parsed_at":"2024-03-18T17:31:11.120Z","dependency_job_id":"c1829738-7866-4170-bcfc-de9f8e769942","html_url":"https://github.com/sgherbst/msdsl","commit_stats":{"total_commits":296,"total_committers":5,"mean_commits":59.2,"dds":"0.18918918918918914","last_synced_commit":"e38d5ecdb88b3574bda62f22a4f91ce3e4173d12"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgherbst%2Fmsdsl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgherbst%2Fmsdsl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgherbst%2Fmsdsl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgherbst%2Fmsdsl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sgherbst","download_url":"https://codeload.github.com/sgherbst/msdsl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253533155,"owners_count":21923372,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ams","analog","analog-circuits","generator","mixed-signal","model","python","real-number-modeling","rnm","simulation","synthesis","synthesizable"],"created_at":"2024-08-03T17:01:31.905Z","updated_at":"2026-01-18T00:29:42.460Z","avatar_url":"https://github.com/sgherbst.png","language":"Python","funding_links":[],"categories":["Verification Frameworks"],"sub_categories":[],"readme":"# msdsl\n[![Actions Status](https://github.com/sgherbst/msdsl/workflows/Regression/badge.svg)](https://github.com/sgherbst/msdsl/actions)\n[![Code Coverage](https://codecov.io/gh/sgherbst/msdsl/branch/master/graph/badge.svg)](https://codecov.io/gh/sgherbst/msdsl)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![PyPI version](https://badge.fury.io/py/msdsl.svg)](https://badge.fury.io/py/msdsl)\n[![Join the chat at https://gitter.im/sgherbst/msdsl](https://badges.gitter.im/sgherbst/msdsl.svg)](https://gitter.im/sgherbst/msdsl?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n**msdsl** is a tool for generating synthesizable real number models (RNMs) for analog circuits for use in FPGA emulation.  It is part of the mixed-signal emulation framework that include [svreal](https://github.com/sgherbst/svreal) and [anasymod](https://github.com/sgherbst/anasymod).\n\n# Installation\n\n## From PyPI\n\n```shell\n\u003e pip install msdsl\n```\n\nIf you get a permissions error when running the **pip** command, you can try adding the **--user** flag.  This will cause **pip** to install packages in your user directory rather than to a system-wide location.\n\n## From GitHub\n\nIf you are a developer of **msdsl**, it is more convenient to clone and install the GitHub repository:\n\n```shell\n\u003e git clone https://github.com/sgherbst/msdsl.git\n\u003e cd msdsl \n\u003e pip install -e .\n```\n\n# Basic example\n\n**msdsl** allows you to describe analog blocks at a variety of abstraction levels.  As a simple example, suppose that you want to model an RC filter with a fixed-timestep equation.  That can be expressed with the following **msdsl** code:\n\n```python\nfrom msdsl import *\nfrom math import exp\nr, c, dt = 1e3, 1e-9, 0.1e-6\nm = MixedSignalModel('rc')\nx = m.add_analog_input('x')\ny = m.add_analog_output('y')\na = exp(-dt/(r*c))\nm.set_next_cycle(y, a*y + (1-a)*x)\nm.compile_and_print(VerilogGenerator())\n```\n\nThe first thing to notice is that **msdsl** is imported just like any other Python package.  This allows you to instantiate a ``MixedSignalModel`` object that is used to described analog behaviors and generate Verilog code.  Next, an analog input (**x**) and analog output (**y**) are declared.  The ``set_next_cycle`` command implements the discrete-time equation:\n\n```text\ny[k+1] = a*y[k] + (1-a)*x[k]\n```\n\nUsers can specify the clock and reset signals that control the initialization and updating of this equation; they default to macros ``CLK_MSDSL`` and ``RST_MSDSL`` when unspecified.\n\nOn the last line, the Verilog code is generated and printed out, resulting in something like this:\n```verilog\n`include \"svreal.sv\"\nmodule rc #(\n    `DECL_REAL(x),\n    `DECL_REAL(y)\n) (\n    `INPUT_REAL(x),\n    `OUTPUT_REAL(y)\n);\n    // Assign signal: y\n    `MUL_CONST_REAL(0.9048374180359596, y, tmp0);\n    `MUL_CONST_REAL(0.09516258196404037, x, tmp1);\n    `ADD_REAL(tmp0, tmp1, tmp2);\n    `DFF_INTO_REAL(tmp2, y, `RST_MSDSL, `CLK_MSDSL, 1'b1, 0);\nendmodule\n```\n\nThis code makes use of macros from [svreal](https://github.com/sgherbst/svreal), which is a library that provides a flexible, synthesizable real-number type.  \n\nFinally, note that although ``compile_and_print`` is used in this example, you may find it more useful to use ``compile_to_file`` in practice, since **msdsl** is often used to generate model files for use in building an emulator.  \n\n# Building models\n\n**msdsl** provides a number of convenient features for building models, such as operator overloading, synthesizable functions, and noise. \n\n## Signals\n\n**msdsl** signals can be declared as analog or digital, and internal or external.  Digital signals default to 1-bit, unsigned, but their width and signedness can be specified.  Analog signals are real values with a specified +/- range that is used to compute fixed-point formats.  It is generally only necessary to specify ranges for model I/O and state variables, since **msdsl** can automatically figure out the rest.\n\nHere are some examples of signal declarations in **msdsl**:\n\n```python\nfrom msdsl import *\nm = MixedSignalModel('model')\na = m.add_analog_input('a')\nb = m.add_digital_output('b', signed=True, width=8)\nc = m.add_analog_state('c', init=1.23, range_=4.56)\nd = m.add_digital_signal('d', width=4)\n```\n\nNote the optional ``init`` argument used for state variables.  Although not shown here, it is also available for digital signals.\n\n## Assignments\n\nThe two basic types of assignments in **msdsl** are **set_this_cycle** and **set_next_cycle**.  **set_this_cycle** acts like an ``assign`` statement in Verilog, which **set_next_cycle** acts like a synchronous assignment in an ``always`` block.  Here are some examples:\n\n```python\nfrom msdsl import *\nm = MixedSignalModel('model')\na = m.add_analog_input('a')\nb = m.add_analog_output('b')\nc = m.add_analog_state('c', init=1.23, range_=4.56)\nm.set_next_cycle(c, 0.9*c + 0.1*a)\nd = m.set_this_cycle('d', 6.78*c + 7.89*a)  # create a new signal, 'd'\nm.set_this_cycle(b, 0.88*d)  # assign to existing signal \n```\n\n## Operators\n\nMany Python operators for arithmetic, comparison, and bitwise operations are overloaded in **msdsl**, allowing you to write down expressions conveniently.  Currently supported operators include ``+``, ``-``, ``*``, ``~``, ``\u0026``, ``|``, ``^``, ``\u003c\u003c``, `\u003e\u003e`, ``\u003c``, ``\u003e``, ``\u003c=``, ``\u003e=``, ``==``, and ``!=``.  The true division operator, ``/``, is only partially supported: dividing by constants works, but dividing by variables does not.    \n\n## Synthesizable functions\n\n**msdsl** makes it possible to convert Python functions into synthesizable approximations.  Here's an example where that feature is used to implement a variable-timestep RC filter:\n\n```python\nimport numpy as np\nfrom msdsl import *\nr, c = 1e3, 1e-9\nm = MixedSignalModel('rc')\nx = m.add_analog_input('x')\ndt = m.add_analog_input('dt')\ny = m.add_analog_output('y')\nfunc = lambda dt: np.exp(-dt/(r*c))\nf = m.make_function(func,\n    domain=[0, 10*r*c], numel=512, order=1)\na = m.set_from_sync_func('a', f, dt)\nx_prev = m.cycle_delay(x, 1)\ny_prev = m.cycle_delay(y, 1)\nm.set_this_cycle(y, a*y_prev + (1-a)*x_prev)\nm.compile_and_print(VerilogGenerator())\n```\n\n``func`` is a regular Python function, and it is converted into an **msdsl** ``Function`` via the ``make_function`` command.  This generates a piecewise-polynomial approximation of the function over a specified domain.  In this example, a piecewise-linear approximation is used (``order=1``) with 512 segments (``numel=512``) and the domain is 10 RC time constants (``domain=[0, 10*r*c]``).  By default, inputs outside of the domain will return the value at the closer edge of the domain.\n\n``set_from_sync_func`` generates hardware to implement the function, meaning that ``make_funcion`` can be called once, and then applied multiple times with ``set_from_sync_func``.  This is convenient since it generates more concise output code.\n\n``msdsl`` also supports single-input, multi-output functions.  This is important because it reduces the hardware overhead as compared to completely independent invocations of the same function.  Here's an example: \n\n```python\nimport numpy as np\nfrom msdsl import *\nm = MixedSignalModel('model')\nx = m.add_analog_input('x')\ny1 = m.add_analog_output('y1')\ny2 = m.add_analog_output('y2')\nfunc1 = lambda t: np.sin(t)\nfunc2 = lambda t: np.cos(t)\nf = m.make_function([func1, func2],\n    domain=[-np.pi, np.pi], numel=512, order=1)\nm.set_from_sync_func([y1, y2], f, x)\nm.compile_and_print(VerilogGenerator())  \n```\n\nThe main difference as compared to the previous example is that ``make_function`` and ``set_from_sync_func`` are called with a list of functions/output variables.\n\n## Pseudorandom noise\n\n**msdsl** provides a means for generating different kinds of pseudorandom noise: uniform, Gaussian, and arbitrary distributions:\n\n```python\nfrom msdsl import *\nm = MixedSignalModel('model')\n\n# uniform noise\nm.set_this_cycle('a', m.uniform_signal(min_val=-1.23, max_val=4.56))\n\n# Gaussian noise\nm.set_gaussian_noise('b', std=1.23, mean=4.56, gen_type=...)\n\n# arbitrary noise distribution\n# specify via the inverse cumulative distribution function\ninv_cdf = lambda x: ...\ninv_cdf_func = m.make_function(inv_cdf, domain=[0.0, 1.0])\nm.set_this_cycle('c', m.arbitrary_noise(inv_cdf_func))\n```\n\nAll noise generators depend on a pseudorandom integer generator, which can be specified with the optional ``gen_type`` parameter (``'lcg'``, ``'mt19937'``, ``'lfsr'``).  The highest-quality generator is MT19937, but it is more resource-intensive, and takes many emulator cycles to start up.  The linear congruential generator (LCG) is an exact implementation of the random number generator called for in the Verilog-2001 specification.  The default is a simple linear feedback shift register (``'lfsr'``).  Random seed values are automatically generated for random number generators, but can be explictly specified as well. \n\n# Abstraction levels\n\nUp until this point, we have considered the low-level features provided by **msdsl** to implement modeling strategies, but **msdsl** also has a bunch of common model abstractions that are ready to use.\n\n## Differential equations\n\n**msdsl** provides a method for writing down symbolic systems of linear differential equations, which are solved at compile time (i.e., through matrix exponentiation) to produce a simple FPGA implementation.\n\n```python\nfrom msdsl import *\nr, c = 1e3, 1e-9\nm = MixedSignalModel('rc', dt=0.1e-6)\nx = m.add_analog_input('x')\ny = m.add_analog_output('y')\nm.add_eqn_sys([c*Deriv(y) == (x-y)/r])\nm.compile_and_print(VerilogGenerator())\n```\n  \n## Switched systems\n\n**msdsl** supports an extension to systems of linear differential equations, in which expressions can take one of several forms, depending on digital inputs.  These expressions are built with the ``eqn_case`` command.  In the example below, a resistor is shorted out by a switch when the digital signal ``s`` is one.  The number of cases can be greater than 2, if the digital select signal has multiple bits. \n\n```python\nfrom msdsl import *\nr, rsw, c = 1e3, 100, 1e-9\nm = MixedSignalModel('rc', dt=0.1e-6)\nx = m.add_analog_input('x')\ns = m.add_digital_input('s')\ny = m.add_analog_output('y')\ng = eqn_case([1/r, 1/r+1/rsw], [s])\nm.add_eqn_sys([c*Deriv(y) == (x-y)*g])\nm.compile_and_print(VerilogGenerator())\n```\n\n## \"Netlist\"\n\n**msdsl** supports a type of \"netlist\", where analog components like resistors, capacitors, and inductors are instantiated.  Internally, this generates symbolic KCL and KVL equations, which are solved at compile time using the previously-described differential equation interface.  Switches and diodes are supported in a limited way, in which they are either \"ON\" or \"OFF\", changing their Thevenin equivalent representation.  For diodes, additional logic is generated to determine whether the diode is on or off during each timestep. \n\nThe example below is a netlist-style description of an RC filter whose resistor can be shorted out with a switch. \n\n```python\nfrom msdsl import *\nr, rsw, c = 1e3, 100, 1e-9\nm = MixedSignalModel('rc', dt=0.1e-6)\nx = m.add_analog_input('x')\ns = m.add_digital_input('s')\ny = m.add_analog_output('y')\ncirc = m.make_circuit()\ngnd = circ.make_ground()\ncirc.capacitor('net_y', gnd, c,\n    voltage_range=RangeOf(y))\ncirc.resistor('net_x', 'net_y', r)\ncirc.switch('net_x', 'net_y', s, rsw)\ncirc.voltage('net_x', gnd, x)\ncirc.add_eqns(AnalogSignal('net_y') == y)\nm.compile_and_print(VerilogGenerator())\n```\n\n## Transfer function\n\n**msdsl** also allows users to specify analog dynamics with transfer functions.  The user provides the coefficients of numerator and denominator polynomials, using the same style as [cont2discrete](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.cont2discrete.html).\n\n```python\nfrom msdsl import *\nr, c = 1e3, 1e-9\nm = MixedSignalModel('rc', dt=0.1e-6)\nx = m.add_analog_input('x')\ny = m.add_analog_output('y')\nm.set_tf(x, y, [[1], [r*c, 1]])\nm.compile_and_print(VerilogGenerator())\n```\n\n## Templates\n\nWe are currently adding higher-level abstractions that represent the function of entire blocks.  This includes a saturation nonlinearity (``SaturationModel``), a lossy-channel, specified from S-parameters (``S4PModel``), and a continuous-time linear equalization model (``CTLEModel``), which is specified by pole/zero values.  These models are implemented using a new variable-timestep discretization developed at Stanford.\n\n```python\nfrom msdsl.templates.saturation import SaturationModel\nm1 = SaturationModel(-1, 'dB', module_name='m1')\n\nfrom msdsl.templates.channel import S4PModel\nm2 = S4PModel(s4p_file='myfile.s4p', dtmax=100e-12, module_name='m2')\n\nfrom msdsl.templates.lds import CTLEModel\nm3 = CTLEModel(fz=1e9, fp1=2e9, fp2=10e9, dtmax=100e-12, fmodule_name='m3')\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgherbst%2Fmsdsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsgherbst%2Fmsdsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgherbst%2Fmsdsl/lists"}