aboutsummaryrefslogtreecommitdiffstats
path: root/backends/cxxrtl/cxxrtl_capi.h
blob: 447c9e1f383d427223bebee909e93ba6e3c2f8d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2020  whitequark <whitequark@whitequark.org>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef CXXRTL_CAPI_H
#define CXXRTL_CAPI_H

// This file is a part of the CXXRTL C API. It should be used together with `cxxrtl_capi.cc`.
//
// The CXXRTL C API makes it possible to drive CXXRTL designs using C or any other language that
// supports the C ABI, for example, Python. It does not provide a way to implement black boxes.

#include <stddef.h>
#include <stdint.h>
#include <assert.h>

#ifdef __cplusplus
extern "C" {
#endif

// Opaque reference to a design toplevel.
//
// A design toplevel can only be used to create a design handle.
typedef struct _cxxrtl_toplevel *cxxrtl_toplevel;

// The constructor for a design toplevel is provided as a part of generated code for that design.
// Its prototype matches:
//
// cxxrtl_toplevel <design-name>_create();

// Opaque reference to a design handle.
//
// A design handle is required by all operations in the C API.
typedef struct _cxxrtl_handle *cxxrtl_handle;

// Create a design handle from a design toplevel.
//
// The `design` is consumed by this operation and cannot be used afterwards.
cxxrtl_handle cxxrtl_create(cxxrtl_toplevel design);

// Release all resources used by a design and its handle.
void cxxrtl_destroy(cxxrtl_handle handle);

// Evaluate the design, propagating changes on inputs to the `next` value of internal state and
// output wires.
//
// Returns 1 if the design is known to immediately converge, 0 otherwise.
int cxxrtl_eval(cxxrtl_handle handle);

// Commit the design, replacing the `curr` value of internal state and output wires with the `next`
// value.
//
// Return 1 if any of the `curr` values were updated, 0 otherwise.
int cxxrtl_commit(cxxrtl_handle handle);

// Simulate the design to a fixed point.
//
// Returns the number of delta cycles.
size_t cxxrtl_step(cxxrtl_handle handle);

// Type of a simulated object.
enum cxxrtl_type {
	// Values correspond to singly buffered netlist nodes, i.e. nodes driven exclusively by
	// combinatorial cells, or toplevel input nodes.
	//
	// Values can be inspected via the `curr` pointer. If the `next` pointer is NULL, the value is
	// driven by a constant and can never be modified. Otherwise, the value can be modified through
	// the `next` pointer (which is equal to `curr` if not NULL). Note that changes to the bits
	// driven by combinatorial cells will be ignored.
	//
	// Values always have depth 1.
	CXXRTL_VALUE = 0,

	// Wires correspond to doubly buffered netlist nodes, i.e. nodes driven, at least in part, by
	// storage cells, or by combinatorial cells that are a part of a feedback path.
	//
	// Wires can be inspected via the `curr` pointer and modified via the `next` pointer (which are
	// distinct for wires). Note that changes to the bits driven by combinatorial cells will be
	// ignored.
	//
	// Wires always have depth 1.
	CXXRTL_WIRE = 1,

	// Memories correspond to memory cells.
	//
	// Memories can be inspected and modified via the `curr` pointer. Due to a limitation of this
	// API, memories cannot yet be modified in a guaranteed race-free way, and the `next` pointer is
	// always NULL.
	CXXRTL_MEMORY = 2,

	// Aliases correspond to netlist nodes driven by another node such that their value is always
	// exactly equal.
	//
	// Aliases can be inspected via the `curr` pointer. They cannot be modified, and the `next`
	// pointer is always NULL.
	CXXRTL_ALIAS = 3,

	// More object types may be added in the future, but the existing ones will never change.
};

// Description of a simulated object.
//
// The `data` array can be accessed directly to inspect and, if applicable, modify the bits
// stored in the object.
struct cxxrtl_object {
	// Type of the object.
	//
	// All objects have the same memory layout determined by `width` and `depth`, but the type
	// determines all other properties of the object.
	uint32_t type; // actually `enum cxxrtl_type`

	// Width of the object in bits.
	size_t width;

	// Index of the least significant bit.
	size_t lsb_at;

	// Depth of the object. Only meaningful for memories; for other objects, always 1.
	size_t depth;

	// Index of the first word. Only meaningful for memories; for other objects, always 0;
	size_t zero_at;

	// Bits stored in the object, as 32-bit chunks, least significant bits first.
	//
	// The width is rounded up to a multiple of 32; the padding bits are always set to 0 by
	// the simulation code, and must be always written as 0 when modified by user code.
	// In memories, every element is stored contiguously. Therefore, the total number of chunks
	// in any object is `((width + 31) / 32) * depth`.
	//
	// To allow the simulation to be partitioned into multiple independent units communicating
	// through wires, the bits are double buffered. To avoid race conditions, user code should
	// always read from `curr` and write to `next`. The `curr` pointer is always valid; for objects
	// that cannot be modified, or cannot be modified in a race-free way, `next` is NULL.
	uint32_t *curr;
	uint32_t *next;

	// More description fields may be added in the future, but the existing ones will never change.
};

// Retrieve description of a simulated object.
//
// The `name` is the full hierarchical name of the object in the Yosys notation, where public names
// have a `\` prefix and hierarchy levels are separated by single spaces. For example, if
// the top-level module instantiates a module `foo`, which in turn contains a wire `bar`, the full
// hierarchical name is `\foo \bar`.
//
// The storage of a single abstract object may be split (usually with the `splitnets` pass) into
// many physical parts, all of which correspond to the same hierarchical name. To handle such cases,
// this function returns an array and writes its length to `parts`. The array is sorted by `lsb_at`.
//
// Returns the object parts if it was found, NULL otherwise. The returned parts are valid until
// the design is destroyed.
struct cxxrtl_object *cxxrtl_get_parts(cxxrtl_handle handle, const char *name, size_t *parts);

// Retrieve description of a single part simulated object.
//
// This function is a shortcut for the most common use of `cxxrtl_get_parts`. It asserts that,
// if the object exists, it consists of a single part. If assertions are disabled, it returns NULL
// for multi-part objects.
inline struct cxxrtl_object *cxxrtl_get(cxxrtl_handle handle, const char *name) {
	size_t parts = 0;
	struct cxxrtl_object *object = cxxrtl_get_parts(handle, name, &parts);
	assert(object == NULL || parts == 1);
	if (object == NULL || parts == 1)
		return object;
	return NULL;
}

// Enumerate simulated objects.
//
// For every object in the simulation, `callback` is called with the provided `data`, the full
// hierarchical name of the object (see `cxxrtl_get` for details), and the object parts.
// The provided `name` and `object` values are valid until the design is destroyed.
void cxxrtl_enum(cxxrtl_handle handle, void *data,
                 void (*callback)(void *data, const char *name,
                                  struct cxxrtl_object *object, size_t parts));

#ifdef __cplusplus
}
#endif

#endif