]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blame - fx2lafw.c
First attempt at a sampling GPIF waveform (untested!).
[sigrok-firmware-fx2lafw.git] / fx2lafw.c
CommitLineData
d5f5ea73
UH
1/*
2 * This file is part of the fx2lafw project.
3 *
4 * Copyright (C) 2011-2012 Uwe Hermann <uwe@hermann-uwe.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/*
22 * fx2lafw is an open-source firmware for Cypress FX2 based logic analyzers.
23 *
24 * It is written in C, using fx2lib as helper library, and sdcc as compiler.
25 * The code is licensed under the terms of the GNU GPL, version 2 or later.
26 *
27 * Technical notes:
28 *
29 * - We use the FX2 in GPIF mode to sample the data (asynchronously).
30 * - We use the internal 48MHz clock for GPIF.
31 * - The 8 channels/pins we sample (the GPIF data bus) are PB0-PB7.
32 * Support for 16 channels is not yet included, but might be added later.
33 * - Endpoint 2 is used for data transfers from FX2 to host.
34 * - The endpoint is quad-buffered.
35 *
36 * Documentation:
37 *
38 * - See http://sigrok.org/wiki/Fx2lafw
39 */
40
41#include <fx2regs.h>
42#include <fx2macros.h>
43#include <delay.h>
44#include <autovector.h>
45#include <setupdat.h>
46#include <eputils.h>
47#include <gpif.h>
48
49#define SYNCDELAY() SYNCDELAY4
50
51/* ... */
52volatile bit got_sud;
53
54/* GPIF terminology: DP = decision point, NDP = non-decision-point */
55
fb0b6d28
UH
56/*
57 * GPIF waveforms.
58 *
59 * See section "10.3.4 State Instructions" in the TRM for details.
60 */
d5f5ea73
UH
61static const BYTE wavedata[128] = {
62 /* Waveform 0: */
63
fb0b6d28
UH
64 /*
65 * This is the basic algorithm implemented in our GPIF state machine:
66 *
67 * State 0: NDP: Sample the FIFO data bus.
68 * State 1: DP: If EP2 is full, go to state 7 (the IDLE state), i.e.,
69 * end the current waveform. Otherwise, go to state 0 again,
70 * i.e., sample data until EP2 is full.
71 * State 2: Unused.
72 * State 3: Unused.
73 * State 4: Unused.
74 * State 5: Unused.
75 * State 6: Unused.
76 */
d5f5ea73
UH
77
78 /* S0-S6: LENGTH/BRANCH */
fb0b6d28
UH
79 /*
80 * For NDPs (LENGTH): Number of IFCLK cycles to stay in this state.
81 * For DPs (BRANCH): [7] ReExec, [5:3]: BRANCHON1, [2:0]: BRANCHON0.
82 *
83 * 0x01: Stay one IFCLK cycle in this state.
84 * 0x38: No Re-execution, BRANCHON1 = state 7, BRANCHON0 = state 0.
85 */
86 0x01, 0x38, 0x01, 0x01, 0x01, 0x01, 0x01,
d5f5ea73
UH
87 /* TRM says "reserved", but GPIF designer always puts a 0x07 here. */
88 0x07,
fb0b6d28 89
d5f5ea73 90 /* S0-S6: OPCODE */
fb0b6d28
UH
91 /*
92 * 0x02: NDP, sample the FIFO data bus.
93 * 0x01: DP, don't sample the FIFO data bus.
94 */
95 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
d5f5ea73
UH
96 /* Reserved */
97 0x00,
fb0b6d28 98
d5f5ea73 99 /* S0-S6: OUTPUT */
fb0b6d28 100 /* Unused, we don't output anything, we only sample the pins. */
d5f5ea73
UH
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 /* Reserved */
103 0x00,
fb0b6d28 104
d5f5ea73 105 /* S0-S6: LOGIC FUNCTION (not used for NDPs) */
fb0b6d28
UH
106 /*
107 * 0x36: LFUNC = "A AND B", A = FIFO flag, B = FIFO flag.
108 * The FIFO flag (FF == full flag, in our case) is configured via
109 * EP2GPIFFLGSEL.
110 *
111 * So: If the EP2 FIFO is full and the EP2 FIFO is full, go to
112 * the state specified by BRANCHON1 (state 7), otherwise BRANCHON0
113 * (state 0). See the LENGTH/BRANCH value above for details.
114 */
115 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
d5f5ea73
UH
116 /* TRM says "reserved", but GPIF designer always puts a 0x3f here. */
117 0x3f,
118
119 /* TODO: Must unused waveforms be "valid"? */
120
121 /* Waveform 1 (unused): */
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126
127 /* Waveform 2 (unused): */
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132
133 /* Waveform 3 (unused): */
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138};
139
140static void gpif_setup_registers(void)
141{
142 /* TODO. Value probably irrelevant, as we don't use RDY* signals? */
143 GPIFREADYCFG = 0;
144
145 /*
146 * Set TRICTL = 0, thus CTL0-CTL5 are CMOS outputs.
147 * TODO: Probably irrelevant, as we don't use CTL0-CTL5?
148 */
149 GPIFCTLCFG = 0;
150
151 /* When GPIF is idle, tri-state the data bus. */
152 /* Bit 7: DONE, bit 0: IDLEDRV. TODO: Set/clear DONE bit? */
153 GPIFIDLECS = (1 << 0);
154
155 /* When GPIF is idle, set CTL0-CTL5 to 0. */
156 GPIFIDLECTL = 0;
157
158 /*
159 * Map index 0 in wavedata[] to FIFORD. The rest is assigned too,
160 * but not used by us.
161 *
162 * GPIFWFSELECT: [7:6] = SINGLEWR index, [5:4] = SINGLERD index,
163 * [3:2] = FIFOWR index, [1:0] = FIFORD index
164 */
165 GPIFWFSELECT = (0x3 << 6) | (0x2 << 4) | (0x1 << 2) | (0x0 << 0);
166
167 /* Contains RDY* pin values. Read-only according to TRM. */
168 GPIFREADYSTAT = 0;
169}
170
171static void gpif_write_waveforms(void)
172{
173 int i;
174
175 /*
176 * Write the four waveforms into the respective WAVEDATA register
177 * locations (0xe400 - 0xe47f) using the FX2's autopointer feature.
178 */
179 AUTOPTRSETUP = 0x07; /* Increment autopointers 1 & 2. */
180 AUTOPTRH1 = MSB((WORD)wavedata); /* Source is the 'wavedata' array. */
181 AUTOPTRL1 = LSB((WORD)wavedata);
182 AUTOPTRH2 = 0xe4; /* Dest is WAVEDATA (0xe400). */
183 AUTOPTRL2 = 0x00;
184 for (i = 0; i < 128; i++)
185 EXTAUTODAT2 = EXTAUTODAT1;
186}
187
188static void gpif_init_addr_pins(void)
189{
190 /*
191 * Configure the 9 GPIF address pins (GPIFADR[8:0], which consist of
192 * PORTC[7:0] and PORTE[7]), and output an initial address (zero).
193 * TODO: Probably irrelevant, the 56pin FX2 has no ports C and E.
194 */
195 PORTCCFG = 0xff; /* Set PORTC[7:0] as alt. func. (GPIFADR[7:0]). */
196 OEC = 0xff; /* Configure PORTC[7:0] as outputs. */
197 PORTECFG |= 0x80; /* Set PORTE[7] as alt. func. (GPIFADR[8]). */
198 OEE |= 0x80; /* Configure PORTE[7] as output. */
199 SYNCDELAY();
200 GPIFADRL = 0x00; /* Clear GPIFADR[7:0]. */
201 SYNCDELAY();
202 GPIFADRH = 0x00; /* Clear GPIFADR[8]. */
203}
204
205static void gpif_init_flowstates(void)
206{
207 /* Clear all flowstate registers, we don't use this functionality. */
208 FLOWSTATE = 0;
209 FLOWLOGIC = 0;
210 FLOWEQ0CTL = 0;
211 FLOWEQ1CTL = 0;
212 FLOWHOLDOFF = 0;
213 FLOWSTB = 0;
214 FLOWSTBEDGE = 0;
215 FLOWSTBHPERIOD = 0;
216}
217
218static void gpif_init_la(void)
219{
220 /*
221 * Setup the FX2 in GPIF master mode, using the internal clock
222 * (non-inverted) at 48MHz, and using async sampling.
223 */
224 IFCONFIG = 0xee;
225
226 /* Abort currently executing GPIF waveform (if any). */
227 GPIFABORT = 0xff;
228
229 /* Setup the GPIF registers. */
230 gpif_setup_registers();
231
232 /* Write the four GPIF waveforms into the WAVEDATA register. */
233 gpif_write_waveforms();
234
235 /* Initialize GPIF address pins, output initial values. */
236 gpif_init_addr_pins();
237
238 /* Initialize flowstate registers (not used by us). */
239 gpif_init_flowstates();
240}
241
242static void setup_endpoints(void)
243{
244 /* Setup EP1 (OUT). */
245 EP1OUTCFG = (1 << 7) | /* EP is valid/activated */
246 (0 << 6) | /* Reserved */
247 (1 << 5) | (0 << 4) | /* EP Type: bulk */
248 (0 << 3) | /* Reserved */
249 (0 << 2) | /* Reserved */
250 (0 << 1) | (0 << 0); /* Reserved */
251 SYNCDELAY();
252
253 /* Setup EP2 (IN). */
254 EP2CFG = (1 << 7) | /* EP is valid/activated */
255 (1 << 6) | /* EP direction: IN */
256 (1 << 5) | (0 << 4) | /* EP Type: bulk */
257 (0 << 3) | /* EP buffer size: 512 */
258 (0 << 2) | /* Reserved. */
259 (0 << 1) | (0 << 0); /* EP buffering: quad buffering */
260 SYNCDELAY();
261
262 /* Disable all other EPs (EP4, EP6, and EP8). */
263 EP4CFG &= ~bmVALID;
264 SYNCDELAY();
265 EP6CFG &= ~bmVALID;
266 SYNCDELAY();
267 EP8CFG &= ~bmVALID;
268 SYNCDELAY();
269
270 /* Reset the FIFOs of EP1 and EP2. */
271 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
272 RESETFIFO(0x01)
273 RESETFIFO(0x02)
274
fb0b6d28
UH
275 /* Set the GPIF flag for EP2 to 'full'. */
276 EP2GPIFFLGSEL = (1 << 1) | (0 << 1);
d5f5ea73
UH
277 SYNCDELAY();
278}
279
280BOOL handle_vendorcommand(BYTE cmd)
281{
282 (void)cmd;
283 return FALSE;
284}
285
286BOOL handle_get_interface(BYTE ifc, BYTE *alt_ifc)
287{
288 /* We only support interface 0, alternate interface 0. */
289 if (ifc != 0)
290 return FALSE;
291
292 *alt_ifc = 0;
293 return TRUE;
294}
295
296BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc)
297{
298 /* We only support interface 0, alternate interface 0. */
299 if (ifc != 0 || alt_ifc != 0)
300 return FALSE;
301
302 /* Perform procedure from TRM, section 2.3.7: */
303
304 /* (1) TODO. */
305
306 /* (2) Reset data toggles of the EPs in the interface. */
307 /* Note: RESETTOGGLE() gets the EP number WITH bit 7 set/cleared. */
308 RESETTOGGLE(0x01);
309 RESETTOGGLE(0x82);
310
311 /* (3) Restore EPs to their default conditions. */
312 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
313 RESETFIFO(0x01);
314 /* TODO */
315 RESETFIFO(0x02);
316 /* TODO */
317
318 /* (4) Clear the HSNAK bit. Not needed, fx2lib does this. */
319
320 return TRUE;
321}
322
323BYTE handle_get_configuration(void)
324{
325 /* We only support configuration 1. */
326 return 1;
327}
328
329BOOL handle_set_configuration(BYTE cfg)
330{
331 /* We only support configuration 1. */
332 return (cfg == 1) ? TRUE : FALSE;
333}
334
335void sudav_isr(void) interrupt SUDAV_ISR
336{
337 got_sud = TRUE;
338 CLEAR_SUDAV();
339}
340
341void sof_isr(void) interrupt SOF_ISR using 1
342{
343 CLEAR_SOF();
344}
345
346void usbreset_isr(void) interrupt USBRESET_ISR
347{
348 handle_hispeed(FALSE);
349 CLEAR_USBRESET();
350}
351
352void hispeed_isr(void) interrupt HISPEED_ISR
353{
354 handle_hispeed(TRUE);
355 CLEAR_HISPEED();
356}
357
358void main(void)
359{
360 /* Set DYN_OUT and ENH_PKT bits, as recommended by the TRM. */
361 REVCTL = (1 << 1) | (1 << 0);
362
363 got_sud = FALSE;
364
365 /* Renumerate. */
366 RENUMERATE_UNCOND();
367
368 SETCPUFREQ(CLK_48M);
369
370 USE_USB_INTS();
371
372 /* TODO: Does the order of the following lines matter? */
373 ENABLE_SUDAV();
374 ENABLE_SOF();
375 ENABLE_HISPEED();
376 ENABLE_USBRESET();
377
378 /* Global (8051) interrupt enable. */
379 EA = 1;
380
381 /* Setup the endpoints. */
382 setup_endpoints();
383
384 /* Put the FX2 into GPIF master mode and setup the GPIF. */
385 gpif_init_la();
386
387 /* TODO */
388 /* Initiate a GPIF read. */
389 (void)EP2GPIFTRIG;
390#if 0
391 /* TODO: This seems to hang? */
392 gpif_fifo_read(GPIF_EP2);
393#endif
394
395 while (1) {
396 if (got_sud) {
397 handle_setupdata();
398 got_sud = FALSE;
399 }
400 }
401}