]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blob - fx2lafw.c
Rearranged main() in preparation for split according to device versions
[sigrok-firmware-fx2lafw.git] / fx2lafw.c
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 /* Protocol commands */
50 #define CMD_SET_SAMPLERATE      0xb0
51 #define CMD_START               0xb1
52 #define CMD_STOP                0xb2
53 #define CMD_GET_FW_VERSION      0xb3
54 /* ... */
55
56 #define SYNCDELAY() SYNCDELAY4
57
58 /* ... */
59 volatile bit got_sud;
60
61 /* GPIF terminology: DP = decision point, NDP = non-decision-point */
62
63 /*
64  * GPIF waveforms.
65  *
66  * See section "10.3.4 State Instructions" in the TRM for details.
67  */
68 static const BYTE wavedata[128] = {
69         /* Waveform 0: */
70
71         /*
72          * This is the basic algorithm implemented in our GPIF state machine:
73          *
74          * State 0: NDP: Sample the FIFO data bus.
75          * State 1: DP: If EP2 is full, go to state 7 (the IDLE state), i.e.,
76          *          end the current waveform. Otherwise, go to state 0 again,
77          *          i.e., sample data until EP2 is full.
78          * State 2: Unused.
79          * State 3: Unused.
80          * State 4: Unused.
81          * State 5: Unused.
82          * State 6: Unused.
83          */
84
85         /* S0-S6: LENGTH/BRANCH */
86         /*
87          * For NDPs (LENGTH): Number of IFCLK cycles to stay in this state.
88          * For DPs (BRANCH): [7] ReExec, [5:3]: BRANCHON1, [2:0]: BRANCHON0.
89          *
90          * 0x01: Stay one IFCLK cycle in this state.
91          * 0x38: No Re-execution, BRANCHON1 = state 7, BRANCHON0 = state 0.
92          */
93         // 0x01, 0x38, 0x01, 0x01, 0x01, 0x01, 0x01,
94         // FIXME: For now just loop over the "sample data" state forever.
95         0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
96         /* TRM says "reserved", but GPIF designer always puts a 0x07 here. */
97         0x07,
98
99         /* S0-S6: OPCODE */
100         /*
101          * 0x02: NDP, sample the FIFO data bus.
102          * 0x01: DP, don't sample the FIFO data bus.
103          */
104         0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
105         /* Reserved */
106         0x00,
107
108         /* S0-S6: OUTPUT */
109         /* Unused, we don't output anything, we only sample the pins. */
110         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111         /* Reserved */
112         0x00,
113
114         /* S0-S6: LOGIC FUNCTION (not used for NDPs) */
115         /*
116          * 0x36: LFUNC = "A AND B", A = FIFO flag, B = FIFO flag.
117          * The FIFO flag (FF == full flag, in our case) is configured via
118          * EP2GPIFFLGSEL.
119          *
120          * So: If the EP2 FIFO is full and the EP2 FIFO is full, go to
121          * the state specified by BRANCHON1 (state 7), otherwise BRANCHON0
122          * (state 0). See the LENGTH/BRANCH value above for details.
123          */
124         0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
125         /* TRM says "reserved", but GPIF designer always puts a 0x3f here. */
126         0x3f,
127
128         /* TODO: Must unused waveforms be "valid"? */
129
130         /* Waveform 1 (unused): */
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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135
136         /* Waveform 2 (unused): */
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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141
142         /* Waveform 3 (unused): */
143         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 };
148
149 static void gpif_setup_registers(void)
150 {
151         /* TODO. Value probably irrelevant, as we don't use RDY* signals? */
152         GPIFREADYCFG = 0;
153
154         /*
155          * Set TRICTL = 0, thus CTL0-CTL5 are CMOS outputs.
156          * TODO: Probably irrelevant, as we don't use CTL0-CTL5?
157          */
158         GPIFCTLCFG = 0;
159
160         /* When GPIF is idle, tri-state the data bus. */
161         /* Bit 7: DONE, bit 0: IDLEDRV. TODO: Set/clear DONE bit? */
162         GPIFIDLECS = (1 << 0);
163
164         /* When GPIF is idle, set CTL0-CTL5 to 0. */
165         GPIFIDLECTL = 0;
166
167         /*
168          * Map index 0 in wavedata[] to FIFORD. The rest is assigned too,
169          * but not used by us.
170          *
171          * GPIFWFSELECT: [7:6] = SINGLEWR index, [5:4] = SINGLERD index,
172          *               [3:2] = FIFOWR index, [1:0] = FIFORD index
173          */
174         GPIFWFSELECT = (0x3 << 6) | (0x2 << 4) | (0x1 << 2) | (0x0 << 0);
175
176         /* Contains RDY* pin values. Read-only according to TRM. */
177         GPIFREADYSTAT = 0;
178 }
179
180 static void gpif_write_waveforms(void)
181 {
182         int i;
183
184         /*
185          * Write the four waveforms into the respective WAVEDATA register
186          * locations (0xe400 - 0xe47f) using the FX2's autopointer feature.
187          */
188         AUTOPTRSETUP = 0x07;             /* Increment autopointers 1 & 2. */
189         AUTOPTRH1 = MSB((WORD)wavedata); /* Source is the 'wavedata' array. */
190         AUTOPTRL1 = LSB((WORD)wavedata);
191         AUTOPTRH2 = 0xe4;                /* Dest is WAVEDATA (0xe400). */
192         AUTOPTRL2 = 0x00;
193         for (i = 0; i < 128; i++)
194                 EXTAUTODAT2 = EXTAUTODAT1;
195 }
196
197 static void gpif_init_addr_pins(void)
198 {
199         /*
200          * Configure the 9 GPIF address pins (GPIFADR[8:0], which consist of
201          * PORTC[7:0] and PORTE[7]), and output an initial address (zero).
202          * TODO: Probably irrelevant, the 56pin FX2 has no ports C and E.
203          */
204         PORTCCFG = 0xff;    /* Set PORTC[7:0] as alt. func. (GPIFADR[7:0]). */
205         OEC = 0xff;         /* Configure PORTC[7:0] as outputs. */
206         PORTECFG |= 0x80;   /* Set PORTE[7] as alt. func. (GPIFADR[8]). */
207         OEE |= 0x80;        /* Configure PORTE[7] as output. */
208         SYNCDELAY();
209         GPIFADRL = 0x00;    /* Clear GPIFADR[7:0]. */
210         SYNCDELAY();
211         GPIFADRH = 0x00;    /* Clear GPIFADR[8]. */
212 }
213
214 static void gpif_init_flowstates(void)
215 {
216         /* Clear all flowstate registers, we don't use this functionality. */
217         FLOWSTATE = 0;
218         FLOWLOGIC = 0;
219         FLOWEQ0CTL = 0;
220         FLOWEQ1CTL = 0;
221         FLOWHOLDOFF = 0;
222         FLOWSTB = 0;
223         FLOWSTBEDGE = 0;
224         FLOWSTBHPERIOD = 0;
225 }
226
227 static void gpif_init_la(void)
228 {
229         /*
230          * Setup the FX2 in GPIF master mode, using the internal clock
231          * (non-inverted) at 48MHz, and using async sampling.
232          */
233         IFCONFIG = 0xee;
234
235         /* Abort currently executing GPIF waveform (if any). */
236         GPIFABORT = 0xff;
237
238         /* Setup the GPIF registers. */
239         gpif_setup_registers();
240
241         /* Write the four GPIF waveforms into the WAVEDATA register. */
242         gpif_write_waveforms();
243
244         /* Initialize GPIF address pins, output initial values. */
245         gpif_init_addr_pins();
246
247         /* Initialize flowstate registers (not used by us). */
248         gpif_init_flowstates();
249 }
250
251 static void setup_endpoints(void)
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         /* Setup EP6 (IN) in the debug build. */
263 #ifdef DEBUG
264         EP6CFG = (1 << 7) |               /* EP is valid/activated */
265                  (1 << 6) |               /* EP direction: IN */
266                  (1 << 5) | (0 << 4) |    /* EP Type: bulk */
267                  (0 << 3) |               /* EP buffer size: 512 */
268                  (0 << 2) |               /* Reserved */
269                  (1 << 1) | (0 << 0);     /* EP buffering: double buffering */
270 #else
271         EP6CFG &= ~bmVALID;
272 #endif
273         SYNCDELAY();
274
275         /* Disable all other EPs (EP4 and EP8). */
276         EP1INCFG &= ~bmVALID;
277         SYNCDELAY();
278         EP1OUTCFG &= ~bmVALID;
279         SYNCDELAY();
280         EP4CFG &= ~bmVALID;
281         SYNCDELAY();
282         EP8CFG &= ~bmVALID;
283         SYNCDELAY();
284
285         /* EP2: Reset the FIFOs. */
286         /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
287         RESETFIFO(0x02)
288 #ifdef DEBUG
289         /* Reset the FIFOs of EP6 when in debug mode. */
290         RESETFIFO(0x06)
291 #endif
292
293         /* EP2: Enable AUTOIN mode. Set FIFO width to 8bits. */
294         EP2FIFOCFG = bmAUTOIN | ~bmWORDWIDE;
295         SYNCDELAY();
296
297         /* EP2: Auto-commit 512 (0x200) byte packets (due to AUTOIN = 1). */
298         EP2AUTOINLENH = 0x02;
299         SYNCDELAY();
300         EP2AUTOINLENL = 0x00;
301         SYNCDELAY();
302
303         /* EP2: Set the GPIF flag to 'full'. */
304         EP2GPIFFLGSEL = (1 << 1) | (0 << 1);
305         SYNCDELAY();
306 }
307
308 BOOL handle_vendorcommand(BYTE cmd)
309 {
310         /* Protocol implementation */
311
312         switch (cmd) {
313         case CMD_SET_SAMPLERATE:
314                 /* TODO */
315                 break;
316         case CMD_START:
317                 /* TODO */
318                 break;
319         case CMD_STOP:
320                 GPIFABORT = 0xff;
321                 /* TODO */
322                 return TRUE;
323                 break;
324         case CMD_GET_FW_VERSION:
325                 /* TODO */
326                 break;
327         default:
328                 /* Unimplemented command. */
329                 break;
330         }
331
332         return FALSE;
333 }
334
335 BOOL handle_get_interface(BYTE ifc, BYTE *alt_ifc)
336 {
337         /* We only support interface 0, alternate interface 0. */
338         if (ifc != 0)
339                 return FALSE;
340
341         *alt_ifc = 0;
342         return TRUE;
343 }
344
345 BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc)
346 {
347         /* We only support interface 0, alternate interface 0. */
348         if (ifc != 0 || alt_ifc != 0)
349                 return FALSE;
350         
351         /* Perform procedure from TRM, section 2.3.7: */
352
353         /* (1) TODO. */
354
355         /* (2) Reset data toggles of the EPs in the interface. */
356         /* Note: RESETTOGGLE() gets the EP number WITH bit 7 set/cleared. */
357         RESETTOGGLE(0x82);
358         RESETTOGGLE(0x76);
359
360         /* (3) Restore EPs to their default conditions. */
361         /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
362         RESETFIFO(0x02);
363         /* TODO */
364
365         RESETFIFO(0x06);
366
367         /* (4) Clear the HSNAK bit. Not needed, fx2lib does this. */
368
369         return TRUE;
370 }
371
372 BYTE handle_get_configuration(void)
373 {
374         /* We only support configuration 1. */
375         return 1;
376 }
377
378 BOOL handle_set_configuration(BYTE cfg)
379 {
380         /* We only support configuration 1. */
381         return (cfg == 1) ? TRUE : FALSE;
382 }
383
384 void sudav_isr(void) interrupt SUDAV_ISR
385 {
386         got_sud = TRUE;
387         CLEAR_SUDAV();
388 }
389
390 void sof_isr(void) interrupt SOF_ISR using 1
391 {
392         CLEAR_SOF();
393 }
394
395 void usbreset_isr(void) interrupt USBRESET_ISR
396 {
397         handle_hispeed(FALSE);
398         CLEAR_USBRESET();
399 }
400
401 void hispeed_isr(void) interrupt HISPEED_ISR
402 {
403         handle_hispeed(TRUE);
404         CLEAR_HISPEED();
405 }
406
407 void fx2lafw_init(void)
408 {
409         /* Set DYN_OUT and ENH_PKT bits, as recommended by the TRM. */
410         REVCTL = bmNOAUTOARM | bmSKIPCOMMIT;
411
412         got_sud = FALSE;
413
414         /* Renumerate. */
415         RENUMERATE_UNCOND();
416
417         SETCPUFREQ(CLK_48M);
418
419         USE_USB_INTS();
420
421         /* TODO: Does the order of the following lines matter? */
422         ENABLE_SUDAV();
423         ENABLE_SOF();
424         ENABLE_HISPEED();
425         ENABLE_USBRESET();
426
427         /* Global (8051) interrupt enable. */
428         EA = 1;
429
430         /* Setup the endpoints. */
431         setup_endpoints();
432
433         /* Put the FX2 into GPIF master mode and setup the GPIF. */
434         gpif_init_la();
435
436         /* Perform the initial GPIF read. */
437         gpif_fifo_read(GPIF_EP2);
438 }
439
440 void fx2lafw_run(void)
441 {
442         if (got_sud) {
443                 handle_setupdata();
444                 got_sud = FALSE;
445         }
446 }
447
448 void main(void)
449 {
450         fx2lafw_init();
451
452         while(1)
453                 fx2lafw_run();
454 }