diff --git a/hardware/sysclk-lwla/lwla.c b/hardware/sysclk-lwla/lwla.c index 8a6496fb..dcb7af77 100644 --- a/hardware/sysclk-lwla/lwla.c +++ b/hardware/sysclk-lwla/lwla.c @@ -145,20 +145,20 @@ SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb, (unsigned char *)command, cmd_len * 2, &xfer_len, USB_TIMEOUT); if (ret != 0) { - sr_dbg("Failed to send command %u: %s.", - LWLA_READ16(command), libusb_error_name(ret)); + sr_dbg("Failed to send command %d: %s.", + LWLA_TO_UINT16(command[0]), libusb_error_name(ret)); return SR_ERR; } if (xfer_len != cmd_len * 2) { - sr_dbg("Failed to send command %u: incorrect length %d != %d.", - LWLA_READ16(command), xfer_len, cmd_len * 2); + sr_dbg("Failed to send command %d: incorrect length %d != %d.", + LWLA_TO_UINT16(command[0]), xfer_len, cmd_len * 2); return SR_ERR; } return SR_OK; } SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb, - uint16_t *reply, int reply_len, int expect_len) + uint32_t *reply, int reply_len, int expect_len) { int ret; int xfer_len; @@ -168,15 +168,15 @@ SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb, xfer_len = 0; ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY, - (unsigned char *)reply, reply_len * 2, + (unsigned char *)reply, reply_len * 4, &xfer_len, USB_TIMEOUT); if (ret != 0) { sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret)); return SR_ERR; } - if (xfer_len != expect_len * 2) { + if (xfer_len != expect_len * 4) { sr_dbg("Failed to receive reply: incorrect length %d != %d.", - xfer_len, expect_len * 2); + xfer_len, expect_len * 4); return SR_ERR; } return SR_OK; @@ -187,7 +187,7 @@ SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb, { int ret; uint16_t command[2]; - uint16_t reply[256]; /* full EP buffer to avoid overflows */ + uint32_t reply[128]; /* full EP buffer to avoid overflows */ command[0] = LWLA_WORD(CMD_READ_REG); command[1] = LWLA_WORD(reg); @@ -197,10 +197,10 @@ SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb, if (ret != SR_OK) return ret; - ret = lwla_receive_reply(usb, reply, G_N_ELEMENTS(reply), 2); + ret = lwla_receive_reply(usb, reply, G_N_ELEMENTS(reply), 1); if (ret == SR_OK) - *value = LWLA_READ32(reply); + *value = LWLA_TO_UINT32(reply[0]); return ret; } diff --git a/hardware/sysclk-lwla/lwla.h b/hardware/sysclk-lwla/lwla.h index fd5b387a..94db07e4 100644 --- a/hardware/sysclk-lwla/lwla.h +++ b/hardware/sysclk-lwla/lwla.h @@ -27,25 +27,25 @@ struct sr_usb_dev_inst; -/* Read mixed endian words from a buffer of 16-bit units. */ -#define LWLA_READ16(buf) GUINT16_FROM_LE(*(buf)) -#define LWLA_READ32(buf) \ - (((uint32_t)GUINT16_FROM_LE((buf)[0]) << 16) | \ - ((uint32_t)GUINT16_FROM_LE((buf)[1]))) -#define LWLA_READ64(buf) \ - (((uint64_t)LWLA_READ32((buf))) | \ - ((uint64_t)LWLA_READ32((buf) + 2) << 32)) +/* Rotate argument n bits to the left. + * This construct is an idiom recognized by GCC as bit rotation. + */ +#define LROTATE(a, n) (((a) << (n)) | ((a) >> (CHAR_BIT * sizeof(a) - (n)))) -/* Convert 16-bit argument to little endian. */ +/* Convert 16-bit little endian LWLA protocol word to machine word order. */ +#define LWLA_TO_UINT16(val) GUINT16_FROM_LE(val) + +/* Convert 32-bit mixed endian LWLA protocol word to machine word order. */ +#define LWLA_TO_UINT32(val) LROTATE(GUINT32_FROM_LE(val), 16) + +/* Convert 16-bit argument to LWLA protocol word. */ #define LWLA_WORD(val) GUINT16_TO_LE(val) -/* Extract 16-bit units from 32/64-bit value in mixed endian order. */ -#define LWLA_WORD_0(val) GUINT16_TO_LE(((val) & 0xFFFF0000u) >> 16) -#define LWLA_WORD_1(val) GUINT16_TO_LE(((val) & 0x0000FFFFu)) -#define LWLA_WORD_2(val) \ - GUINT16_TO_LE(((val) & G_GUINT64_CONSTANT(0xFFFF000000000000)) >> 48) -#define LWLA_WORD_3(val) \ - GUINT16_TO_LE(((val) & G_GUINT64_CONSTANT(0x0000FFFF00000000)) >> 32) +/* Extract 16-bit units in mixed endian order from 32/64-bit value. */ +#define LWLA_WORD_0(val) GUINT16_TO_LE(((val) >> 16) & 0xFFFF) +#define LWLA_WORD_1(val) GUINT16_TO_LE((val) & 0xFFFF) +#define LWLA_WORD_2(val) GUINT16_TO_LE(((val) >> 48) & 0xFFFF) +#define LWLA_WORD_3(val) GUINT16_TO_LE(((val) >> 32) & 0xFFFF) /** USB device end points. */ @@ -108,7 +108,7 @@ SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb, const uint16_t *command, int cmd_len); SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb, - uint16_t *reply, int reply_len, int expect_len); + uint32_t *reply, int reply_len, int expect_len); SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb, uint16_t reg, uint32_t *value); diff --git a/hardware/sysclk-lwla/protocol.c b/hardware/sysclk-lwla/protocol.c index 82c1055c..5b1f2483 100644 --- a/hardware/sysclk-lwla/protocol.c +++ b/hardware/sysclk-lwla/protocol.c @@ -287,7 +287,7 @@ static void process_capture_length(const struct sr_dev_inst *sdi) devc->transfer_error = TRUE; return; } - acq->mem_addr_fill = LWLA_READ32(acq->xfer_buf_in); + acq->mem_addr_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]); sr_dbg("%zu words in capture buffer.", acq->mem_addr_fill); @@ -362,9 +362,9 @@ static void process_capture_status(const struct sr_dev_inst *sdi) * in the FPGA. These fields are definitely less than 64 bit wide * internally, and the unused bits occasionally even contain garbage. */ - mem_fill = LWLA_READ32(&acq->xfer_buf_in[0]); - duration = LWLA_READ32(&acq->xfer_buf_in[8]); - flags = LWLA_READ32(&acq->xfer_buf_in[16]) & STATUS_FLAG_MASK; + mem_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]); + duration = LWLA_TO_UINT32(acq->xfer_buf_in[4]); + flags = LWLA_TO_UINT32(acq->xfer_buf_in[8]) & STATUS_FLAG_MASK; /* The LWLA1034 runs at 125 MHz if the clock divider is bypassed. * However, the time base used for the duration is apparently not @@ -452,7 +452,7 @@ static int process_sample_data(const struct sr_dev_inst *sdi) struct dev_context *devc; struct acquisition_state *acq; uint8_t *out_p; - uint16_t *slice; + uint32_t *slice; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; size_t expect_len; @@ -472,7 +472,7 @@ static int process_sample_data(const struct sr_dev_inst *sdi) in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done, READ_CHUNK_LEN); - expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint16_t); + expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint32_t); actual_len = acq->xfer_in->actual_length; if (actual_len != expect_len) { @@ -530,8 +530,8 @@ static int process_sample_data(const struct sr_dev_inst *sdi) break; /* done with current chunk */ /* Now work on the current slice. */ - high_nibbles = LWLA_READ32(&slice[8 * 2]); - word = LWLA_READ32(&slice[si * 2]); + high_nibbles = LWLA_TO_UINT32(slice[8]); + word = LWLA_TO_UINT32(slice[si]); word |= (high_nibbles << (4 * si + 4)) & ((uint64_t)0xF << 32); if (acq->rle == RLE_STATE_DATA) { @@ -545,10 +545,9 @@ static int process_sample_data(const struct sr_dev_inst *sdi) } /* Move to next word. */ - if (++si >= 8) { - si = 0; - slice += 9 * 2; - } + si = (si + 1) % 8; + if (si == 0) + slice += 9; --in_words_left; } diff --git a/hardware/sysclk-lwla/protocol.h b/hardware/sysclk-lwla/protocol.h index 29a191aa..762a17b5 100644 --- a/hardware/sysclk-lwla/protocol.h +++ b/hardware/sysclk-lwla/protocol.h @@ -69,21 +69,21 @@ */ #define READ_CHUNK_LEN (28 * 8) -/** Calculate the required buffer size in 16-bit units for reading a given +/** Calculate the required buffer size in 32-bit units for reading a given * number of device memory words. Rounded to a multiple of 8 device words. */ -#define LWLA1034_MEMBUF_LEN(count) (((count) + 7) / 8 * 18) +#define LWLA1034_MEMBUF_LEN(count) (((count) + 7) / 8 * 9) /** Maximum number of 16-bit words sent at a time during acquisition. * Used for allocating the libusb transfer buffer. */ #define MAX_ACQ_SEND_WORDS 8 /* 5 for memory read request plus stuffing */ -/** Maximum number of 16-bit words received at a time during acquisition. +/** Maximum number of 32-bit words received at a time during acquisition. * Round to the next multiple of the endpoint buffer size to avoid nasty * transfer overflow conditions on hiccups. */ -#define MAX_ACQ_RECV_WORDS ((READ_CHUNK_LEN / 4 * 9 + 255) / 256 * 256) +#define MAX_ACQ_RECV_LEN ((READ_CHUNK_LEN / 8 * 9 + 127) / 128 * 128) /** Maximum length of a register write sequence. */ @@ -174,9 +174,9 @@ struct acquisition_state { /** Whether to bypass the clock divider. */ gboolean bypass_clockdiv; - /* Payload data buffers for outgoing and incoming transfers. */ + /* Payload data buffers for incoming and outgoing transfers. */ + uint32_t xfer_buf_in[MAX_ACQ_RECV_LEN]; uint16_t xfer_buf_out[MAX_ACQ_SEND_WORDS]; - uint16_t xfer_buf_in[MAX_ACQ_RECV_WORDS]; /* Payload buffer for sigrok logic packets. */ uint8_t out_packet[PACKET_LENGTH * UNIT_SIZE];