PySHDL 0.1.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.
- pyshdl-0.1.0/.gitignore +16 -0
- pyshdl-0.1.0/C_API.md +200 -0
- pyshdl-0.1.0/DOCS.md +623 -0
- pyshdl-0.1.0/PKG-INFO +142 -0
- pyshdl-0.1.0/README.md +134 -0
- pyshdl-0.1.0/examples/SHDL_components/addSub16.shdl +46 -0
- pyshdl-0.1.0/examples/SHDL_components/fullAdder.shdl +19 -0
- pyshdl-0.1.0/examples/SHDL_components/reg16.shdl +33 -0
- pyshdl-0.1.0/examples/interacting.py +40 -0
- pyshdl-0.1.0/pyproject.toml +17 -0
- pyshdl-0.1.0/src/PySHDL/__init__.py +21 -0
- pyshdl-0.1.0/src/PySHDL/circuit.py +180 -0
- pyshdl-0.1.0/src/PySHDL/cli.py +191 -0
- pyshdl-0.1.0/src/PySHDL/py.typed +0 -0
- pyshdl-0.1.0/src/PySHDL/shdlc.py +1011 -0
- pyshdl-0.1.0/uv.lock +8 -0
pyshdl-0.1.0/.gitignore
ADDED
pyshdl-0.1.0/C_API.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# SHDL Compiler - Library API Update
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The SHDL compiler generates a **C library APIs** instead of standalone executables. This enables integration with testing frameworks, property-based testing, fuzzing, and scripting languages like Python.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Library API
|
|
9
|
+
The compiler generates a basic API with these functions:
|
|
10
|
+
|
|
11
|
+
```c
|
|
12
|
+
void reset(void);
|
|
13
|
+
void poke(const char *signal_name, uint64_t value);
|
|
14
|
+
uint64_t peek(const char *signal_name);
|
|
15
|
+
void step(int cycles);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## API Functions
|
|
19
|
+
|
|
20
|
+
### `void reset(void)`
|
|
21
|
+
Resets all internal state to zero. Call this before starting a test.
|
|
22
|
+
|
|
23
|
+
```c
|
|
24
|
+
reset();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### `void poke(const char *signal_name, uint64_t value)`
|
|
28
|
+
Sets an input signal to a specific value. Marks outputs as dirty (requiring recomputation).
|
|
29
|
+
|
|
30
|
+
```c
|
|
31
|
+
poke("A", 42);
|
|
32
|
+
poke("B", 17);
|
|
33
|
+
poke("Cin", 1);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### `uint64_t peek(const char *signal_name)`
|
|
37
|
+
Reads the current value of an input or output signal. Automatically computes outputs if needed.
|
|
38
|
+
|
|
39
|
+
```c
|
|
40
|
+
uint64_t sum = peek("Sum");
|
|
41
|
+
uint64_t cout = peek("Cout");
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### `void step(int cycles)`
|
|
45
|
+
Advances the simulation by the specified number of clock cycles. This commits state changes.
|
|
46
|
+
|
|
47
|
+
```c
|
|
48
|
+
step(1); // Advance by 1 cycle
|
|
49
|
+
step(10); // Advance by 10 cycles
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Two-Phase Update Model
|
|
53
|
+
|
|
54
|
+
The simulator uses a two-phase update model for correct timing:
|
|
55
|
+
|
|
56
|
+
1. **Pending State**: Computed from current state + inputs.
|
|
57
|
+
2. **Current State**: Committed state after `step()`
|
|
58
|
+
|
|
59
|
+
This ensures:
|
|
60
|
+
- We can write combinational and sequential logic correctly
|
|
61
|
+
- Using feedback loops we can store state
|
|
62
|
+
- Multiple `poke()` calls can be made before evaluation
|
|
63
|
+
- Clock boundaries are clearly defined
|
|
64
|
+
|
|
65
|
+
## Usage Example
|
|
66
|
+
|
|
67
|
+
### Basic C Test
|
|
68
|
+
|
|
69
|
+
```c
|
|
70
|
+
#include "adder16.c"
|
|
71
|
+
|
|
72
|
+
int main(void) {
|
|
73
|
+
reset();
|
|
74
|
+
|
|
75
|
+
// Test case: 42 + 17 + carry_in=1 = 60
|
|
76
|
+
poke("A", 42);
|
|
77
|
+
poke("B", 17);
|
|
78
|
+
poke("Cin", 1);
|
|
79
|
+
|
|
80
|
+
step(4); // Advance time to compute outputs
|
|
81
|
+
|
|
82
|
+
uint64_t sum = peek("Sum");
|
|
83
|
+
uint64_t cout = peek("Cout");
|
|
84
|
+
|
|
85
|
+
printf("Sum: %llu, Cout: %llu\n", sum, cout);
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Python Integration (via ctypes)
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import ctypes
|
|
96
|
+
|
|
97
|
+
# Load the shared library
|
|
98
|
+
lib = ctypes.CDLL("./adder16.so")
|
|
99
|
+
|
|
100
|
+
# Define function signatures
|
|
101
|
+
lib.reset.restype = None
|
|
102
|
+
lib.poke.argtypes = [ctypes.c_char_p, ctypes.c_uint64]
|
|
103
|
+
lib.peek.restype = ctypes.c_uint64
|
|
104
|
+
lib.peek.argtypes = [ctypes.c_char_p]
|
|
105
|
+
lib.step.argtypes = [ctypes.c_int]
|
|
106
|
+
|
|
107
|
+
# Run test
|
|
108
|
+
lib.reset()
|
|
109
|
+
lib.poke(b"A", 42)
|
|
110
|
+
lib.poke(b"B", 17)
|
|
111
|
+
lib.poke(b"Cin", 1)
|
|
112
|
+
lib.step(4)
|
|
113
|
+
|
|
114
|
+
sum_val = lib.peek(b"Sum")
|
|
115
|
+
cout_val = lib.peek(b"Cout")
|
|
116
|
+
|
|
117
|
+
print(f"Sum: {sum_val}, Cout: {cout_val}")
|
|
118
|
+
|
|
119
|
+
# Property-based testing example
|
|
120
|
+
import hypothesis
|
|
121
|
+
from hypothesis import given, strategies as st
|
|
122
|
+
|
|
123
|
+
@given(st.integers(0, 65535), st.integers(0, 65535), st.integers(0, 1))
|
|
124
|
+
def test_adder_properties(a, b, cin):
|
|
125
|
+
lib.reset()
|
|
126
|
+
lib.poke(b"A", a)
|
|
127
|
+
lib.poke(b"B", b)
|
|
128
|
+
lib.poke(b"Cin", cin)
|
|
129
|
+
|
|
130
|
+
lib.step(4)
|
|
131
|
+
|
|
132
|
+
sum_val = lib.peek(b"Sum")
|
|
133
|
+
cout_val = lib.peek(b"Cout")
|
|
134
|
+
|
|
135
|
+
# Verify result
|
|
136
|
+
expected = a + b + cin
|
|
137
|
+
actual = (cout_val << 16) | sum_val
|
|
138
|
+
assert actual == expected, f"{a} + {b} + {cin} = {expected}, got {actual}"
|
|
139
|
+
|
|
140
|
+
# Run property tests
|
|
141
|
+
test_adder_properties()
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Building the Library
|
|
145
|
+
|
|
146
|
+
### As a Shared Library (.so)
|
|
147
|
+
```bash
|
|
148
|
+
gcc -shared -fPIC -O3 adder16.c -o adder16.so
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### As a Static Library (.a)
|
|
152
|
+
```bash
|
|
153
|
+
gcc -c -O3 adder16.c -o adder16.o
|
|
154
|
+
ar rcs libadder16.a adder16.o
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### With a Test Harness
|
|
158
|
+
```bash
|
|
159
|
+
gcc -O3 adder16.c test_harness.c -o test_adder
|
|
160
|
+
./test_adder
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Benefits
|
|
164
|
+
|
|
165
|
+
1. **Testability**: Write comprehensive test suites in any language
|
|
166
|
+
2. **CI Integration**: Automate testing on every commit
|
|
167
|
+
3. **Property Testing**: Use tools like Hypothesis (Python) or QuickCheck (Haskell)
|
|
168
|
+
4. **Fuzzing**: Feed random inputs to find edge cases
|
|
169
|
+
5. **Performance Benchmarking**: Measure throughput easily
|
|
170
|
+
6. **Debugging**: Inspect intermediate signals at any point
|
|
171
|
+
|
|
172
|
+
## Internal State Access
|
|
173
|
+
|
|
174
|
+
You can also peek at internal state vectors for debugging:
|
|
175
|
+
|
|
176
|
+
```c
|
|
177
|
+
uint64_t xor_state = peek("XOR_O_0");
|
|
178
|
+
uint64_t and_state = peek("AND_O_0");
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
This is useful for understanding the internal behavior of complex designs.
|
|
182
|
+
|
|
183
|
+
```c
|
|
184
|
+
reset();
|
|
185
|
+
poke("A", 42);
|
|
186
|
+
poke("B", 17);
|
|
187
|
+
poke("Cin", 1);
|
|
188
|
+
step(4);
|
|
189
|
+
printf("Sum=%llu\n", peek("Sum"));
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Future Enhancements
|
|
193
|
+
|
|
194
|
+
Potential additions to the library API:
|
|
195
|
+
|
|
196
|
+
- **VCD Generation**: Full waveform dumping for debugging.
|
|
197
|
+
- **GPIO Support**: Simulate your circuit with real pins.
|
|
198
|
+
- **GDB like Debugging**: Would be awesome.
|
|
199
|
+
- **Verilog Support**: Compile to Verilog for synthesis or simulation.
|
|
200
|
+
|