diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c index 043c08551..295c72fd6 100644 --- a/src/hardware/openbench-logic-sniffer/api.c +++ b/src/hardware/openbench-logic-sniffer/api.c @@ -45,11 +45,19 @@ static const uint32_t devopts[] = { SR_CONF_RLE | SR_CONF_GET | SR_CONF_SET, }; -static const int32_t trigger_matches[] = { +static const int32_t basic_trigger_matches[] = { SR_TRIGGER_ZERO, SR_TRIGGER_ONE, }; +static const int32_t advanced_trigger_matches[] = { + SR_TRIGGER_ZERO, + SR_TRIGGER_ONE, + SR_TRIGGER_RISING, + SR_TRIGGER_FALLING, + SR_TRIGGER_EDGE, +}; + static const char *external_clock_edges[] = { "rising", /* positive edge */ "falling" /* negative edge */ @@ -382,7 +390,7 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { - struct dev_context *devc; + struct dev_context *devc = sdi ? sdi->priv : NULL; int num_ols_changrp, i; uint64_t samplerates_ovrd[3]; @@ -404,7 +412,12 @@ static int config_list(uint32_t key, GVariant **data, *data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates_ovrd)); break; case SR_CONF_TRIGGER_MATCH: - *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); + if (!devc) + return SR_ERR_ARG; + /* Advanced Triggering is only available on the Demon Core. */ + *data = devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE + ? std_gvar_array_i32(ARRAY_AND_SIZE(advanced_trigger_matches)) + : std_gvar_array_i32(ARRAY_AND_SIZE(basic_trigger_matches)); break; case SR_CONF_CLOCK_EDGE: *data = std_gvar_array_str(ARRAY_AND_SIZE(external_clock_edges)); @@ -413,9 +426,8 @@ static int config_list(uint32_t key, GVariant **data, *data = g_variant_new_strv(ARRAY_AND_SIZE(patterns)); break; case SR_CONF_LIMIT_SAMPLES: - if (!sdi) + if (!devc) return SR_ERR_ARG; - devc = sdi->priv; if (devc->max_samples == 0) /* Device didn't specify sample memory size in metadata. */ return SR_ERR_NA; @@ -454,7 +466,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return ret; /* Start acquisition on the device. */ - if (send_shortcommand(serial, CMD_ARM_BASIC_TRIGGER) != SR_OK) + if (send_shortcommand(serial, + devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE ? + CMD_ARM_ADVANCED_TRIGGER : + CMD_ARM_BASIC_TRIGGER) != SR_OK) return SR_ERR; /* Reset all operational states. */ diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c index 6bbbd5977..5b791cd04 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.c +++ b/src/hardware/openbench-logic-sniffer/protocol.c @@ -2,6 +2,7 @@ * This file is part of the libsigrok project. * * Copyright (C) 2013 Bert Vermeulen + * Copyright (C) 2011 Ian Davis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,10 @@ struct ols_basic_trigger_desc { int num_stages; }; +static int +ols_convert_and_set_up_advanced_trigger(const struct sr_dev_inst *sdi, + int *num_stages); + SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial, uint8_t command) { @@ -112,8 +117,8 @@ SR_PRIV uint32_t ols_channel_mask(const struct sr_dev_inst *sdi) return channel_mask; } -static int convert_trigger(const struct sr_dev_inst *sdi, - struct ols_basic_trigger_desc *ols_trigger) +static int ols_convert_basic_trigger(const struct sr_dev_inst *sdi, + struct ols_basic_trigger_desc *ols_trigger) { struct sr_trigger *trigger; struct sr_trigger_stage *stage; @@ -144,11 +149,21 @@ static int convert_trigger(const struct sr_dev_inst *sdi, if (!match->channel->enabled) /* Ignore disabled channels with a trigger. */ continue; + ols_trigger->trigger_mask[stage->stage] |= 1 << match->channel->index; - if (match->match == SR_TRIGGER_ONE) + switch (match->match) { + case SR_TRIGGER_ZERO: + break; + case SR_TRIGGER_ONE: ols_trigger->trigger_value[stage->stage] |= 1 << match->channel->index; + break; + default: + sr_err("Unsupported trigger type: %d", + match->match); + return SR_ERR; + } } } @@ -360,12 +375,18 @@ SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi, SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi) { + int ret; struct sr_serial_dev_inst *serial = sdi->conn; ols_send_reset(serial); - serial_source_remove(sdi->session, serial); - std_session_send_df_end(sdi); + ret = serial_source_remove(sdi->session, serial); + if (ret != SR_OK) + sr_warn("Couldn't close serial port: %i", ret); + + ret = std_session_send_df_end(sdi); + if (ret != SR_OK) + sr_warn("Couldn't end session: %i", ret); } SR_PRIV void set_rle_trigger_point_if_unset(struct dev_context *devc) @@ -385,7 +406,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) struct sr_datafeed_logic logic; uint32_t sample; int num_bytes_read, bytes_left_to_read; - unsigned int i, j, num_changroups; + unsigned int num_changroups; gboolean received_a_byte; (void)fd; @@ -400,7 +421,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) } num_changroups = 0; - for (i = 0x20; i > 0x02; i >>= 1) { + for (uint16_t i = 0x20; i > 0x02; i >>= 1) { if ((devc->capture_flags & i) == 0) { num_changroups++; } @@ -423,7 +444,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) devc->raw_sample_size); if (devc->raw_sample_size == num_changroups) { - unsigned int samples_to_write, new_sample_buf_size; + unsigned int samples_to_write; + uint64_t new_sample_buf_size; devc->cnt_rx_raw_samples++; /* @@ -448,8 +470,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) sample &= ~(0x80 << (devc->raw_sample_size - 1) * 8); - devc->rle_count = sample; - sr_dbg("RLE count: %u.", + devc->rle_count += sample; + sr_dbg("RLE count: %" PRIu64, devc->rle_count); devc->raw_sample_size = 0; @@ -475,9 +497,9 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * For simplicity we expand the sample to 32 bits * little endian, and crop below */ - j = 0; + unsigned int j = 0; uint8_t tmp_sample[4] = { 0, 0, 0, 0 }; - for (i = 0; i < 4; i++) { + for (unsigned int i = 0; i < 4; i++) { if (((devc->capture_flags >> 2) & (1 << i)) == 0) { /* @@ -503,7 +525,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) MAX(devc->limit_samples, devc->cnt_samples + samples_to_write); if (devc->sample_buf_size < new_sample_buf_size) { - unsigned int old_size = devc->sample_buf_size; + uint64_t old_size = devc->sample_buf_size; new_sample_buf_size *= 2; devc->sample_buf = g_try_realloc( devc->sample_buf, new_sample_buf_size); @@ -521,7 +543,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) if (devc->capture_flags & CAPTURE_FLAG_RLE) set_rle_trigger_point_if_unset(devc); - for (i = 0; i < samples_to_write; i++) + for (uint64_t i = 0; i < samples_to_write; i++) memcpy(devc->sample_buf + (devc->cnt_samples + i) * devc->unitsize, devc->raw_sample, devc->unitsize); @@ -549,7 +571,8 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * we've acquired all the samples we asked for -- we're done. * Send the (properly-ordered) buffer to the frontend. */ - sr_dbg("Received %d bytes, %d raw samples, %d decompressed samples.", + sr_dbg("Received %d bytes, %d raw samples, %" PRIu64 + " decompressed samples.", devc->cnt_rx_bytes, devc->cnt_rx_raw_samples, devc->cnt_samples); @@ -570,7 +593,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data) * The OLS sends its sample buffer backwards. * Flip it back before sending it on the session bus. */ - for (i = 0; i < devc->cnt_samples / 2; i++) { + for (uint64_t i = 0; i < devc->cnt_samples / 2; i++) { uint8_t temp[devc->unitsize]; memcpy(temp, &devc->sample_buf[devc->unitsize * i], devc->unitsize); memmove(&devc->sample_buf[devc->unitsize * i], @@ -664,6 +687,14 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) struct dev_context *devc = sdi->priv; struct sr_serial_dev_inst *serial = sdi->conn; + /* + * According to http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf + * reset command must be send prior each arm command + */ + sr_dbg("Send reset command before trigger configure"); + if ((ret = ols_send_reset(serial)) != SR_OK) + return ret; + int num_changroups = 0; uint8_t changroup_mask = 0; uint32_t channel_mask = ols_channel_mask(sdi); @@ -683,37 +714,51 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) readcount = devc->limit_samples / 4; trigger_point = OLS_NO_TRIGGER; - /* Basic triggers. */ - struct ols_basic_trigger_desc basic_trigger_desc; - if (convert_trigger(sdi, &basic_trigger_desc) != SR_OK) { - sr_err("Failed to configure channels."); - return SR_ERR; - } - if (basic_trigger_desc.num_stages > 0) { - /* - * According to http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf - * reset command must be send prior each arm command - */ - sr_dbg("Send reset command before trigger configure"); - if (ols_send_reset(serial) != SR_OK) + if (!(devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE)) { + /* basic trigger only */ + struct ols_basic_trigger_desc basic_trigger_desc; + if (ols_convert_basic_trigger(sdi, &basic_trigger_desc) != + SR_OK) { + sr_err("Failed to configure channels."); return SR_ERR; - - delaycount = readcount * (1 - devc->capture_ratio / 100.0); - trigger_point = (readcount - delaycount) * 4 - 1; - for (int i = 0; i < basic_trigger_desc.num_stages; i++) { - sr_dbg("Setting OLS stage %d trigger.", i); + } + if (basic_trigger_desc.num_stages > 0) { + delaycount = + readcount * (1 - devc->capture_ratio / 100.0); + trigger_point = (readcount - delaycount) * 4 - 1; + for (int i = 0; i < basic_trigger_desc.num_stages; + i++) { + sr_dbg("Setting OLS stage %d trigger.", i); + ret = ols_set_basic_trigger_stage( + &basic_trigger_desc, serial, i); + if (ret != SR_OK) + return ret; + } + } else { + /* No triggers configured, force trigger on first stage. */ + sr_dbg("Forcing trigger at stage 0."); + basic_trigger_desc.num_stages = 1; if ((ret = ols_set_basic_trigger_stage( - &basic_trigger_desc, serial, i)) != SR_OK) + &basic_trigger_desc, serial, 0)) != SR_OK) return ret; + + delaycount = readcount; } } else { - /* No triggers configured, force trigger on first stage. */ - sr_dbg("Forcing trigger at stage 0."); - basic_trigger_desc.num_stages = 1; - if ((ret = ols_set_basic_trigger_stage(&basic_trigger_desc, - serial, 0)) != SR_OK) - return ret; - delaycount = readcount; + /* advanced trigger setup */ + gboolean will_trigger = FALSE; + if (ols_convert_and_set_up_advanced_trigger( + sdi, &will_trigger) != SR_OK) { + sr_err("Advanced trigger setup failed."); + return SR_ERR; + } + + if (will_trigger) { + delaycount = + readcount * (1 - devc->capture_ratio / 100.0); + trigger_point = (readcount - delaycount) * 4; + } else + delaycount = readcount; } /* @@ -779,10 +824,554 @@ SR_PRIV int ols_prepare_acquisition(const struct sr_dev_inst *sdi) devc->capture_flags &= ~0x3c; devc->capture_flags |= ~(changroup_mask << 2) & 0x3c; - /* RLE mode is always zero, for now. */ + /* + * Demon Core supports RLE mode 3. In this mode, an arbitrary number of + * consecutive RLE messages can occur. The value is only sent whenever + * it changes. In contrast, mode 0 repeats the value after every RLE + * message, even if it didn't change. + */ + if (devc->device_flags & DEVICE_FLAG_IS_DEMON_CORE) + devc->capture_flags |= CAPTURE_FLAG_RLEMODE0 | + CAPTURE_FLAG_RLEMODE1; + else + devc->capture_flags &= + ~(CAPTURE_FLAG_RLEMODE0 | CAPTURE_FLAG_RLEMODE1); if (ols_send_longdata(serial, CMD_SET_FLAGS, devc->capture_flags) != SR_OK) return SR_ERR; return SR_OK; } + +/* set up a level trigger stage to trigger when (input & mask) == target */ +static int ols_set_advanced_level_trigger( + struct sr_serial_dev_inst *serial, + uint8_t num_trigger_term, /* 0-9 for trigger terms a-j */ + uint32_t target, uint32_t mask) +{ + int ret; + uint32_t lutmask = 1; + uint32_t lutbits[4] = { 0, 0, 0, 0 }; + + for (uint32_t i = 0; i < 16; ++i) { + if (((i ^ ((target >> 0) & 0xF)) & ((mask >> 0) & 0xF)) == 0) + lutbits[0] |= lutmask; + if (((i ^ ((target >> 4) & 0xF)) & ((mask >> 4) & 0xF)) == 0) + lutbits[0] |= (lutmask << 16); + if (((i ^ ((target >> 8) & 0xF)) & ((mask >> 8) & 0xF)) == 0) + lutbits[1] |= lutmask; + if (((i ^ ((target >> 12) & 0xF)) & ((mask >> 12) & 0xF)) == 0) + lutbits[1] |= (lutmask << 16); + if (((i ^ ((target >> 16) & 0xF)) & ((mask >> 16) & 0xF)) == 0) + lutbits[2] |= lutmask; + if (((i ^ ((target >> 20) & 0xF)) & ((mask >> 20) & 0xF)) == 0) + lutbits[2] |= (lutmask << 16); + if (((i ^ ((target >> 24) & 0xF)) & ((mask >> 24) & 0xF)) == 0) + lutbits[3] |= lutmask; + if (((i ^ ((target >> 28) & 0xF)) & ((mask >> 28) & 0xF)) == 0) + lutbits[3] |= (lutmask << 16); + lutmask <<= 1; + } + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, 0x20 + (num_trigger_term % 10)); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[3]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[2]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[1]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits[0]); + if (ret != SR_OK) + return ret; + + return SR_OK; +} + +#define OLS_ADV_TRIG_EDGERISE0 0x0A0A +#define OLS_ADV_TRIG_EDGERISE1 0x00CC +#define OLS_ADV_TRIG_EDGEFALL0 0x5050 +#define OLS_ADV_TRIG_EDGEFALL1 0x3300 +#define OLS_ADV_TRIG_EDGEBOTH0 (OLS_ADV_TRIG_EDGERISE0 | OLS_ADV_TRIG_EDGEFALL0) +#define OLS_ADV_TRIG_EDGEBOTH1 (OLS_ADV_TRIG_EDGERISE1 | OLS_ADV_TRIG_EDGEFALL1) +#define OLS_ADV_TRIG_EDGENEITHER0 (~OLS_ADV_TRIG_EDGEBOTH0 & 0xFFFF) /* means neither rise nor fall: constant signal */ +#define OLS_ADV_TRIG_EDGENEITHER1 (~OLS_ADV_TRIG_EDGEBOTH1 & 0xFFFF) + +/* Set up edge trigger LUTs. + * + * All edge triggers of one unit are ORed together, not ANDed. This + * differs from level triggers, where all levels have to be met at the + * same time. This code is at least consistent in that it also ORs together + * pairs of edge triggers. + */ +static int +ols_set_advanced_edge_trigger(struct sr_serial_dev_inst *serial, + int edgesel, /* which edge trigger unit, 0 or 1 */ + uint32_t rising_edge, uint32_t falling_edge, + uint32_t neither_edge) +{ + int ret; + uint32_t lutbits = 0; + uint32_t bitmask = 0x80000000; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, + 0x34 + (edgesel & 1)); + if (ret != SR_OK) + return ret; + + for (unsigned int i = 0; i < 16; i = i + 1) { + /* Evaluate indata bit1... */ + if (neither_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGENEITHER1; + else { + if (rising_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGERISE1; + if (falling_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGEFALL1; + } + bitmask >>= 1; + + /* Evaluate indata bit0... */ + if (neither_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGENEITHER0; + else { + if (rising_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGERISE0; + if (falling_edge & bitmask) + lutbits |= OLS_ADV_TRIG_EDGEFALL0; + } + bitmask >>= 1; + + if ((i & 1) == 0) + lutbits <<= 16; + else { + /* write total of 256 bits */ + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_WRITE, lutbits); + if (ret != SR_OK) + return ret; + lutbits = 0; + } + } + + return SR_OK; +} + +static int ols_set_advanced_trigger_timer(struct sr_serial_dev_inst *serial, + int timersel, /* 0 or 1 */ + uint64_t count_10ns) +{ + int ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_SEL, 0x38 + (timersel & 1) * 2); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_WRITE, count_10ns & 0xFFFFFFFF); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_SEL, 0x39 + (timersel & 1) * 2); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata( + serial, CMD_SET_ADVANCED_TRIG_WRITE, count_10ns >> 32); + if (ret != SR_OK) + return ret; + + return SR_OK; +} + +#define OLS_ADV_TRIG_STATETERM_HIT 0 +#define OLS_ADV_TRIG_STATETERM_ELSE 1 +#define OLS_ADV_TRIG_STATETERM_CAPTURE 2 + +#define OLS_ADV_TRIG_OP_NOP 0 +#define OLS_ADV_TRIG_OP_ANY 1 +#define OLS_ADV_TRIG_OP_AND 2 +#define OLS_ADV_TRIG_OP_NAND 3 +#define OLS_ADV_TRIG_OP_OR 4 +#define OLS_ADV_TRIG_OP_NOR 5 +#define OLS_ADV_TRIG_OP_XOR 6 +#define OLS_ADV_TRIG_OP_NXOR 7 +#define OLS_ADV_TRIG_OP_A 8 +#define OLS_ADV_TRIG_OP_B 9 +/* NOP ANY AND NAND OR NOR XOR NXOR A B */ +static const uint32_t pairvalue[] = {0x0000, 0xFFFF, 0x8000, 0x7FFF, 0xF888, 0x0777, 0x7888, 0x8777, 0x8888, 0xF000}; +static const uint32_t midvalue[] = {0x0000, 0xFFFF, 0x8000, 0x7FFF, 0xFFFE, 0x0001, 0x0116, 0xFEE9, 0xEEEE, 0xFFF0}; +static const uint32_t finalvalue[] = {0x0000, 0xFFFF, 0x0008, 0x0007, 0x000E, 0x0001, 0x0006, 0x0009, 0x0002, 0x0004}; + +/* + * Trigger input summing stage: Combines different inputs in arbitrary ways. + * Keep in mind that all primary inputs (a, edge etc.) output a pair of bits per + * input. That's why those LUTs have 2 inputs, whereas the mid LUTs have + * 4 inputs. Only half of the final LUT is used. + */ +static int ols_set_advanced_trigger_sum( + struct sr_serial_dev_inst *serial, + int statenum, /* 0-15 */ + int stateterm, /* 0: hit, 1: else, 2: capture */ + int op_ab, + int op_c_range1, + int op_d_edge1, + int op_e_timer1, + int op_fg, + int op_h_range2, + int op_i_edge2, + int op_j_timer2, + int op_mid1, /* sums up a, b, c, range1, d, edge1, e, timer1 */ + int op_mid2, /* sums up f, g, h, range2, i, edge2, j, timer2 */ + int op_final) /* sums up mid1, mid2 */ +{ + int ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, + 0x40 + (statenum * 4) + stateterm); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + finalvalue[op_final]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (midvalue[op_mid2] << 16) | midvalue[op_mid1]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_j_timer2] << 16) | pairvalue[op_i_edge2]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_h_range2] << 16) | pairvalue[op_fg]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_e_timer1] << 16) | pairvalue[op_d_edge1]); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, + (pairvalue[op_c_range1] << 16) | pairvalue[op_ab]); + if (ret != SR_OK) + return ret; + + return SR_OK; +} + +#define TRIGSTATE_STATENUM_MASK 0xF +#define TRIGSTATE_OBTAIN_MASK 0x000FFFFF +#define TRIGSTATE_ELSE_BITOFS 20 +#define TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER0 0x01000000 +#define TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER1 0x02000000 +#define TRIGSTATE_CLEAR_TIMER0 0x04000000 +#define TRIGSTATE_CLEAR_TIMER1 0x08000000 +#define TRIGSTATE_START_TIMER0 0x10000000 +#define TRIGSTATE_START_TIMER1 0x20000000 +#define TRIGSTATE_TRIGGER_FLAG 0x40000000 +#define TRIGSTATE_LASTSTATE 0x80000000 + +static int ols_set_advanced_trigger_state( + struct sr_serial_dev_inst *serial, + uint8_t statenum, /* 0 to 15 */ + gboolean last_state, + gboolean set_trigger, + uint8_t start_timer, /* bit0=timer1, bit1=timer2 */ + uint8_t stop_timer, /* bit0=timer1, bit1=timer2 */ + uint8_t clear_timer, /* bit0=timer1, bit1=timer2 */ + uint8_t else_state, /* 0 to 15 */ + uint32_t obtain_count) +{ + int ret; + + uint32_t value = ((else_state & TRIGSTATE_STATENUM_MASK) + << TRIGSTATE_ELSE_BITOFS) | + (obtain_count & TRIGSTATE_OBTAIN_MASK); + if (last_state) value |= TRIGSTATE_LASTSTATE; + if (set_trigger) value |= TRIGSTATE_TRIGGER_FLAG; + if (start_timer & 1) value |= TRIGSTATE_START_TIMER0; + if (start_timer & 2) value |= TRIGSTATE_START_TIMER1; + if (stop_timer & 1) value |= TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER0; + if (stop_timer & 2) value |= TRIGSTATE_STOLS_ADV_TRIG_OP_TIMER1; + if (clear_timer & 1) value |= TRIGSTATE_CLEAR_TIMER0; + if (clear_timer & 2) value |= TRIGSTATE_CLEAR_TIMER1; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_SEL, + statenum & TRIGSTATE_STATENUM_MASK); + if (ret != SR_OK) + return ret; + + ret = ols_send_longdata(serial, CMD_SET_ADVANCED_TRIG_WRITE, value); + if (ret != SR_OK) + return ret; + + return SR_OK; +} + +static int ols_set_advanced_trigger_sums_and_stages( + struct sr_serial_dev_inst *serial, int ols_stage, int sum_inputs[8], + gboolean is_last_stage, gboolean start_timer0) +{ + int ret; + + /* + * Hit only when all inputs are true. Always capture for pre-trigger and + * acquisition. Never execute the "Else" action, since we advance trigger + * stages implicity via hits. + */ + ret = ols_set_advanced_trigger_sum(serial, ols_stage, OLS_ADV_TRIG_STATETERM_HIT, + sum_inputs[0], sum_inputs[1], sum_inputs[2], sum_inputs[3], + sum_inputs[4], sum_inputs[5], sum_inputs[6], sum_inputs[7], + OLS_ADV_TRIG_OP_AND, OLS_ADV_TRIG_OP_AND, + OLS_ADV_TRIG_OP_AND); + if (ret != SR_OK) + return ret; + + ret = ols_set_advanced_trigger_sum(serial, ols_stage, OLS_ADV_TRIG_STATETERM_CAPTURE, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_AND, OLS_ADV_TRIG_OP_AND, + OLS_ADV_TRIG_OP_ANY); + if (ret != SR_OK) + return ret; + + ret = ols_set_advanced_trigger_sum(serial, ols_stage, OLS_ADV_TRIG_STATETERM_ELSE, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_AND, OLS_ADV_TRIG_OP_AND, + OLS_ADV_TRIG_OP_NOP); + if (ret != SR_OK) + return ret; + + /* + * Tell the state machine to move to the next stage on a hit by not + * setting the trigger flag. The last stage executes the trigger. + */ + ret = ols_set_advanced_trigger_state(serial, ols_stage, is_last_stage, + is_last_stage, + start_timer0 ? 1 : 0, 0, 0, 0, 0); + if (ret != SR_OK) + return ret; + + return SR_OK; +} + +static int +ols_convert_and_set_up_advanced_trigger(const struct sr_dev_inst *sdi, + gboolean *will_trigger) +{ + int ret; + + struct sr_serial_dev_inst *serial = sdi->conn; + struct dev_context *devc = sdi->priv; + + int ols_stage = 0; + + if (devc->capture_ratio > 0) { + /* + * We need to set up a timer to ensure enough samples are captured to + * fulfill the pre-trigger ratio. In RLE mode, this is not necessarily + * true. It would be possible to wait longer, to ensure that enough + * compressed samples are captured, but this could take ages and is + * probably not what the user wants. + */ + + uint64_t effective_divider = + devc->capture_flags & CAPTURE_FLAG_DEMUX ? + (devc->cur_samplerate_divider + 1) / 2 : + (devc->cur_samplerate_divider + 1); + uint64_t pretrigger_10ns_ticks = + devc->limit_samples * effective_divider * + devc->capture_ratio / 100 /* percent */; + sr_dbg("Inserting pre-trigger delay of %" PRIu64 "0 ns", + pretrigger_10ns_ticks); + + if ((ret = ols_set_advanced_trigger_timer( + serial, 0, pretrigger_10ns_ticks)) != SR_OK) + return ret; + + int sum_inputs[8] = { + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY + }; + + /* first stage: start timer, advance immediately to second stage */ + if ((ret = ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage++, sum_inputs, FALSE, TRUE)) != SR_OK) + return ret; + + /* second stage: wait until timer expires */ + sum_inputs[3] = OLS_ADV_TRIG_OP_B; + if ((ret = ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage++, sum_inputs, FALSE, TRUE)) != SR_OK) + return ret; + } + + struct sr_trigger *trigger; + if (!(trigger = sr_session_trigger_get(sdi->session))) { + *will_trigger = FALSE; + + /* Set up immediate trigger to capture and trigger regardless of any input. */ + int sum_inputs[8] = { + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY + }; + return ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage, sum_inputs, TRUE, FALSE); + } + + int num_req_trigger_stages = g_slist_length(trigger->stages); + if (ols_stage + num_req_trigger_stages > NUM_ADVANCED_TRIGGER_STAGES) { + sr_err("Too many trigger stages: %d requested + %d internal > %d available", + num_req_trigger_stages, ols_stage, + NUM_ADVANCED_TRIGGER_STAGES); + return SR_ERR; + } + + sr_dbg("Setting OLS advanced trigger for %i stages", + num_req_trigger_stages); + + const int last_stage = ols_stage + num_req_trigger_stages - 1; + int num_stages_with_level_trigger = 0; + int num_stages_with_edge_trigger = 0; + for (const GSList *l = trigger->stages; l; l = l->next) { + struct sr_trigger_stage *stage = l->data; + + /* channel bit masks: */ + uint32_t level_mask = 0; + uint32_t level_value = 0; + uint32_t edge_rising = 0; + uint32_t edge_falling = 0; + + int current_level_term = -1; + int current_edge_term = -1; + + for (const GSList *m = stage->matches; m; m = m->next) { + struct sr_trigger_match *match = m->data; + if (!match->channel->enabled) + /* Ignore disabled channels with a trigger. */ + continue; + + int chan_bit = 1 << match->channel->index; + switch (match->match) { + case SR_TRIGGER_ZERO: + level_mask |= chan_bit; + break; + case SR_TRIGGER_ONE: + level_mask |= chan_bit; + level_value |= chan_bit; + break; + case SR_TRIGGER_RISING: + edge_rising |= chan_bit; + break; + case SR_TRIGGER_FALLING: + edge_falling |= chan_bit; + break; + case SR_TRIGGER_EDGE: + edge_rising |= chan_bit; + edge_falling |= chan_bit; + break; + default: + sr_err("Unsupported trigger type: %d", + match->match); + return SR_ERR; + } + } + + if (level_mask) { + if (num_stages_with_level_trigger >= + NUM_ADVANCED_LEVEL_TRIGGERS) { + sr_err("Too many level triggers, only %d supported.", + NUM_ADVANCED_LEVEL_TRIGGERS); + return SR_ERR; + } + + ols_set_advanced_level_trigger( + serial, num_stages_with_level_trigger, + level_value, level_mask); + current_level_term = num_stages_with_level_trigger; + ++num_stages_with_level_trigger; + } + + if (edge_rising | edge_falling) { + if (num_stages_with_edge_trigger >= + NUM_ADVANCED_EDGE_TRIGGERS) { + sr_err("Too many edge triggers, only %d supported.", + NUM_ADVANCED_EDGE_TRIGGERS); + return SR_ERR; + } + + ols_set_advanced_edge_trigger( + serial, num_stages_with_edge_trigger, + edge_rising, edge_falling, 0U); + current_edge_term = num_stages_with_edge_trigger; + ++num_stages_with_edge_trigger; + } + + gboolean is_last_stage = ols_stage == last_stage; + + /* map stage indices to the input pairs and pair position in the summing unit: */ + int sum_inputs[8] = { + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, + OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY, OLS_ADV_TRIG_OP_ANY + }; + #define A OLS_ADV_TRIG_OP_A + #define B OLS_ADV_TRIG_OP_B + static const int level_stage_to_input_pair[10] = {0, 0, 1, 2, 3, 4, 4, 5, 6, 7}; + static const int level_stage_to_input_ab[10] = {A, B, A, A, A, A, B, A, A, A}; + static const int edge_stage_to_input_pair[2] = {2, 6}; + #undef A + #undef B + + int level_summing_input = current_level_term >= 0 + ? level_stage_to_input_pair[current_level_term] : -1 ; + int edge_summing_input = current_edge_term >= 0 + ? edge_stage_to_input_pair[current_edge_term] : -1; + + if (level_summing_input >= 0) + sum_inputs[level_summing_input] = + level_stage_to_input_ab[current_level_term]; + if (edge_summing_input >= 0) + sum_inputs[edge_summing_input] = OLS_ADV_TRIG_OP_B; + + /* If level and edge input end up in on the same input pair, and them together: */ + if (level_summing_input >= 0 && + level_summing_input == edge_summing_input) + sum_inputs[level_summing_input] = OLS_ADV_TRIG_OP_AND; + + sr_spew(" Stage %d, lvl mask %.4x, edge %.4x, level term %d, " + "edge term %d -> " + "trigger sum %.4X %.4X %.4X %.4X %.4X %.4X %.4X %.4X", + ols_stage, level_mask, (edge_falling | edge_rising), + current_level_term, current_edge_term, sum_inputs[0], + sum_inputs[1], sum_inputs[2], sum_inputs[3], + sum_inputs[4], sum_inputs[5], sum_inputs[6], + sum_inputs[7]); + + ret = ols_set_advanced_trigger_sums_and_stages( + serial, ols_stage, sum_inputs, is_last_stage, 0); + if (ret != SR_OK) + return ret; + + ++ols_stage; + } + + *will_trigger = ols_stage > 0 ? TRUE : FALSE; + return SR_OK; +} diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h index dd7ae422b..1c52efe79 100644 --- a/src/hardware/openbench-logic-sniffer/protocol.h +++ b/src/hardware/openbench-logic-sniffer/protocol.h @@ -29,6 +29,9 @@ #define LOG_PREFIX "openbench-logic-sniffer" #define NUM_BASIC_TRIGGER_STAGES 4 +#define NUM_ADVANCED_TRIGGER_STAGES 15 +#define NUM_ADVANCED_EDGE_TRIGGERS 2 +#define NUM_ADVANCED_LEVEL_TRIGGERS 10 #define CLOCK_RATE SR_MHZ(100) #define MIN_NUM_SAMPLES 4 #define DEFAULT_SAMPLERATE SR_KHZ(200) @@ -123,10 +126,10 @@ struct dev_context { raw_sample[4]; /* raw sample, assembled from received bytes */ unsigned int cnt_rx_raw_samples; /* number of raw samples received */ - unsigned int rle_count; + uint64_t rle_count; unsigned char *sample_buf; unsigned int sample_buf_size; - unsigned int cnt_samples; /* number of final samples in sample_buf */ + uint64_t cnt_samples; /* number of final samples in sample_buf */ uint16_t unitsize; };