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

Integrate self-describing wishbone device descriptor blocks.

parent 20017b98
Branches
Tags
No related merge requests found
......@@ -139,14 +139,55 @@ typedef void (*eb_callback_t )(eb_user_data_t, eb_operation_t, eb_status_t);
typedef int eb_descriptor_t;
typedef void (*eb_descriptor_callback_t)(eb_user_data_t, eb_descriptor_t);
/* ID block is converted to host endian when read */
typedef struct sdwb_header {
uint64_t magic;
uint64_t wbidb_addr;
uint64_t wbddb_addr;
uint64_t wbddb_size; /* in bytes */
} *sdwb_header_t;
/* ID block is converted to host endian when read */
typedef struct sdwb_id_block {
uint64_t bitstream_devtype;
uint32_t bitstream_version;
uint32_t bitstream_date;
uint8_t bitstream_source[16]; /* bigendian */
} *sdwb_id_block_t;
/* Descriptor is converted to host endian when read */
typedef struct sdwb_device_descriptor {
uint64_t vendor;
uint32_t device;
uint8_t wbd_granularity;
uint8_t wbd_width;
uint8_t wbd_ver_major;
uint8_t wbd_ver_minor;
uint64_t hdl_base;
uint64_t hdl_size;
#define WBD_FLAG_PRESENT 0x01
#define WBD_FLAG_LITTLE_ENDIAN 0x02
uint32_t wbd_flags;
uint32_t hdl_class;
uint32_t hdl_version;
uint32_t hdl_date;
int8_t vendor_name[16];
int8_t device_name[16];
} *sdwb_device_descriptor_t;
/* Complete bus description */
typedef struct sdwb {
struct sdwb_header header;
struct sdwb_id_block id_block;
struct sdwb_device_descriptor device_descriptor[];
} *sdwb_t;
/* Handler descriptor */
typedef struct eb_handler {
eb_address_t base;
eb_address_t mask;
/* This pointer must remain valid until after you detach the device */
sdwb_device_descriptor_t device;
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;
......@@ -229,6 +270,8 @@ uint32_t eb_socket_timeout(eb_socket_t socket);
/* Add a device to the virtual bus.
* This handler receives all reads and writes to the specified address.
* The handler structure passed to eb_socket_attach need not be preserved.
* The sdwb_device_descriptor MUST be preserved until the device is detached.
* NOTE: the address range [0x0, 0x7fff) is reserved for internal use.
*
* Return codes:
......@@ -246,7 +289,7 @@ eb_status_t eb_socket_attach(eb_socket_t socket, eb_handler_t handler);
* ADDRESS - there is no device at the specified address.
*/
EB_PUBLIC
eb_status_t eb_socket_detach(eb_socket_t socket, eb_address_t address);
eb_status_t eb_socket_detach(eb_socket_t socket, sdwb_device_descriptor_t device);
/* Open a remote Etherbone device.
* This resolves the address and performs Etherbone end-point discovery.
......@@ -433,6 +476,20 @@ EB_PUBLIC eb_data_t eb_operation_data(eb_operation_t op);
/* What was the format of this operation? */
EB_PUBLIC eb_format_t eb_operation_format(eb_operation_t op);
/* Read the SDWB information from the remote bus.
*
* Your callback is called from either eb_socket_poll or eb_device_flush.
* It receives these arguments: (user_data, sdwb, sdwb_len, status)
*
* If status != OK, the SDWB information could not be retrieved.
* If status == OK, the structure was retrieved.
*
* The sdwb object passed to your callback is only valid until you return.
* If you need persistent information, you must copy the memory yourself.
*/
typedef void (*sdwb_callback_t)(eb_user_data_t, sdwb_t, int, eb_status_t);
void eb_sdwb_scan(eb_device_t device, eb_user_data_t data, sdwb_callback_t cb);
#ifdef __cplusplus
}
......@@ -466,8 +523,8 @@ class Socket {
status_t close();
/* attach/detach a virtual device */
status_t attach(address_t base, address_t mask, Handler* handler);
status_t detach(address_t address);
status_t attach(sdwb_device_descriptor_t device, Handler* handler);
status_t detach(sdwb_device_descriptor_t device);
void poll();
int block(int timeout_us);
......@@ -586,18 +643,17 @@ inline status_t Socket::close() {
EB_PUBLIC eb_status_t eb_proxy_read_handler(eb_user_data_t data, eb_address_t address, eb_width_t width, eb_data_t* ptr);
EB_PUBLIC eb_status_t eb_proxy_write_handler(eb_user_data_t data, eb_address_t address, eb_width_t width, eb_data_t value);
inline status_t Socket::attach(address_t base, address_t mask, Handler* handler) {
inline status_t Socket::attach(sdwb_device_descriptor_t device, Handler* handler) {
struct eb_handler h;
h.base = base;
h.mask = mask;
h.device = device;
h.data = handler;
h.read = &eb_proxy_read_handler;
h.write = &eb_proxy_write_handler;
return eb_socket_attach(socket, &h);
}
inline status_t Socket::detach(address_t address) {
return eb_socket_detach(socket, address);
inline status_t Socket::detach(sdwb_device_descriptor_t device) {
return eb_socket_detach(socket, device);
}
inline void Socket::poll() {
......
......@@ -39,6 +39,8 @@ eb_status_t eb_socket_attach(eb_socket_t socketp, eb_handler_t handler) {
struct eb_socket* socket;
struct eb_handler_address* address;
struct eb_handler_callback* callback;
uint64_t new_start, new_end;
uint64_t dev_start, dev_end;
/* Get memory */
addressp = eb_new_handler_address();
......@@ -51,12 +53,20 @@ eb_status_t eb_socket_attach(eb_socket_t socketp, eb_handler_t handler) {
return EB_OOM;
}
new_start = handler->device->hdl_base;
new_end = new_start + handler->device->hdl_size;
socket = EB_SOCKET(socketp);
/* See if it overlaps other devices */
for (i = socket->first_handler; i != EB_NULL; i = address->next) {
address = EB_HANDLER_ADDRESS(i);
if (((address->base ^ handler->base) & ~(address->mask | handler->mask)) == 0) {
dev_start = address->device->hdl_base;
dev_end = dev_start + address->device->hdl_base;
/* Do the address ranges overlap? */
if (new_start <= dev_end && dev_start <= new_end) {
eb_free_handler_callback(callbackp);
eb_free_handler_address(addressp);
return EB_ADDRESS;
......@@ -67,8 +77,7 @@ eb_status_t eb_socket_attach(eb_socket_t socketp, eb_handler_t handler) {
address = EB_HANDLER_ADDRESS(addressp);
callback = EB_HANDLER_CALLBACK(callbackp);
address->base = handler->base;
address->mask = handler->mask;
address->device = handler->device;
address->callback = callbackp;
callback->data = handler->data;
callback->read = handler->read;
......@@ -79,7 +88,7 @@ eb_status_t eb_socket_attach(eb_socket_t socketp, eb_handler_t handler) {
return EB_OK;
}
eb_status_t eb_socket_detach(eb_socket_t socketp, eb_address_t target_address) {
eb_status_t eb_socket_detach(eb_socket_t socketp, sdwb_device_descriptor_t device) {
eb_handler_address_t i, *ptr;
struct eb_socket* socket;
struct eb_handler_address* address;
......@@ -89,7 +98,7 @@ eb_status_t eb_socket_detach(eb_socket_t socketp, eb_address_t target_address) {
/* Find the device */
for (ptr = &socket->first_handler; (i = *ptr) != EB_NULL; ptr = &address->next) {
address = EB_HANDLER_ADDRESS(i);
if (address->base == target_address)
if (address->device == device)
break;
}
......
......@@ -42,8 +42,7 @@ struct eb_handler_callback {
typedef EB_POINTER(eb_handler_address) eb_handler_address_t;
struct eb_handler_address {
eb_address_t base;
eb_address_t mask;
sdwb_device_descriptor_t device;
eb_handler_callback_t callback;
eb_handler_address_t next;
};
......
......@@ -127,12 +127,15 @@ void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr,
eb_handler_address_t addressp;
struct eb_handler_address* address;
struct eb_socket* socket;
eb_address_t start, end;
int fail;
socket = EB_SOCKET(socketp);
for (addressp = socket->first_handler; addressp != EB_NULL; addressp = address->next) {
address = EB_HANDLER_ADDRESS(addressp);
if (((addr ^ address->base) & (~address->mask)) == 0) break;
start = address->device->hdl_base;
end = start + (eb_address_t)address->device->hdl_size;
if (start <= addr && addr < end) break;
}
if (addressp == EB_NULL) {
......@@ -184,12 +187,15 @@ eb_data_t eb_socket_read(eb_socket_t socketp, eb_width_t widths, eb_address_t ad
eb_handler_address_t addressp;
struct eb_handler_address* address;
struct eb_socket* socket;
eb_address_t start, end;
int fail;
socket = EB_SOCKET(socketp);
for (addressp = socket->first_handler; addressp != EB_NULL; addressp = address->next) {
address = EB_HANDLER_ADDRESS(addressp);
if (((addr ^ address->base) & (~address->mask)) == 0) break;
start = address->device->hdl_base;
end = start + (eb_address_t)address->device->hdl_size;
if (start <= addr && addr < end) break;
}
if (addressp == EB_NULL) {
......
......@@ -33,6 +33,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <list>
......@@ -349,13 +350,29 @@ void test_width(Socket socket, width_t width) {
}
int main() {
struct sdwb_device_descriptor device;
status_t err;
device.vendor = 0x651; /* GSI */
device.device = 0x2;
device.wbd_granularity = 1; /* byte-level access supported */
device.wbd_width = 0x0F;
device.wbd_ver_major = 1;
device.wbd_ver_minor = 0;
device.hdl_base = 0;
device.hdl_size = ~(uint64_t)0;
device.wbd_flags = WBD_FLAG_PRESENT; /* bigendian */
device.hdl_class = 0x1;
device.hdl_version = 1;
device.hdl_date = 0x20120228;
memcpy(device.vendor_name, "GSI GmbH ", 16);
memcpy(device.device_name, "Block memory ", 16);
Socket socket;
if ((err = socket.open("60368", EB_DATA16|EB_ADDR32)) != EB_OK) die("socket.open", err);
Echo echo;
if ((err = socket.attach(0, ~0, &echo)) != EB_OK) die("socket.attach", err);
if ((err = socket.attach(&device, &echo)) != EB_OK) die("socket.attach", err);
/* for widths */
test_width(socket, EB_DATAX | EB_ADDRX);
......
......@@ -27,6 +27,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../etherbone.h"
static uint8_t my_memory[256];
......@@ -60,6 +62,7 @@ static eb_status_t my_write(eb_user_data_t user, eb_address_t address, eb_width_
}
int main(int argc, const char** argv) {
struct sdwb_device_descriptor device;
struct eb_handler handler;
const char* port;
eb_status_t status;
......@@ -72,9 +75,23 @@ int main(int argc, const char** argv) {
}
port = argv[1];
handler.base = strtoull(argv[2], 0, 0);
handler.mask = strtoull(argv[3], 0, 0);
device.vendor = 0x651; /* GSI */
device.device = 0x2;
device.wbd_granularity = 1; /* byte-level access supported */
device.wbd_width = 0x0F;
device.wbd_ver_major = 1;
device.wbd_ver_minor = 0;
device.hdl_base = strtoull(argv[2], 0, 0);
device.hdl_size = strtoull(argv[3], 0, 0);
device.wbd_flags = WBD_FLAG_PRESENT; /* bigendian */
device.hdl_class = 0x1;
device.hdl_version = 1;
device.hdl_date = 0x20120228;
memcpy(device.vendor_name, "GSI GmbH ", 16);
memcpy(device.device_name, "Block memory ", 16);
handler.device = &device;
handler.data = 0;
handler.read = &my_read;
handler.write = &my_write;
......
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