]> sigrok.org Git - libsigrok.git/commitdiff
sysclk-lwla: Simplify and optimize word extraction.
authorDaniel Elstner <redacted>
Sun, 26 Jan 2014 19:28:59 +0000 (20:28 +0100)
committerDaniel Elstner <redacted>
Tue, 28 Jan 2014 22:34:53 +0000 (23:34 +0100)
It turns out that all LWLA protocol responses consist either
of 32-bit units or of 32-bit units combined into 64-bit units.
Thus it makes sense to double the basic unit size for reading
from 16 bit to 32 bit.
We cannot do the same for command messages though, as those
actually do use 16-bit quantities in some places, and 32-bit
arguments are not always aligned to 32-bit boundaries.

(acquisition_state.xfer_buf_in): Change unit type to uint32_t,
and update related macros and code accordingly.
(LWLA_TO_UINT32): New macro to replace LWLA_READ32, operating
directly on 32-bit values instead of pointers to 16-bit units.
Make use of a compiler-recognized idiom for bitwise rotation
to efficiently swap the 16-bit halves of a 32-bit word.
(LWLA_TO_UINT16): New macro to replace LWLA_READ16.
(LWLA_READ64): Remove unused macro.
(LWLA_WORD_[0123]): Slightly simplify 16-bit word extraction.

hardware/sysclk-lwla/lwla.c
hardware/sysclk-lwla/lwla.h
hardware/sysclk-lwla/protocol.c
hardware/sysclk-lwla/protocol.h

index 8a6496fba3b7f3f0015c7bb3aedff15c7e4083e0..dcb7af7782d72fb8384c9289348888a3f530f51a 100644 (file)
@@ -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;
 }
index fd5b387a3c6afc10bc1b32f3501f2c53f91ad1dd..94db07e4eb0f07b569e2a855af1e1e5c96ec7768 100644 (file)
 
 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))
-
-/* Convert 16-bit argument to little endian. */
+/* 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 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);
index 82c1055c197dae1306707c56ef39568d577a6b30..5b1f2483e6ba0b38a875a0f0a1ef6b41c99d7ef0 100644 (file)
@@ -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;
        }
 
index 29a191aab4b477b71e22a1513a00c3a2c0c16618..762a17b595c5d71fb4a67ceee9a1a350f899eec1 100644 (file)
  */
 #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];