ubb-la/ubb-la.c |
99 | 99 | { |
100 | 100 | assert(!(nibbles & 63)); |
101 | 101 | |
| 102 | /* need to reset DSA, DTA, DTC when done. uncertain about DCS */ |
102 | 103 | DCS(DMA) = DCS_NDES; /* no-descriptor transfer */ |
103 | 104 | DSA(DMA) = REG_PADDR(MSC_RXFIFO); /* source */ |
104 | 105 | DTA(DMA) = buf; /* destination */ |
... | ... | |
166 | 167 | } |
167 | 168 | |
168 | 169 | |
| 170 | static void xfers(unsigned long *bufs, int n_bufs, int nibbles) |
| 171 | { |
| 172 | int i = 0; |
| 173 | |
| 174 | dma_init(); |
| 175 | |
| 176 | MSC_STRPCL = MSC_STRPCRL_START_CLOCK; /* start the bus clock */ |
| 177 | MSC_RESTO = MSC_RESTO_MASK; /* maximum response time-out */ |
| 178 | MSC_RDTO = MSC_RDTO_MASK; |
| 179 | MSC_BLKLEN = nibbles >> 1; |
| 180 | |
| 181 | MSC_CMDAT = |
| 182 | MSC_CMDAT_BUS_WIDTH_4 << MSC_CMDAT_BUS_WIDTH_SHIFT | |
| 183 | MSC_CMDAT_DMA_EN | /* DMA */ |
| 184 | MSC_CMDAT_DATA_EN | /* with data transfer */ |
| 185 | MSC_CMDAT_RESPONSE_FORMAT_NONE; /* no response required */ |
| 186 | |
| 187 | disable_interrupts(); |
| 188 | |
| 189 | OUT(UBB_CMD); |
| 190 | dma_setup(bufs[0], nibbles); |
| 191 | |
| 192 | while (1) { |
| 193 | MSC_STRPCL = MSC_STRPCRL_START_OP; |
| 194 | |
| 195 | while (MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY); |
| 196 | |
| 197 | IN(UBB_CMD); |
| 198 | |
| 199 | DCS(DMA) = |
| 200 | DCS_NDES | /* no descriptor */ |
| 201 | DCS_CTE; /* enable channel */ |
| 202 | |
| 203 | /* |
| 204 | * @@@ We could enable interrupts while waiting, particularly |
| 205 | * at low sample rates, as long as the probability of missing |
| 206 | * the end of the DMA transfer is acceptably low. |
| 207 | */ |
| 208 | wait_dma_done(); |
| 209 | |
| 210 | if (++i == n_bufs) |
| 211 | break; |
| 212 | |
| 213 | OUT(UBB_CMD); |
| 214 | dma_setup(bufs[i], nibbles); |
| 215 | |
| 216 | while (!(MSC_STAT & MSC_STAT_DATA_TRAN_DONE)); |
| 217 | } |
| 218 | |
| 219 | enable_interrupts(); |
| 220 | |
| 221 | dma_cleanup(); |
| 222 | } |
| 223 | |
| 224 | |
169 | 225 | static void print_samples(FILE *file, uint8_t *buf, int skip, int nibbles) |
170 | 226 | { |
171 | 227 | uint8_t v, last = 0xff; |
... | ... | |
225 | 281 | } |
226 | 282 | |
227 | 283 | |
| 284 | static void do_bufs(int n_bufs, int nibbles) |
| 285 | { |
| 286 | uint8_t *bufs[n_bufs]; |
| 287 | struct physmem_vec vecs[n_bufs]; |
| 288 | unsigned long addrs[n_bufs]; |
| 289 | int i,n; |
| 290 | |
| 291 | if (mlockall(MCL_CURRENT | MCL_FUTURE)) { |
| 292 | perror("mlockall"); |
| 293 | exit(1); |
| 294 | } |
| 295 | |
| 296 | for (i = 0; i != n_bufs; i++) { |
| 297 | bufs[i] = physmem_malloc(4096); |
| 298 | memset(bufs[i], 0, 4096); |
| 299 | physmem_flush(bufs[i], 4096); |
| 300 | |
| 301 | n = physmem_xlat(bufs[i], nibbles >> 1, vecs+i, 1); |
| 302 | if (n != 1) { |
| 303 | fprintf(stderr, |
| 304 | "physmem_xlat_vec: expected 1, got %d\n", n); |
| 305 | exit(1); |
| 306 | } |
| 307 | addrs[i] = vecs[i].addr; |
| 308 | } |
| 309 | xfers(addrs, n_bufs, nibbles); |
| 310 | |
| 311 | for (i = 0; i != n_bufs; i++) |
| 312 | print_samples(stdout, bufs[i], INITIAL_SKIP, nibbles); |
| 313 | } |
| 314 | |
| 315 | |
228 | 316 | /* ----- Command-line processing ------------------------------------------- */ |
229 | 317 | |
230 | 318 | |
... | ... | |
263 | 351 | static void usage(const char *name) |
264 | 352 | { |
265 | 353 | fprintf(stderr, |
266 | | "usage: %s [-C] [-t pattern/mask] [-f frequency_MHz]\n\n" |
| 354 | "usage: %s [-C] [-t pattern/mask] [-f frequency_MHz] [-n N]\n\n" |
267 | 355 | " -C output the MMC clock on CLK/TRIG (for debugging)\n" |
268 | 356 | " -f freq_MHz select the specified frequency (default; 1 MHz)\n" |
| 357 | " -n N capture N buffers worth of samples without waiting for a\n" |
| 358 | " trigger\n" |
269 | 359 | " -t pattern/mask start capture at the specified pattern (DAT0 = 1, etc.,\n" |
270 | 360 | " CLK = 16). Default: any change on TRIG.\n" |
271 | 361 | , name); |
... | ... | |
277 | 367 | { |
278 | 368 | double freq_mhz = 1; |
279 | 369 | unsigned long trigger = 1, mask = 0; |
| 370 | unsigned long multi = 0; |
280 | 371 | int clkout = 0; |
281 | 372 | struct mmcclk clk; |
282 | 373 | char *end; |
283 | 374 | int c, res; |
284 | 375 | |
285 | | while ((c = getopt(argc, argv, "Cf:t:")) != EOF) |
| 376 | while ((c = getopt(argc, argv, "Cf:n:t:")) != EOF) |
286 | 377 | switch (c) { |
287 | 378 | case 'C': |
288 | 379 | clkout = 1; |
... | ... | |
292 | 383 | if (*end) |
293 | 384 | usage(*argv); |
294 | 385 | break; |
| 386 | case 'n': |
| 387 | multi = strtoul(optarg, &end, 0); |
| 388 | if (*end) |
| 389 | usage(*argv); |
| 390 | break; |
295 | 391 | case 't': |
296 | 392 | trigger = strtoul(optarg, &end, 0); |
297 | 393 | if (*end != '/') |
... | ... | |
327 | 423 | mask = UBB_CLK; |
328 | 424 | } |
329 | 425 | |
330 | | res = !do_buf(8128, trigger, mask); |
| 426 | if (!multi) { |
| 427 | res = !do_buf(8128, trigger, mask); |
| 428 | } else { |
| 429 | do_bufs(multi, 8128); |
| 430 | res = 0; |
| 431 | } |
331 | 432 | |
332 | 433 | mmcclk_stop(); |
333 | 434 | ubb_close(UBB_ALL); |