forked from grandideastudio/jtagulator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPropSUMP.spin
608 lines (484 loc) · 20.9 KB
/
PropSUMP.spin
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
{{
+-------------------------------------------------+
| SUMP-compatible Logic Analyzer |
| Interface Object |
| |
| Authors: Ben Gardiner & Joe Grand |
| Copyright (c) 2015-2020 Ben Gardiner |
| Copyright (c) 2018-2020 Joe Grand |
| |
| Distributed under a Creative Commons |
| Attribution 3.0 United States license |
| http://creativecommons.org/licenses/by/3.0/us/ |
+-------------------------------------------------+
Program Description:
This object provides the low-level communication interface for the SUMP-compatible
logic analyzer functionality (http://sigrok.org/wiki/Openbench_Logic_Sniffer#Protocol
and http://dangerousprototypes.com/docs/Logic_Analyzer_core:_Background#2.3_The_SUMP_Protocol)
TODOs:
* don't waste 1024B of the 4096B buffer
* capture pre-trigger samples
* support trigger delays
* support serial trigger mode
* support RLE
}}
CON
' Serial terminal
BaudRate = 115_200
RxPin = |<31
TxPin = |<30
' Control characters
CAN = 24 ''CAN: Cancel (Ctrl-X)
MAX_INPUT_LEN = 5 'SUMP long commands are five bytes
MAX_SAMPLE_BYTES = 4096
MAX_PROBES = 24
MAX_CH_GROUPS = MAX_PROBES / 8
MAX_SAMPLE_PERIODS = MAX_SAMPLE_BYTES / 4 'We capture 32bits at a time keep the sampler cog fast(er than it would be otherwise)
'TODO: don't waste 25% of the buffer *AND* get a >1Msps max sample rate :)
MAX_RX_DELAY_MS = 100 'Wait time (in ms) for the each byte in long commands to be sent before aborting
' used to convert between the protocol requests based on the OLS 100MHz clock and the JTAGulator's 80MHz clock
SR_FACTOR_NUM = 4 ' 80E6/100E6 = 4/5
SR_FACTOR_DEN = 5
CMD_RESET = $00 ' reset
CMD_RUN = $01 ' start capture or arm trigger
CMD_QUERY_ID = $02 ' query device identification
CMD_QUERY_META = $04 ' query metadata
CMD_QUERY_INPUT_DATA = $06 ' query input data (snapshot of current logic analyzer channels)
CMD_DIV = $80 ' set divider
CMD_CNT = $81 ' set read & delay count
CMD_FLAGS = $82 ' set flags
CMD_TRIG1_MASK = $C0 ' set trigger mask
CMD_TRIG2_MASK = $C4
CMD_TRIG3_MASK = $C8
CMD_TRIG4_MASK = $CC
CMD_TRIG1_VAL = $C1 ' set trigger values
CMD_TRIG2_VAL = $C5
CMD_TRIG3_VAL = $C9
CMD_TRIG4_VAL = $CD
CMD_TRIG1_CONF = $C2 ' set trigger configuration
CMD_TRIG2_CONF = $C6
CMD_TRIG3_CONF = $CA
CMD_TRIG4_CONF = $CE
DEFAULT_CLOCKS_WAIT = 66 '1.2 MHz
DEFAULT_READ_PERIODS = MAX_SAMPLE_PERIODS
DEFAULT_DELAY_PERIODS = DEFAULT_READ_PERIODS
DEFAULT_DISABLE_FLAGS = %00100000 ' disable ch group 4
DISABLE_FLAGS_MASK = %00111100
TRIGGER_CH_MASK = %00000000111111111111111111111111
VAR
long Cog ' Used to store ID of newly started cog
byte vCmd[MAX_INPUT_LEN + 1] ' Buffer for command input string
long larg
CON 'offsets of the structure below
CLOCKSWAIT_OFF = 0
READPERIODS_OFF = 4
DELAYPERIODS_OFF = 8
DISABLEFLAGS_OFF = 12
TRIG1MASK_OFF = 16
TRIG2MASK_OFF = 20
TRIG3MASK_OFF = 24
TRIG4MASK_OFF = 28
TRIG1VAL_OFF = 32
TRIG2VAL_OFF = 36
TRIG3VAL_OFF = 40
TRIG4VAL_OFF = 44
ISTRIG1START_OFF = 48
ISTRIG2START_OFF = 52
ISTRIG3START_OFF = 56
ISTRIG4START_OFF = 60
SAMPLERRUNNING_OFF = 64
SAMPLEBUFFER_OFF = 68
VAR 'This is a struct used by the sampler cog; its layout and the offsets above must be in sync
long clocksWait 'struct head
long readPeriods
long delayPeriods
long disableFlags
long trig1Mask
long trig2Mask
long trig3Mask
long trig4Mask
long trig1Val
long trig2Val
long trig3Val
long trig4Val
long isTrig1Start
long isTrig2Start
long isTrig3Start
long isTrig4Start
long samplerRunning
long sampleBuffer ' Address of global buffer from top object
OBJ
u : "JTAGulatorUtil" ' JTAGulator general purpose utilities
pst : "JDCogSerial" ' UART/Asynchronous Serial communication engine (Carl Jacobs, http://obex.parallax.com/object/298)
PRI Start ' Start a new cog to run PASM routine
Stop ' Call the Stop function, just in case the calling object called Start two times in a row
Cog := cognew(@samplerInit, @clocksWait) + 1 ' Launch the cog with a pointer to the parameters
if Cog =< 0 ' Failed to start SUMP sampler
repeat ' Repeat until system reset
u.LEDYellow
u.Pause(500)
u.LEDOff
u.Pause(500)
PRI Stop
' Stop the cog we started earlier, if any
if Cog
cogstop(Cog~ - 1)
Cog := 0
PUB Go(bufPtr) | coggood, i, isSendSamples
pst.Start(RxPin, TxPin, BaudRate) ' Configure UART
sampleBuffer := bufPtr
clocksWait:=DEFAULT_CLOCKS_WAIT
readPeriods:=DEFAULT_READ_PERIODS
delayPeriods:=DEFAULT_DELAY_PERIODS
disableFlags:=DEFAULT_DISABLE_FLAGS
trig1Mask:=0
trig2Mask:=0
trig3Mask:=0
trig4Mask:=0
trig1Val:=0
trig2Val:=0
trig3Val:=0
trig4Val:=0
isTrig1Start:=1
isTrig2Start:=1
isTrig3Start:=1
isTrig4Start:=1
samplerRunning:=0
Start ' Start sampler cog
u.LEDRed ' We are initialized and ready to go
u.TXSEnable ' Enable level shifter outputs (all channels set to inputs)
' Start command receive/process cycle
repeat
vCmd[0]:=pst.Rx
case vCmd[0]
CAN: ' If Ctrl-X (CAN) character received, exit SUMP mode
Stop ' Stop sampler cog
pst.Stop ' Stop serial communications
return ' Go back to main JTAGulator mode
'the 'short' commands follow; all are 1 byte, no parameters
CMD_RESET:
if samplerRunning ' If the sampler cog is still running, capture was likely stopped by user
samplerRunning:=0
Stop ' Stop sampler cog
Start ' Restart sampler cog
u.LEDRed
CMD_QUERY_ID:
pst.StrMax(@ID, @METADATA - @ID)
CMD_QUERY_META:
pst.StrMax(@METADATA, @END_METADATA - @METADATA + 1)
CMD_QUERY_INPUT_DATA:
SendSamples(ina[23..0])
CMD_RUN:
u.LEDYellow
i:=0
repeat while i < MAX_SAMPLE_PERIODS ' Clear buffer before starting capture
long[sampleBuffer][i++]:=$00000000
samplerRunning:=1 ' Arm the sampler cog
isSendSamples:=1 ' Send samples after successful capture
repeat until (samplerRunning == 0) ' Wait for the sampler cog to finish
vCmd[0]:=pst.RxCheck ' Check if byte is sent from client during capture
case vCmd[0]
CAN: ' If Ctrl-X (CAN) character received, exit SUMP mode
Stop ' Stop sampler cog
pst.Stop ' Stop serial communications
return ' Go back to main JTAGulator mode
CMD_RESET: ' If user canceled before trigger or acquisition is complete
isSendSamples:=0
samplerRunning:=0
Stop ' Stop sampler cog
Start ' Restart sampler cog
if isSendSamples
SendAllSamples
u.LEDRed
'remaining commands are 'long' commands, which all take 4 parameters
CMD_CNT:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[2]
larg<<=8
larg|=vCmd[1]
readPeriods:=(larg+1)*4 'the protocol doesn't indicate the +1 is needed; but sigrok's OLS API does
if readPeriods > DEFAULT_READ_PERIODS
readPeriods:=DEFAULT_READ_PERIODS
larg:=vCmd[4]
larg<<=8
larg|=vCmd[3]
delayPeriods:=(larg+1)*4 'the protocol doesn't indicate the +1 is needed; but sigrok's OLS API does
if delayPeriods > DEFAULT_DELAY_PERIODS
delayPeriods:=DEFAULT_DELAY_PERIODS
'TODO: support readPeriods > delayPeriods (i.e. capturing pre-trigger window)
if readPeriods > delayPeriods
readPeriods := delayPeriods
CMD_DIV:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[3]
larg<<=8
larg|=vCmd[2]
larg<<=8
larg|=vCmd[1]
clocksWait:=((larg+1)*SR_FACTOR_NUM)/SR_FACTOR_DEN
if clocksWait < DEFAULT_CLOCKS_WAIT ' set minimum allowable value
clocksWait:=DEFAULT_CLOCKS_WAIT
CMD_FLAGS:
if (GetFourMoreParamBytes == -1)
next
disableFlags:=vCmd[1] & DISABLE_FLAGS_MASK
CMD_TRIG1_MASK:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig1Mask:=larg & TRIGGER_CH_MASK
CMD_TRIG2_MASK:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig2Mask:=larg & TRIGGER_CH_MASK
CMD_TRIG3_MASK:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig3Mask:=larg & TRIGGER_CH_MASK
CMD_TRIG4_MASK:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig4Mask:=larg & TRIGGER_CH_MASK
CMD_TRIG1_VAL:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig1Val:=larg & TRIGGER_CH_MASK
CMD_TRIG2_VAL:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig2Val:=larg & TRIGGER_CH_MASK
CMD_TRIG3_VAL:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig3Val:=larg & TRIGGER_CH_MASK
CMD_TRIG4_VAL:
if (GetFourMoreParamBytes == -1)
next
larg:=vCmd[4]
larg<<=8
larg:=vCmd[3]
larg<<=8
larg:=vCmd[2]
larg<<=8
larg:=vCmd[1]
trig4Val:=larg & TRIGGER_CH_MASK
'TODO: support full triggers including delays and serial forms; for now support only sigrok OLS features
CMD_TRIG1_CONF:
if (GetFourMoreParamBytes == -1)
next
isTrig1Start:=(vCmd[4] & 1<<3)
CMD_TRIG2_CONF:
if (GetFourMoreParamBytes == -1)
next
isTrig2Start:=(vCmd[4] & 1<<3)
CMD_TRIG3_CONF:
if (GetFourMoreParamBytes == -1)
next
isTrig3Start:=(vCmd[4] & 1<<3)
CMD_TRIG4_CONF:
if (GetFourMoreParamBytes == -1)
next
isTrig4Start:=(vCmd[4] & 1<<3) ' NB: ignored; all 4th stage triggers start the sampler
PRI GetFourMoreParamBytes : val
if (vCmd[1]:=pst.RxTime(MAX_RX_DELAY_MS)) < 0
val:=-1
if (vCmd[2]:=pst.RxTime(MAX_RX_DELAY_MS)) < 0
val:=-1
if (vCmd[3]:=pst.RxTime(MAX_RX_DELAY_MS)) < 0
val:=-1
if (vCmd[4]:=pst.RxTime(MAX_RX_DELAY_MS)) < 0
val:=-1
PRI SendAllSamples | i 'NB: OLS sends samples in reverse
i := 0
repeat while i < readPeriods
SendSamples(long[sampleBuffer][delayPeriods - 1 - i])
++i
PRI SendSamples(value) | b
'bits: %76543210
'ch disable flag: --4321--
if disableFlags & %00000100 == 0
b:=(value) & $FF
pst.Tx(b)
'ch disable flag: --4321--
if disableFlags & %00001000 == 0
b:=(value >> 8) & $FF
pst.Tx(b)
'ch disable flag: --4321--
if disableFlags & %00010000 == 0
b:=(value >> 16) & $FF
pst.Tx(b)
'channel group 4 not currently used since JTAGulator has 24 channels (3 groups of 8-bits)
DAT
ORG
ID byte "1ALS"
METADATA byte $01, "JTAGulator", $00 ' device name
byte $21
byte $00, $00, $0c, $00 ' sample memory 3072 in MSB -- must match MAX_SAMPLE_PERIODS*MAX_CH_GROUPS
byte $23
byte $00, $12, $4F, $80 ' 1_200_000 in MSB (1.2MHz) -- highest stable sample rate
byte $40
byte MAX_PROBES ' number of probes
byte $41
byte $02 ' protocol version 2
END_METADATA byte $00
'*****************************
'* the sampler *
'*****************************
ORG 0
samplerInit MOVS samplerTramp, #samplerOff
MOV samplerRunningA, PAR
ADD samplerRunningA, #SAMPLERRUNNING_OFF
JMP #samplerCommon
'check samplerRunning; arm if set
samplerOff RDLONG t1, samplerRunningA WZ
IF_NE MOVS samplerTramp, #samplerArm
JMP #samplerCommon
samplerArm MOVS samplerTramp, #samplerArmed1
MOV samplerTargetA, PAR
ADD samplerTargetA, #SAMPLEBUFFER_OFF
RDLONG samplerTargetA, samplerTargetA ' point to the beginning of sampleBuffer
MOV t1, PAR
ADD t1, #DELAYPERIODS_OFF
RDLONG samplerLimitA, t1
SHL samplerLimitA, #2 ' we capture 4 channels at a time
ADD samplerLimitA, samplerTargetA
MOV t1, PAR
ADD t1, #CLOCKSWAIT_OFF
RDLONG samplerWait, t1
MOV t1, PAR
ADD t1, #TRIG1VAL_OFF
RDLONG samplerTrigVal, t1
MOV t1, PAR
ADD t1, #TRIG1MASK_OFF
RDLONG samplerTrigMask, t1
MOV t1, PAR
ADD t1, #ISTRIG1START_OFF
RDLONG samplerTrigStart, t1
JMP #samplerCommon
samplerArmed1 CMP samplerTrigMask, #0 WZ
IF_NE WAITPEQ samplerTrigVal, samplerTrigMask
CMP samplerTrigStart, #0 WZ
IF_NE MOVS samplerTramp, #samplerStart
IF_NE JMP #samplerCommon
MOVS samplerTramp, #samplerArmed2
MOV t1, PAR
ADD t1, #TRIG2VAL_OFF
RDLONG samplerTrigVal, t1
MOV t1, PAR
ADD t1, #TRIG2MASK_OFF
RDLONG samplerTrigMask, t1
MOV t1, PAR
ADD t1, #ISTRIG2START_OFF
RDLONG samplerTrigStart, t1
JMP #samplerCommon
samplerArmed2 CMP samplerTrigMask, #0 WZ
IF_NE WAITPEQ samplerTrigVal, samplerTrigMask
CMP samplerTrigStart, #0 WZ
IF_NE MOVS samplerTramp, #samplerStart
IF_NE JMP #samplerCommon
MOVS samplerTramp, #samplerArmed3
MOV t1, PAR
ADD t1, #TRIG3VAL_OFF
RDLONG samplerTrigVal, t1
MOV t1, PAR
ADD t1, #TRIG3MASK_OFF
RDLONG samplerTrigMask, t1
MOV t1, PAR
ADD t1, #ISTRIG3START_OFF
RDLONG samplerTrigStart, t1
JMP #samplerCommon
samplerArmed3 CMP samplerTrigMask, #0 WZ
IF_NE WAITPEQ samplerTrigVal, samplerTrigMask
CMP samplerTrigStart, #0 WZ
IF_NE MOVS samplerTramp, #samplerStart
IF_NE JMP #samplerCommon
MOVS samplerTramp, #samplerArmed4
MOV t1, PAR
ADD t1, #TRIG4VAL_OFF
RDLONG samplerTrigVal, t1
MOV t1, PAR
ADD t1, #TRIG4MASK_OFF
RDLONG samplerTrigMask, t1
JMP #samplerCommon
samplerArmed4 CMP samplerTrigMask, #0 WZ
IF_NE WAITPEQ samplerTrigVal, samplerTrigMask
MOVS samplerTramp, #samplerStart
JMP #samplerCommon
samplerStart MOVS samplerTramp, #samplerSampling
MOV samplerStamp, CNT
ADD samplerStamp, samplerWait
JMP #samplerCommon
samplerSampling MOV t1, INA
WRLONG t1, samplerTargetA 'the rate-limiting step in the sampler
ADD samplerTargetA, #4 'TODO: inc by 3 here (and waste a byte before the buffer) to reclaim wasted 1/4 of 4096 buffer
CMP samplerTargetA, samplerLimitA WZ
IF_E MOVS samplerTramp, #samplerFinish
IF_NE WAITCNT samplerStamp, samplerWait
samplerCommon JMP samplerTramp
samplerFinish MOVS samplerTramp, #samplerOff
MOV t1, #0
WRLONG t1, samplerRunningA 'NB always sets Z
JMP #samplerCommon
' VARIABLES stored in cog RAM (uninitialized)
t1 RES 1
samplerTramp RES 1
samplerRunningA RES 1
samplerTrigVal RES 1
samplerTrigMask RES 1
samplerTrigStart RES 1
samplerTargetA RES 1
samplerLimitA RES 1
samplerStamp RES 1
samplerWait RES 1
FIT ' make sure all instructions/data fit within the cog's RAM
'****************************