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

Add support for software emulated little-endian devices.

Added help and command-line options to eb-snoop---including little-endian option.
parent 847d7eaf
No related merge requests found
......@@ -32,6 +32,7 @@
#include <string.h>
#include "../transport/transport.h"
#include "../glue/readwrite.h"
#include "../glue/socket.h"
#include "../glue/device.h"
#include "../glue/widths.h"
......@@ -221,10 +222,13 @@ resume_cycle:
/* Start processing the payload */
while (rptr <= eos - record_alignment) {
int total, wconfig, wfifo, rconfig, rfifo, bconfig, sel_ok;
eb_address_t bwa, bra, ra;
eb_address_t bwa, bwa_b, bwa_l;
eb_address_t ra, ra_b, ra_l;
eb_address_t bra;
eb_data_t wv, data_mask;
eb_width_t op_width, op_widths;
uint8_t op_shift, addr_low, bits, bits1;
uint8_t op_shift, bits, bits1;
uint8_t addr_low_big_endian, addr_low_little_endian;
uint8_t flags = rptr[0];
uint8_t select = rptr[1];
uint8_t wcount = rptr[2];
......@@ -254,7 +258,8 @@ resume_cycle:
&& 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 */
addr_low_big_endian = data - (op_shift+op_width);
addr_low_little_endian = op_shift;
/* Create a mask for filtering out the important write data */
data_mask = ~(eb_data_t)0;
......@@ -312,10 +317,12 @@ resume_cycle:
if (wconfig) {
/* Our config space uses all bits of the address for WBA */
/* If it ever supports register write access, this would need to change */
bwa_b = bwa_l = 0; /* appease warning */
} else {
/* Wishbone devices ignore the low address bits and use the select lines */
bwa &= address_filter_bits;
bwa |= addr_low;
bwa_b = bwa | addr_low_big_endian;
bwa_l = bwa | addr_low_little_endian;
}
while (wcount--) {
......@@ -330,7 +337,7 @@ resume_cycle:
eb_socket_write_config(socketp, op_width, bwa, wv);
} else {
if (sel_ok)
eb_socket_write(socketp, op_width, bwa, wv, &error);
eb_socket_write(socketp, op_width, bwa_b, bwa_l, wv, &error);
else
error = (error<<1) | 1;
}
......@@ -374,17 +381,18 @@ resume_cycle:
/* Wishbone devices ignore the low address bits and use the select lines */
ra &= address_filter_bits;
ra |= addr_low;
ra_b = ra | addr_low_big_endian;
ra_l = ra | addr_low_little_endian;
if (rconfig) {
if (sel_ok) {
wv = eb_socket_read_config(socketp, op_width, ra, error);
wv = eb_socket_read_config(socketp, op_width, ra_b, error);
} else {
wv = 0;
}
} else {
if (sel_ok) {
wv = eb_socket_read(socketp, op_width, ra, &error);
wv = eb_socket_read(socketp, op_width, ra_b, ra_l, &error);
} else {
wv = 0;
error = (error<<1) | 1;
......
......@@ -119,4 +119,3 @@ eb_status_t eb_socket_detach(eb_socket_t socketp, sdwb_device_t device) {
eb_free_handler_address(i);
return EB_OK;
}
......@@ -27,6 +27,7 @@
#define ETHERBONE_IMPL
#include "readwrite.h"
#include "socket.h"
#include "cycle.h"
#include "operation.h"
......@@ -124,7 +125,7 @@ void eb_socket_write_config(eb_socket_t socketp, eb_width_t widths, eb_address_t
}
}
void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr, eb_data_t value, uint64_t* error) {
void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr_b, eb_address_t addr_l, eb_data_t value, uint64_t* error) {
/* Write to local WB bus */
eb_handler_address_t addressp;
struct eb_handler_address* address;
......@@ -133,7 +134,7 @@ void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr,
int fail;
/* SDWB address? It's read only ... */
if (addr < 0x4000) {
if (addr_b < 0x4000) {
*error = (*error << 1) | 1;
return;
}
......@@ -143,7 +144,7 @@ void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr,
address = EB_HANDLER_ADDRESS(addressp);
dev_begin = address->device->wbd_begin;
dev_end = address->device->wbd_end;
if (dev_begin <= addr && addr <= dev_end) break;
if (dev_begin <= addr_b && addr_b <= dev_end) break;
}
if (addressp == EB_NULL) {
......@@ -153,7 +154,10 @@ void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr,
struct eb_handler_callback* callback = EB_HANDLER_CALLBACK(address->callback);
if (callback->write) {
/* Run the virtual device */
fail = (*callback->write)(callback->data, addr, widths, value) != EB_OK;
if ((address->device->wbd_flags & WBD_FLAG_LITTLE_ENDIAN) != 0)
fail = (*callback->write)(callback->data, addr_l, widths, value) != EB_OK;
else
fail = (*callback->write)(callback->data, addr_b, widths, value) != EB_OK;
} else {
/* Not writeable => error */
fail = 1;
......@@ -179,7 +183,7 @@ eb_data_t eb_socket_read_config(eb_socket_t socketp, eb_width_t widths, eb_addre
/* Read out of bounds */
if (addr >= 8) return 0;
/* Read memory */
/* Read memory -- config space always bigendian */
out = 0;
while (len--) {
out <<= 8;
......@@ -189,7 +193,7 @@ eb_data_t eb_socket_read_config(eb_socket_t socketp, eb_width_t widths, eb_addre
return out;
}
eb_data_t eb_socket_read(eb_socket_t socketp, eb_width_t widths, eb_address_t addr, uint64_t* error) {
eb_data_t eb_socket_read(eb_socket_t socketp, eb_width_t widths, eb_address_t addr_b, eb_address_t addr_l, uint64_t* error) {
/* Read to local WB bus */
eb_data_t out;
eb_handler_address_t addressp;
......@@ -199,9 +203,9 @@ eb_data_t eb_socket_read(eb_socket_t socketp, eb_width_t widths, eb_address_t ad
int fail;
/* SDWB address? */
if (addr < 0x4000) {
if (addr_b < 0x4000) {
*error = (*error << 1);
return eb_sdwb(socketp, widths, addr);
return eb_sdwb(socketp, widths, addr_b); /* always bigendian */
}
socket = EB_SOCKET(socketp);
......@@ -209,7 +213,7 @@ eb_data_t eb_socket_read(eb_socket_t socketp, eb_width_t widths, eb_address_t ad
address = EB_HANDLER_ADDRESS(addressp);
dev_begin = address->device->wbd_begin;
dev_end = address->device->wbd_end;
if (dev_begin <= addr && addr <= dev_end) break;
if (dev_begin <= addr_b && addr_b <= dev_end) break;
}
if (addressp == EB_NULL) {
......@@ -220,7 +224,10 @@ eb_data_t eb_socket_read(eb_socket_t socketp, eb_width_t widths, eb_address_t ad
struct eb_handler_callback* callback = EB_HANDLER_CALLBACK(address->callback);
if (callback->read) {
/* Run the virtual device */
fail = (*callback->read)(callback->data, addr, widths, &out) != EB_OK;
if ((address->device->wbd_flags & WBD_FLAG_LITTLE_ENDIAN) != 0)
fail = (*callback->read)(callback->data, addr_l, widths, &out) != EB_OK;
else
fail = (*callback->read)(callback->data, addr_b, widths, &out) != EB_OK;
} else {
/* Not readable => error */
out = 0;
......
/** @file readwrite.h
* @brief Process inbound read/write operations.
*
* Copyright (C) 2011-2012 GSI Helmholtz Centre for Heavy Ion Research GmbH
*
* All methods can assume eb_width_refined.
*
* @author Wesley W. Terpstra <w.terpstra@gsi.de>
*
* @bug None!
*
*******************************************************************************
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************
*/
#ifndef EB_READ_WRITE_H
#define EB_READ_WRITE_H
#include "../etherbone.h"
/* Process inbound read/write requests */
EB_PRIVATE eb_data_t eb_socket_read (eb_socket_t socket, eb_width_t width, eb_address_t addr_b, eb_address_t addr_l, uint64_t* error);
EB_PRIVATE void eb_socket_write (eb_socket_t socket, eb_width_t width, eb_address_t addr_b, eb_address_t addr_l, eb_data_t value, uint64_t* error);
EB_PRIVATE eb_data_t eb_socket_read_config (eb_socket_t socket, eb_width_t width, eb_address_t addr, uint64_t error);
EB_PRIVATE void eb_socket_write_config(eb_socket_t socket, eb_width_t width, eb_address_t addr, eb_data_t value);
#endif
......@@ -37,4 +37,6 @@ struct eb_sdwb_scan {
eb_address_t bus_base;
};
EB_PRIVATE eb_data_t eb_sdwb(eb_socket_t socket, eb_width_t width, eb_address_t addr);
#endif
......@@ -76,11 +76,4 @@ EB_PRIVATE eb_response_t eb_response_flip(eb_response_t firstp);
/* Kill all responses inflight for this device */
EB_PRIVATE void eb_socket_kill_inflight(eb_socket_t socketp, eb_device_t devicep);
/* Process inbound read/write requests */
EB_PRIVATE eb_data_t eb_socket_read (eb_socket_t socket, eb_width_t width, eb_address_t addr, uint64_t* error);
EB_PRIVATE void eb_socket_write (eb_socket_t socket, eb_width_t width, eb_address_t addr, eb_data_t value, uint64_t* error);
EB_PRIVATE eb_data_t eb_socket_read_config (eb_socket_t socket, eb_width_t width, eb_address_t addr, uint64_t error);
EB_PRIVATE void eb_socket_write_config(eb_socket_t socket, eb_width_t width, eb_address_t addr, eb_data_t value);
EB_PRIVATE eb_data_t eb_sdwb (eb_socket_t socket, eb_width_t width, eb_address_t addr);
#endif
......@@ -25,77 +25,196 @@
*******************************************************************************
*/
#define _POSIX_C_SOURCE 200112L /* strtoull */
#define _POSIX_C_SOURCE 200112L /* strtoull + getopt */
#include <unistd.h> /* getopt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../etherbone.h"
#include "common.h"
static uint8_t my_memory[256];
static uint8_t* my_memory;
static eb_status_t my_read(eb_user_data_t user, eb_address_t address, eb_width_t width, eb_data_t* data) {
static void help(void) {
static char revision[20] = "$Rev:: $";
static char date[50] = "$Date:: $";
*strchr(&revision[7], ' ') = 0;
*strchr(&date[8], ' ') = 0;
fprintf(stderr, "Usage: %s [OPTION] <port> <address-range>\n", program);
fprintf(stderr, "\n");
fprintf(stderr, " -a <width> acceptable address bus widths (8/16/32/64)\n");
fprintf(stderr, " -d <width> acceptable data bus widths (8/16/32/64)\n");
fprintf(stderr, " -w <width> SDWB device operation widths (8/16/32/64)\n");
fprintf(stderr, " -b big-endian operation (auto)\n");
fprintf(stderr, " -l little-endian operation (auto)\n");
fprintf(stderr, " -v verbose operation\n");
fprintf(stderr, " -q quiet: do not display warnings\n");
fprintf(stderr, " -h display this help and exit\n");
fprintf(stderr, "\n");
fprintf(stderr, "Report Etherbone bugs to <etherbone-core@ohwr.org>\n");
fprintf(stderr, "Version r%s (%s). Licensed under the LGPL v3.\n", &revision[7], &date[8]);
}
static eb_status_t my_read(eb_user_data_t user, eb_address_t req_address, eb_width_t width, eb_data_t* data) {
int i;
eb_data_t out;
fprintf(stdout, "Received read to address %016"EB_ADDR_FMT" of %d bits\n", address, (width&EB_DATAX)*8);
if (verbose)
fprintf(stdout, "Received read to address 0x%"EB_ADDR_FMT" of %d bits: ", req_address, (width&EB_DATAX)*8);
/* Software slaves must be bigendian */
out = 0;
for (width &= EB_DATAX; width > 0; --width) {
out <<= 8;
out |= my_memory[address++ & 0xff];
width &= EB_DATAX;
req_address -= address;
if (endian == EB_BIG_ENDIAN) {
for (i = 0; i < width; ++i) {
out <<= 8;
out |= my_memory[req_address+i];
}
} else { /* little endian */
for (i = width-1; i >= 0; --i) {
out <<= 8;
out |= my_memory[req_address+i];
}
}
if (verbose)
fprintf(stdout, "0x%"EB_ADDR_FMT"\n", out);
*data = out;
return EB_OK;
}
static eb_status_t my_write(eb_user_data_t user, eb_address_t address, eb_width_t width, eb_data_t data) {
fprintf(stdout, "Received write to address %016"EB_ADDR_FMT" of %d bits: %016"EB_DATA_FMT"\n", address, (width&EB_DATAX)*8, data);
static eb_status_t my_write(eb_user_data_t user, eb_address_t req_address, eb_width_t width, eb_data_t data) {
int i;
if (verbose)
fprintf(stdout, "Received write to address 0x%"EB_ADDR_FMT" of %d bits: 0x%"EB_DATA_FMT"\n", req_address, (width&EB_DATAX)*8, data);
/* Software slaves must be bigendian */
for (width &= EB_DATAX; width > 0; --width) {
my_memory[(address+width-1)&0xff] = data & 0xff;
data >>= 8;
width &= EB_DATAX;
req_address -= address;
if (endian == EB_BIG_ENDIAN) {
for (i = width-1; i >= 0; --i) {
my_memory[req_address+i] = data & 0xff;
data >>= 8;
}
} else { /* little endian */
for (i = 0; i < width; ++i) {
my_memory[req_address+i] = data & 0xff;
data >>= 8;
}
}
return EB_OK;
}
int main(int argc, const char** argv) {
int main(int argc, char** argv) {
long value;
char* value_end;
int opt, error;
struct sdwb_device device;
struct eb_handler handler;
const char* port;
char* conv_end;
eb_status_t status;
eb_socket_t socket;
int i;
if (argc != 3) {
fprintf(stderr, "Syntax: %s <port> <address-range>\n", argv[0]);
/* Specific command-line arguments */
eb_format_t width;
const char* port;
/* Default arguments */
program = argv[0];
address_width = EB_ADDRX;
data_width = EB_DATAX;
width = EB_DATAX;
endian = EB_BIG_ENDIAN;
verbose = 0;
quiet = 0;
error = 0;
/* Process the command-line arguments */
while ((opt = getopt(argc, argv, "a:d:w:blvqh")) != -1) {
switch (opt) {
case 'a':
value = parse_width(optarg);
if (value < 0) {
fprintf(stderr, "%s: invalid address width -- '%s'\n", program, optarg);
return 1;
}
address_width = value << 4;
break;
case 'd':
value = parse_width(optarg);
if (value < 0) {
fprintf(stderr, "%s: invalid data width -- '%s'\n", program, optarg);
return 1;
}
data_width = value;
break;
case 'w':
value = parse_width(optarg);
if (value < 0) {
fprintf(stderr, "%s: invalid SDWB width -- '%s'\n", program, optarg);
return 1;
}
width = value;
break;
case 'b':
endian = EB_BIG_ENDIAN;
break;
case 'l':
endian = EB_LITTLE_ENDIAN;
break;
case 'v':
verbose = 1;
break;
case 'q':
quiet = 1;
break;
case 'h':
help();
return 1;
case ':':
case '?':
error = 1;
break;
default:
fprintf(stderr, "%s: bad getopt result\n", program);
return 1;
}
}
if (error) return 1;
if (optind + 2 != argc) {
fprintf(stderr, "%s: expecting two non-optional arguments: <port> <address-range>\n", program);
return 1;
}
port = argv[1];
port = argv[optind];
device.wbd_begin = strtoull(argv[2], &conv_end, 0);
if (*conv_end != '-') {
address = device.wbd_begin = strtoull(argv[optind+1], &value_end, 0);
if (*value_end != '-') {
fprintf(stderr, "%s: wrong address-range format <begin>-<end> -- '%s'\n",
argv[0], argv[2]);
program, argv[optind+1]);
return 1;
}
device.wbd_end = strtoull(conv_end+1, &conv_end, 0);
if (*conv_end != 0) {
device.wbd_end = strtoull(value_end+1, &value_end, 0);
if (*value_end != 0) {
fprintf(stderr, "%s: wrong address-range format <begin>-<end> -- '%s'\n",
argv[0], argv[2]);
program, argv[optind+1]);
return 1;
}
device.sdwb_child = 0;
device.wbd_flags = WBD_FLAG_PRESENT; /* bigendian */
device.wbd_width = EB_DATAX; /* Support all access widths */
device.wbd_flags = WBD_FLAG_PRESENT | ((endian == EB_LITTLE_ENDIAN)?WBD_FLAG_LITTLE_ENDIAN:0);
device.wbd_width = width;
device.abi_ver_major = 1;
device.abi_ver_minor = 0;
device.abi_class = 0x1;
......@@ -110,11 +229,13 @@ int main(int argc, const char** argv) {
handler.read = &my_read;
handler.write = &my_write;
/* Initialize the system 'memory' */
for (i = 0; i < 256; ++i)
my_memory[i] = i;
if ((my_memory = calloc((device.wbd_end-device.wbd_begin)+1, 1)) == 0) {
fprintf(stderr, "%s: insufficient memory for 0x%"EB_ADDR_FMT"-0x%"EB_ADDR_FMT"\n",
program, (eb_address_t)device.wbd_begin, (eb_address_t)device.wbd_end);
return 1;
}
if ((status = eb_socket_open(EB_ABI_CODE, port, EB_DATAX|EB_ADDRX, &socket)) != EB_OK) {
if ((status = eb_socket_open(EB_ABI_CODE, port, address_width|data_width, &socket)) != EB_OK) {
fprintf(stderr, "Failed to open Etherbone socket: %s\n", eb_status(status));
return 1;
}
......@@ -128,4 +249,6 @@ int main(int argc, const char** argv) {
eb_socket_block(socket, -1);
eb_socket_poll(socket);
}
return 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