First cut of AWS test program

This commit is contained in:
bsdevlin 2019-06-27 15:37:58 +08:00
parent fcdc3c4975
commit c144db9064
1 changed files with 206 additions and 151 deletions

View File

@ -19,51 +19,51 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#ifdef SV_TEST #include <fpga_pci.h>
#include "fpga_pci_sv.h" #include <fpga_mgmt.h>
#else #include <utils/lcd.h>
#include <fpga_pci.h>
#include <fpga_mgmt.h>
#include <utils/lcd.h>
#endif
#include <utils/sh_dpi_tasks.h> #include <utils/sh_dpi_tasks.h>
/* Constants determined by the CL */ #define AXI_FIFO_OFFSET UINT64_C(0x0)
/* a set of register offsets; this CL has only one */ #define ZCASH_OFFSET UINT64_C(0x1000)
/* these register addresses should match the addresses in */
/* /aws-fpga/hdk/cl/examples/common/cl_common_defines.vh */
/* SV_TEST macro should be set if SW/HW co-simulation should be enabled */
#define HELLO_WORLD_REG_ADDR UINT64_C(0x500)
#define VLED_REG_ADDR UINT64_C(0x504)
/* use the stdout logger for printing debug information */ /* use the stdout logger for printing debug information */
#ifndef SV_TEST
const struct logger *logger = &logger_stdout; const struct logger *logger = &logger_stdout;
/* /*
* pci_vendor_id and pci_device_id values below are Amazon's and avaliable to use for a given FPGA slot. * pci_vendor_id and pci_device_id values below are Amazon's and avaliable to use for a given FPGA slot.
* Users may replace these with their own if allocated to them by PCI SIG * Users may replace these with their own if allocated to them by PCI SIG
*/ */
static uint16_t pci_vendor_id = 0x1D0F; /* Amazon PCI Vendor ID */ static uint16_t pci_vendor_id = 0x1D0F; /* Amazon PCI Vendor ID */
static uint16_t pci_device_id = 0xF000; /* PCI Device ID preassigned by Amazon for F1 applications */ static uint16_t pci_device_id = 0xF000; /* PCI Device ID preassigned by Amazon for F1 applications */
pci_bar_handle_t pci_bar_handle_bar0 = PCI_BAR_HANDLE_INIT;
pci_bar_handle_t pci_bar_handle_bar4 = PCI_BAR_HANDLE_INIT;
/* /*
* check if the corresponding AFI for hello_world is loaded * check if the corresponding AFI for hello_world is loaded
*/ */
int check_afi_ready(int slot_id); int check_afi_ready(int slot_id);
/* /*
* An example to attach to an arbitrary slot, pf, and bar with register access. * Initialize the FPGA
*/ */
int peek_poke_example(uint32_t value, int slot_id, int pf_id, int bar_id); int init(int slot_id);
/*
* Read / Write to the FPGA stream interface
*/
int read_stream(uint8_t* data, unsigned int size); // Size is the buffer size being passed
int write_stream(uint8_t* data, unsigned int len);
void usage(char* program_name) { void usage(char* program_name) {
printf("usage: %s [--slot <slot-id>][<poke-value>]\n", program_name); printf("usage: %s [--slot <slot-id>][<poke-value>]\n", program_name);
} }
uint32_t byte_swap(uint32_t value); uint32_t byte_swap(uint32_t value);
#endif
uint32_t byte_swap(uint32_t value) { uint32_t byte_swap(uint32_t value) {
uint32_t swapped_value = 0; uint32_t swapped_value = 0;
@ -74,28 +74,13 @@ uint32_t byte_swap(uint32_t value) {
return swapped_value; return swapped_value;
} }
#ifdef SV_TEST
//For cadence and questa simulators the main has to return some value
#ifdef INT_MAIN
int test_main(uint32_t *exit_code) {
#else
void test_main(uint32_t *exit_code) {
#endif
#else
int main(int argc, char **argv) {
#endif
//The statements within SCOPE ifdef below are needed for HW/SW co-simulation with VCS
#ifdef SCOPE
svScope scope;
scope = svGetScopeFromName("tb");
svSetScope(scope);
#endif
uint32_t value = 0xefbeadde; int main(int argc, char **argv) {
int slot_id = 0; int slot_id = 0;
int rc; int rc;
#ifndef SV_TEST
// Process command line args // Process command line args
{ {
int i; int i;
@ -119,61 +104,196 @@ uint32_t byte_swap(uint32_t value) {
} }
} }
} }
#endif
/* initialize the fpga_pci library so we could have access to FPGA PCIe from this applications */ // Initialize all the FPGA connections
rc = fpga_pci_init(); rc = init(slot_id);
fail_on(rc, out, "Unable to initialize the fpga_pci library"); fail_on(rc, out, "Unable to initialize the FPGA");
#ifndef SV_TEST // Test: read from register in BLS core
rc = check_afi_ready(slot_id); uint32_t rdata;
fail_on(rc, out, "AFI not ready"); rc = fpga_pci_peek(pci_bar_handle_bar0, ZCASH_OFFSET, &rdata);
#endif fail_on(rc, out, "Unable to read from FPGA!");
printf("INFO: Read 0x%x from address 0", rdata);
/* Accessing the CL registers via AppPF BAR0, which maps to sh_cl_ocl_ AXI-Lite bus between AWS FPGA Shell and the CL*/
printf("===== Starting with peek_poke_example =====\n"); // Test: send status message
rc = peek_poke_example(value, slot_id, FPGA_APP_PF, APP_PF_BAR0); uint8_t message[8];
fail_on(rc, out, "peek-poke example failed"); memset(message, 0, 8);
message[0] = 8;
message[4] = 1;
rc = write_stream(message, sizeof(message));
fail_on(rc, out, "Unable to read from FPGA!");
printf("Developers are encouraged to modify the Virtual DIP Switch by calling the linux shell command to demonstrate how AWS FPGA Virtual DIP switches can be used to change a CustomLogic functionality:\n"); // Try read reply
printf("$ fpga-set-virtual-dip-switch -S (slot-id) -D (16 digit setting)\n\n"); uint8_t reply[256];
printf("In this example, setting a virtual DIP switch to zero clears the corresponding LED, even if the peek-poke example would set it to 1.\nFor instance:\n"); int timeout = 0;
unsigned int read_len = 0;
while ((read_len = read_stream(reply, 256)) == 0) {
usleep(10);
timeout++;
if (timeout > 1000) {
printf("ERROR: No reply received, timeout\n");
rc = 1;
goto out;
}
}
printf("Reply received of %d bytes:0x", read_len);
for (int i = 0; i < read_len; i++)
printf("%x", reply[i]);
printf("\n");
printf(
"# sudo fpga-set-virtual-dip-switch -S 0 -D 1111111111111111\n"
"# sudo fpga-get-virtual-led -S 0\n"
"FPGA slot id 0 have the following Virtual LED:\n"
"1010-1101-1101-1110\n"
"# sudo fpga-set-virtual-dip-switch -S 0 -D 0000000000000000\n"
"# sudo fpga-get-virtual-led -S 0\n"
"FPGA slot id 0 have the following Virtual LED:\n"
"0000-0000-0000-0000\n"
);
#ifndef SV_TEST
return rc; return rc;
out: out:
return 1; return 1;
#else
out:
#ifdef INT_MAIN
*exit_code = 0;
return 0;
#else
*exit_code = 0;
#endif
#endif
} }
/* As HW simulation test is not run on a AFI, the below function is not valid */ int write_stream(uint8_t* data, unsigned int len);
#ifndef SV_TEST int rc;
uint32_t rdata;
unsigned int len_send = 0;
int check_afi_ready(int slot_id) { rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET + 0xCULL, &rdata);
struct fpga_mgmt_image_info info = {0}; fail_on(rc, out, "Unable to read from FPGA!");
if (len > rdata) {
printf("ERROR: write_stream does not have enough space to write %d bytes! (%d free)\n", len, rdata);
goto out;
}
while(len_send < len) {
fpga_pci_poke64(pci_bar_handle_bar4, 0, *(uint64_t*)(&data[len_send]));
len_send += 8;
}
rc = fpga_pci_poke(pci_bar_handle_bar0, AXI_FIFO_OFFSET+0x14ULL, len); // Reset ISR
fail_on(rc, out, "Unable to write to FPGA!");
printf("INFO: write_stream::Wrote %d bytes of data", len);
// Check transmit complete bit and reset it
rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET, &rdata);
fail_on(rc, out, "Unable to read from FPGA!");
if (rdata & (1 << 27) == 0) {
printf("WARNING: write_stream transmit bit not set, register returned 0x%x\n", rdata);
}
rc = fpga_pci_poke(pci_bar_handle_bar0, AXI_FIFO_OFFSET, 0x08000000); // Reset ISR
fail_on(rc, out, "Unable to write to FPGA!");
return rc;
out:
return 1;
}
int read_stream(uint8_t* data, unsigned int size);
uint32_t rdata;
int read_len = 0;
if (size == 0) {
printf("WARNING: Size was 0, cannot read into empty buffer!\n");
return 0;
}
rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET, &rdata);
fail_on(rc, out, "Unable to read from FPGA!");
if (rdata & (1 << 26) == 0) return 0; // Nothing to read
rc = fpga_pci_poke(pci_bar_handle_bar0, AXI_FIFO_OFFSET, 0x04000000); // clear ISR
fail_on(rc, out, "Unable to write to FPGA!");
rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET + 0x1CULL, &rdata); //RDFO should be non-zero (slots used in FIFO)
fail_on(rc, out, "Unable to read from FPGA!");
if (rdata == 0) {
printf("WARNING: Read FIFO shows data but length was 0!\n");
return 0;
}
rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET + 0x24ULL, &rdata); //RLR - length of packet in bytes
fail_on(rc, out, "Unable to read from FPGA!");
while(rdata > 0 && size >= read_len+8) {
rc = fpga_pci_peek64(pci_bar_handle_bar4, 0, (uint64_t*)(&data[read_len]));
fail_on(rc, out, "Unable to read from FPGA PCIS!");
read_len += 8;
}
printf("INFO: Read %d bytes from read_stream()\n", read_len);
return read_len;
out:
return -1;
}
int init(int slot_id) {
int rc;
uint32_t rdata;
/* initialize the fpga_pci library so we could have access to FPGA PCIe from this applications */
rc = fpga_pci_init();
fail_on(rc, out, "Unable to initialize the fpga_pci library");
rc = check_afi_ready(slot_id);
fail_on(rc, out, "AFI not ready");
// We need to attach to the FPGA BAR0 (OCL) and BAR4 (PCIS)
rc = fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR0, 0, &pci_bar_handle_bar0);
fail_on(rc, out, "Unable to attach to the AFI BAR0 on slot id %d", slot_id);
rc = fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR4, BURST_CAPABLE, &pci_bar_handle_bar4);
fail_on(rc, out, "Unable to attach to the AFI BAR4 on slot id %d", slot_id);
// Now setup the streaming interface
rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET, &rdata); //ISR
fail_on(rc, out, "Unable to read from FPGA!");
printf("INFO: Read 0x%x from ISR register.\n", rdata);
if (rdata != 0x01D00000) {
printf("WARNING: Expected 0x01D00000.\n");
}
rc = fpga_pci_poke(pci_bar_handle_bar0, AXI_FIFO_OFFSET, 0xFFFFFFFF); // Reset ISR
fail_on(rc, out, "Unable to write to FPGA!");
rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET+0xCULL, &rdata); //TDFV
fail_on(rc, out, "Unable to read from FPGA!");
printf("INFO: Read 0x%x from TDFV register.\n", rdata);
if (rdata != 0x000001FC) {
printf("WARNING: Expected 0x000001FC.\n");
}
rc = fpga_pci_peek(pci_bar_handle_bar0, AXI_FIFO_OFFSET+0x1CULL, &rdata); //RDFO
fail_on(rc, out, "Unable to read from FPGA!");
printf("INFO: Read 0x%x from RDFO register.\n", rdata);
if (rdata != 0x00000000) {
printf("WARNING: Expected 0x00000000.\n");
}
rc = fpga_pci_poke(pci_bar_handle_bar0, AXI_FIFO_OFFSET+0x4ULL, 0x0C000000); // Clear IER
fail_on(rc, out, "Unable to write to FPGA!");
printf("INFO: Finished initializing FPGA.\n");
return rc;
out:
/* clean up */
if (pci_bar_handle_bar0 >= 0) {
rc = fpga_pci_detach(pci_bar_handle_bar0);
if (rc) printf("Failure while detaching bar0 from the fpga.\n");
}
if (pci_bar_handle_bar4 >= 0) {
rc = fpga_pci_detach(pci_bar_handle_bar4);
if (rc) printf("Failure while detaching bar4 from the fpga.\n");
}
return 1;
}
int check_afi_ready(int slot_id) {
struct fpga_mgmt_image_info info = {0};
int rc; int rc;
/* get local image description, contains status, vendor id, and device id. */ /* get local image description, contains status, vendor id, and device id. */
@ -214,75 +334,10 @@ out:
"the expected values."); "the expected values.");
} }
} }
return rc; return rc;
out: out:
return 1; return 1;
}
#endif
/*
* An example to attach to an arbitrary slot, pf, and bar with register access.
*/
int peek_poke_example(uint32_t value, int slot_id, int pf_id, int bar_id) {
int rc;
/* pci_bar_handle_t is a handler for an address space exposed by one PCI BAR on one of the PCI PFs of the FPGA */
pci_bar_handle_t pci_bar_handle = PCI_BAR_HANDLE_INIT;
/* attach to the fpga, with a pci_bar_handle out param
* To attach to multiple slots or BARs, call this function multiple times,
* saving the pci_bar_handle to specify which address space to interact with in
* other API calls.
* This function accepts the slot_id, physical function, and bar number
*/
#ifndef SV_TEST
rc = fpga_pci_attach(slot_id, pf_id, bar_id, 0, &pci_bar_handle);
fail_on(rc, out, "Unable to attach to the AFI on slot id %d", slot_id);
#endif
/* write a value into the mapped address space */
uint32_t expected = byte_swap(value);
printf("Writing 0x%08x to HELLO_WORLD register (0x%016lx)\n", value, HELLO_WORLD_REG_ADDR);
rc = fpga_pci_poke(pci_bar_handle, HELLO_WORLD_REG_ADDR, value);
fail_on(rc, out, "Unable to write to the fpga !");
/* read it back and print it out; you should expect the byte order to be
* reversed (That's what this CL does) */
rc = fpga_pci_peek(pci_bar_handle, HELLO_WORLD_REG_ADDR, &value);
fail_on(rc, out, "Unable to read read from the fpga !");
printf("===== Entering peek_poke_example =====\n");
printf("register: 0x%x\n", value);
if(value == expected) {
printf("TEST PASSED");
printf("Resulting value matched expected value 0x%x. It worked!\n", expected);
}
else{
printf("TEST FAILED");
printf("Resulting value did not match expected value 0x%x. Something didn't work.\n", expected);
}
out:
/* clean up */
if (pci_bar_handle >= 0) {
rc = fpga_pci_detach(pci_bar_handle);
if (rc) {
printf("Failure while detaching from the fpga.\n");
}
}
/* if there is an error code, exit with status 1 */
return (rc != 0 ? 1 : 0);
} }
#ifdef SV_TEST
/*This function is used transfer string buffer from SV to C.
This function currently returns 0 but can be used to update a buffer on the 'C' side.*/
int send_rdbuf_to_c(char* rd_buf)
{
return 0;
}
#endif