]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blame - fx2lafw.c
Eliminate EP1, commands should use EP0.
[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 */
dc7ac8bf
UH
86 // 0x01, 0x38, 0x01, 0x01, 0x01, 0x01, 0x01,
87 // FIXME: For now just loop over the "sample data" state forever.
88 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
d5f5ea73
UH
89 /* TRM says "reserved", but GPIF designer always puts a 0x07 here. */
90 0x07,
fb0b6d28 91
d5f5ea73 92 /* S0-S6: OPCODE */
fb0b6d28
UH
93 /*
94 * 0x02: NDP, sample the FIFO data bus.
95 * 0x01: DP, don't sample the FIFO data bus.
96 */
97 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
d5f5ea73
UH
98 /* Reserved */
99 0x00,
fb0b6d28 100
d5f5ea73 101 /* S0-S6: OUTPUT */
fb0b6d28 102 /* Unused, we don't output anything, we only sample the pins. */
d5f5ea73
UH
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 /* Reserved */
105 0x00,
fb0b6d28 106
d5f5ea73 107 /* S0-S6: LOGIC FUNCTION (not used for NDPs) */
fb0b6d28
UH
108 /*
109 * 0x36: LFUNC = "A AND B", A = FIFO flag, B = FIFO flag.
110 * The FIFO flag (FF == full flag, in our case) is configured via
111 * EP2GPIFFLGSEL.
112 *
113 * So: If the EP2 FIFO is full and the EP2 FIFO is full, go to
114 * the state specified by BRANCHON1 (state 7), otherwise BRANCHON0
115 * (state 0). See the LENGTH/BRANCH value above for details.
116 */
117 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
d5f5ea73
UH
118 /* TRM says "reserved", but GPIF designer always puts a 0x3f here. */
119 0x3f,
120
121 /* TODO: Must unused waveforms be "valid"? */
122
123 /* Waveform 1 (unused): */
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128
129 /* Waveform 2 (unused): */
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134
135 /* Waveform 3 (unused): */
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140};
141
142static void gpif_setup_registers(void)
143{
144 /* TODO. Value probably irrelevant, as we don't use RDY* signals? */
145 GPIFREADYCFG = 0;
146
147 /*
148 * Set TRICTL = 0, thus CTL0-CTL5 are CMOS outputs.
149 * TODO: Probably irrelevant, as we don't use CTL0-CTL5?
150 */
151 GPIFCTLCFG = 0;
152
153 /* When GPIF is idle, tri-state the data bus. */
154 /* Bit 7: DONE, bit 0: IDLEDRV. TODO: Set/clear DONE bit? */
155 GPIFIDLECS = (1 << 0);
156
157 /* When GPIF is idle, set CTL0-CTL5 to 0. */
158 GPIFIDLECTL = 0;
159
160 /*
161 * Map index 0 in wavedata[] to FIFORD. The rest is assigned too,
162 * but not used by us.
163 *
164 * GPIFWFSELECT: [7:6] = SINGLEWR index, [5:4] = SINGLERD index,
165 * [3:2] = FIFOWR index, [1:0] = FIFORD index
166 */
167 GPIFWFSELECT = (0x3 << 6) | (0x2 << 4) | (0x1 << 2) | (0x0 << 0);
168
169 /* Contains RDY* pin values. Read-only according to TRM. */
170 GPIFREADYSTAT = 0;
171}
172
173static void gpif_write_waveforms(void)
174{
175 int i;
176
177 /*
178 * Write the four waveforms into the respective WAVEDATA register
179 * locations (0xe400 - 0xe47f) using the FX2's autopointer feature.
180 */
181 AUTOPTRSETUP = 0x07; /* Increment autopointers 1 & 2. */
182 AUTOPTRH1 = MSB((WORD)wavedata); /* Source is the 'wavedata' array. */
183 AUTOPTRL1 = LSB((WORD)wavedata);
184 AUTOPTRH2 = 0xe4; /* Dest is WAVEDATA (0xe400). */
185 AUTOPTRL2 = 0x00;
186 for (i = 0; i < 128; i++)
187 EXTAUTODAT2 = EXTAUTODAT1;
188}
189
190static void gpif_init_addr_pins(void)
191{
192 /*
193 * Configure the 9 GPIF address pins (GPIFADR[8:0], which consist of
194 * PORTC[7:0] and PORTE[7]), and output an initial address (zero).
195 * TODO: Probably irrelevant, the 56pin FX2 has no ports C and E.
196 */
197 PORTCCFG = 0xff; /* Set PORTC[7:0] as alt. func. (GPIFADR[7:0]). */
198 OEC = 0xff; /* Configure PORTC[7:0] as outputs. */
199 PORTECFG |= 0x80; /* Set PORTE[7] as alt. func. (GPIFADR[8]). */
200 OEE |= 0x80; /* Configure PORTE[7] as output. */
201 SYNCDELAY();
202 GPIFADRL = 0x00; /* Clear GPIFADR[7:0]. */
203 SYNCDELAY();
204 GPIFADRH = 0x00; /* Clear GPIFADR[8]. */
205}
206
207static void gpif_init_flowstates(void)
208{
209 /* Clear all flowstate registers, we don't use this functionality. */
210 FLOWSTATE = 0;
211 FLOWLOGIC = 0;
212 FLOWEQ0CTL = 0;
213 FLOWEQ1CTL = 0;
214 FLOWHOLDOFF = 0;
215 FLOWSTB = 0;
216 FLOWSTBEDGE = 0;
217 FLOWSTBHPERIOD = 0;
218}
219
220static void gpif_init_la(void)
221{
222 /*
223 * Setup the FX2 in GPIF master mode, using the internal clock
224 * (non-inverted) at 48MHz, and using async sampling.
225 */
226 IFCONFIG = 0xee;
227
228 /* Abort currently executing GPIF waveform (if any). */
229 GPIFABORT = 0xff;
230
231 /* Setup the GPIF registers. */
232 gpif_setup_registers();
233
234 /* Write the four GPIF waveforms into the WAVEDATA register. */
235 gpif_write_waveforms();
236
237 /* Initialize GPIF address pins, output initial values. */
238 gpif_init_addr_pins();
239
240 /* Initialize flowstate registers (not used by us). */
241 gpif_init_flowstates();
242}
243
244static void setup_endpoints(void)
245{
d5f5ea73
UH
246 /* Setup EP2 (IN). */
247 EP2CFG = (1 << 7) | /* EP is valid/activated */
248 (1 << 6) | /* EP direction: IN */
249 (1 << 5) | (0 << 4) | /* EP Type: bulk */
250 (0 << 3) | /* EP buffer size: 512 */
251 (0 << 2) | /* Reserved. */
252 (0 << 1) | (0 << 0); /* EP buffering: quad buffering */
253 SYNCDELAY();
254
4ad20a4c
UH
255 /* Disable all other EPs (EP1, EP4, EP6, and EP8). */
256 EP1INCFG &= ~bmVALID;
257 SYNCDELAY();
258 EP1OUTCFG &= ~bmVALID;
259 SYNCDELAY();
d5f5ea73
UH
260 EP4CFG &= ~bmVALID;
261 SYNCDELAY();
262 EP6CFG &= ~bmVALID;
263 SYNCDELAY();
264 EP8CFG &= ~bmVALID;
265 SYNCDELAY();
266
4ad20a4c 267 /* EP2: Reset the FIFOs. */
d5f5ea73 268 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
d5f5ea73
UH
269 RESETFIFO(0x02)
270
dc7ac8bf
UH
271 /* EP2: Enable AUTOIN mode. Set FIFO width to 8bits. */
272 EP2FIFOCFG = bmAUTOIN | ~bmWORDWIDE;
273 SYNCDELAY();
274
275 /* EP2: Auto-commit 512 (0x200) byte packets (due to AUTOIN = 1). */
276 EP2AUTOINLENH = 0x02;
277 SYNCDELAY();
278 EP2AUTOINLENL = 0x00;
279 SYNCDELAY();
280
4ad20a4c 281 /* EP2: Set the GPIF flag to 'full'. */
fb0b6d28 282 EP2GPIFFLGSEL = (1 << 1) | (0 << 1);
d5f5ea73
UH
283 SYNCDELAY();
284}
285
286BOOL handle_vendorcommand(BYTE cmd)
287{
288 (void)cmd;
4ad20a4c
UH
289
290 /*
291 * TODO: Implement the protocol using control requests of type
292 * 'vendor-specific' (bmRequestType[6:5] = 2).
293 */
294
d5f5ea73
UH
295 return FALSE;
296}
297
298BOOL handle_get_interface(BYTE ifc, BYTE *alt_ifc)
299{
300 /* We only support interface 0, alternate interface 0. */
301 if (ifc != 0)
302 return FALSE;
303
304 *alt_ifc = 0;
305 return TRUE;
306}
307
308BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc)
309{
310 /* We only support interface 0, alternate interface 0. */
311 if (ifc != 0 || alt_ifc != 0)
312 return FALSE;
313
314 /* Perform procedure from TRM, section 2.3.7: */
315
316 /* (1) TODO. */
317
318 /* (2) Reset data toggles of the EPs in the interface. */
319 /* Note: RESETTOGGLE() gets the EP number WITH bit 7 set/cleared. */
d5f5ea73
UH
320 RESETTOGGLE(0x82);
321
322 /* (3) Restore EPs to their default conditions. */
323 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
d5f5ea73
UH
324 RESETFIFO(0x02);
325 /* TODO */
326
327 /* (4) Clear the HSNAK bit. Not needed, fx2lib does this. */
328
329 return TRUE;
330}
331
332BYTE handle_get_configuration(void)
333{
334 /* We only support configuration 1. */
335 return 1;
336}
337
338BOOL handle_set_configuration(BYTE cfg)
339{
340 /* We only support configuration 1. */
341 return (cfg == 1) ? TRUE : FALSE;
342}
343
344void sudav_isr(void) interrupt SUDAV_ISR
345{
346 got_sud = TRUE;
347 CLEAR_SUDAV();
348}
349
350void sof_isr(void) interrupt SOF_ISR using 1
351{
352 CLEAR_SOF();
353}
354
355void usbreset_isr(void) interrupt USBRESET_ISR
356{
357 handle_hispeed(FALSE);
358 CLEAR_USBRESET();
359}
360
361void hispeed_isr(void) interrupt HISPEED_ISR
362{
363 handle_hispeed(TRUE);
364 CLEAR_HISPEED();
365}
366
367void main(void)
368{
369 /* Set DYN_OUT and ENH_PKT bits, as recommended by the TRM. */
e7434142 370 REVCTL = bmNOAUTOARM | bmSKIPCOMMIT;
d5f5ea73
UH
371
372 got_sud = FALSE;
373
374 /* Renumerate. */
375 RENUMERATE_UNCOND();
376
377 SETCPUFREQ(CLK_48M);
378
379 USE_USB_INTS();
380
381 /* TODO: Does the order of the following lines matter? */
382 ENABLE_SUDAV();
383 ENABLE_SOF();
384 ENABLE_HISPEED();
385 ENABLE_USBRESET();
386
387 /* Global (8051) interrupt enable. */
388 EA = 1;
389
390 /* Setup the endpoints. */
391 setup_endpoints();
392
393 /* Put the FX2 into GPIF master mode and setup the GPIF. */
394 gpif_init_la();
395
dc7ac8bf 396 /* Perform the initial GPIF read. */
d5f5ea73 397 gpif_fifo_read(GPIF_EP2);
d5f5ea73
UH
398
399 while (1) {
400 if (got_sud) {
401 handle_setupdata();
402 got_sud = FALSE;
403 }
404 }
405}