]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blame - fx2lafw.c
Initial version (work in progress).
[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
56/* GPIF waveforms */
57static const BYTE wavedata[128] = {
58 /* Waveform 0: */
59
60 /* TODO: This is just a dummy entry, fill with useful data. */
61
62 /* S0-S6: LENGTH/BRANCH */
63 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
64 /* TRM says "reserved", but GPIF designer always puts a 0x07 here. */
65 0x07,
66 /* S0-S6: OPCODE */
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 /* Reserved */
69 0x00,
70 /* S0-S6: OUTPUT */
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 /* Reserved */
73 0x00,
74 /* S0-S6: LOGIC FUNCTION (not used for NDPs) */
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 /* TRM says "reserved", but GPIF designer always puts a 0x3f here. */
77 0x3f,
78
79 /* TODO: Must unused waveforms be "valid"? */
80
81 /* Waveform 1 (unused): */
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86
87 /* Waveform 2 (unused): */
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92
93 /* Waveform 3 (unused): */
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98};
99
100static void gpif_setup_registers(void)
101{
102 /* TODO. Value probably irrelevant, as we don't use RDY* signals? */
103 GPIFREADYCFG = 0;
104
105 /*
106 * Set TRICTL = 0, thus CTL0-CTL5 are CMOS outputs.
107 * TODO: Probably irrelevant, as we don't use CTL0-CTL5?
108 */
109 GPIFCTLCFG = 0;
110
111 /* When GPIF is idle, tri-state the data bus. */
112 /* Bit 7: DONE, bit 0: IDLEDRV. TODO: Set/clear DONE bit? */
113 GPIFIDLECS = (1 << 0);
114
115 /* When GPIF is idle, set CTL0-CTL5 to 0. */
116 GPIFIDLECTL = 0;
117
118 /*
119 * Map index 0 in wavedata[] to FIFORD. The rest is assigned too,
120 * but not used by us.
121 *
122 * GPIFWFSELECT: [7:6] = SINGLEWR index, [5:4] = SINGLERD index,
123 * [3:2] = FIFOWR index, [1:0] = FIFORD index
124 */
125 GPIFWFSELECT = (0x3 << 6) | (0x2 << 4) | (0x1 << 2) | (0x0 << 0);
126
127 /* Contains RDY* pin values. Read-only according to TRM. */
128 GPIFREADYSTAT = 0;
129}
130
131static void gpif_write_waveforms(void)
132{
133 int i;
134
135 /*
136 * Write the four waveforms into the respective WAVEDATA register
137 * locations (0xe400 - 0xe47f) using the FX2's autopointer feature.
138 */
139 AUTOPTRSETUP = 0x07; /* Increment autopointers 1 & 2. */
140 AUTOPTRH1 = MSB((WORD)wavedata); /* Source is the 'wavedata' array. */
141 AUTOPTRL1 = LSB((WORD)wavedata);
142 AUTOPTRH2 = 0xe4; /* Dest is WAVEDATA (0xe400). */
143 AUTOPTRL2 = 0x00;
144 for (i = 0; i < 128; i++)
145 EXTAUTODAT2 = EXTAUTODAT1;
146}
147
148static void gpif_init_addr_pins(void)
149{
150 /*
151 * Configure the 9 GPIF address pins (GPIFADR[8:0], which consist of
152 * PORTC[7:0] and PORTE[7]), and output an initial address (zero).
153 * TODO: Probably irrelevant, the 56pin FX2 has no ports C and E.
154 */
155 PORTCCFG = 0xff; /* Set PORTC[7:0] as alt. func. (GPIFADR[7:0]). */
156 OEC = 0xff; /* Configure PORTC[7:0] as outputs. */
157 PORTECFG |= 0x80; /* Set PORTE[7] as alt. func. (GPIFADR[8]). */
158 OEE |= 0x80; /* Configure PORTE[7] as output. */
159 SYNCDELAY();
160 GPIFADRL = 0x00; /* Clear GPIFADR[7:0]. */
161 SYNCDELAY();
162 GPIFADRH = 0x00; /* Clear GPIFADR[8]. */
163}
164
165static void gpif_init_flowstates(void)
166{
167 /* Clear all flowstate registers, we don't use this functionality. */
168 FLOWSTATE = 0;
169 FLOWLOGIC = 0;
170 FLOWEQ0CTL = 0;
171 FLOWEQ1CTL = 0;
172 FLOWHOLDOFF = 0;
173 FLOWSTB = 0;
174 FLOWSTBEDGE = 0;
175 FLOWSTBHPERIOD = 0;
176}
177
178static void gpif_init_la(void)
179{
180 /*
181 * Setup the FX2 in GPIF master mode, using the internal clock
182 * (non-inverted) at 48MHz, and using async sampling.
183 */
184 IFCONFIG = 0xee;
185
186 /* Abort currently executing GPIF waveform (if any). */
187 GPIFABORT = 0xff;
188
189 /* Setup the GPIF registers. */
190 gpif_setup_registers();
191
192 /* Write the four GPIF waveforms into the WAVEDATA register. */
193 gpif_write_waveforms();
194
195 /* Initialize GPIF address pins, output initial values. */
196 gpif_init_addr_pins();
197
198 /* Initialize flowstate registers (not used by us). */
199 gpif_init_flowstates();
200}
201
202static void setup_endpoints(void)
203{
204 /* Setup EP1 (OUT). */
205 EP1OUTCFG = (1 << 7) | /* EP is valid/activated */
206 (0 << 6) | /* Reserved */
207 (1 << 5) | (0 << 4) | /* EP Type: bulk */
208 (0 << 3) | /* Reserved */
209 (0 << 2) | /* Reserved */
210 (0 << 1) | (0 << 0); /* Reserved */
211 SYNCDELAY();
212
213 /* Setup EP2 (IN). */
214 EP2CFG = (1 << 7) | /* EP is valid/activated */
215 (1 << 6) | /* EP direction: IN */
216 (1 << 5) | (0 << 4) | /* EP Type: bulk */
217 (0 << 3) | /* EP buffer size: 512 */
218 (0 << 2) | /* Reserved. */
219 (0 << 1) | (0 << 0); /* EP buffering: quad buffering */
220 SYNCDELAY();
221
222 /* Disable all other EPs (EP4, EP6, and EP8). */
223 EP4CFG &= ~bmVALID;
224 SYNCDELAY();
225 EP6CFG &= ~bmVALID;
226 SYNCDELAY();
227 EP8CFG &= ~bmVALID;
228 SYNCDELAY();
229
230 /* Reset the FIFOs of EP1 and EP2. */
231 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
232 RESETFIFO(0x01)
233 RESETFIFO(0x02)
234
235 /* Set the GPIF flag for EP2 to 'empty'. */
236 EP2GPIFFLGSEL = (0 << 1) | (1 << 1);
237 SYNCDELAY();
238}
239
240BOOL handle_vendorcommand(BYTE cmd)
241{
242 (void)cmd;
243 return FALSE;
244}
245
246BOOL handle_get_interface(BYTE ifc, BYTE *alt_ifc)
247{
248 /* We only support interface 0, alternate interface 0. */
249 if (ifc != 0)
250 return FALSE;
251
252 *alt_ifc = 0;
253 return TRUE;
254}
255
256BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc)
257{
258 /* We only support interface 0, alternate interface 0. */
259 if (ifc != 0 || alt_ifc != 0)
260 return FALSE;
261
262 /* Perform procedure from TRM, section 2.3.7: */
263
264 /* (1) TODO. */
265
266 /* (2) Reset data toggles of the EPs in the interface. */
267 /* Note: RESETTOGGLE() gets the EP number WITH bit 7 set/cleared. */
268 RESETTOGGLE(0x01);
269 RESETTOGGLE(0x82);
270
271 /* (3) Restore EPs to their default conditions. */
272 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
273 RESETFIFO(0x01);
274 /* TODO */
275 RESETFIFO(0x02);
276 /* TODO */
277
278 /* (4) Clear the HSNAK bit. Not needed, fx2lib does this. */
279
280 return TRUE;
281}
282
283BYTE handle_get_configuration(void)
284{
285 /* We only support configuration 1. */
286 return 1;
287}
288
289BOOL handle_set_configuration(BYTE cfg)
290{
291 /* We only support configuration 1. */
292 return (cfg == 1) ? TRUE : FALSE;
293}
294
295void sudav_isr(void) interrupt SUDAV_ISR
296{
297 got_sud = TRUE;
298 CLEAR_SUDAV();
299}
300
301void sof_isr(void) interrupt SOF_ISR using 1
302{
303 CLEAR_SOF();
304}
305
306void usbreset_isr(void) interrupt USBRESET_ISR
307{
308 handle_hispeed(FALSE);
309 CLEAR_USBRESET();
310}
311
312void hispeed_isr(void) interrupt HISPEED_ISR
313{
314 handle_hispeed(TRUE);
315 CLEAR_HISPEED();
316}
317
318void main(void)
319{
320 /* Set DYN_OUT and ENH_PKT bits, as recommended by the TRM. */
321 REVCTL = (1 << 1) | (1 << 0);
322
323 got_sud = FALSE;
324
325 /* Renumerate. */
326 RENUMERATE_UNCOND();
327
328 SETCPUFREQ(CLK_48M);
329
330 USE_USB_INTS();
331
332 /* TODO: Does the order of the following lines matter? */
333 ENABLE_SUDAV();
334 ENABLE_SOF();
335 ENABLE_HISPEED();
336 ENABLE_USBRESET();
337
338 /* Global (8051) interrupt enable. */
339 EA = 1;
340
341 /* Setup the endpoints. */
342 setup_endpoints();
343
344 /* Put the FX2 into GPIF master mode and setup the GPIF. */
345 gpif_init_la();
346
347 /* TODO */
348 /* Initiate a GPIF read. */
349 (void)EP2GPIFTRIG;
350#if 0
351 /* TODO: This seems to hang? */
352 gpif_fifo_read(GPIF_EP2);
353#endif
354
355 while (1) {
356 if (got_sud) {
357 handle_setupdata();
358 got_sud = FALSE;
359 }
360 }
361}