tenncell 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. tenncell-0.7.0/LICENSE +21 -0
  2. tenncell-0.7.0/PKG-INFO +502 -0
  3. tenncell-0.7.0/README.md +485 -0
  4. tenncell-0.7.0/pyproject.toml +124 -0
  5. tenncell-0.7.0/src/nnc/__init__.py +3 -0
  6. tenncell-0.7.0/src/nnc/__main__.py +6 -0
  7. tenncell-0.7.0/src/nnc/_version.py +1 -0
  8. tenncell-0.7.0/src/nnc/cli.py +152 -0
  9. tenncell-0.7.0/src/nnc/cli_transform.py +268 -0
  10. tenncell-0.7.0/src/nnc/inputs/__init__.py +1 -0
  11. tenncell-0.7.0/src/nnc/inputs/yaml/__init__.py +1 -0
  12. tenncell-0.7.0/src/nnc/inputs/yaml/errors.py +61 -0
  13. tenncell-0.7.0/src/nnc/inputs/yaml/lexical.py +60 -0
  14. tenncell-0.7.0/src/nnc/inputs/yaml/locations.py +89 -0
  15. tenncell-0.7.0/src/nnc/inputs/yaml/lowering/__init__.py +24 -0
  16. tenncell-0.7.0/src/nnc/inputs/yaml/lowering/common.py +85 -0
  17. tenncell-0.7.0/src/nnc/inputs/yaml/lowering/fsm.py +203 -0
  18. tenncell-0.7.0/src/nnc/inputs/yaml/lowering/rules.py +60 -0
  19. tenncell-0.7.0/src/nnc/inputs/yaml/module_config.py +57 -0
  20. tenncell-0.7.0/src/nnc/inputs/yaml/parsing.py +41 -0
  21. tenncell-0.7.0/src/nnc/inputs/yaml/raw_model.py +52 -0
  22. tenncell-0.7.0/src/nnc/inputs/yaml/resolution.py +51 -0
  23. tenncell-0.7.0/src/nnc/inputs/yaml/sections.py +30 -0
  24. tenncell-0.7.0/src/nnc/inputs/yaml/yaml_loader.py +217 -0
  25. tenncell-0.7.0/src/nnc/model/__init__.py +16 -0
  26. tenncell-0.7.0/src/nnc/model/cell.py +25 -0
  27. tenncell-0.7.0/src/nnc/model/rule.py +45 -0
  28. tenncell-0.7.0/src/nnc/model/system.py +456 -0
  29. tenncell-0.7.0/src/nnc/parser/__init__.py +13 -0
  30. tenncell-0.7.0/src/nnc/parser/ast/__init__.py +61 -0
  31. tenncell-0.7.0/src/nnc/parser/ast/boolean_expression.py +152 -0
  32. tenncell-0.7.0/src/nnc/parser/ast/expression.py +268 -0
  33. tenncell-0.7.0/src/nnc/parser/ast/value/__init__.py +12 -0
  34. tenncell-0.7.0/src/nnc/parser/ast/value/array_value.py +64 -0
  35. tenncell-0.7.0/src/nnc/parser/ast/value/base_value.py +34 -0
  36. tenncell-0.7.0/src/nnc/parser/ast/value/float_value.py +35 -0
  37. tenncell-0.7.0/src/nnc/parser/ast/value/math_functions.py +156 -0
  38. tenncell-0.7.0/src/nnc/parser/ast/value/numerical_value.py +313 -0
  39. tenncell-0.7.0/src/nnc/parser/ast/variable.py +16 -0
  40. tenncell-0.7.0/src/nnc/parser/parser.py +357 -0
  41. tenncell-0.7.0/src/nnc/transformers/__init__.py +22 -0
  42. tenncell-0.7.0/src/nnc/transformers/base_transformer.py +50 -0
  43. tenncell-0.7.0/src/nnc/transformers/python/__init__.py +11 -0
  44. tenncell-0.7.0/src/nnc/transformers/python/core_emitter.py +320 -0
  45. tenncell-0.7.0/src/nnc/transformers/python/csv_script_emitter.py +188 -0
  46. tenncell-0.7.0/src/nnc/transformers/python/emission_context.py +17 -0
  47. tenncell-0.7.0/src/nnc/transformers/python/expression_emitter.py +192 -0
  48. tenncell-0.7.0/src/nnc/transformers/python_transformer.py +182 -0
  49. tenncell-0.7.0/src/nnc/transformers/verilog/__init__.py +33 -0
  50. tenncell-0.7.0/src/nnc/transformers/verilog/generation/__init__.py +1 -0
  51. tenncell-0.7.0/src/nnc/transformers/verilog/generation/context.py +33 -0
  52. tenncell-0.7.0/src/nnc/transformers/verilog/generation/conversions.py +343 -0
  53. tenncell-0.7.0/src/nnc/transformers/verilog/generation/encodings.py +76 -0
  54. tenncell-0.7.0/src/nnc/transformers/verilog/generation/expressions.py +517 -0
  55. tenncell-0.7.0/src/nnc/transformers/verilog/generation/literals.py +159 -0
  56. tenncell-0.7.0/src/nnc/transformers/verilog/generation/references.py +505 -0
  57. tenncell-0.7.0/src/nnc/transformers/verilog/generation/state.py +165 -0
  58. tenncell-0.7.0/src/nnc/transformers/verilog/generation/structure.py +486 -0
  59. tenncell-0.7.0/src/nnc/transformers/verilog/hardware_config.py +209 -0
  60. tenncell-0.7.0/src/nnc/transformers/verilog/verilog_yaml_section_parser.py +395 -0
  61. tenncell-0.7.0/src/nnc/transformers/verilog_transformer.py +253 -0
  62. tenncell-0.7.0/src/nnc/transformers/webots/__init__.py +22 -0
  63. tenncell-0.7.0/src/nnc/transformers/webots/emission_context.py +14 -0
  64. tenncell-0.7.0/src/nnc/transformers/webots/webots_config.py +50 -0
  65. tenncell-0.7.0/src/nnc/transformers/webots/webots_yaml_section_parser.py +147 -0
  66. tenncell-0.7.0/src/nnc/transformers/webots_transformer.py +217 -0
  67. tenncell-0.7.0/tests/__init__.py +0 -0
  68. tenncell-0.7.0/tests/cli_tests/test_cli.py +92 -0
  69. tenncell-0.7.0/tests/cli_tests/test_cli_transform.py +422 -0
  70. tenncell-0.7.0/tests/contracts/functional/example1.md +6 -0
  71. tenncell-0.7.0/tests/contracts/functional/example2.md +6 -0
  72. tenncell-0.7.0/tests/contracts/functional/math_functions.md +6 -0
  73. tenncell-0.7.0/tests/contracts/functional_contracts.md +38 -0
  74. tenncell-0.7.0/tests/contracts/public_contracts.md +60 -0
  75. tenncell-0.7.0/tests/contracts/unit_contracts.md +68 -0
  76. tenncell-0.7.0/tests/fixtures/cli/compute_mode.yaml +13 -0
  77. tenncell-0.7.0/tests/fixtures/cli/io_mode.yaml +17 -0
  78. tenncell-0.7.0/tests/fixtures/functional/example1.yaml +14 -0
  79. tenncell-0.7.0/tests/fixtures/functional/example2.yaml +27 -0
  80. tenncell-0.7.0/tests/fixtures/functional/math_functions.yaml +31 -0
  81. tenncell-0.7.0/tests/fixtures/transformers/python/expected/basic.py +94 -0
  82. tenncell-0.7.0/tests/fixtures/transformers/python/expected/composed_root.py +179 -0
  83. tenncell-0.7.0/tests/fixtures/transformers/python/expected/csv_with_input.py +125 -0
  84. tenncell-0.7.0/tests/fixtures/transformers/python/expected/csv_without_input.py +96 -0
  85. tenncell-0.7.0/tests/fixtures/transformers/python/expected/no_outputs.py +84 -0
  86. tenncell-0.7.0/tests/fixtures/transformers/python/expected/zero_reset.py +115 -0
  87. tenncell-0.7.0/tests/fixtures/transformers/python/input/basic.yaml +9 -0
  88. tenncell-0.7.0/tests/fixtures/transformers/python/input/composed_child.yaml +11 -0
  89. tenncell-0.7.0/tests/fixtures/transformers/python/input/composed_root.yaml +16 -0
  90. tenncell-0.7.0/tests/fixtures/transformers/python/input/csv_with_input.yaml +11 -0
  91. tenncell-0.7.0/tests/fixtures/transformers/python/input/csv_without_input.yaml +10 -0
  92. tenncell-0.7.0/tests/fixtures/transformers/python/input/no_outputs.yaml +6 -0
  93. tenncell-0.7.0/tests/fixtures/transformers/python/input/zero_reset.yaml +12 -0
  94. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/blink_uart_boundary/blink_uart_tx_driver.sv +116 -0
  95. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/blink_uart_boundary/root.sv +132 -0
  96. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/external_output_connection/root.sv +49 -0
  97. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/external_output_wire/root.sv +53 -0
  98. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/fsm_if.sv +90 -0
  99. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/helper_generated_literals/root.sv +52 -0
  100. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/import_connection/root.sv +44 -0
  101. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/imports_externals/controller.sv +82 -0
  102. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/imports_externals/sensor.sv +45 -0
  103. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/inferred_ports.sv +44 -0
  104. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/logic_vector.sv +45 -0
  105. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/logic_vectors.sv +67 -0
  106. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/simple.sv +39 -0
  107. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/top_io.sv +50 -0
  108. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/unsigned_fixed.sv +69 -0
  109. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/zero_reset.sv +55 -0
  110. tenncell-0.7.0/tests/fixtures/transformers/verilog/expected/zero_reset_input.sv +45 -0
  111. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/bad.yaml +7 -0
  112. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/blink_uart_boundary/blink_uart_tx_driver.yaml +58 -0
  113. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/blink_uart_boundary/root.yaml +73 -0
  114. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/blink_uart_boundary/uart_tx.header.yaml +36 -0
  115. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/blink_uart_typed/blink_uart_tx_driver.yaml +58 -0
  116. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/blink_uart_typed/blink_uart_typed.yaml +78 -0
  117. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/blink_uart_typed/uart_tx.header.yaml +36 -0
  118. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/external_output_connection/root.yaml +29 -0
  119. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/external_output_connection/uart_tx.header.yaml +11 -0
  120. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/external_output_wire/root.yaml +32 -0
  121. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/external_output_wire/uart.header.yaml +11 -0
  122. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/fsm_if.yaml +45 -0
  123. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/helper_generated_literals/child.yaml +21 -0
  124. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/helper_generated_literals/root.yaml +28 -0
  125. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/import_connection/child.yaml +21 -0
  126. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/import_connection/root.yaml +18 -0
  127. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/imports_externals/controller.yaml +48 -0
  128. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/imports_externals/sensor.yaml +21 -0
  129. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/imports_externals/uart.header.yaml +24 -0
  130. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/inferred_ports.yaml +21 -0
  131. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/logic_vector.yaml +21 -0
  132. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/logic_vectors.yaml +26 -0
  133. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/simple.yaml +11 -0
  134. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/top_io.yaml +30 -0
  135. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/unsigned_fixed.yaml +25 -0
  136. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/zero_reset.yaml +24 -0
  137. tenncell-0.7.0/tests/fixtures/transformers/verilog/input/zero_reset_input.yaml +29 -0
  138. tenncell-0.7.0/tests/fixtures/transformers/webots/expected/motor_velocity.py +91 -0
  139. tenncell-0.7.0/tests/fixtures/transformers/webots/expected/sensor_led.py +88 -0
  140. tenncell-0.7.0/tests/fixtures/transformers/webots/input/invalid_binding_method.yaml +5 -0
  141. tenncell-0.7.0/tests/fixtures/transformers/webots/input/invalid_bindings_init.yaml +3 -0
  142. tenncell-0.7.0/tests/fixtures/transformers/webots/input/invalid_controller_name.yaml +6 -0
  143. tenncell-0.7.0/tests/fixtures/transformers/webots/input/invalid_init.yaml +6 -0
  144. tenncell-0.7.0/tests/fixtures/transformers/webots/input/invalid_timestep.yaml +6 -0
  145. tenncell-0.7.0/tests/fixtures/transformers/webots/input/missing_input_binding.yaml +16 -0
  146. tenncell-0.7.0/tests/fixtures/transformers/webots/input/missing_output_binding.yaml +16 -0
  147. tenncell-0.7.0/tests/fixtures/transformers/webots/input/missing_webots.yaml +9 -0
  148. tenncell-0.7.0/tests/fixtures/transformers/webots/input/motor_velocity.yaml +34 -0
  149. tenncell-0.7.0/tests/fixtures/transformers/webots/input/sensor_led.yaml +23 -0
  150. tenncell-0.7.0/tests/fixtures/transformers/webots/input/special_init_values.yaml +8 -0
  151. tenncell-0.7.0/tests/functional_tests/sequence_helper.py +38 -0
  152. tenncell-0.7.0/tests/functional_tests/test_example1_contract.py +48 -0
  153. tenncell-0.7.0/tests/functional_tests/test_example2_contract.py +33 -0
  154. tenncell-0.7.0/tests/functional_tests/test_math_functions_contract.py +144 -0
  155. tenncell-0.7.0/tests/unit_tests/__init__.py +0 -0
  156. tenncell-0.7.0/tests/unit_tests/model/test_model_package_exports.py +25 -0
  157. tenncell-0.7.0/tests/unit_tests/model/test_system.py +36 -0
  158. tenncell-0.7.0/tests/unit_tests/model/test_system_errors.py +150 -0
  159. tenncell-0.7.0/tests/unit_tests/model/test_system_imports.py +487 -0
  160. tenncell-0.7.0/tests/unit_tests/model/test_system_resolution.py +79 -0
  161. tenncell-0.7.0/tests/unit_tests/model/test_system_runtime_helpers.py +351 -0
  162. tenncell-0.7.0/tests/unit_tests/parser/test_array_value.py +112 -0
  163. tenncell-0.7.0/tests/unit_tests/parser/test_boolean_expression.py +176 -0
  164. tenncell-0.7.0/tests/unit_tests/parser/test_expression.py +196 -0
  165. tenncell-0.7.0/tests/unit_tests/parser/test_function_call.py +360 -0
  166. tenncell-0.7.0/tests/unit_tests/parser/test_parser_errors.py +44 -0
  167. tenncell-0.7.0/tests/unit_tests/parser/test_value.py +114 -0
  168. tenncell-0.7.0/tests/unit_tests/test_public_contract_imports.py +29 -0
  169. tenncell-0.7.0/tests/unit_tests/transformers/__init__.py +1 -0
  170. tenncell-0.7.0/tests/unit_tests/transformers/base/test_base_transformer.py +135 -0
  171. tenncell-0.7.0/tests/unit_tests/transformers/package/test_transformers_init.py +132 -0
  172. tenncell-0.7.0/tests/unit_tests/transformers/python/test_python_expression_emitter.py +161 -0
  173. tenncell-0.7.0/tests/unit_tests/transformers/python/test_python_transformer.py +111 -0
  174. tenncell-0.7.0/tests/unit_tests/transformers/python/test_python_transformer_locations.py +27 -0
  175. tenncell-0.7.0/tests/unit_tests/transformers/verilog/test_verilog_expression_emitter.py +271 -0
  176. tenncell-0.7.0/tests/unit_tests/transformers/verilog/test_verilog_helper_coverage.py +382 -0
  177. tenncell-0.7.0/tests/unit_tests/transformers/verilog/test_verilog_transformer.py +138 -0
  178. tenncell-0.7.0/tests/unit_tests/transformers/verilog/test_verilog_yaml_section_parser.py +173 -0
  179. tenncell-0.7.0/tests/unit_tests/transformers/webots/test_webots_transformer.py +41 -0
  180. tenncell-0.7.0/tests/unit_tests/transformers/webots/test_webots_yaml_section_parser.py +90 -0
  181. tenncell-0.7.0/tests/unit_tests/yaml/test_lowering_helpers.py +361 -0
  182. tenncell-0.7.0/tests/unit_tests/yaml/test_yaml_loader_bang_expressions.py +55 -0
tenncell-0.7.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Serghei Verlan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,502 @@
1
+ Metadata-Version: 2.1
2
+ Name: tenncell
3
+ Version: 0.7.0
4
+ Summary: Transformation and Execution of Numerical Networks of Cells
5
+ Author-Email: Sergey Verlan <dont-spam-me@no.spam>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Development Status :: 4 - Beta
11
+ Project-URL: Homepage, https://github.com/sverlan/tenncell
12
+ Project-URL: Repository, https://github.com/sverlan/tenncell
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: lark~=1.1
15
+ Requires-Dist: PyYAML~=6.0
16
+ Description-Content-Type: text/markdown
17
+
18
+ # TENNCell
19
+
20
+ TENNCell stands for Transformation and Execution of Numerical Networks of
21
+ Cells. It is a model related to numerical P systems that generalizes many of
22
+ their variants. This package parses and simulates TENNCell systems and exports
23
+ them to generated code.
24
+
25
+ ## Current Capabilities
26
+ - Python simulation of standalone and import-composed TENNCell YAML systems
27
+ - Python source export through `nnc-gen -t python`, including import-composed systems as a single generated file
28
+ - Verilog/SystemVerilog export through `nnc-gen -t verilog`
29
+ - Webots Python controller export through `nnc-gen -t webots`
30
+ - Optional import/composition metadata for optimized Verilog generation
31
+
32
+ ## Installation
33
+
34
+ Use one of these depending on how you want to consume the package:
35
+
36
+ - `pip install tenncell` if you want the package and commands in your current Python environment
37
+ - `pipx install tenncell` if you want an isolated command-line installation
38
+ - `pdm install --dev` if you are developing from a clone of this repository
39
+
40
+ ## Quick Start
41
+ If you want to try the package immediately, start with one of the examples:
42
+
43
+ - simulate a standalone TENNCell file: `nnc-sim examples/simple/example1.yaml`
44
+ - generate Verilog from a typed FPGA example: `nnc-gen examples/fpga/blink_uart_typed/blink_uart_typed.yaml -t verilog`
45
+ - inspect the available commands: `nnc-sim --help` and `nnc-gen --help`
46
+
47
+ The `python -m nnc` form invokes the simulator with the same defaults as `nnc-sim`.
48
+
49
+ ## Simulation
50
+
51
+ TENNCell has two simulation modes:
52
+
53
+ ### IO mode
54
+ - This is the default mode.
55
+ - It reads CSV input rows and writes CSV output rows.
56
+ - Use it when you want to process a stream of inputs and capture the produced outputs.
57
+
58
+ Example:
59
+ ```powershell
60
+ nnc-sim examples/simple/example1.yaml input.csv output.csv
61
+ ```
62
+
63
+ ### Compute mode
64
+ - This mode does not consume CSV input.
65
+ - It runs the system for a fixed number of steps and prints the output state.
66
+ - Use it when you want a bounded run with no CSV input file.
67
+
68
+ Example:
69
+ ```powershell
70
+ nnc-sim examples/simple/example1.yaml -c -s 10
71
+ ```
72
+
73
+ The `--csv` flag only affects compute mode and makes the output CSV-formatted.
74
+
75
+ The simulator supports standalone TENNCell YAML and import-composed TENNCell systems.
76
+
77
+ ## Transformers
78
+
79
+ Use `nnc-gen` to generate backend-specific outputs:
80
+
81
+ ```powershell
82
+ nnc-gen <system_file.yaml> -t {python,verilog,webots} [options]
83
+ ```
84
+
85
+ Options:
86
+ - `-o`, `--output-dir DIR`: output directory
87
+ - `--output-suffix SUFFIX`: suffix inserted before the generated file extension
88
+ - `--import-path DIR`: extra import search path, may be repeated
89
+ - `--import-paths LIST`: path-separated import search list
90
+ - `-v`, `--verbose`: verbose logging
91
+
92
+ Import resolution order:
93
+ 1. relative to the importing YAML file
94
+ 2. `--import-path` / `--import-paths` directories in the order provided
95
+
96
+ ### Python backend
97
+ `nnc-gen -t python` generates a single Python source file for the selected TENNCell model.
98
+ It flattens import-composed systems into one generated file.
99
+ Use this backend when you want a Python artifact you can inspect, run, or integrate into a larger Python workflow.
100
+
101
+ Example:
102
+ ```powershell
103
+ nnc-gen examples/composition/python_composed/python_composed_controller.yaml -t python
104
+ ```
105
+
106
+ The generated file is a Python module. It exposes the TENNCell model as normal Python classes and methods, so you can import it into another script or run it directly as a generated artifact. If the source TENNCell system has inputs, the generated code uses the same CSV conventions as the simulator; otherwise it can be stepped directly. The generated main class exposes a `step` method for integration into a larger workflow.
107
+
108
+ ### Webots backend
109
+ `nnc-gen -t webots` generates a Python controller for Webots.
110
+ The Webots YAML adds sensor and actuator metadata through `webots.bindings` and `webots.init`.
111
+ `webots.bindings` maps TENNCell variables to Webots devices and names the read or write method the controller should call.
112
+ `webots.init` sets initial device state for outputs or actuators that need a startup value.
113
+ Use this backend when you want TENNCell to drive a Webots robot or read its sensors.
114
+
115
+ Example:
116
+ ```powershell
117
+ nnc-gen examples/webots/e_puck_pid/e_puck_pid.yaml -t webots
118
+ ```
119
+
120
+ ### Verilog backend
121
+ `nnc-gen -t verilog` generates SystemVerilog RTL.
122
+ The current form uses:
123
+ - `.sv` output files
124
+ - `` `default_nettype none`` throughout the generated module
125
+ - `always_comb` for next-state logic and `always_ff` for registered state
126
+ - module-local `localparam` aliases for fixed-point literals
127
+ - `verilog.real_encoding` as the module numeric contract
128
+ - `verilog.ports` for top-level port declarations and boundary typing
129
+ - `verilog.externals` for wiring external RTL modules through explicit connections
130
+
131
+ Verilog port entries may specify `kind`; it defaults to `logic` when omitted.
132
+ The `clock` and `reset` fields are scalar names for the generated boundary signals.
133
+ They are not TENNCell aliases, but external module connections may still wire to them
134
+ through `verilog.externals.connections`.
135
+
136
+ The simple UART-to-LED example below shows the overall shape without introducing
137
+ the more complex typed blink example.
138
+
139
+ ## YAML Schema
140
+
141
+ A sample example looks like
142
+
143
+ ```yaml
144
+ module:
145
+ name: fir
146
+ description: "3-tap FIR filter"
147
+ cells:
148
+ - id: 1
149
+ contents:
150
+ - x=0
151
+ - x1=0, x2=0
152
+ - y=0
153
+ input: [x]
154
+ output: [y]
155
+ rules:
156
+ - x -> x1
157
+ - x1 -> x2
158
+ - 0.2 * x + 0.5 * x1 + 0.3 * x2 -> y
159
+ - 0 * y -> y
160
+ - 0 * x1 -> x1
161
+ - 0 * x2 -> x2
162
+ ```
163
+
164
+ An important parameter is `module.zero_reset_mode`, which defaults to false. In this mode, if a variable is not used, it keeps its previous value, so it can accumulate between steps. When true, the variable values are reset to zero at each step, regardless of whether they are used or not. In particular, this simplifies Verilog code generation.
165
+
166
+
167
+ The system can have additional `verilog` and/or `webots` sections that contain instructions specific to these backends:
168
+
169
+ ```yaml
170
+ module: controller
171
+ zero_reset_mode: true
172
+ ...
173
+ verilog:
174
+ ...
175
+ webots:
176
+ ...
177
+ ```
178
+
179
+ Additional YAML sugar is also supported:
180
+ - top-level `if` / `then` / `else` blocks
181
+ - recursive nested `if` blocks anywhere a rule list is allowed
182
+ - `fsm:` blocks with one or more FSMs per module
183
+
184
+ Example:
185
+ ```yaml
186
+ fsm:
187
+ - name: ctrl
188
+ variable: ctrl_state
189
+ initial: IDLE
190
+ states:
191
+ - IDLE:
192
+ rules:
193
+ - if: start > 0
194
+ then: RUN -> ctrl_state
195
+ - RUN:
196
+ rules:
197
+ - if: done > 0
198
+ then: IDLE -> ctrl_state
199
+ ```
200
+
201
+ Single-item sugar is accepted in branch bodies, so these are equivalent:
202
+ ```yaml
203
+ then:
204
+ - 1 -> y
205
+ ```
206
+
207
+ ```yaml
208
+ then: 1 -> y
209
+ ```
210
+
211
+ Qualified references supported by the parser:
212
+ - local variable: `x`
213
+ - imported TENNCell IO: `sensor0.level`
214
+ - Verilog port names are not part of TENNCell alias resolution
215
+
216
+ Constants may be literal numbers or load-time constant expressions. Expressions are evaluated in declaration order and may reference only previously declared constants:
217
+
218
+ ```yaml
219
+ constants:
220
+ A: 2 * 5
221
+ B: 3 * A + 1
222
+ ```
223
+
224
+ Aliases can be defined, that correspond to variable renaming. They are mostly used for imported modules:
225
+
226
+ ```yaml
227
+ aliases:
228
+ sensed: sensor0.level
229
+ ```
230
+
231
+ ### Imports vs Externals
232
+ - `imports:` composes TENNCell modules together.
233
+ - `verilog.externals` wraps external RTL modules and wires TENNCell variables to their ports.
234
+ - For import composition patterns, see `examples/composition/`.
235
+ - For external-module wiring examples, see `examples/fpga/`.
236
+
237
+ ## Defaults
238
+
239
+ TENNCell YAML files without a module section are still supported:
240
+
241
+ ```yaml
242
+ cells:
243
+ - id: 1
244
+ contents:
245
+ - x = 0
246
+ - y = 1
247
+ input: [x]
248
+ output: [y]
249
+
250
+ rules:
251
+ - x + 1 -> y
252
+ ```
253
+
254
+ If `module` is absent, the effective defaults are:
255
+ - module name: source filename stem
256
+ - `zero_reset_mode`: `false`
257
+
258
+ If `constants`, `aliases`, `imports`, `verilog.externals`, or `webots.bindings` are absent, they default to empty where the selected backend allows them.
259
+
260
+
261
+ These defaults are also documented in `rules.md`.
262
+
263
+ ## Development
264
+
265
+ For day-to-day development in a clone of the repository:
266
+
267
+ ```powershell
268
+ pdm install --dev
269
+ ```
270
+
271
+ Common checks:
272
+
273
+ ```powershell
274
+ pdm run lint
275
+ pdm run typecheck
276
+ pdm test
277
+ ```
278
+
279
+ For CI or reproducible installs from the lockfile, use:
280
+
281
+ ```powershell
282
+ pdm sync --clean --dev
283
+ ```
284
+
285
+ ## Webots backend metadata
286
+
287
+ The `webots` backend emits a single Python controller file:
288
+ - file extension: `.py`
289
+ - embeds the generated Python TENNCell model without the standalone CSV CLI
290
+ - creates a Webots `Robot`
291
+ - binds TENNCell input variables to configured Webots device read methods
292
+ - binds TENNCell output variables and initialization values to configured device write methods
293
+ - uses `webots.timestep` when provided, otherwise reads the basic timestep from the robot
294
+
295
+ Each declared TENNCell input must have a binding with `read_method`.
296
+ Each declared TENNCell output must have a binding with `write_method`.
297
+ The rules use TENNCell variable names; the bindings control which Webots methods read or write those variables.
298
+
299
+ Initialization entries under `webots.init` must refer to bindings with `write_method`.
300
+
301
+ The backend does not generate Webots world or PROTO files. It only emits the
302
+ controller glue that reads Webots devices, advances the generated TENNCell model,
303
+ and writes outputs back to Webots devices.
304
+
305
+ ```yaml
306
+ ...
307
+ speed -> right_speed
308
+ ...
309
+
310
+ webots:
311
+ controller_name: e_puck_pid_controller
312
+ timestep: 64
313
+ bindings:
314
+ left_sensor:
315
+ device: ps0
316
+ read_method: getValue
317
+ right_sensor:
318
+ device: ps7
319
+ read_method: getValue
320
+ left_speed:
321
+ device: left wheel motor
322
+ write_method: setVelocity
323
+ right_speed:
324
+ device: right wheel motor
325
+ write_method: setVelocity
326
+ left_position:
327
+ device: left wheel motor
328
+ write_method: setPosition
329
+ right_position:
330
+ device: right wheel motor
331
+ write_method: setPosition
332
+ init:
333
+ left_position: inf
334
+ right_position: inf
335
+ ```
336
+
337
+ ## Verilog backend metadata
338
+
339
+ The Verilog backend metadata allows you to describe port and internal variable shapes. It also allows you to include external RTL modules.
340
+
341
+ Supported expression subset:
342
+ - constants
343
+ - local variables
344
+ - qualified references
345
+ - addition and subtraction
346
+ - unary minus
347
+ - constant multiplication and constant division
348
+ - boolean comparisons
349
+ - boolean `&&`, `||`, `!`
350
+
351
+ Rejected constructs:
352
+ - generic function calls
353
+ - variable-by-variable multiplication
354
+ - non-constant division
355
+ - arrays
356
+
357
+ Each TENNCell module uses its own `real_encoding`. Boundary conversions are inserted automatically for imported TENNCell IO and external ports.
358
+ In the Verilog backend, it is recommended to use `zero_reset_mode: true`. This simplifies the generated code by removing the checks for variable consumption.
359
+
360
+ Here is a simple led blink example:
361
+ ```yaml
362
+ module:
363
+ name: fpga_blink
364
+ zero_reset_mode: true
365
+ verilog:
366
+ real_encoding:
367
+ kind: fixed_point
368
+ signed: false
369
+ width: 48
370
+ frac_bits: 10
371
+ clock: clk
372
+ reset: rst
373
+ ports:
374
+ - name: led
375
+ direction: output
376
+ kind: logic
377
+ width: 1
378
+ signed: false
379
+
380
+ constants:
381
+ BLINK_DELAY: 27000000
382
+
383
+ cells:
384
+ - id: 1
385
+ contents:
386
+ - counter = 0
387
+ - led = 0
388
+ output: [led]
389
+
390
+ rules:
391
+ - if: counter < BLINK_DELAY
392
+ then:
393
+ # Increment the counter
394
+ - counter + 1 -> counter
395
+ # Keep the led state (otherwise it resets to zero)
396
+ - led -> led
397
+ else:
398
+ # When the delay expires, toggle the LED.
399
+ # The counter resets to zero by itself (because of the zero_reset_mode)
400
+ - led == 0 | 1 -> led
401
+ - led > 0 | 0 -> led
402
+ ```
403
+ The next example shows the use of an external module. It reads `rx_valid` and `rx_data` from the UART external and turns the LED on or
404
+ off when the received byte is `1` or `0`.
405
+
406
+
407
+ ```yaml
408
+ module:
409
+ name: fpga_uart_led
410
+ zero_reset_mode: true
411
+
412
+ verilog:
413
+ real_encoding:
414
+ kind: fixed_point
415
+ signed: true
416
+ width: 32
417
+ frac_bits: 16
418
+ clock: clk
419
+ reset: rst
420
+ ports:
421
+ uart_rx:
422
+ direction: input
423
+ width: 1
424
+ led:
425
+ direction: output
426
+ width: 1
427
+ externals:
428
+ uart0:
429
+ header: uart.header.yaml
430
+ parameters:
431
+ CLOCK_FREQ: 50000000
432
+ BAUD_RATE: 115200
433
+ connections:
434
+ clk: clk
435
+ rst: rst
436
+ rx: uart_rx
437
+
438
+ cells:
439
+ - id: 1
440
+ contents:
441
+ - uart_rx = 0
442
+ - led = 0
443
+ - rx_data = 0
444
+ - rx_valid = 0
445
+ input: [uart_rx]
446
+ output: [led]
447
+
448
+ rules:
449
+ - rx_valid == 1 && rx_data == 1 | 1 -> led
450
+ - rx_valid == 1 && rx_data == 0 | 0 -> led
451
+ ```
452
+
453
+
454
+ More details can be seen in the examples under `examples/fpga/`, especially `blink_uart/`, `blink_uart_typed/`, `fpga_uart_led/`, `sensor_controller/`, `fpga_spi_gpio_bridge/`, and `axii/`.
455
+
456
+ ### Technical RTL generation details
457
+
458
+ The `verilog` backend emits SystemVerilog-style RTL:
459
+ - file extension: `.sv`
460
+ - wraps each generated module with `` `default_nettype none`` and keeps it in effect throughout the generated file
461
+ - module parameters in the module header
462
+ - `always_comb` for next-state logic
463
+ - `always_ff` for sequential updates
464
+ - fixed-point values stay as integer literals in the emitted RTL, wrapped in generated module-local `localparam` aliases such as `_VAL_1_0`
465
+ - generated fixed-point state, helper signatures, and literals follow `verilog.real_encoding`
466
+ - boundary conversions use generated helper functions
467
+ - if a TENNCell input/output is described in `verilog.ports`, the generated RTL converts between the module-local fixed-point encoding and the declared Verilog port format at the module boundary
468
+ - if a TENNCell module does not declare `verilog.ports`, the Verilog backend infers the full module boundary from that module's input/output variables and `verilog.real_encoding`
469
+ - if a TENNCell input/output is described in `verilog.externals`, the generated RTL rewires that variable internally to the external module rather than exposing it at the top-level interface; if the target is a TENNCell output that is also a top-level port, the top-level port is driven directly from the external module output
470
+ - plain variable names such as `sample` or `alarm` refer to the local TENNCell variable, while Verilog port names are emitted only through `verilog.ports`
471
+ - fixed-point to integer top-port conversion truncates toward zero
472
+ - generated literal aliases are documented with comments showing the original source values and fixed-point format
473
+
474
+
475
+ ## Backend Boundaries
476
+
477
+ - Python simulation and `nnc-gen -t python` use TENNCell model semantics and support TENNCell imports only.
478
+ - Python simulation and the Python backend do not consume `verilog.externals`.
479
+ - Verilog generation uses the TENNCell model plus `verilog.real_encoding`, `verilog.ports`, `verilog.externals`, and TENNCell imports.
480
+ - Webots generation uses the TENNCell model plus `webots.bindings` / `webots.init`.
481
+ - Webots generation emits controller code only: one Python controller for the root YAML file, with no world, PROTO, or external RTL files.
482
+
483
+ ## Examples
484
+
485
+ See `examples/` for:
486
+ - standalone YAML under `examples/simple/`, such as `example1.yaml`, `example2.yaml`, `example3.yaml`, `example3io.yaml`, `example3o.yaml`, `example_add.yaml`, `ballistic.yaml`, and `ballistic_if.yaml`
487
+ - recursive conditional YAML in `examples/fsm/if_recursive.yaml`
488
+ - FSM-oriented YAML in `examples/fsm/fsm_counter.yaml` and `examples/fsm/fsm_dual.yaml`
489
+ - import-only Python composition in `examples/composition/python_composed/`
490
+ - imported multicell Python composition in `examples/composition/imported_composition/`
491
+ - Verilog composition examples in `examples/composition/verilog_composed/`
492
+ - FPGA-oriented examples under `examples/fpga/`, including standalone `blink.yaml`, `blink_if.yaml`, and `ledwalk.yaml`, plus dedicated folders for `blink_uart/`, `blink_uart_typed/`, `sensor_controller/`, `fpga_uart_led/`, `fpga_spi_gpio_bridge/`, and `axii/`
493
+ - Webots controller examples under `examples/webots/`, including `e_puck_pid/` and `pioneer3_dx_obstacle_avoidance/`
494
+
495
+ ## Notes
496
+ - Top-level `name` and `description` are treated as metadata and ignored by Verilog generation.
497
+ - Detailed behavior and schema rules live in `rules.md`.
498
+
499
+
500
+ Since version `0.3.0`, AI has been used to help with code-generation and refactoring work in this repository.
501
+
502
+ The project is distributed under the MIT license.