Skip to content
Snippets Groups Projects
Commit 7a14ffe2 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra
Browse files

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.
parent d2ba4111
Branches
Tags
No related merge requests found
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment