* few discrete values, while setter routines accept any user specified
* rate that is supported by the hardware.
*/
-SR_PRIV const uint64_t samplerates[] = {
+static const uint64_t samplerates[] = {
/* 50MHz and integer divider. 1/2/5 steps (where possible). */
SR_KHZ(200), SR_KHZ(500),
SR_MHZ(1), SR_MHZ(2), SR_MHZ(5),
SR_MHZ(100), SR_MHZ(200),
};
-SR_PRIV const size_t samplerates_count = ARRAY_SIZE(samplerates);
+SR_PRIV GVariant *sigma_get_samplerates_list(void)
+{
+ return std_gvar_samplerates(samplerates, ARRAY_SIZE(samplerates));
+}
static const char *firmware_files[] = {
[SIGMA_FW_50MHZ] = "asix-sigma-50.fw", /* 50MHz, 8bit divider. */
#define SIGMA_FIRMWARE_SIZE_LIMIT (256 * 1024)
+static int sigma_ftdi_open(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ int vid, pid;
+ const char *serno;
+ int ret;
+
+ devc = sdi->priv;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ if (devc->ftdi.is_open)
+ return SR_OK;
+
+ vid = devc->id.vid;
+ pid = devc->id.pid;
+ serno = sdi->serial_num;
+ if (!vid || !pid || !serno || !*serno)
+ return SR_ERR_ARG;
+
+ ret = ftdi_init(&devc->ftdi.ctx);
+ if (ret < 0) {
+ sr_err("Cannot initialize FTDI context (%d): %s.",
+ ret, ftdi_get_error_string(&devc->ftdi.ctx));
+ return SR_ERR_IO;
+ }
+ ret = ftdi_usb_open_desc_index(&devc->ftdi.ctx,
+ vid, pid, NULL, serno, 0);
+ if (ret < 0) {
+ sr_err("Cannot open device (%d): %s.",
+ ret, ftdi_get_error_string(&devc->ftdi.ctx));
+ return SR_ERR_IO;
+ }
+ devc->ftdi.is_open = TRUE;
+
+ return SR_OK;
+}
+
+static int sigma_ftdi_close(struct dev_context *devc)
+{
+ int ret;
+
+ ret = ftdi_usb_close(&devc->ftdi.ctx);
+ devc->ftdi.is_open = FALSE;
+ devc->ftdi.must_close = FALSE;
+ ftdi_deinit(&devc->ftdi.ctx);
+
+ return ret == 0 ? SR_OK : SR_ERR_IO;
+}
+
+SR_PRIV int sigma_check_open(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ int ret;
+
+ if (!sdi)
+ return SR_ERR_ARG;
+ devc = sdi->priv;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ if (devc->ftdi.is_open)
+ return SR_OK;
+
+ ret = sigma_ftdi_open(sdi);
+ if (ret != SR_OK)
+ return ret;
+ devc->ftdi.must_close = TRUE;
+
+ return ret;
+}
+
+SR_PRIV int sigma_check_close(struct dev_context *devc)
+{
+ int ret;
+
+ if (!devc)
+ return SR_ERR_ARG;
+
+ if (devc->ftdi.must_close) {
+ ret = sigma_ftdi_close(devc);
+ if (ret != SR_OK)
+ return ret;
+ devc->ftdi.must_close = FALSE;
+ }
+
+ return SR_OK;
+}
+
+SR_PRIV int sigma_force_open(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ int ret;
+
+ if (!sdi)
+ return SR_ERR_ARG;
+ devc = sdi->priv;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ ret = sigma_ftdi_open(sdi);
+ if (ret != SR_OK)
+ return ret;
+ devc->ftdi.must_close = FALSE;
+
+ return SR_OK;
+}
+
+SR_PRIV int sigma_force_close(struct dev_context *devc)
+{
+ return sigma_ftdi_close(devc);
+}
+
/*
* BEWARE! Error propagation is important, as are kinds of return values.
*
{
int ret;
- ret = ftdi_read_data(&devc->ftdic, (unsigned char *)buf, size);
+ ret = ftdi_read_data(&devc->ftdi.ctx, (unsigned char *)buf, size);
if (ret < 0) {
sr_err("USB data read failed: %s",
- ftdi_get_error_string(&devc->ftdic));
+ ftdi_get_error_string(&devc->ftdi.ctx));
}
return ret;
{
int ret;
- ret = ftdi_write_data(&devc->ftdic, buf, size);
+ ret = ftdi_write_data(&devc->ftdi.ctx, buf, size);
if (ret < 0) {
sr_err("USB data write failed: %s",
- ftdi_get_error_string(&devc->ftdic));
+ ftdi_get_error_string(&devc->ftdi.ctx));
} else if ((size_t)ret != size) {
sr_err("USB data write length mismatch.");
}
* that's a programmer's error and needs adjustment in the complete call
* stack of the respective code path.
*/
+#define SIGMA_MAX_REG_DEPTH 32
+
+/*
+ * Implementor's note: The FPGA command set supports register access
+ * with automatic address adjustment. This operation is documented to
+ * wrap within a 16-address range, it cannot cross boundaries where the
+ * register address' nibble overflows. An internal helper assumes that
+ * callers remain within this auto-adjustment range, and thus multi
+ * register access requests can never exceed that count.
+ */
+#define SIGMA_MAX_REG_COUNT 16
+
SR_PRIV int sigma_write_register(struct dev_context *devc,
uint8_t reg, uint8_t *data, size_t len)
{
- uint8_t buf[80], *wrptr;
+ uint8_t buf[2 + SIGMA_MAX_REG_DEPTH * 2], *wrptr;
size_t idx;
- if (2 + 2 * len > sizeof(buf)) {
+ if (len > SIGMA_MAX_REG_DEPTH) {
sr_err("Short write buffer for %zu bytes to reg %u.", len, reg);
return SR_ERR_BUG;
}
wrptr = buf;
- write_u8_inc(&wrptr, REG_ADDR_LOW | (reg & 0xf));
- write_u8_inc(&wrptr, REG_ADDR_HIGH | (reg >> 4));
+ write_u8_inc(&wrptr, REG_ADDR_LOW | LO4(reg));
+ write_u8_inc(&wrptr, REG_ADDR_HIGH | HI4(reg));
for (idx = 0; idx < len; idx++) {
- write_u8_inc(&wrptr, REG_DATA_LOW | (data[idx] & 0xf));
- write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | (data[idx] >> 4));
+ write_u8_inc(&wrptr, REG_DATA_LOW | LO4(data[idx]));
+ write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | HI4(data[idx]));
}
return sigma_write_sr(devc, buf, wrptr - buf);
int ret;
wrptr = buf;
- write_u8_inc(&wrptr, REG_ADDR_LOW | (reg & 0xf));
- write_u8_inc(&wrptr, REG_ADDR_HIGH | (reg >> 4));
+ write_u8_inc(&wrptr, REG_ADDR_LOW | LO4(reg));
+ write_u8_inc(&wrptr, REG_ADDR_HIGH | HI4(reg));
write_u8_inc(&wrptr, REG_READ_ADDR);
ret = sigma_write_sr(devc, buf, wrptr - buf);
if (ret != SR_OK)
return sigma_read_sr(devc, data, len);
}
+static int sigma_get_register(struct dev_context *devc,
+ uint8_t reg, uint8_t *data)
+{
+ return sigma_read_register(devc, reg, data, sizeof(*data));
+}
+
+static int sigma_get_registers(struct dev_context *devc,
+ uint8_t reg, uint8_t *data, size_t count)
+{
+ uint8_t buf[2 + SIGMA_MAX_REG_COUNT], *wrptr;
+ size_t idx;
+ int ret;
+
+ if (count > SIGMA_MAX_REG_COUNT) {
+ sr_err("Short command buffer for %zu reg reads at %u.", count, reg);
+ return SR_ERR_BUG;
+ }
+
+ wrptr = buf;
+ write_u8_inc(&wrptr, REG_ADDR_LOW | LO4(reg));
+ write_u8_inc(&wrptr, REG_ADDR_HIGH | HI4(reg));
+ for (idx = 0; idx < count; idx++)
+ write_u8_inc(&wrptr, REG_READ_ADDR | REG_ADDR_INC);
+ ret = sigma_write_sr(devc, buf, wrptr - buf);
+ if (ret != SR_OK)
+ return ret;
+
+ return sigma_read_sr(devc, data, count);
+}
+
static int sigma_read_pos(struct dev_context *devc,
uint32_t *stoppos, uint32_t *triggerpos, uint8_t *mode)
{
- /*
- * Read 7 registers starting at trigger position LSB.
- * Which yields two 24bit counter values, and mode flags.
- */
- const uint8_t buf[] = {
- /* Setup first register address. */
- REG_ADDR_LOW | READ_TRIGGER_POS_LOW,
- /* Retrieve trigger position. */
- REG_READ_ADDR | REG_ADDR_INC,
- REG_READ_ADDR | REG_ADDR_INC,
- REG_READ_ADDR | REG_ADDR_INC,
- /* Retrieve stop position. */
- REG_READ_ADDR | REG_ADDR_INC,
- REG_READ_ADDR | REG_ADDR_INC,
- REG_READ_ADDR | REG_ADDR_INC,
- /* Retrieve mode register. */
- REG_READ_ADDR | REG_ADDR_INC,
- }, *rdptr;
uint8_t result[7];
+ const uint8_t *rdptr;
uint32_t v32;
uint8_t v8;
int ret;
- ret = sigma_write_sr(devc, buf, sizeof(buf));
- if (ret != SR_OK)
- return ret;
-
- ret = sigma_read_sr(devc, result, sizeof(result));
+ /*
+ * Read 7 registers starting at trigger position LSB.
+ * Which yields two 24bit counter values, and mode flags.
+ */
+ ret = sigma_get_registers(devc, READ_TRIGGER_POS_LOW,
+ result, sizeof(result));
if (ret != SR_OK)
return ret;
}
static int sigma_read_dram(struct dev_context *devc,
- uint16_t startchunk, size_t numchunks, uint8_t *data)
+ size_t startchunk, size_t numchunks, uint8_t *data)
{
- uint8_t buf[128], *wrptr;
+ uint8_t buf[128], *wrptr, regval;
size_t chunk;
int sel, ret;
gboolean is_last;
/* Communicate DRAM start address (memory row, aka samples line). */
wrptr = buf;
- write_u8_inc(&wrptr, startchunk >> 8);
- write_u8_inc(&wrptr, startchunk & 0xff);
+ write_u16be_inc(&wrptr, startchunk);
ret = sigma_write_register(devc, WRITE_MEMROW, buf, wrptr - buf);
if (ret != SR_OK)
return ret;
for (chunk = 0; chunk < numchunks; chunk++) {
sel = chunk % 2;
is_last = chunk == numchunks - 1;
- if (!is_last)
- write_u8_inc(&wrptr, REG_DRAM_BLOCK | REG_DRAM_SEL_BOOL(!sel));
- write_u8_inc(&wrptr, REG_DRAM_BLOCK_DATA | REG_DRAM_SEL_BOOL(sel));
+ if (!is_last) {
+ regval = REG_DRAM_BLOCK | REG_DRAM_SEL_BOOL(!sel);
+ write_u8_inc(&wrptr, regval);
+ }
+ regval = REG_DRAM_BLOCK_DATA | REG_DRAM_SEL_BOOL(sel);
+ write_u8_inc(&wrptr, regval);
if (!is_last)
write_u8_inc(&wrptr, REG_DRAM_WAIT_ACK);
}
SR_PRIV int sigma_write_trigger_lut(struct dev_context *devc,
struct triggerlut *lut)
{
- int i;
- uint8_t tmp[2];
+ size_t lut_addr;
uint16_t bit;
- uint8_t buf[6], *wrptr, regval;
+ uint8_t m3d, m2d, m1d, m0d;
+ uint8_t buf[6], *wrptr, v8;
+ uint16_t selreg;
int ret;
- /* Transpose the table and send to Sigma. */
- for (i = 0; i < 16; i++) {
- bit = 1 << i;
+ /*
+ * Translate the LUT part of the trigger configuration from the
+ * application's perspective to the hardware register's bitfield
+ * layout. Send the LUT to the device. This configures the logic
+ * which combines pin levels or edges.
+ */
+ for (lut_addr = 0; lut_addr < 16; lut_addr++) {
+ bit = 1 << lut_addr;
- tmp[0] = tmp[1] = 0;
+ /* - M4 M3S M3Q */
+ m3d = 0;
+ if (lut->m4 & bit)
+ m3d |= 1 << 2;
+ if (lut->m3s & bit)
+ m3d |= 1 << 1;
+ if (lut->m3q & bit)
+ m3d |= 1 << 0;
- if (lut->m2d[0] & bit)
- tmp[0] |= 0x01;
- if (lut->m2d[1] & bit)
- tmp[0] |= 0x02;
- if (lut->m2d[2] & bit)
- tmp[0] |= 0x04;
+ /* M2D3 M2D2 M2D1 M2D0 */
+ m2d = 0;
if (lut->m2d[3] & bit)
- tmp[0] |= 0x08;
+ m2d |= 1 << 3;
+ if (lut->m2d[2] & bit)
+ m2d |= 1 << 2;
+ if (lut->m2d[1] & bit)
+ m2d |= 1 << 1;
+ if (lut->m2d[0] & bit)
+ m2d |= 1 << 0;
- if (lut->m3 & bit)
- tmp[0] |= 0x10;
- if (lut->m3s & bit)
- tmp[0] |= 0x20;
- if (lut->m4 & bit)
- tmp[0] |= 0x40;
+ /* M1D3 M1D2 M1D1 M1D0 */
+ m1d = 0;
+ if (lut->m1d[3] & bit)
+ m1d |= 1 << 3;
+ if (lut->m1d[2] & bit)
+ m1d |= 1 << 2;
+ if (lut->m1d[1] & bit)
+ m1d |= 1 << 1;
+ if (lut->m1d[0] & bit)
+ m1d |= 1 << 0;
- if (lut->m0d[0] & bit)
- tmp[1] |= 0x01;
- if (lut->m0d[1] & bit)
- tmp[1] |= 0x02;
- if (lut->m0d[2] & bit)
- tmp[1] |= 0x04;
+ /* M0D3 M0D2 M0D1 M0D0 */
+ m0d = 0;
if (lut->m0d[3] & bit)
- tmp[1] |= 0x08;
-
- if (lut->m1d[0] & bit)
- tmp[1] |= 0x10;
- if (lut->m1d[1] & bit)
- tmp[1] |= 0x20;
- if (lut->m1d[2] & bit)
- tmp[1] |= 0x40;
- if (lut->m1d[3] & bit)
- tmp[1] |= 0x80;
+ m0d |= 1 << 3;
+ if (lut->m0d[2] & bit)
+ m0d |= 1 << 2;
+ if (lut->m0d[1] & bit)
+ m0d |= 1 << 1;
+ if (lut->m0d[0] & bit)
+ m0d |= 1 << 0;
/*
- * This logic seems redundant, but separates the value
- * determination from the wire format, and is useful
- * during future maintenance and research.
+ * Send 16bits with M3D/M2D and M1D/M0D bit masks to the
+ * TriggerSelect register, then strobe the LUT write by
+ * passing A3-A0 to TriggerSelect2. Hold RESET during LUT
+ * programming.
*/
wrptr = buf;
- write_u8_inc(&wrptr, tmp[0]);
- write_u8_inc(&wrptr, tmp[1]);
- ret = sigma_write_register(devc, WRITE_TRIGGER_SELECT, buf, wrptr - buf);
+ write_u8_inc(&wrptr, (m3d << 4) | (m2d << 0));
+ write_u8_inc(&wrptr, (m1d << 4) | (m0d << 0));
+ ret = sigma_write_register(devc, WRITE_TRIGGER_SELECT,
+ buf, wrptr - buf);
if (ret != SR_OK)
return ret;
- ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x30 | i);
+ v8 = TRGSEL2_RESET | TRGSEL2_LUT_WRITE |
+ (lut_addr & TRGSEL2_LUT_ADDR_MASK);
+ ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, v8);
if (ret != SR_OK)
return ret;
}
- /* Send the parameters */
+ /*
+ * Send the parameters. This covers counters and durations.
+ */
wrptr = buf;
- regval = 0;
- regval |= lut->params.selc << 6;
- regval |= lut->params.selpresc << 0;
- write_u8_inc(&wrptr, regval);
- regval = 0;
- regval |= lut->params.selinc << 6;
- regval |= lut->params.selres << 4;
- regval |= lut->params.sela << 2;
- regval |= lut->params.selb << 0;
- write_u8_inc(&wrptr, regval);
- write_u16le_inc(&wrptr, lut->params.cmpb);
- write_u16le_inc(&wrptr, lut->params.cmpa);
+ selreg = 0;
+ selreg |= (lut->params.selinc & TRGSEL_SELINC_MASK) << TRGSEL_SELINC_SHIFT;
+ selreg |= (lut->params.selres & TRGSEL_SELRES_MASK) << TRGSEL_SELRES_SHIFT;
+ selreg |= (lut->params.sela & TRGSEL_SELA_MASK) << TRGSEL_SELA_SHIFT;
+ selreg |= (lut->params.selb & TRGSEL_SELB_MASK) << TRGSEL_SELB_SHIFT;
+ selreg |= (lut->params.selc & TRGSEL_SELC_MASK) << TRGSEL_SELC_SHIFT;
+ selreg |= (lut->params.selpresc & TRGSEL_SELPRESC_MASK) << TRGSEL_SELPRESC_SHIFT;
+ write_u16be_inc(&wrptr, selreg);
+ write_u16be_inc(&wrptr, lut->params.cmpb);
+ write_u16be_inc(&wrptr, lut->params.cmpa);
ret = sigma_write_register(devc, WRITE_TRIGGER_SELECT, buf, wrptr - buf);
if (ret != SR_OK)
return ret;
BB_PIN_CCLK,
BB_PIN_CCLK,
};
- int retries, ret;
+ size_t retries;
+ int ret;
uint8_t data;
/* Section 2. part 1), do the FPGA suicide. */
if (ret != SR_OK)
return ret;
g_usleep(10 * 1000);
- ftdi_usb_purge_buffers(&devc->ftdic);
+ ftdi_usb_purge_buffers(&devc->ftdi.ctx);
/*
* Wait until the FPGA asserts INIT_B. Check in a maximum number
*/
static int sigma_fpga_init_la(struct dev_context *devc)
{
- uint8_t buf[16], *wrptr;
+ uint8_t buf[20], *wrptr;
uint8_t data_55, data_aa, mode;
uint8_t result[3];
const uint8_t *rdptr;
wrptr = buf;
/* Read ID register. */
- write_u8_inc(&wrptr, REG_ADDR_LOW | (READ_ID & 0xf));
- write_u8_inc(&wrptr, REG_ADDR_HIGH | (READ_ID >> 4));
+ write_u8_inc(&wrptr, REG_ADDR_LOW | LO4(READ_ID));
+ write_u8_inc(&wrptr, REG_ADDR_HIGH | HI4(READ_ID));
write_u8_inc(&wrptr, REG_READ_ADDR);
/* Write 0x55 to scratch register, read back. */
data_55 = 0x55;
- write_u8_inc(&wrptr, REG_ADDR_LOW | (WRITE_TEST & 0xf));
- write_u8_inc(&wrptr, REG_DATA_LOW | (data_55 & 0xf));
- write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | (data_55 >> 4));
+ write_u8_inc(&wrptr, REG_ADDR_LOW | LO4(WRITE_TEST));
+ write_u8_inc(&wrptr, REG_ADDR_HIGH | HI4(WRITE_TEST));
+ write_u8_inc(&wrptr, REG_DATA_LOW | LO4(data_55));
+ write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | HI4(data_55));
write_u8_inc(&wrptr, REG_READ_ADDR);
/* Write 0xaa to scratch register, read back. */
data_aa = 0xaa;
- write_u8_inc(&wrptr, REG_ADDR_LOW | (WRITE_TEST & 0xf));
- write_u8_inc(&wrptr, REG_DATA_LOW | (data_aa & 0xf));
- write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | (data_aa >> 4));
+ write_u8_inc(&wrptr, REG_ADDR_LOW | LO4(WRITE_TEST));
+ write_u8_inc(&wrptr, REG_ADDR_HIGH | HI4(WRITE_TEST));
+ write_u8_inc(&wrptr, REG_DATA_LOW | LO4(data_aa));
+ write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | HI4(data_aa));
write_u8_inc(&wrptr, REG_READ_ADDR);
/* Initiate SDRAM initialization in mode register. */
mode = WMR_SDRAMINIT;
- write_u8_inc(&wrptr, REG_ADDR_LOW | (WRITE_MODE & 0xf));
- write_u8_inc(&wrptr, REG_DATA_LOW | (mode & 0xf));
- write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | (mode >> 4));
+ write_u8_inc(&wrptr, REG_ADDR_LOW | LO4(WRITE_MODE));
+ write_u8_inc(&wrptr, REG_ADDR_HIGH | HI4(WRITE_MODE));
+ write_u8_inc(&wrptr, REG_DATA_LOW | LO4(mode));
+ write_u8_inc(&wrptr, REG_DATA_HIGH_WRITE | HI4(mode));
/*
* Send the command sequence which contains 3 READ requests.
* by the caller of this function.
*/
static int sigma_fw_2_bitbang(struct sr_context *ctx, const char *name,
- uint8_t **bb_cmd, gsize *bb_cmd_size)
+ uint8_t **bb_cmd, size_t *bb_cmd_size)
{
uint8_t *firmware;
size_t file_size;
devc->state.state = SIGMA_CONFIG;
/* Set the cable to bitbang mode. */
- ret = ftdi_set_bitmode(&devc->ftdic, BB_PINMASK, BITMODE_BITBANG);
+ ret = ftdi_set_bitmode(&devc->ftdi.ctx, BB_PINMASK, BITMODE_BITBANG);
if (ret < 0) {
sr_err("Could not setup cable mode for upload: %s",
- ftdi_get_error_string(&devc->ftdic));
+ ftdi_get_error_string(&devc->ftdi.ctx));
return SR_ERR;
}
- ret = ftdi_set_baudrate(&devc->ftdic, BB_BITRATE);
+ ret = ftdi_set_baudrate(&devc->ftdi.ctx, BB_BITRATE);
if (ret < 0) {
sr_err("Could not setup bitrate for upload: %s",
- ftdi_get_error_string(&devc->ftdic));
+ ftdi_get_error_string(&devc->ftdi.ctx));
return SR_ERR;
}
}
/* Leave bitbang mode and discard pending input data. */
- ret = ftdi_set_bitmode(&devc->ftdic, 0, BITMODE_RESET);
+ ret = ftdi_set_bitmode(&devc->ftdi.ctx, 0, BITMODE_RESET);
if (ret < 0) {
sr_err("Could not setup cable mode after upload: %s",
- ftdi_get_error_string(&devc->ftdic));
+ ftdi_get_error_string(&devc->ftdi.ctx));
return SR_ERR;
}
- ftdi_usb_purge_buffers(&devc->ftdic);
+ ftdi_usb_purge_buffers(&devc->ftdi.ctx);
while (sigma_read_raw(devc, &pins, sizeof(pins)) > 0)
;
g_variant_unref(data);
count_msecs = 0;
if (user_count)
- count_msecs = 1000 * user_count / devc->samplerate + 1;
+ count_msecs = 1000 * user_count / devc->clock.samplerate + 1;
/* Get time limit, which is in msecs. */
ret = sr_sw_limits_config_get(&devc->cfg_limits,
return SR_OK;
/* Add some slack, and use that timeout for acquisition. */
- worst_cluster_time_ms = 1000 * 65536 / devc->samplerate;
+ worst_cluster_time_ms = 1000 * 65536 / devc->clock.samplerate;
acquire_msecs += 2 * worst_cluster_time_ms;
data = g_variant_new_uint64(acquire_msecs);
ret = sr_sw_limits_config_set(&devc->acq_limits,
return SR_ERR_ARG;
}
+/* Gets called at probe time. Can seed software settings from hardware state. */
+SR_PRIV int sigma_fetch_hw_config(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ int ret;
+ uint8_t regaddr, regval;
+
+ devc = sdi->priv;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ /* Seed configuration values from defaults. */
+ devc->firmware_idx = SIGMA_FW_NONE;
+ devc->clock.samplerate = samplerates[0];
+
+ /* TODO
+ * Ideally the device driver could retrieve recently stored
+ * details from hardware registers, thus re-use user specified
+ * configuration values across sigrok sessions. Which could
+ * avoid repeated expensive though unnecessary firmware uploads,
+ * improve performance and usability. Unfortunately it appears
+ * that the registers range which is documented as available for
+ * application use keeps providing 0xff data content. At least
+ * with the netlist version which ships with sigrok. The same
+ * was observed with unused registers in the first page.
+ */
+ return SR_ERR_NA;
+
+ /* This is for research, currently does not work yet. */
+ ret = sigma_check_open(sdi);
+ regaddr = 16;
+ regaddr = 14;
+ ret = sigma_set_register(devc, regaddr, 'F');
+ ret = sigma_get_register(devc, regaddr, ®val);
+ sr_warn("%s() reg[%u] val[%u] rc[%d]", __func__, regaddr, regval, ret);
+ ret = sigma_check_close(devc);
+ return ret;
+}
+
+/* Gets called after successful (volatile) hardware configuration. */
+SR_PRIV int sigma_store_hw_config(const struct sr_dev_inst *sdi)
+{
+ /* TODO See above, registers seem to not hold written data. */
+ (void)sdi;
+ return SR_ERR_NA;
+}
+
SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct drv_context *drvc;
uint64_t samplerate;
int ret;
- int num_channels;
+ size_t num_channels;
devc = sdi->priv;
drvc = sdi->driver->context;
/* Accept any caller specified rate which the hardware supports. */
- ret = sigma_normalize_samplerate(devc->samplerate, &samplerate);
+ ret = sigma_normalize_samplerate(devc->clock.samplerate, &samplerate);
if (ret != SR_OK)
return ret;
devc->samples_per_event = 16 / devc->num_channels;
}
+ /*
+ * Store the firmware type and most recently configured samplerate
+ * in hardware, such that subsequent sessions can start from there.
+ * This is a "best effort" approach. Failure is non-fatal.
+ */
+ if (ret == SR_OK)
+ (void)sigma_store_hw_config(sdi);
+
return ret;
}
struct sr_trigger_stage *stage;
struct sr_trigger_match *match;
const GSList *l, *m;
- int channelbit, trigger_set;
+ uint16_t channelbit;
+ size_t trigger_set;
devc = sdi->priv;
memset(&devc->trigger, 0, sizeof(devc->trigger));
if (!match->channel->enabled)
continue;
channelbit = 1 << match->channel->index;
- if (devc->samplerate >= SR_MHZ(100)) {
+ if (devc->clock.samplerate >= SR_MHZ(100)) {
/* Fast trigger support. */
if (trigger_set) {
sr_err("100/200MHz modes limited to single trigger pin.");
struct sigma_trigger *t)
{
const uint8_t *rdptr;
- int i;
+ size_t i;
uint16_t sample;
rdptr = samples;
{
struct sigma_state *ss;
uint16_t tsdiff, ts, sample, item16;
- unsigned int i;
+ size_t count;
+ size_t evt;
if (!devc->use_triggers || !ASIX_SIGMA_WITH_TRIGGER)
triggered = FALSE;
ts = sigma_dram_cluster_ts(dram_cluster);
tsdiff = ts - ss->lastts;
if (tsdiff > 0) {
- size_t count;
sample = ss->lastsample;
count = tsdiff * devc->samples_per_event;
(void)check_and_submit_sample(devc, sample, count, FALSE);
* buffer depth is neither assumed nor required here.
*/
sample = 0;
- for (i = 0; i < events_in_cluster; i++) {
- item16 = sigma_dram_cluster_data(dram_cluster, i);
- if (devc->samplerate == SR_MHZ(200)) {
+ for (evt = 0; evt < events_in_cluster; evt++) {
+ item16 = sigma_dram_cluster_data(dram_cluster, evt);
+ if (devc->clock.samplerate == SR_MHZ(200)) {
sample = sigma_deinterlace_200mhz_data(item16, 0);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_200mhz_data(item16, 1);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_200mhz_data(item16, 3);
check_and_submit_sample(devc, sample, 1, triggered);
- } else if (devc->samplerate == SR_MHZ(100)) {
+ } else if (devc->clock.samplerate == SR_MHZ(100)) {
sample = sigma_deinterlace_100mhz_data(item16, 0);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_100mhz_data(item16, 1);
size_t events_in_line, size_t trigger_event)
{
struct sigma_dram_cluster *dram_cluster;
- unsigned int clusters_in_line;
- unsigned int events_in_cluster;
- unsigned int i;
- uint32_t trigger_cluster;
+ size_t clusters_in_line;
+ size_t events_in_cluster;
+ size_t cluster;
+ size_t trigger_cluster;
clusters_in_line = events_in_line;
clusters_in_line += EVENTS_PER_CLUSTER - 1;
clusters_in_line /= EVENTS_PER_CLUSTER;
- trigger_cluster = ~0;
/* Check if trigger is in this chunk. */
+ trigger_cluster = ~0UL;
if (trigger_event < EVENTS_PER_ROW) {
- if (devc->samplerate <= SR_MHZ(50)) {
+ if (devc->clock.samplerate <= SR_MHZ(50)) {
trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
trigger_event);
}
}
/* For each full DRAM cluster. */
- for (i = 0; i < clusters_in_line; i++) {
- dram_cluster = &dram_line->cluster[i];
+ for (cluster = 0; cluster < clusters_in_line; cluster++) {
+ dram_cluster = &dram_line->cluster[cluster];
/* The last cluster might not be full. */
- if ((i == clusters_in_line - 1) &&
+ if ((cluster == clusters_in_line - 1) &&
(events_in_line % EVENTS_PER_CLUSTER)) {
events_in_cluster = events_in_line % EVENTS_PER_CLUSTER;
} else {
}
sigma_decode_dram_cluster(devc, dram_cluster,
- events_in_cluster, i == trigger_cluster);
+ events_in_cluster, cluster == trigger_cluster);
}
return SR_OK;
struct sigma_dram_line *dram_line;
uint32_t stoppos, triggerpos;
uint8_t modestatus;
- uint32_t i;
- uint32_t dl_lines_total, dl_lines_curr, dl_lines_done;
- uint32_t dl_first_line, dl_line;
- uint32_t dl_events_in_line, trigger_event;
- uint32_t trg_line, trg_event;
+ size_t line_idx;
+ size_t dl_lines_total, dl_lines_curr, dl_lines_done;
+ size_t dl_first_line, dl_line;
+ size_t dl_events_in_line, trigger_event;
+ size_t trg_line, trg_event;
int ret;
devc = sdi->priv;
if (ret != SR_OK)
return ret;
do {
- ret = sigma_read_register(devc, READ_MODE,
- &modestatus, sizeof(modestatus));
+ ret = sigma_get_register(devc, READ_MODE, &modestatus);
if (ret != SR_OK) {
sr_err("Could not poll for post-trigger state.");
return FALSE;
sr_err("Could not query capture positions/state.");
return FALSE;
}
- trg_line = ~0;
- trg_event = ~0;
+ trg_line = ~0UL;
+ trg_event = ~0UL;
if (modestatus & RMR_TRIGGERED) {
trg_line = triggerpos >> ROW_SHIFT;
trg_event = triggerpos & ROW_MASK;
devc->state.lastsample = 0;
}
- for (i = 0; i < dl_lines_curr; i++) {
+ for (line_idx = 0; line_idx < dl_lines_curr; line_idx++) {
/* The last "DRAM line" need not span its full length. */
dl_events_in_line = EVENTS_PER_ROW;
- if (dl_lines_done + i == dl_lines_total - 1)
+ if (dl_lines_done + line_idx == dl_lines_total - 1)
dl_events_in_line = stoppos & ROW_MASK;
/* Test if the trigger happened on this line. */
- trigger_event = ~0;
- if (dl_lines_done + i == trg_line)
+ trigger_event = ~0UL;
+ if (dl_lines_done + line_idx == trg_line)
trigger_event = trg_event;
- decode_chunk_ts(devc, dram_line + i,
+ decode_chunk_ts(devc, dram_line + line_idx,
dl_events_in_line, trigger_event);
}
}
/* Build a LUT entry used by the trigger functions. */
-static void build_lut_entry(uint16_t value, uint16_t mask, uint16_t *entry)
+static void build_lut_entry(uint16_t *lut_entry,
+ uint16_t spec_value, uint16_t spec_mask)
{
- int i, j, k, bit;
-
- /* For each quad channel. */
- for (i = 0; i < 4; i++) {
- entry[i] = 0xffff;
-
- /* For each bit in LUT. */
- for (j = 0; j < 16; j++) {
-
- /* For each channel in quad. */
- for (k = 0; k < 4; k++) {
- bit = 1 << (i * 4 + k);
+ size_t quad, bitidx, ch;
+ uint16_t quadmask, bitmask;
+ gboolean spec_value_low, bit_idx_low;
- /* Set bit in entry */
- if ((mask & bit) && ((!(value & bit)) !=
- (!(j & (1 << k)))))
- entry[i] &= ~(1 << j);
+ /*
+ * For each quad-channel-group, for each bit in the LUT (each
+ * bit pattern of the channel signals, aka LUT address), for
+ * each channel in the quad, setup the bit in the LUT entry.
+ *
+ * Start from all-ones in the LUT (true, always matches), then
+ * "pessimize the truthness" for specified conditions.
+ */
+ for (quad = 0; quad < 4; quad++) {
+ lut_entry[quad] = ~0;
+ for (bitidx = 0; bitidx < 16; bitidx++) {
+ for (ch = 0; ch < 4; ch++) {
+ quadmask = 1 << ch;
+ bitmask = quadmask << (quad * 4);
+ if (!(spec_mask & bitmask))
+ continue;
+ /*
+ * This bit is part of the spec. The
+ * condition which gets checked here
+ * (got checked in all implementations
+ * so far) is uncertain. A bit position
+ * in the current index' number(!) is
+ * checked?
+ */
+ spec_value_low = !(spec_value & bitmask);
+ bit_idx_low = !(bitidx & quadmask);
+ if (spec_value_low == bit_idx_low)
+ continue;
+ lut_entry[quad] &= ~(1 << bitidx);
}
}
}
/* Add a logical function to LUT mask. */
static void add_trigger_function(enum triggerop oper, enum triggerfunc func,
- int index, int neg, uint16_t *mask)
+ size_t index, gboolean neg, uint16_t *mask)
{
- int i, j;
+ size_t i, j;
int x[2][2], tmp, a, b, aset, bset, rset;
memset(x, 0, sizeof(x));
SR_PRIV int sigma_build_basic_trigger(struct dev_context *devc,
struct triggerlut *lut)
{
- int i,j;
uint16_t masks[2];
+ size_t bitidx, condidx;
+ uint16_t value, mask;
+ /* Start assuming simple triggers. */
memset(lut, 0, sizeof(*lut));
- memset(&masks, 0, sizeof(masks));
-
- /* Constant for simple triggers. */
lut->m4 = 0xa000;
+ lut->m3q = 0xffff;
- /* Value/mask trigger support. */
- build_lut_entry(devc->trigger.simplevalue, devc->trigger.simplemask,
- lut->m2d);
+ /* Process value/mask triggers. */
+ value = devc->trigger.simplevalue;
+ mask = devc->trigger.simplemask;
+ build_lut_entry(lut->m2d, value, mask);
- /* Rise/fall trigger support. */
- for (i = 0, j = 0; i < 16; i++) {
- if (devc->trigger.risingmask & (1 << i) ||
- devc->trigger.fallingmask & (1 << i))
- masks[j++] = 1 << i;
+ /* Scan for and process rise/fall triggers. */
+ memset(&masks, 0, sizeof(masks));
+ condidx = 0;
+ for (bitidx = 0; bitidx < 16; bitidx++) {
+ mask = 1 << bitidx;
+ value = devc->trigger.risingmask | devc->trigger.fallingmask;
+ if (!(value & mask))
+ continue;
+ if (condidx == 0)
+ build_lut_entry(lut->m0d, mask, mask);
+ if (condidx == 1)
+ build_lut_entry(lut->m1d, mask, mask);
+ masks[condidx++] = mask;
+ if (condidx == ARRAY_SIZE(masks))
+ break;
}
- build_lut_entry(masks[0], masks[0], lut->m0d);
- build_lut_entry(masks[1], masks[1], lut->m1d);
-
- /* Add glue logic */
+ /* Add glue logic for rise/fall triggers. */
if (masks[0] || masks[1]) {
- /* Transition trigger. */
+ lut->m3q = 0;
if (masks[0] & devc->trigger.risingmask)
- add_trigger_function(OP_RISE, FUNC_OR, 0, 0, &lut->m3);
+ add_trigger_function(OP_RISE, FUNC_OR, 0, 0, &lut->m3q);
if (masks[0] & devc->trigger.fallingmask)
- add_trigger_function(OP_FALL, FUNC_OR, 0, 0, &lut->m3);
+ add_trigger_function(OP_FALL, FUNC_OR, 0, 0, &lut->m3q);
if (masks[1] & devc->trigger.risingmask)
- add_trigger_function(OP_RISE, FUNC_OR, 1, 0, &lut->m3);
+ add_trigger_function(OP_RISE, FUNC_OR, 1, 0, &lut->m3q);
if (masks[1] & devc->trigger.fallingmask)
- add_trigger_function(OP_FALL, FUNC_OR, 1, 0, &lut->m3);
- } else {
- /* Only value/mask trigger. */
- lut->m3 = 0xffff;
+ add_trigger_function(OP_FALL, FUNC_OR, 1, 0, &lut->m3q);
}
/* Triggertype: event. */
- lut->params.selres = 3;
+ lut->params.selres = TRGSEL_SELCODE_NEVER;
+ lut->params.selinc = TRGSEL_SELCODE_LEVEL;
+ lut->params.sela = 0; /* Counter >= CMPA && LEVEL */
+ lut->params.cmpa = 0; /* Count 0 -> 1 already triggers. */
return SR_OK;
}