libsigrok/hardware/zeroplus-logic-cube/analyzer.c

580 lines
13 KiB
C
Raw Normal View History

/*
2010-04-15 20:59:43 +00:00
* This file is part of the sigrok project.
*
* Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
* Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
2010-04-15 20:59:43 +00:00
#include <assert.h>
#include "analyzer.h"
#include "gl_usb.h"
enum {
2010-04-15 20:59:43 +00:00
HARD_DATA_CHECK_SUM = 0x00,
PASS_WORD,
2010-04-15 20:59:43 +00:00
DEVICE_ID0 = 0x10,
DEVICE_ID1,
2010-04-15 20:59:43 +00:00
START_STATUS = 0x20,
DEVICE_STATUS = 0x21,
FREQUENCY_REG0 = 0x30,
FREQUENCY_REG1,
FREQUENCY_REG2,
FREQUENCY_REG3,
FREQUENCY_REG4,
MEMORY_LENGTH,
CLOCK_SOURCE,
2010-04-15 20:59:43 +00:00
TRIGGER_STATUS0 = 0x40,
TRIGGER_STATUS1,
TRIGGER_STATUS2,
TRIGGER_STATUS3,
TRIGGER_STATUS4,
TRIGGER_STATUS5,
TRIGGER_STATUS6,
TRIGGER_STATUS7,
TRIGGER_STATUS8,
2010-04-15 20:59:43 +00:00
TRIGGER_COUNT0 = 0x50,
TRIGGER_COUNT1,
2010-04-15 20:59:43 +00:00
TRIGGER_LEVEL0 = 0x55,
TRIGGER_LEVEL1,
TRIGGER_LEVEL2,
TRIGGER_LEVEL3,
RAMSIZE_TRIGGERBAR_ADDRESS0 = 0x60,
RAMSIZE_TRIGGERBAR_ADDRESS1,
RAMSIZE_TRIGGERBAR_ADDRESS2,
TRIGGERBAR_ADDRESS0,
TRIGGERBAR_ADDRESS1,
TRIGGERBAR_ADDRESS2,
DONT_CARE_TRIGGERBAR,
FILTER_ENABLE = 0x70,
FILTER_STATUS,
2010-04-15 20:59:43 +00:00
ENABLE_DELAY_TIME0 = 0x7a,
ENABLE_DELAY_TIME1,
2010-04-15 20:59:43 +00:00
ENABLE_INSERT_DATA0 = 0x80,
ENABLE_INSERT_DATA1,
ENABLE_INSERT_DATA2,
ENABLE_INSERT_DATA3,
COMPRESSION_TYPE0,
COMPRESSION_TYPE1,
2010-04-15 20:59:43 +00:00
TRIGGER_ADDRESS0 = 0x90,
TRIGGER_ADDRESS1,
TRIGGER_ADDRESS2,
2010-04-15 20:59:43 +00:00
NOW_ADDRESS0 = 0x96,
NOW_ADDRESS1,
NOW_ADDRESS2,
2010-04-15 20:59:43 +00:00
STOP_ADDRESS0 = 0x9b,
STOP_ADDRESS1,
STOP_ADDRESS2,
2010-04-15 20:59:43 +00:00
READ_RAM_STATUS = 0xa0,
};
2010-04-15 20:59:43 +00:00
static int g_trigger_status[9] = { 0 };
static int g_trigger_count = 1;
2010-04-15 20:59:43 +00:00
static int g_filter_status[8] = { 0 };
static int g_filter_enable = 0;
static int g_freq_value = 100;
static int g_freq_scale = FREQ_SCALE_MHZ;
static int g_memory_size = MEMORY_SIZE_512K;
2010-04-15 20:59:43 +00:00
static int g_ramsize_triggerbar_addr = 0x80000 >> 2;
static int g_triggerbar_addr = 0x3fe;
static int g_compression = COMPRESSION_NONE;
2010-04-15 20:59:43 +00:00
/* Maybe unk specifies an "endpoint" or "register" of sorts. */
static int analyzer_write_status(libusb_device_handle *devh, unsigned char unk,
unsigned char flags)
{
assert(unk <= 3);
return gl_reg_write(devh, START_STATUS, unk << 6 | flags);
}
static int __analyzer_set_freq(libusb_device_handle *devh, int freq, int scale)
{
2010-04-15 20:59:43 +00:00
int reg0 = 0, divisor = 0, reg2 = 0;
switch (scale) {
2010-04-15 20:59:43 +00:00
case FREQ_SCALE_MHZ: /* MHz */
if (freq >= 100 && freq <= 200) {
reg0 = freq * 0.1;
divisor = 1;
reg2 = 0;
break;
}
if (freq >= 50 && freq < 100) {
reg0 = freq * 0.2;
divisor = 2;
reg2 = 0;
break;
}
if (freq >= 10 && freq < 50) {
if (freq == 25) {
reg0 = 25;
divisor = 5;
2010-04-15 20:59:43 +00:00
reg2 = 1;
break;
2010-04-15 20:59:43 +00:00
} else {
reg0 = freq * 0.5;
divisor = 5;
2010-04-15 20:59:43 +00:00
reg2 = 1;
break;
}
2010-04-15 20:59:43 +00:00
}
if (freq >= 2 && freq < 10) {
divisor = 5;
2010-04-15 20:59:43 +00:00
reg0 = freq * 2;
reg2 = 2;
break;
2010-04-15 20:59:43 +00:00
}
if (freq == 1) {
divisor = 5;
2010-04-15 20:59:43 +00:00
reg2 = 16;
reg0 = 5;
2010-04-15 20:59:43 +00:00
break;
}
divisor = 5;
reg0 = 5;
reg2 = 64;
break;
case FREQ_SCALE_HZ: /* Hz */
if (freq >= 500 && freq < 1000) {
reg0 = freq * 0.01;
divisor = 10;
reg2 = 64;
break;
2010-04-15 20:59:43 +00:00
}
if (freq >= 300 && freq < 500) {
reg0 = freq * 0.005 * 8;
divisor = 5;
reg2 = 67;
break;
}
if (freq >= 100 && freq < 300) {
reg0 = freq * 0.005 * 16;
divisor = 5;
reg2 = 68;
break;
}
divisor = 5;
reg0 = 5;
reg2 = 64;
break;
case FREQ_SCALE_KHZ: /* KHz */
if (freq >= 500 && freq < 1000) {
reg0 = freq * 0.01;
divisor = 5;
reg2 = 17;
break;
}
if (freq >= 100 && freq < 500) {
reg0 = freq * 0.05;
divisor = 5;
reg2 = 32;
break;
}
if (freq >= 50 && freq < 100) {
reg0 = freq * 0.1;
divisor = 5;
reg2 = 33;
break;
}
if (freq >= 10 && freq < 50) {
if (freq == 25) {
reg0 = 25;
divisor = 5;
2010-04-15 20:59:43 +00:00
reg2 = 49;
break;
}
2010-04-15 20:59:43 +00:00
reg0 = freq * 0.5;
divisor = 5;
2010-04-15 20:59:43 +00:00
reg2 = 48;
break;
2010-04-15 20:59:43 +00:00
}
if (freq >= 2 && freq < 10) {
divisor = 5;
2010-04-15 20:59:43 +00:00
reg0 = freq * 2;
reg2 = 50;
break;
2010-04-15 20:59:43 +00:00
}
divisor = 5;
reg0 = 5;
reg2 = 64;
break;
default:
divisor = 5;
reg0 = 5;
reg2 = 64;
break;
}
if (gl_reg_write(devh, FREQUENCY_REG0, divisor) < 0)
2010-04-15 20:59:43 +00:00
return -1; /* Divisor maybe? */
if (gl_reg_write(devh, FREQUENCY_REG1, reg0) < 0)
2010-04-15 20:59:43 +00:00
return -1; /* 10 / 0.2 */
if (gl_reg_write(devh, FREQUENCY_REG2, 0x02) < 0)
2010-04-15 20:59:43 +00:00
return -1; /* Always 2 */
if (gl_reg_write(devh, FREQUENCY_REG4, reg2) < 0)
return -1;
return 0;
}
2010-04-15 20:59:43 +00:00
static void __analyzer_set_ramsize_trigger_address(libusb_device_handle *devh,
unsigned int address)
{
2010-04-15 20:59:43 +00:00
gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
}
2010-04-15 20:59:43 +00:00
static void __analyzer_set_triggerbar_address(libusb_device_handle *devh,
unsigned int address)
{
2010-04-15 20:59:43 +00:00
gl_reg_write(devh, TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
gl_reg_write(devh, TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
gl_reg_write(devh, TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
}
2010-04-15 20:59:43 +00:00
static void __analyzer_set_compression(libusb_device_handle *devh,
unsigned int type)
{
gl_reg_write(devh, COMPRESSION_TYPE0, (type >> 0) & 0xFF);
gl_reg_write(devh, COMPRESSION_TYPE1, (type >> 8) & 0xFF);
}
2010-04-15 20:59:43 +00:00
static void __analyzer_set_trigger_count(libusb_device_handle *devh,
unsigned int count)
{
gl_reg_write(devh, TRIGGER_COUNT0, (count >> 0) & 0xFF);
gl_reg_write(devh, TRIGGER_COUNT1, (count >> 8) & 0xFF);
}
static void analyzer_write_enable_insert_data(libusb_device_handle *devh)
{
gl_reg_write(devh, ENABLE_INSERT_DATA0, 0x12);
gl_reg_write(devh, ENABLE_INSERT_DATA1, 0x34);
gl_reg_write(devh, ENABLE_INSERT_DATA2, 0x56);
gl_reg_write(devh, ENABLE_INSERT_DATA3, 0x78);
}
static void analyzer_set_filter(libusb_device_handle *devh)
{
int i;
gl_reg_write(devh, FILTER_ENABLE, g_filter_enable);
for (i = 0; i < 8; i++)
gl_reg_write(devh, FILTER_STATUS + i, g_filter_status[i]);
}
void analyzer_reset(libusb_device_handle *devh)
{
2010-04-15 20:59:43 +00:00
analyzer_write_status(devh, 3, STATUS_FLAG_NONE); // reset device
analyzer_write_status(devh, 3, STATUS_FLAG_RESET); // reset device
}
void analyzer_initialize(libusb_device_handle *devh)
{
analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
}
void analyzer_wait(libusb_device_handle *devh, int set, int unset)
{
int status;
2010-04-15 20:59:43 +00:00
while (1) {
status = gl_reg_read(devh, DEVICE_STATUS);
if ((status & set) && ((status & unset) == 0))
return;
}
}
void analyzer_read_start(libusb_device_handle *devh)
{
int i;
analyzer_write_status(devh, 3, STATUS_FLAG_20 | STATUS_FLAG_READ);
for (i = 0; i < 8; i++)
(void)gl_reg_read(devh, READ_RAM_STATUS);
}
2010-04-15 20:59:43 +00:00
int analyzer_read_data(libusb_device_handle *devh, void *buffer,
unsigned int size)
{
return gl_read_bulk(devh, buffer, size);
}
void analyzer_read_stop(libusb_device_handle *devh)
{
analyzer_write_status(devh, 3, STATUS_FLAG_20);
analyzer_write_status(devh, 3, STATUS_FLAG_NONE);
}
void analyzer_start(libusb_device_handle *devh)
{
analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
analyzer_write_status(devh, 1, STATUS_FLAG_GO);
}
void analyzer_configure(libusb_device_handle *devh)
{
2010-04-15 20:59:43 +00:00
int i;
/* Write_Start_Status */
analyzer_write_status(devh, 1, STATUS_FLAG_RESET);
analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
2010-04-15 20:59:43 +00:00
/* Start_Config_Outside_Device ? */
analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
2010-04-15 20:59:43 +00:00
/* SetData_To_Frequence_Reg */
__analyzer_set_freq(devh, g_freq_value, g_freq_scale);
2010-04-15 20:59:43 +00:00
/* SetMemory_Length */
gl_reg_write(devh, MEMORY_LENGTH, g_memory_size);
2010-04-15 20:59:43 +00:00
/* Sele_Inside_Outside_Clock */
gl_reg_write(devh, CLOCK_SOURCE, 0x03);
2010-04-15 20:59:43 +00:00
/* Set_Trigger_Status */
for (i = 0; i < 9; i++)
gl_reg_write(devh, TRIGGER_STATUS0 + i, g_trigger_status[i]);
__analyzer_set_trigger_count(devh, g_trigger_count);
2010-04-15 20:59:43 +00:00
/* Set_Trigger_Level */
gl_reg_write(devh, TRIGGER_LEVEL0, 0x31);
gl_reg_write(devh, TRIGGER_LEVEL1, 0x31);
gl_reg_write(devh, TRIGGER_LEVEL2, 0x31);
gl_reg_write(devh, TRIGGER_LEVEL3, 0x31);
2010-04-15 20:59:43 +00:00
/* Size of actual memory >> 2 */
__analyzer_set_ramsize_trigger_address(devh, g_ramsize_triggerbar_addr);
__analyzer_set_triggerbar_address(devh, g_triggerbar_addr);
2010-04-15 20:59:43 +00:00
/* Set_Dont_Care_TriggerBar */
gl_reg_write(devh, DONT_CARE_TRIGGERBAR, 0x01);
2010-04-15 20:59:43 +00:00
/* Enable_Status */
analyzer_set_filter(devh);
2010-04-15 20:59:43 +00:00
/* Set_Enable_Delay_Time */
gl_reg_write(devh, 0x7a, 0x00);
gl_reg_write(devh, 0x7b, 0x00);
analyzer_write_enable_insert_data(devh);
2010-04-15 20:59:43 +00:00
__analyzer_set_compression(devh, g_compression);
}
void analyzer_add_trigger(int channel, int type)
{
2010-04-15 20:59:43 +00:00
int i;
if ((channel & 0xf) >= 8)
return;
if (type == TRIGGER_HIGH || type == TRIGGER_LOW) {
if (channel & CHANNEL_A)
i = 0;
else if (channel & CHANNEL_B)
i = 2;
else if (channel & CHANNEL_C)
i = 4;
else if (channel & CHANNEL_D)
i = 6;
else
return;
if ((channel & 0xf) >= 4) {
i++;
channel -= 4;
}
2010-04-15 20:59:43 +00:00
g_trigger_status[i] |=
1 << ((2 * channel) + (type == TRIGGER_LOW ? 1 : 0));
} else {
if (type == TRIGGER_POSEDGE)
g_trigger_status[8] = 0x40;
2010-04-15 20:59:43 +00:00
else if (type == TRIGGER_NEGEDGE)
g_trigger_status[8] = 0x80;
else
g_trigger_status[8] = 0xc0;
2010-04-15 20:59:43 +00:00
/* FIXME: Just guessed the index; need to verify. */
if (channel & CHANNEL_B)
g_trigger_status[8] += 8;
else if (channel & CHANNEL_C)
g_trigger_status[8] += 16;
else if (channel & CHANNEL_D)
g_trigger_status[8] += 24;
g_trigger_status[8] += channel % 8;
}
}
void analyzer_add_filter(int channel, int type)
{
2010-04-15 20:59:43 +00:00
int i;
if (type != FILTER_HIGH && type != FILTER_LOW)
return;
if ((channel & 0xf) >= 8)
return;
if (channel & CHANNEL_A)
i = 0;
else if (channel & CHANNEL_B)
i = 2;
else if (channel & CHANNEL_C)
i = 4;
else if (channel & CHANNEL_D)
i = 6;
else
return;
2010-04-15 20:59:43 +00:00
if ((channel & 0xf) >= 4) {
i++;
channel -= 4;
}
2010-04-15 20:59:43 +00:00
g_filter_status[i] |=
1 << ((2 * channel) + (type == FILTER_LOW ? 1 : 0));
g_filter_enable = 1;
}
void analyzer_set_trigger_count(int count)
{
g_trigger_count = count;
}
void analyzer_set_freq(int freq, int scale)
{
g_freq_value = freq;
g_freq_scale = scale;
}
void analyzer_set_memory_size(unsigned int size)
{
g_memory_size = size;
}
void analyzer_set_ramsize_trigger_address(unsigned int address)
{
g_ramsize_triggerbar_addr = address;
}
void analyzer_set_triggerbar_address(unsigned int address)
{
g_triggerbar_addr = address;
}
unsigned int analyzer_read_id(libusb_device_handle *devh)
{
2010-04-15 20:59:43 +00:00
return gl_reg_read(devh, DEVICE_ID1) << 8 | gl_reg_read(devh,
DEVICE_ID0);
}
unsigned int analyzer_get_stop_address(libusb_device_handle *devh)
{
2010-04-15 20:59:43 +00:00
return gl_reg_read(devh, STOP_ADDRESS2) << 16 | gl_reg_read(devh,
STOP_ADDRESS1) << 8 | gl_reg_read(devh, STOP_ADDRESS0);
}
unsigned int analyzer_get_now_address(libusb_device_handle *devh)
{
2010-04-15 20:59:43 +00:00
return gl_reg_read(devh, NOW_ADDRESS2) << 16 | gl_reg_read(devh,
NOW_ADDRESS1) << 8 | gl_reg_read(devh, NOW_ADDRESS0);
}
unsigned int analyzer_get_trigger_address(libusb_device_handle *devh)
{
2010-04-15 20:59:43 +00:00
return gl_reg_read(devh, TRIGGER_ADDRESS2) << 16 | gl_reg_read(devh,
TRIGGER_ADDRESS1) << 8 | gl_reg_read(devh, TRIGGER_ADDRESS0);
}
void analyzer_set_compression(unsigned int type)
{
g_compression = type;
}
void analyzer_wait_button(libusb_device_handle *devh)
{
analyzer_wait(devh, STATUS_BUTTON_PRESSED, 0);
}
void analyzer_wait_data(libusb_device_handle *devh)
{
analyzer_wait(devh, STATUS_READY | 8, STATUS_BUSY);
}
2010-04-15 20:59:43 +00:00
int analyzer_decompress(void *input, unsigned int input_len, void *output,
unsigned int output_len)
{
unsigned char *in = input;
unsigned char *out = output;
unsigned int A, B, C, count;
unsigned int written = 0;
while (input_len > 0) {
A = *in++;
B = *in++;
C = *in++;
count = (*in++) + 1;
if (count > output_len)
count = output_len;
output_len -= count;
written += count;
while (count--) {
*out++ = A;
*out++ = B;
*out++ = C;
2010-04-15 20:59:43 +00:00
*out++ = 0; /* Channel D */
}
input_len -= 4;
if (output_len == 0)
break;
}
return written;
}