nsqdriver 0.2.6__py3-none-any.whl → 0.3.0__py3-none-any.whl
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.
Potentially problematic release.
This version of nsqdriver might be problematic. Click here for more details.
- nsqdriver/NS_MCI.py +17 -1
- nsqdriver/NS_QSYNC.py +20 -1
- nsqdriver/__init__.py +3 -2
- nsqdriver/compiler/__init__.py +0 -0
- nsqdriver/compiler/ns_wave.py +483 -0
- nsqdriver/compiler/py_wave_asm.py +538 -0
- nsqdriver/wrapper/BD_NSMCI.py +310 -0
- {nsqdriver-0.2.6.dist-info → nsqdriver-0.3.0.dist-info}/METADATA +2 -4
- nsqdriver-0.3.0.dist-info/RECORD +17 -0
- nsqdriver-0.2.6.dist-info/RECORD +0 -13
- {nsqdriver-0.2.6.dist-info → nsqdriver-0.3.0.dist-info}/WHEEL +0 -0
- {nsqdriver-0.2.6.dist-info → nsqdriver-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
import struct
|
|
2
|
+
import copy
|
|
3
|
+
import uuid
|
|
4
|
+
from typing import Union, List, Tuple, Dict
|
|
5
|
+
from enum import IntEnum
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from itertools import chain
|
|
8
|
+
from collections import ChainMap
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import waveforms as wf
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'AssemblyError', 'GenTagMixin', 'Assembler', 'NSQCommand',
|
|
15
|
+
'QInsWait', 'QInsWaitTrig', 'QInsEnd', 'QInsFrame', 'QInsEnvelop',
|
|
16
|
+
'QInsJumpWithJudge', 'QInsJump', 'QInsJumpWithReg', 'QInsCapture',
|
|
17
|
+
'QInsMov', 'QInsIncPhase', 'QInsPlayZero', 'QInsPlayWave', 'QInsResetF',
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
global_config = {
|
|
21
|
+
'play_zero_step': 4e-9,
|
|
22
|
+
'OUTSrate': 8e9,
|
|
23
|
+
'envelope_dtype': np.int16, # 描述包络每个点的数据类型
|
|
24
|
+
'envelope_step': 64, # 包络步进粒度,单位为bytes
|
|
25
|
+
'envelope_quant': 16383, # 包络量化范围
|
|
26
|
+
'envelope_cache': 204800, # 包络缓存大小,单位bytes
|
|
27
|
+
'envelope_head': np.array([2, 0, 0, 512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=np.int16), # 包络更新包头
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AssemblyError(RuntimeError):
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class GenTagMixin:
|
|
36
|
+
@property
|
|
37
|
+
def generate_tag(self):
|
|
38
|
+
return uuid.uuid4().hex[:10]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class NSQCommand:
|
|
43
|
+
"""!
|
|
44
|
+
所有参数化波形指令队列的基类
|
|
45
|
+
"""
|
|
46
|
+
tag: str = field(kw_only=True)
|
|
47
|
+
|
|
48
|
+
def _check_attr(self):
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
def __bytes__(self):
|
|
52
|
+
self._check_attr()
|
|
53
|
+
cmd = self._pack_cmd()
|
|
54
|
+
return self.list2bytes(cmd)
|
|
55
|
+
|
|
56
|
+
def _pack_cmd(self) -> list:
|
|
57
|
+
return [0x00, 0, 0, 0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def overhead(self):
|
|
61
|
+
return 16e-9
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def list2bytes(cmd: list):
|
|
65
|
+
cmd += [0x00] * 8
|
|
66
|
+
cmd_raw = struct.pack('=BBIIHHHII' + 'B' * 8, *cmd)
|
|
67
|
+
return cmd_raw
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def frequency_normalization32(freq) -> np.uint32:
|
|
71
|
+
return np.uint32(round(freq / global_config['OUTSrate'] * (1 << 32)))
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def phase_normalization32(phase) -> np.uint32:
|
|
75
|
+
return np.uint32(round(np.fmod(np.fmod(phase / np.pi / 2, 1) + 1, 1) * (1 << 32)))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class _ProbeCommand:
|
|
80
|
+
tag: str = field(kw_only=True)
|
|
81
|
+
|
|
82
|
+
def _check_attr(self):
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
def __bytes__(self):
|
|
86
|
+
self._check_attr()
|
|
87
|
+
cmd = self._pack_cmd()
|
|
88
|
+
return self.list2bytes(cmd)
|
|
89
|
+
|
|
90
|
+
def _pack_cmd(self) -> list:
|
|
91
|
+
return [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000]
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def overhead(self):
|
|
95
|
+
return 16e-9
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def list2bytes(cmd: list):
|
|
99
|
+
cmd_raw = struct.pack('=HHHHHHHH', *cmd[::-1])
|
|
100
|
+
return cmd_raw
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class QInsEnvelop(NSQCommand):
|
|
105
|
+
envelop: Union[np.ndarray, wf.Waveform]
|
|
106
|
+
|
|
107
|
+
def __post_init__(self):
|
|
108
|
+
self.envelop_slice = slice(0, None, 1)
|
|
109
|
+
|
|
110
|
+
def __bytes__(self):
|
|
111
|
+
if isinstance(self.envelop, wf.Waveform):
|
|
112
|
+
if self.envelop.start is None or self.envelop.stop is None:
|
|
113
|
+
raise AssemblyError(f'When the type of {self.__class__.__name__}.envelop is wf.Waveform, '
|
|
114
|
+
f'it must have start and stop attributes')
|
|
115
|
+
wave = self.envelop.sample(global_config['OUTSrate'])
|
|
116
|
+
elif isinstance(self.envelop, np.ndarray):
|
|
117
|
+
wave = self.envelop
|
|
118
|
+
else:
|
|
119
|
+
raise AssemblyError(f'The type of {self.__class__.__name__}.envelop must be one of np.ndarray or wf.Waveform')
|
|
120
|
+
wave *= global_config['envelope_quant']
|
|
121
|
+
return wave.astype(global_config['envelope_dtype']).tobytes()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class QInsFrame(NSQCommand):
|
|
126
|
+
freq: float
|
|
127
|
+
|
|
128
|
+
def __post_init__(self):
|
|
129
|
+
self.frame_idx = 0
|
|
130
|
+
|
|
131
|
+
def _pack_cmd(self) -> list:
|
|
132
|
+
return [0x11, self.frame_idx * 4 + 0, self.frequency_normalization32(self.freq),
|
|
133
|
+
0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclass
|
|
137
|
+
class QInsResetF(NSQCommand):
|
|
138
|
+
type: str
|
|
139
|
+
frame: str = ''
|
|
140
|
+
|
|
141
|
+
def __post_init__(self):
|
|
142
|
+
self.frame_idx = 0
|
|
143
|
+
self.type2head = {'all': 0x51, 'single': 0x41, 'phase': 0x31}
|
|
144
|
+
|
|
145
|
+
def _pack_cmd(self) -> list:
|
|
146
|
+
head = self.type2head.get(self.type.lower(), None)
|
|
147
|
+
if head is None:
|
|
148
|
+
raise AssemblyError(f'{self.__class__.__name__}.type can only be one of {self.type2head.keys()}')
|
|
149
|
+
return [head, self.frame_idx * 4, 0, 0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@dataclass
|
|
153
|
+
class QInsMov(NSQCommand):
|
|
154
|
+
reg: int
|
|
155
|
+
value: int
|
|
156
|
+
type: str = '='
|
|
157
|
+
|
|
158
|
+
def __post_init__(self):
|
|
159
|
+
self.type2head = {'=': 0x38, '+': 0x48}
|
|
160
|
+
|
|
161
|
+
def _pack_cmd(self) -> list:
|
|
162
|
+
head = self.type2head.get(self.type, None)
|
|
163
|
+
if head is None:
|
|
164
|
+
raise AssemblyError(f'{self.__class__.__name__}.type can only be one of {self.type2head.keys()}')
|
|
165
|
+
return [head, self.reg, self.value, 0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@dataclass
|
|
169
|
+
class QInsWaitTrig(NSQCommand):
|
|
170
|
+
def _pack_cmd(self) -> list:
|
|
171
|
+
return [0xF4, 0, 0, 0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@dataclass
|
|
175
|
+
class QInsIncPhase(NSQCommand):
|
|
176
|
+
phase: float
|
|
177
|
+
frame: str
|
|
178
|
+
|
|
179
|
+
def __post_init__(self):
|
|
180
|
+
self.frame_idx = 0
|
|
181
|
+
|
|
182
|
+
def _pack_cmd(self) -> list:
|
|
183
|
+
return [0x21, self.frame_idx * 4 + 1, self.phase_normalization32(self.phase),
|
|
184
|
+
0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@dataclass
|
|
188
|
+
class QInsPlayZero(NSQCommand):
|
|
189
|
+
width: float
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def overhead(self):
|
|
193
|
+
return self.width
|
|
194
|
+
|
|
195
|
+
def _pack_cmd(self) -> list:
|
|
196
|
+
frames = round(self.width / global_config['play_zero_step'])
|
|
197
|
+
return [0x44, 0, 0, frames, 0, 0x0000, 0x0000, 0, 0]
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@dataclass
|
|
201
|
+
class QInsPlayWave(NSQCommand):
|
|
202
|
+
frame: str
|
|
203
|
+
envelop: str
|
|
204
|
+
amp: float
|
|
205
|
+
attach_freq: float
|
|
206
|
+
attach_phase: float
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def overhead(self):
|
|
210
|
+
return self.envelop_slice.step/global_config['OUTSrate']
|
|
211
|
+
|
|
212
|
+
def __post_init__(self):
|
|
213
|
+
self.frame_idx = 0
|
|
214
|
+
self.envelop_slice = slice(0, None, 1)
|
|
215
|
+
|
|
216
|
+
def _pack_cmd(self) -> list:
|
|
217
|
+
return [
|
|
218
|
+
0x04, self.frame_idx * 4,
|
|
219
|
+
np.uint32(self.envelop_slice.start / global_config['envelope_step']),
|
|
220
|
+
np.uint32(self.envelop_slice.step / global_config['envelope_step']),
|
|
221
|
+
np.int32(self.amp * (1 << 15)), 0x0000, 0x0000,
|
|
222
|
+
self.frequency_normalization32(self.attach_freq),
|
|
223
|
+
self.phase_normalization32(self.attach_phase)
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@dataclass
|
|
228
|
+
class QInsWait(NSQCommand):
|
|
229
|
+
def _pack_cmd(self) -> list:
|
|
230
|
+
return [0x00, 0, 0, 0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@dataclass
|
|
234
|
+
class QInsJump(NSQCommand):
|
|
235
|
+
target: str
|
|
236
|
+
|
|
237
|
+
def __post_init__(self):
|
|
238
|
+
self.ins_idx = 0
|
|
239
|
+
|
|
240
|
+
def _pack_cmd(self) -> list:
|
|
241
|
+
return [0x18, 0, 0, self.ins_idx, 0, 0x0000, 0x0000, 0, 0]
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@dataclass
|
|
245
|
+
class QInsJumpWithReg(NSQCommand):
|
|
246
|
+
reg: int
|
|
247
|
+
value: int
|
|
248
|
+
target: str
|
|
249
|
+
|
|
250
|
+
def __post_init__(self):
|
|
251
|
+
self.ins_idx = 0
|
|
252
|
+
|
|
253
|
+
def _pack_cmd(self) -> list:
|
|
254
|
+
return [0x28, self.reg, self.value, self.ins_idx, 0, 0x0000, 0x0000, 0, 0]
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
@dataclass
|
|
258
|
+
class QInsJumpWithJudge(NSQCommand):
|
|
259
|
+
value: int
|
|
260
|
+
mask: int
|
|
261
|
+
target: str
|
|
262
|
+
|
|
263
|
+
def __post_init__(self):
|
|
264
|
+
self.ins_idx = 0
|
|
265
|
+
|
|
266
|
+
def _pack_cmd(self) -> list:
|
|
267
|
+
return [0x28, 0x10, self.mask << 16 | self.value, self.ins_idx, 0, 0x0000, 0x0000, 0, 0]
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@dataclass
|
|
271
|
+
class QInsEnd(NSQCommand):
|
|
272
|
+
def _pack_cmd(self) -> list:
|
|
273
|
+
return [0xF8, 0, 0, 0x00000000, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00000000]
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@dataclass
|
|
277
|
+
class QInsCapture(NSQCommand):
|
|
278
|
+
width: float
|
|
279
|
+
probe_delay: float = 0
|
|
280
|
+
|
|
281
|
+
def __post_init__(self):
|
|
282
|
+
self.ch_flag = {'all': 3, 'ad': 2, 'da': 1}
|
|
283
|
+
|
|
284
|
+
def __bytes__(self):
|
|
285
|
+
delay_length = int(round(self.probe_delay/16e-9))
|
|
286
|
+
length = int(round(self.width/16e-9))
|
|
287
|
+
cmds = [
|
|
288
|
+
[0x0002, self.ch_flag['da'], 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, delay_length],
|
|
289
|
+
[0x0002, self.ch_flag['all'], 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, length],
|
|
290
|
+
]
|
|
291
|
+
return b''.join(self.list2bytes(cmd) for cmd in cmds)
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
def list2bytes(cmd: list):
|
|
295
|
+
cmd_raw = struct.pack('=HHHHHHHH', *cmd[::-1])
|
|
296
|
+
return cmd_raw
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@dataclass
|
|
300
|
+
class _QInsPTrigDelay(_ProbeCommand):
|
|
301
|
+
tag: str = field(kw_only=True)
|
|
302
|
+
delay: float
|
|
303
|
+
|
|
304
|
+
def __post_init__(self):
|
|
305
|
+
self.ch_flag = {'all': 3, 'ad': 2, 'da': 1}
|
|
306
|
+
|
|
307
|
+
def _pack_cmd(self) -> list:
|
|
308
|
+
length = int(round(self.delay / 16e-9))
|
|
309
|
+
return [0x0002, self.ch_flag['all'], 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, length]
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
@dataclass
|
|
313
|
+
class _QInsPWaitTrig(_ProbeCommand):
|
|
314
|
+
def _pack_cmd(self) -> list:
|
|
315
|
+
return [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000]
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@dataclass
|
|
319
|
+
class _QInsPJump(_ProbeCommand):
|
|
320
|
+
target: str
|
|
321
|
+
|
|
322
|
+
def __post_init__(self):
|
|
323
|
+
self.ins_idx = 0
|
|
324
|
+
|
|
325
|
+
def _pack_cmd(self) -> list:
|
|
326
|
+
return [0x0003, 0x0000, 0x0000, self.ins_idx, 0x0000, 0x0000, 0x0000, 0x0000]
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class Assembler(GenTagMixin):
|
|
330
|
+
def __init__(self, ch_map=None):
|
|
331
|
+
if ch_map is None:
|
|
332
|
+
ch_map = {
|
|
333
|
+
1: [3, 4, 5, 6, 7, 8],
|
|
334
|
+
2: [11, 12, 13, 14, 15, 16]
|
|
335
|
+
}
|
|
336
|
+
self.ch_map = ch_map
|
|
337
|
+
self.drive2probe = {j: i for i in ch_map.keys() for j in ch_map[i]}
|
|
338
|
+
self.raw_cmdq = {j: [] for i in ch_map.values() for j in i}
|
|
339
|
+
self.probe_cmdq = {i: [] for i in ch_map.keys()}
|
|
340
|
+
self.drive_cmdq = {j: [] for i in ch_map.values() for j in i}
|
|
341
|
+
|
|
342
|
+
self.envelop_cache = {
|
|
343
|
+
j: np.zeros((global_config['envelope_cache'] // 2,), dtype=np.int16) for i in ch_map.values() for j in i
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
self.frame_symbol = {j: {} for i in ch_map.values() for j in i}
|
|
347
|
+
self.envelop_symbol = {j: {} for i in ch_map.values() for j in i}
|
|
348
|
+
self.drive_symbol = {j: {} for i in ch_map.values() for j in i}
|
|
349
|
+
self.probe_symbol = {i: {} for i in ch_map.keys()}
|
|
350
|
+
|
|
351
|
+
def set_chnl_cmdq(self, ch_id, cmdq):
|
|
352
|
+
if ch_id not in self.drive2probe:
|
|
353
|
+
raise AssemblyError(f'OUT channel {ch_id} does not exist')
|
|
354
|
+
self.raw_cmdq[ch_id] = cmdq
|
|
355
|
+
self.envelop_symbol[ch_id], cmdq = self.extract_envelop(ch_id, cmdq)
|
|
356
|
+
self.frame_symbol[ch_id] = self.extract_frame(cmdq)
|
|
357
|
+
(self.drive_cmdq[ch_id], self.probe_cmdq[self.drive2probe[ch_id]],
|
|
358
|
+
self.drive_symbol[ch_id], self.probe_symbol[self.drive2probe[ch_id]]) = self.divide_cmd(ch_id, cmdq)
|
|
359
|
+
|
|
360
|
+
def extract_envelop(self, ch_id, cmdq: List[NSQCommand]) -> "Tuple[dict, List[NSQCommand]]":
|
|
361
|
+
"""!
|
|
362
|
+
在指令队列中提取包络指令,并建立符号表
|
|
363
|
+
|
|
364
|
+
@param ch_id:
|
|
365
|
+
@param cmdq:
|
|
366
|
+
@return:
|
|
367
|
+
"""
|
|
368
|
+
res_cmdq, envelops = [], []
|
|
369
|
+
for cmd in cmdq:
|
|
370
|
+
if not isinstance(cmd, QInsEnvelop):
|
|
371
|
+
res_cmdq.append(copy.copy(cmd))
|
|
372
|
+
else:
|
|
373
|
+
envelops.append(cmd)
|
|
374
|
+
|
|
375
|
+
cache = self.envelop_cache[ch_id]
|
|
376
|
+
# 给cache头部打上包络更新指令包头
|
|
377
|
+
cache[:16] = global_config['envelope_head']
|
|
378
|
+
data_cache = cache[16:]
|
|
379
|
+
data_cache[:] = 0
|
|
380
|
+
|
|
381
|
+
start = 0
|
|
382
|
+
symbol_map = {}
|
|
383
|
+
for env in envelops:
|
|
384
|
+
wave = bytes(env)
|
|
385
|
+
length = len(wave)
|
|
386
|
+
end = start + length
|
|
387
|
+
data_cache[start//2:end//2] = np.frombuffer(wave, dtype=global_config['envelope_dtype'])
|
|
388
|
+
env.envelop_slice = slice(start, end, length)
|
|
389
|
+
start += length
|
|
390
|
+
symbol_map[env.tag] = env
|
|
391
|
+
return symbol_map, res_cmdq
|
|
392
|
+
|
|
393
|
+
@staticmethod
|
|
394
|
+
def extract_frame(cmdq: List[NSQCommand]) -> "dict":
|
|
395
|
+
"""!
|
|
396
|
+
在指令队列中提取包络配置指令,并且建立包络符号表
|
|
397
|
+
|
|
398
|
+
@param cmdq:
|
|
399
|
+
@return:
|
|
400
|
+
"""
|
|
401
|
+
frames = []
|
|
402
|
+
for cmd in cmdq:
|
|
403
|
+
if not isinstance(cmd, QInsFrame):
|
|
404
|
+
continue
|
|
405
|
+
frames.append(cmd)
|
|
406
|
+
|
|
407
|
+
symbol_map = {}
|
|
408
|
+
for idx, frame in enumerate(frames):
|
|
409
|
+
frame.frame_idx = idx
|
|
410
|
+
symbol_map[frame.tag] = frame
|
|
411
|
+
return symbol_map
|
|
412
|
+
|
|
413
|
+
def divide_cmd(self, ch_id, cmdq) -> "Tuple[list, list, dict, dict]":
|
|
414
|
+
"""!
|
|
415
|
+
|
|
416
|
+
@param ch_id:
|
|
417
|
+
@param cmdq:
|
|
418
|
+
@return:
|
|
419
|
+
"""
|
|
420
|
+
drive_queue, probe_queue, drive_symbol, probe_symbol = self._link_wave(ch_id, cmdq)
|
|
421
|
+
drive_queue, drive_symbol = self._optimize_drive_q(drive_queue, drive_symbol)
|
|
422
|
+
probe_queue, probe_symbol = self._optimize_probe_q(probe_queue)
|
|
423
|
+
drive_queue, probe_queue = self._link_jump(drive_queue, probe_queue, drive_symbol, probe_symbol)
|
|
424
|
+
return drive_queue, probe_queue, drive_symbol, probe_symbol
|
|
425
|
+
|
|
426
|
+
def _link_wave(self, ch_id, cmdq):
|
|
427
|
+
"""!
|
|
428
|
+
建立frame和envelop到指令的关联,并生成基础的指令符号表,初步分割drive与probe的指令
|
|
429
|
+
|
|
430
|
+
@param ch_id:
|
|
431
|
+
@param cmdq:
|
|
432
|
+
@return:
|
|
433
|
+
"""
|
|
434
|
+
symbols = ChainMap(self.frame_symbol[ch_id], self.envelop_symbol[ch_id])
|
|
435
|
+
drive_queue, probe_queue, drive_symbol, probe_symbol = [], [], {}, {}
|
|
436
|
+
probe_queue.append(_QInsPWaitTrig(tag=self.generate_tag))
|
|
437
|
+
probe_symbol[probe_queue[-1].tag] = 0
|
|
438
|
+
|
|
439
|
+
for cmd in cmdq:
|
|
440
|
+
if hasattr(cmd, 'frame_idx') and hasattr(cmd, 'frame'):
|
|
441
|
+
frame: QInsFrame = symbols.get(cmd.frame, None)
|
|
442
|
+
if frame is None:
|
|
443
|
+
raise AssemblyError(f'The frame tag required by instruction {cmd} '
|
|
444
|
+
f'does not exist in the instruction queue of channel {ch_id}')
|
|
445
|
+
cmd.frame_idx = frame.frame_idx
|
|
446
|
+
if hasattr(cmd, 'envelop_slice') and hasattr(cmd, 'envelop'):
|
|
447
|
+
envelop: QInsEnvelop = symbols.get(cmd.envelop, None)
|
|
448
|
+
if envelop is None:
|
|
449
|
+
raise AssemblyError(f'The envelop tag required by instruction {cmd} '
|
|
450
|
+
f'does not exist in the instruction queue of channel {ch_id}')
|
|
451
|
+
cmd.envelop_slice = envelop.envelop_slice
|
|
452
|
+
if isinstance(cmd, QInsCapture):
|
|
453
|
+
# 这里要保证占capture位置的playzero指令依然能被跳转
|
|
454
|
+
wait = QInsPlayZero(tag=cmd.tag, width=cmd.width + cmd.probe_delay)
|
|
455
|
+
cmd.tag = self.generate_tag
|
|
456
|
+
drive_queue.append(wait)
|
|
457
|
+
probe_queue.append(cmd)
|
|
458
|
+
else:
|
|
459
|
+
wait = _QInsPTrigDelay(tag=self.generate_tag, delay=cmd.overhead)
|
|
460
|
+
drive_queue.append(cmd)
|
|
461
|
+
probe_queue.append(wait)
|
|
462
|
+
drive_symbol[drive_queue[-1].tag] = len(drive_queue)-1
|
|
463
|
+
probe_symbol[probe_queue[-1].tag] = len(probe_queue)-1
|
|
464
|
+
probe_queue.append(_QInsPJump(target=probe_queue[0].tag, tag=self.generate_tag))
|
|
465
|
+
probe_symbol[probe_queue[-1].tag] = len(probe_queue)-1
|
|
466
|
+
return drive_queue, probe_queue, drive_symbol, probe_symbol
|
|
467
|
+
|
|
468
|
+
def _link_jump(self, drive_queue: List[NSQCommand], probe_queue, drive_symbol, probe_symbol):
|
|
469
|
+
"""!
|
|
470
|
+
连接指令队列中的跳转指令
|
|
471
|
+
|
|
472
|
+
@param drive_queue:
|
|
473
|
+
@param probe_queue:
|
|
474
|
+
@return:
|
|
475
|
+
"""
|
|
476
|
+
for cmd in drive_queue:
|
|
477
|
+
if hasattr(cmd, 'ins_idx') and hasattr(cmd, 'target'):
|
|
478
|
+
cmd.ins_idx = drive_symbol[cmd.target]
|
|
479
|
+
|
|
480
|
+
for cmd in probe_queue:
|
|
481
|
+
if hasattr(cmd, 'ins_idx') and hasattr(cmd, 'target'):
|
|
482
|
+
cmd.ins_idx = probe_symbol[cmd.target]
|
|
483
|
+
return drive_queue, probe_queue
|
|
484
|
+
|
|
485
|
+
def _optimize_probe_q(self, queue):
|
|
486
|
+
"""!
|
|
487
|
+
优化probe指令队列
|
|
488
|
+
|
|
489
|
+
@param queue:
|
|
490
|
+
@param symbol:
|
|
491
|
+
@return:
|
|
492
|
+
"""
|
|
493
|
+
symbol, idx = {}, 0
|
|
494
|
+
cache = []
|
|
495
|
+
res_q = []
|
|
496
|
+
# 合并所有相邻的_QInsProbeDelay,减少指令队列长度
|
|
497
|
+
for cmd in queue:
|
|
498
|
+
if isinstance(cmd, _QInsPTrigDelay):
|
|
499
|
+
cache.append(cmd)
|
|
500
|
+
else:
|
|
501
|
+
delay = _QInsPTrigDelay(tag=self.generate_tag, delay=sum(i.delay for i in cache))
|
|
502
|
+
if delay.delay != 0:
|
|
503
|
+
res_q.append(delay)
|
|
504
|
+
symbol[delay.tag] = idx
|
|
505
|
+
idx += 1
|
|
506
|
+
res_q.append(cmd)
|
|
507
|
+
symbol[cmd.tag] = idx
|
|
508
|
+
idx += 1
|
|
509
|
+
cache = []
|
|
510
|
+
return res_q, symbol
|
|
511
|
+
|
|
512
|
+
def _optimize_drive_q(self, queue, symbol):
|
|
513
|
+
"""!
|
|
514
|
+
优化drive指令队列
|
|
515
|
+
|
|
516
|
+
@param queue:
|
|
517
|
+
@param symbol:
|
|
518
|
+
@return:
|
|
519
|
+
"""
|
|
520
|
+
return queue, symbol
|
|
521
|
+
|
|
522
|
+
def assemble(self) -> "Tuple[dict, dict, dict]":
|
|
523
|
+
envelop_cache = {}
|
|
524
|
+
drive_cache = {}
|
|
525
|
+
for pch, dch_list in self.ch_map.items():
|
|
526
|
+
memory = np.zeros((10240 * 8 * len(dch_list), ), dtype=np.uint32).reshape((len(dch_list), 8*10240))
|
|
527
|
+
for idx, ch in enumerate(dch_list):
|
|
528
|
+
_data = np.frombuffer(b''.join(bytes(i) for i in self.drive_cmdq[ch]), dtype=np.int32)
|
|
529
|
+
memory[idx, :_data.size] = _data
|
|
530
|
+
drive_cache[pch] = memory
|
|
531
|
+
envelop_cache[pch] = np.array([self.envelop_cache[ch] for ch in dch_list], dtype=np.int16)
|
|
532
|
+
|
|
533
|
+
probe_cache = {}
|
|
534
|
+
for pch, queue in self.probe_cmdq.items():
|
|
535
|
+
memory = np.frombuffer(b''.join(bytes(i) for i in queue), dtype=np.int32)
|
|
536
|
+
probe_cache[pch] = memory
|
|
537
|
+
|
|
538
|
+
return envelop_cache, drive_cache, probe_cache
|