]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blob - fx2lafw.c
First somewhat working GPIF waveform and setup code.
[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 #define SYNCDELAY() SYNCDELAY4
50
51 /* ... */
52 volatile bit got_sud;
53
54 /* GPIF terminology: DP = decision point, NDP = non-decision-point */
55
56 /*
57  * GPIF waveforms.
58  *
59  * See section "10.3.4 State Instructions" in the TRM for details.
60  */
61 static const BYTE wavedata[128] = {
62         /* Waveform 0: */
63
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          */
77
78         /* S0-S6: LENGTH/BRANCH */
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,
87         // FIXME: For now just loop over the "sample data" state forever.
88         0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
89         /* TRM says "reserved", but GPIF designer always puts a 0x07 here. */
90         0x07,
91
92         /* S0-S6: OPCODE */
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,
98         /* Reserved */
99         0x00,
100
101         /* S0-S6: OUTPUT */
102         /* Unused, we don't output anything, we only sample the pins. */
103         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104         /* Reserved */
105         0x00,
106
107         /* S0-S6: LOGIC FUNCTION (not used for NDPs) */
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,
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
142 static 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
173 static 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
190 static 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
207 static 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
220 static 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
244 static void setup_endpoints(void)
245 {
246         /* Setup EP1 (OUT). */
247         EP1OUTCFG = (1 << 7) |            /* EP is valid/activated */
248                     (0 << 6) |            /* Reserved */
249                     (1 << 5) | (0 << 4) | /* EP Type: bulk */
250                     (0 << 3) |            /* Reserved */
251                     (0 << 2) |            /* Reserved */
252                     (0 << 1) | (0 << 0);  /* Reserved */
253         SYNCDELAY();
254
255         /* Setup EP2 (IN). */
256         EP2CFG = (1 << 7) |               /* EP is valid/activated */
257                  (1 << 6) |               /* EP direction: IN */
258                  (1 << 5) | (0 << 4) |    /* EP Type: bulk */
259                  (0 << 3) |               /* EP buffer size: 512 */
260                  (0 << 2) |               /* Reserved. */
261                  (0 << 1) | (0 << 0);     /* EP buffering: quad buffering */
262         SYNCDELAY();
263
264         /* Disable all other EPs (EP4, EP6, and EP8). */
265         EP4CFG &= ~bmVALID;
266         SYNCDELAY();
267         EP6CFG &= ~bmVALID;
268         SYNCDELAY();
269         EP8CFG &= ~bmVALID;
270         SYNCDELAY();
271
272         /* Reset the FIFOs of EP1 and EP2. */
273         /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
274         RESETFIFO(0x01)
275         RESETFIFO(0x02)
276
277         /* EP2: Enable AUTOIN mode. Set FIFO width to 8bits. */
278         EP2FIFOCFG = bmAUTOIN | ~bmWORDWIDE;
279         SYNCDELAY();
280
281         /* EP2: Auto-commit 512 (0x200) byte packets (due to AUTOIN = 1). */
282         EP2AUTOINLENH = 0x02;
283         SYNCDELAY();
284         EP2AUTOINLENL = 0x00;
285         SYNCDELAY();
286
287         /* Set the GPIF flag for EP2 to 'full'. */
288         EP2GPIFFLGSEL = (1 << 1) | (0 << 1);
289         SYNCDELAY();
290 }
291
292 BOOL handle_vendorcommand(BYTE cmd)
293 {
294         (void)cmd;
295         return FALSE;
296 }
297
298 BOOL 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
308 BOOL 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. */
320         RESETTOGGLE(0x01);
321         RESETTOGGLE(0x82);
322
323         /* (3) Restore EPs to their default conditions. */
324         /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
325         RESETFIFO(0x01);
326         /* TODO */
327         RESETFIFO(0x02);
328         /* TODO */
329
330         /* (4) Clear the HSNAK bit. Not needed, fx2lib does this. */
331
332         return TRUE;
333 }
334
335 BYTE handle_get_configuration(void)
336 {
337         /* We only support configuration 1. */
338         return 1;
339 }
340
341 BOOL handle_set_configuration(BYTE cfg)
342 {
343         /* We only support configuration 1. */
344         return (cfg == 1) ? TRUE : FALSE;
345 }
346
347 void sudav_isr(void) interrupt SUDAV_ISR
348 {
349         got_sud = TRUE;
350         CLEAR_SUDAV();
351 }
352
353 void sof_isr(void) interrupt SOF_ISR using 1
354 {
355         CLEAR_SOF();
356 }
357
358 void usbreset_isr(void) interrupt USBRESET_ISR
359 {
360         handle_hispeed(FALSE);
361         CLEAR_USBRESET();
362 }
363
364 void hispeed_isr(void) interrupt HISPEED_ISR
365 {
366         handle_hispeed(TRUE);
367         CLEAR_HISPEED();
368 }
369
370 void main(void)
371 {
372         /* Set DYN_OUT and ENH_PKT bits, as recommended by the TRM. */
373         REVCTL = (1 << 1) | (1 << 0);
374
375         got_sud = FALSE;
376
377         /* Renumerate. */
378         RENUMERATE_UNCOND();
379
380         SETCPUFREQ(CLK_48M);
381
382         USE_USB_INTS();
383
384         /* TODO: Does the order of the following lines matter? */
385         ENABLE_SUDAV();
386         ENABLE_SOF();
387         ENABLE_HISPEED();
388         ENABLE_USBRESET();
389
390         /* Global (8051) interrupt enable. */
391         EA = 1;
392
393         /* Setup the endpoints. */
394         setup_endpoints();
395
396         /* Put the FX2 into GPIF master mode and setup the GPIF. */
397         gpif_init_la();
398
399         /* Perform the initial GPIF read. */
400         gpif_fifo_read(GPIF_EP2);
401
402         while (1) {
403                 if (got_sud) {
404                         handle_setupdata();
405                         got_sud = FALSE;
406                 }
407         }
408 }