From 7a14ffe2a0f849d5ad006706452486e94b446373 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" <w.terpstra@gsi.de> Date: Wed, 22 Feb 2012 14:29:38 +0000 Subject: [PATCH] Use the select lines for the low address bits of a sub-word access. Virtual wishbone devices are bigendian. Added code for both big and little -endian to master accesses. Currently, it always uses bigendian code-path. --- api/etherbone.h | 1 + api/format/master.c | 20 ++++++++++++-------- api/format/slave.c | 43 ++++++++++++++++++++++++++++++------------- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/api/etherbone.h b/api/etherbone.h index d7da75b..2dc171d 100644 --- a/api/etherbone.h +++ b/api/etherbone.h @@ -139,6 +139,7 @@ typedef struct eb_handler { eb_user_data_t data; + /* If these support sub-word access, it must be bigendian. */ eb_status_t (*read) (eb_user_data_t, eb_address_t, eb_width_t, eb_data_t*); eb_status_t (*write)(eb_user_data_t, eb_address_t, eb_width_t, eb_data_t); } *eb_handler_t; diff --git a/api/format/master.c b/api/format/master.c index 3b84963..7ac2fde 100644 --- a/api/format/master.c +++ b/api/format/master.c @@ -232,7 +232,7 @@ void eb_device_flush(eb_device_t devicep) { eb_data_t wv; eb_operation_flags_t rcfg, wcfg; eb_width_t width; - uint8_t bus_alignment; + uint8_t op_shift, low_addr; scanp = operationp; @@ -246,14 +246,14 @@ void eb_device_flush(eb_device_t devicep) { wcfg = 0; width = EB_DATAX; - bus_alignment = 0; + low_addr = 0; } else { wcfg = scan->flags & EB_OP_CFG_SPACE; bwa = scan->address; scanp = scan->next; width = scan->width; - bus_alignment = bwa & (data-1); + low_addr = bwa & (data-1); if (wcfg == 0) ++ops; @@ -315,14 +315,14 @@ void eb_device_flush(eb_device_t devicep) { if (ops >= maxops || scanp == EB_NULL || ((scan = EB_OPERATION(scanp))->flags & EB_OP_MASK) == EB_OP_WRITE || - (width != EB_DATAX && (scan->width != width || (scan->address & (data-1)) != bus_alignment))) { + (width != EB_DATAX && (scan->width != width || (scan->address & (data-1)) != low_addr))) { /* No reads in this record */ rcount = 0; rcfg = 0; } else { rcfg = scan->flags & EB_OP_CFG_SPACE; width = scan->width; - bus_alignment = scan->address & (data-1); + low_addr = scan->address & (data-1); if (rcfg == 0) ++ops; rcount = 1; @@ -331,7 +331,7 @@ void eb_device_flush(eb_device_t devicep) { if ((scan->flags & EB_OP_MASK) == EB_OP_WRITE) break; if ((scan->flags & EB_OP_CFG_SPACE) != rcfg) break; if (scan->width != width) break; - if ((scan->address & (data-1)) != bus_alignment) break; + if ((scan->address & (data-1)) != low_addr) break; if (rcount >= 255) break; if (ops >= maxops) break; if (rcfg == 0) ++ops; @@ -401,6 +401,10 @@ void eb_device_flush(eb_device_t devicep) { cycle_end = scanp == EB_NULL && (!needs_check || ops == 0 || rxcount != rcount); + + /* The low address bits determine how far to shift values */ + //op_shift = low_addr; /* Little-endian !!! -- must somehow decide if slave is big/little-endian */ + op_shift = data - (low_addr+width); /* Big endian */ /* Start by preparting the header */ memset(wptr, 0, record_alignment); @@ -409,7 +413,7 @@ void eb_device_flush(eb_device_t devicep) { (wcfg ? EB_RECORD_WCA : 0) | (fifo ? EB_RECORD_WFF : 0) | (cycle_end ? EB_RECORD_CYC : 0); - wptr[1] = (0xFF >> (8-width)) << bus_alignment; + wptr[1] = (0xFF >> (8-width)) << op_shift; wptr[2] = wcount; wptr[3] = rxcount; wptr += record_alignment; @@ -425,7 +429,7 @@ void eb_device_flush(eb_device_t devicep) { operation = EB_OPERATION(operationp); wv = operation->write_value; - wv <<= (bus_alignment<<3); + wv <<= (op_shift<<3); EB_mWRITE(wptr, wv, alignment); wptr += alignment; diff --git a/api/format/slave.c b/api/format/slave.c index 5548ac1..44a6f05 100644 --- a/api/format/slave.c +++ b/api/format/slave.c @@ -70,7 +70,7 @@ void eb_device_slave(eb_socket_t socketp, eb_transport_t transportp, eb_device_t uint8_t* wptr, * rptr, * eos; uint64_t error; eb_width_t widths, biggest, data, addr; - eb_address_t address_check_bits; + eb_address_t address_filter_bits; int alignment, record_alignment, header_alignment, stride, cycle; int reply, header, passive, active; @@ -180,9 +180,10 @@ void eb_device_slave(eb_socket_t socketp, eb_transport_t transportp, eb_device_t /* FIFO stride size */ stride = data; - address_check_bits = ~(eb_address_t)0; - address_check_bits >>= (sizeof(eb_address_t) - addr) << 3; - address_check_bits = ~address_check_bits | (data-1); + /* Only these bits of incoming addresses are processed */ + address_filter_bits = ~(eb_address_t)0; + address_filter_bits >>= (sizeof(eb_address_t) - addr) << 3; + address_filter_bits -= (data-1); /* Setup the initial pointers */ wptr = &buffer[0]; @@ -199,11 +200,11 @@ resume_cycle: /* Start processing the payload */ while (rptr <= eos - record_alignment) { - int total, wconfig, wfifo, rconfig, rfifo, bconfig, addr_ok, sel_ok; + int total, wconfig, wfifo, rconfig, rfifo, bconfig, sel_ok; eb_address_t bwa, bra, ra; eb_data_t wv, data_mask; eb_width_t op_width, op_widths; - uint8_t op_shift, bits, bits1; + uint8_t op_shift, addr_low, bits, bits1; uint8_t flags = rptr[0]; uint8_t select = rptr[1]; uint8_t wcount = rptr[2]; @@ -232,6 +233,9 @@ resume_cycle: && op_width <= data /* The width must be supported by the port */ && op_shift < data; /* The shift must be supported by the port */ + /* Determine the low address bits of the operation */ + addr_low = data - (op_shift+op_width); /* Big endian */ + /* Create a mask for filtering out the important write data */ data_mask = ~(eb_data_t)0; data_mask >>= (sizeof(eb_data_t) - op_width) << 3; @@ -276,8 +280,14 @@ resume_cycle: bwa = EB_LOAD(rptr, alignment); rptr += alignment; - addr_ok = sel_ok && (bwa & address_check_bits) == (eb_address_t)op_shift; - + if (wconfig) { + /* Our config space uses all bits of the address */ + } else { + /* Wishbone devices ignore the low address bits and use the select lines */ + bwa &= address_filter_bits; + bwa |= addr_low; + } + while (wcount--) { wv = EB_LOAD(rptr, alignment); rptr += alignment; @@ -286,9 +296,10 @@ resume_cycle: wv &= data_mask; if (wconfig) { - eb_socket_write_config(socketp, op_width, bwa, wv); + if (sel_ok) + eb_socket_write_config(socketp, op_width, bwa, wv); } else { - if (addr_ok) + if (sel_ok) eb_socket_write(socketp, op_width, bwa, wv, &error); else error = (error<<1) | 1; @@ -328,16 +339,22 @@ resume_cycle: ra = EB_LOAD(rptr, alignment); rptr += alignment; - addr_ok = sel_ok && (ra & address_check_bits) == (eb_address_t)op_shift; + if (rconfig) { + /* Our config space uses all bits of the address */ + } else { + /* Wishbone devices ignore the low address bits and use the select lines */ + ra &= address_filter_bits; + ra |= addr_low; + } if (rconfig) { - if (addr_ok) { + if (sel_ok) { wv = eb_socket_read_config(socketp, op_width, ra, error); } else { wv = 0; } } else { - if (addr_ok) { + if (sel_ok) { wv = eb_socket_read(socketp, op_width, ra, &error); } else { wv = 0; -- GitLab