diff --git a/api/etherbone.h b/api/etherbone.h index bafc718cdb648beff958f579539ee6cf9058d1a4..e85c0a5987e6eb902b521a6e4c625669bf7c07f0 100644 --- a/api/etherbone.h +++ b/api/etherbone.h @@ -280,17 +280,19 @@ EB_PUBLIC void eb_device_flush(eb_device_t device); /* Begin a wishbone cycle on the remote device. - * Read/write phases within a cycle hold the device locked. + * Read/write operations within a cycle hold the device locked. * Read/write operations are executed in the order they are queued. * Until the cycle is closed and flushed, the operations are not sent. - * If there is insufficient memory, EB_NULL is returned. + * If there is insufficient memory to begin a cycle, EB_NULL is returned. * * Your callback is called from either eb_socket_poll or eb_device_flush. * It receives these arguments: (user_data, operations, status) * * If status != OK, the cycle was never sent to the remote bus. * If status == OK, the cycle was sent. - * Individual wishbone operation error status is reported by 'operations'. + * + * When status == EB_OK, 'operations' report the wishbone ERR flag. + * When status != EB_OK, 'operations' points to the offending operation. * * Status codes: * OK - operation completed successfully @@ -298,7 +300,7 @@ void eb_device_flush(eb_device_t device); * WIDTH - a specified value exceeded device bus port width * OVERFLOW - too many operations queued for this cycle (wire limit) * TIMEOUT - remote system never responded to EB request - * FAIL - underlying transport has broken connection + * FAIL - remote host violated protocol * OOM - out of memory while queueing operations to the cycle */ EB_PUBLIC diff --git a/api/format/master.c b/api/format/master.c index 0680a59b2d00e4cde97429bf1b7eb7bf9ec009d5..e8bdb306e07a18706ba920ea9cfe675eccf36f30 100644 --- a/api/format/master.c +++ b/api/format/master.c @@ -62,22 +62,31 @@ void eb_device_flush(eb_device_t devicep) { struct eb_response* response; eb_cycle_t cyclep, nextp, prevp; eb_response_t responsep; - eb_width_t biggest, data; + eb_width_t biggest, data, width; + eb_data_t data_mask; + eb_address_t address_mask; uint8_t buffer[sizeof(eb_max_align_t)*(255+255+1+1)+8]; /* big enough for worst-case record */ uint8_t * wptr, * cptr, * eob; int alignment, record_alignment, header_alignment, stride, mtu, readback; device = EB_DEVICE(devicep); transport = EB_TRANSPORT(device->transport); + width = device->widths; /* assert (device->passive != devicep); - assert (eb_width_refined(device->widths) != 0); + assert (eb_width_refined(width) != 0); */ + /* Determine alignment and masking sets */ + data_mask = ((eb_data_t)1) << (((width&EB_DATAX)<<3)-1); + data_mask = (data_mask-1) << 1 | 1; + address_mask = ((eb_address_t)1) << (((width&EB_ADDRX)>>1)-1); + address_mask = (address_mask-1) << 1 | 1; + /* Calculate alignment values */ - data = device->widths & EB_DATAX; - biggest = (device->widths >> 4) | data; + data = width & EB_DATAX; + biggest = (width >> 4) | data; alignment = 2; alignment += (biggest >= EB_DATA32)*2; alignment += (biggest >= EB_DATA64)*4; @@ -93,7 +102,7 @@ void eb_device_flush(eb_device_t devicep) { buffer[0] = 0x4E; buffer[1] = 0x6F; buffer[2] = 0x10; /* V1. no probe. */ - buffer[3] = device->widths; + buffer[3] = width; cptr = wptr = &buffer[header_alignment]; eob = &buffer[mtu]; } else { @@ -117,6 +126,7 @@ void eb_device_flush(eb_device_t devicep) { eb_operation_t scanp; int needs_check, cycle_end; unsigned int ops, maxops; + eb_status_t reason; cycle = EB_CYCLE(cyclep); nextp = cycle->next; @@ -137,6 +147,38 @@ void eb_device_flush(eb_device_t devicep) { continue; } + /* Are there out of range widths? */ + reason = EB_OK; /* silence warning */ + for (operationp = cycle->first; operationp != EB_NULL; operationp = operation->next) { + operation = EB_OPERATION(operationp); + /* Is the address too big for a bus op? */ + if ((operation->flags & EB_OP_CFG_SPACE) == 0 && + (operation->address & address_mask) != operation->address) { + reason = EB_ADDRESS; + break; + } + /* Is the address too big for a cfg op? */ + if ((operation->flags & EB_OP_CFG_SPACE) != 0 && + (operation->address & 0xFFFFU) != operation->address) { + reason = EB_ADDRESS; + break; + } + /* Is the data too big for the port? */ + if ((operation->flags & EB_OP_MASK) == EB_OP_WRITE && + (operation->write_value & data_mask) != operation->write_value) { + reason = EB_WIDTH; + break; + } + } + if (operationp != EB_NULL) { + /* Report the bad operation to the user */ + if (cycle->callback) + (*cycle->callback)(cycle->user_data, operationp, reason); + eb_cycle_destroy(cyclep); + eb_free_cycle(cyclep); + continue; + } + /* Record to hook it into socket */ responsep = eb_new_response(); /* invalidates: cycle device transport */ if (responsep == EB_NULL) { @@ -310,7 +352,7 @@ void eb_device_flush(eb_device_t devicep) { if (length > eob - wptr) { /* Blow up in the face of the user */ if (cycle->callback) - (*cycle->callback)(cycle->user_data, cycle->first, EB_OVERFLOW); + (*cycle->callback)(cycle->user_data, operationp, EB_OVERFLOW); eb_cycle_destroy(cyclep); eb_free_cycle(cyclep); eb_free_response(responsep); diff --git a/api/glue/socket.c b/api/glue/socket.c index 646afb1d11f993cb5a96d4fc601fb177d109c262..56642ef8a0d61b80cf332dc2edcb894eaa81daf5 100644 --- a/api/glue/socket.c +++ b/api/glue/socket.c @@ -184,7 +184,7 @@ eb_status_t eb_socket_close(eb_socket_t socketp) { /* Report the cycle callback */ cycle = EB_CYCLE(response->cycle); if (cycle->callback) - (*cycle->callback)(cycle->user_data, cycle->first, EB_FAIL); /* invalidate: socket response cycle */ + (*cycle->callback)(cycle->user_data, cycle->first, EB_TIMEOUT); /* invalidate: socket response cycle */ socket = EB_SOCKET(socketp); response = EB_RESPONSE(tmp);