From 8940183c10ec5c4d4d9cea695844a230098aaf69 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 6 Apr 2021 19:04:07 -0700 Subject: [PATCH 01/55] updates to opencl benchmarks --- benchmarks/opencl/saxpy/Makefile | 12 ++--- benchmarks/opencl/saxpy/main.cc | 68 +++++++++++++++++++--------- benchmarks/opencl/sfilter/Makefile | 12 ++--- benchmarks/opencl/sfilter/main.cc | 72 ++++++++++++++++++++---------- benchmarks/opencl/sgemm/main.cc | 2 + benchmarks/opencl/vecadd/main.cc | 2 + 6 files changed, 114 insertions(+), 54 deletions(-) diff --git a/benchmarks/opencl/saxpy/Makefile b/benchmarks/opencl/saxpy/Makefile index 9d6f91b6..0414fcff 100644 --- a/benchmarks/opencl/saxpy/Makefile +++ b/benchmarks/opencl/saxpy/Makefile @@ -7,6 +7,8 @@ POCL_RT_PATH ?= /opt/pocl/runtime VORTEX_DRV_PATH ?= $(realpath ../../../driver) VORTEX_RT_PATH ?= $(realpath ../../../runtime) +OPTS ?= -n1024 + K_LLCFLAGS += "-O3 -march=riscv32 -target-abi=ilp32f -mcpu=generic-rv32 -mattr=+m,+f -float-abi=hard -code-model=small" K_CFLAGS += "-v -O3 --sysroot=$(SYSROOT) --gcc-toolchain=$(RISCV_TOOLCHAIN_PATH) -march=rv32imf -mabi=ilp32f -I$(VORTEX_RT_PATH)/include -fno-rtti -fno-exceptions -ffreestanding -nostartfiles -fdata-sections -ffunction-sections" K_LDFLAGS += "-Wl,-Bstatic,-T$(VORTEX_RT_PATH)/linker/vx_link.ld -Wl,--gc-sections $(VORTEX_RT_PATH)/libvortexrt.a -lm" @@ -33,19 +35,19 @@ $(PROJECT): $(SRCS) $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ run-fpga: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-asesim: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/ase:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/ase:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-vlsim: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/vlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/vlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-simx: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/simx:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/simx:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-rtlsim: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/rtlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/rtlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) .depend: $(SRCS) $(CXX) $(CXXFLAGS) -MM $^ > .depend; diff --git a/benchmarks/opencl/saxpy/main.cc b/benchmarks/opencl/saxpy/main.cc index 7d64f03d..d4076d70 100644 --- a/benchmarks/opencl/saxpy/main.cc +++ b/benchmarks/opencl/saxpy/main.cc @@ -29,11 +29,9 @@ #include #include #include +#include #include -//#define NUM_DATA 65536 -#define NUM_DATA 1024 - #define CL_CHECK(_expr) \ do { \ cl_int _err = _expr; \ @@ -85,14 +83,18 @@ uint8_t *kernel_bin = NULL; /// // Cleanup any created OpenCL resources // -void Cleanup(cl_context context, cl_command_queue commandQueue, - cl_program program, cl_kernel kernel, cl_mem memObjects[3]) { - for (int i = 0; i < 3; i++) { +void Cleanup(cl_device_id device_id, cl_context context, cl_command_queue commandQueue, + cl_program program, cl_kernel kernel, cl_mem memObjects[2]) { + if (kernel_bin) + free(kernel_bin); + + if (commandQueue != 0) + clReleaseCommandQueue(commandQueue); + + for (int i = 0; i < 2; i++) { if (memObjects[i] != 0) clReleaseMemObject(memObjects[i]); } - if (commandQueue != 0) - clReleaseCommandQueue(commandQueue); if (kernel != 0) clReleaseKernel(kernel); @@ -103,11 +105,40 @@ void Cleanup(cl_context context, cl_command_queue commandQueue, if (context != 0) clReleaseContext(context); - if (kernel_bin) free(kernel_bin); + if (device_id != 0) + clReleaseDevice(device_id); +} + +int size = 1024; + +static void show_usage() { + printf("Usage: [-n size] [-h: help]\n"); +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "n:h?")) != -1) { + switch (c) { + case 'n': + size = atoi(optarg); + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } + + printf("Workload size=%d\n", size); } int main(int argc, char **argv) { - printf("enter demo main\n"); + // parse command arguments + parse_args(argc, argv); cl_platform_id platform_id; cl_device_id device_id; @@ -139,7 +170,7 @@ int main(int argc, char **argv) { context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err)); if (program == NULL) { std::cerr << "Failed to write program binary" << std::endl; - Cleanup(context, queue, program, kernel, memObjects); + Cleanup(device_id, context, queue, program, kernel, memObjects); return 1; } else { std::cout << "Read program from binary." << std::endl; @@ -148,7 +179,7 @@ int main(int argc, char **argv) { // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); - size_t nbytes = sizeof(float) * NUM_DATA; + size_t nbytes = sizeof(float) * size; printf("attempting to create input buffer\n"); cl_mem input_buffer; @@ -175,13 +206,13 @@ int main(int argc, char **argv) { printf("attempting to enqueue write buffer\n"); float* h_src = (float*)malloc(nbytes); - for (int i = 0; i < NUM_DATA; i++) { + for (int i = 0; i < size; i++) { h_src[i] = ((float)rand() / (float)(RAND_MAX)) * 100.0; } CL_CHECK(clEnqueueWriteBuffer(queue, input_buffer, CL_TRUE, 0, nbytes, h_src, 0, NULL, NULL)); free(h_src); - size_t global_work_size[] = {NUM_DATA/2, NUM_DATA/2}; + size_t global_work_size[] = {size/2, size/2}; printf("attempting to enqueue kernel\n"); auto time_start = std::chrono::high_resolution_clock::now(); CL_CHECK(clEnqueueNDRangeKernel(queue, kernel, 1, NULL, global_work_size, @@ -196,18 +227,13 @@ int main(int argc, char **argv) { CL_CHECK(clEnqueueReadBuffer(queue, output_buffer, CL_TRUE, 0, nbytes, h_dst, 0, NULL, NULL)); /*printf("Result:"); - for (int i = 0; i < NUM_DATA; i++) { + for (int i = 0; i < size; i++) { float data = h_dst[i]; printf(" %f", data); }*/ free(h_dst); - CL_CHECK(clReleaseMemObject(memObjects[0])); - CL_CHECK(clReleaseMemObject(memObjects[1])); - - CL_CHECK(clReleaseKernel(kernel)); - CL_CHECK(clReleaseProgram(program)); - CL_CHECK(clReleaseContext(context)); + Cleanup(device_id, context, queue, program, kernel, memObjects); return 0; } diff --git a/benchmarks/opencl/sfilter/Makefile b/benchmarks/opencl/sfilter/Makefile index 62099e37..6a22e827 100644 --- a/benchmarks/opencl/sfilter/Makefile +++ b/benchmarks/opencl/sfilter/Makefile @@ -7,6 +7,8 @@ POCL_RT_PATH ?= /opt/pocl/runtime VORTEX_DRV_PATH ?= $(realpath ../../../driver) VORTEX_RT_PATH ?= $(realpath ../../../runtime) +OPTS ?= -n16 + K_LLCFLAGS += "-O3 -march=riscv32 -target-abi=ilp32f -mcpu=generic-rv32 -mattr=+m,+f -float-abi=hard -code-model=small" K_CFLAGS += "-v -O3 --sysroot=$(SYSROOT) --gcc-toolchain=$(RISCV_TOOLCHAIN_PATH) -march=rv32imf -mabi=ilp32f -I$(VORTEX_RT_PATH)/include -fno-rtti -fno-exceptions -ffreestanding -nostartfiles -fdata-sections -ffunction-sections" K_LDFLAGS += "-Wl,-Bstatic,-T$(VORTEX_RT_PATH)/linker/vx_link.ld -Wl,--gc-sections $(VORTEX_RT_PATH)/libvortexrt.a -lm" @@ -33,19 +35,19 @@ $(PROJECT): $(SRCS) $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ run-fpga: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-asesim: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/ase:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/ase:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-vlsim: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/vlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/opae/vlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-simx: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/simx:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/simx:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) run-rtlsim: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/rtlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) + LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_DRV_PATH)/rtlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) .depend: $(SRCS) $(CXX) $(CXXFLAGS) -MM $^ > .depend; diff --git a/benchmarks/opencl/sfilter/main.cc b/benchmarks/opencl/sfilter/main.cc index 2f6992d1..17f4cea0 100644 --- a/benchmarks/opencl/sfilter/main.cc +++ b/benchmarks/opencl/sfilter/main.cc @@ -35,8 +35,6 @@ #include #include -#define NUM_DATA (16+2) - #define CL_CHECK(_expr) \ do { \ cl_int _err = _expr; \ @@ -159,14 +157,18 @@ float poclu_cl_half_to_float(cl_half value) { /// // Cleanup any created OpenCL resources // -void Cleanup(cl_context context, cl_command_queue commandQueue, - cl_program program, cl_kernel kernel, cl_mem memObjects[3]) { - for (int i = 0; i < 3; i++) { +void Cleanup(cl_device_id device_id, cl_context context, cl_command_queue commandQueue, + cl_program program, cl_kernel kernel, cl_mem memObjects[2]) { + if (kernel_bin) + free(kernel_bin); + + if (commandQueue != 0) + clReleaseCommandQueue(commandQueue); + + for (int i = 0; i < 2; i++) { if (memObjects[i] != 0) clReleaseMemObject(memObjects[i]); } - if (commandQueue != 0) - clReleaseCommandQueue(commandQueue); if (kernel != 0) clReleaseKernel(kernel); @@ -177,11 +179,40 @@ void Cleanup(cl_context context, cl_command_queue commandQueue, if (context != 0) clReleaseContext(context); - if (kernel_bin) free(kernel_bin); + if (device_id != 0) + clReleaseDevice(device_id); +} + +int size = 16+2; + +static void show_usage() { + printf("Usage: [-n size] [-h: help]\n"); +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "n:h?")) != -1) { + switch (c) { + case 'n': + size = atoi(optarg)+2; + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } + + printf("Workload size=%d\n", size); } int main(int argc, char **argv) { - printf("enter demo main\n"); + // parse command arguments + parse_args(argc, argv); cl_platform_id platform_id; cl_device_id device_id; @@ -213,7 +244,7 @@ int main(int argc, char **argv) { context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err)); if (program == NULL) { std::cerr << "Failed to write program binary" << std::endl; - Cleanup(context, queue, program, kernel, memObjects); + Cleanup(device_id, context, queue, program, kernel, memObjects); return 1; } else { std::cout << "Read program from binary." << std::endl; @@ -222,7 +253,7 @@ int main(int argc, char **argv) { // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); - size_t nbytes = sizeof(float) * NUM_DATA * NUM_DATA; + size_t nbytes = sizeof(float) * size * size; printf("attempting to create input buffer\n"); cl_mem input_buffer; @@ -235,7 +266,7 @@ int main(int argc, char **argv) { memObjects[0] = input_buffer; memObjects[1] = output_buffer; - long long ldc = NUM_DATA; + long long ldc = size; float m0 = 1.0; float m1 = 1.0; @@ -265,15 +296,15 @@ int main(int argc, char **argv) { printf("attempting to enqueue write buffer\n"); float* h_src = (float*)malloc(nbytes); - for (int i = 0; i < NUM_DATA * NUM_DATA; i++) { + for (int i = 0; i < size * size; i++) { h_src[i] = ((float)rand() / (float)(RAND_MAX)) * 100.0; } CL_CHECK(clEnqueueWriteBuffer(queue, input_buffer, CL_TRUE, 0, nbytes, h_src, 0, NULL, NULL)); free(h_src); size_t global_offset[2] = {1, 1}; - size_t global_work_size[2] = {NUM_DATA - 2, NUM_DATA - 2}; // avoid the edges - const size_t local_work_size[2] = {NUM_DATA - 2, 1}; + size_t global_work_size[2] = {size - 2, size - 2}; // avoid the edges + const size_t local_work_size[2] = {size - 2, 1}; printf("attempting to enqueue kernel\n"); auto time_start = std::chrono::high_resolution_clock::now(); CL_CHECK(clEnqueueNDRangeKernel(queue, kernel, 2, global_offset, @@ -286,20 +317,15 @@ int main(int argc, char **argv) { printf("Download destination buffer\n"); float* h_dst = (float*)malloc(nbytes); CL_CHECK(clEnqueueReadBuffer(queue, output_buffer, CL_TRUE, 0, nbytes, h_dst, 0, NULL, NULL)); - + /*printf("Result:"); - for (int i = 0; i < NUM_DATA * NUM_DATA; i++) { + for (int i = 0; i < size; i++) { float data = h_dst[i]; printf(" %f", data); }*/ free(h_dst); - CL_CHECK(clReleaseMemObject(memObjects[0])); - CL_CHECK(clReleaseMemObject(memObjects[1])); - - CL_CHECK(clReleaseKernel(kernel)); - CL_CHECK(clReleaseProgram(program)); - CL_CHECK(clReleaseContext(context)); + Cleanup(device_id, context, queue, program, kernel, memObjects); return 0; } diff --git a/benchmarks/opencl/sgemm/main.cc b/benchmarks/opencl/sgemm/main.cc index 1f92a14a..f61a8727 100644 --- a/benchmarks/opencl/sgemm/main.cc +++ b/benchmarks/opencl/sgemm/main.cc @@ -129,6 +129,8 @@ static void parse_args(int argc, char **argv) { printf("Error: invalid size!\n"); exit(-1); } + + printf("Workload size=%d\n", size); } int main (int argc, char **argv) { diff --git a/benchmarks/opencl/vecadd/main.cc b/benchmarks/opencl/vecadd/main.cc index 14f35877..5b8c3a83 100644 --- a/benchmarks/opencl/vecadd/main.cc +++ b/benchmarks/opencl/vecadd/main.cc @@ -112,6 +112,8 @@ static void parse_args(int argc, char **argv) { exit(-1); } } + + printf("Workload size=%d\n", size); } int main (int argc, char **argv) { From 6ef0c993895a5a9f509c328fcc5ea9d2c42f0ff7 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 6 Apr 2021 23:03:26 -0700 Subject: [PATCH 02/55] opencl benchmark fixes --- benchmarks/opencl/bfs/CLHelper.h | 27 ++++-- benchmarks/opencl/bfs/main.cc | 12 +-- benchmarks/opencl/bfs/util.h | 4 +- benchmarks/opencl/guassian/clutils.cpp | 118 ++++++++++++++----------- benchmarks/opencl/guassian/main.cc | 13 ++- benchmarks/opencl/nearn/clutils.cpp | 56 +++++++----- benchmarks/opencl/nearn/main.cc | 35 +++++--- benchmarks/opencl/saxpy/main.cc | 2 +- 8 files changed, 165 insertions(+), 102 deletions(-) diff --git a/benchmarks/opencl/bfs/CLHelper.h b/benchmarks/opencl/bfs/CLHelper.h index 94536d7c..6ac9c609 100755 --- a/benchmarks/opencl/bfs/CLHelper.h +++ b/benchmarks/opencl/bfs/CLHelper.h @@ -233,7 +233,7 @@ free(allPlatforms);*/ //--cambine-4: Create an OpenCL command queue oclHandles.queue = clCreateCommandQueue( oclHandles.context, oclHandles.devices[DEVICE_ID_INUSED], 0, &resultCL); - printf("resultCL=%d, queue=0x%x\n", resultCL, oclHandles.queue); + //printf("resultCL=%d, queue=0x%x\n", resultCL, oclHandles.queue); if ((resultCL != CL_SUCCESS) || (oclHandles.queue == NULL)) throw(string("InitCL()::Creating Command Queue. (clCreateCommandQueue)")); @@ -383,8 +383,8 @@ void _clRelease() { errorFlag = true; } oclHandles.kernel[nKernel] = NULL; + printf("clReleaseKernel()\n"); } - oclHandles.kernel.clear(); } if (oclHandles.program != NULL) { @@ -394,6 +394,7 @@ void _clRelease() { errorFlag = true; } oclHandles.program = NULL; + printf("clReleaseProgram()\n"); } if (oclHandles.queue != NULL) { @@ -403,10 +404,9 @@ void _clRelease() { errorFlag = true; } oclHandles.queue = NULL; + printf("clReleaseCommandQueue()\n"); } - free(oclHandles.devices); - if (oclHandles.context != NULL) { cl_int resultCL = clReleaseContext(oclHandles.context); if (resultCL != CL_SUCCESS) { @@ -414,6 +414,17 @@ void _clRelease() { errorFlag = true; } oclHandles.context = NULL; + printf("clReleaseContext()\n"); + } + + if (oclHandles.devices != NULL) { + cl_int resultCL = clReleaseDevice(oclHandles.devices[0]); + if (resultCL != CL_SUCCESS) { + cerr << "ReleaseCL()::Error: In clReleaseDevice" << endl; + errorFlag = true; + } + free(oclHandles.devices); + printf("clReleaseDevice()\n"); } if (errorFlag) @@ -675,7 +686,7 @@ void _clFinish() throw(string) { void _clInvokeKernel(int kernel_id, int work_items, int work_group_size) throw(string) { cl_uint work_dim = WORK_DIM; - cl_event e[1]; + //cl_event e[1]; if (work_items % work_group_size != 0) // process situations that work_items // cannot be divided by work_group_size work_items = @@ -684,7 +695,7 @@ void _clInvokeKernel(int kernel_id, int work_items, size_t global_work_size[] = {work_items, 1}; oclHandles.cl_status = clEnqueueNDRangeKernel( oclHandles.queue, oclHandles.kernel[kernel_id], work_dim, 0, - global_work_size, local_work_size, 0, 0, &(e[0])); + global_work_size, local_work_size, 0, 0, NULL); #ifdef ERRMSG oclHandles.error_str = "excpetion in _clInvokeKernel() -> "; switch (oclHandles.cl_status) { @@ -749,13 +760,13 @@ void _clInvokeKernel2D(int kernel_id, int range_x, int range_y, int group_x, cl_uint work_dim = WORK_DIM; size_t local_work_size[] = {group_x, group_y}; size_t global_work_size[] = {range_x, range_y}; - cl_event e[1]; + //cl_event e[1]; /*if(work_items%work_group_size != 0) //process situations that work_items cannot be divided by work_group_size work_items = work_items + (work_group_size-(work_items%work_group_size));*/ oclHandles.cl_status = clEnqueueNDRangeKernel( oclHandles.queue, oclHandles.kernel[kernel_id], work_dim, 0, - global_work_size, local_work_size, 0, 0, &(e[0])); + global_work_size, local_work_size, 0, 0, NULL); #ifdef ERRMSG oclHandles.error_str = "excpetion in _clInvokeKernel() -> "; switch (oclHandles.cl_status) { diff --git a/benchmarks/opencl/bfs/main.cc b/benchmarks/opencl/bfs/main.cc index 701209d4..1a1cf1d2 100755 --- a/benchmarks/opencl/bfs/main.cc +++ b/benchmarks/opencl/bfs/main.cc @@ -78,14 +78,15 @@ void run_bfs_gpu(int no_of_nodes, Node *h_graph_nodes, int edge_list_size, char h_over; cl_mem d_graph_nodes, d_graph_edges, d_graph_mask, d_updating_graph_mask, d_graph_visited, d_cost, d_over; + try { //--1 transfer data from host to device _clInit(); + d_graph_nodes = _clMalloc(no_of_nodes * sizeof(Node), h_graph_nodes); d_graph_edges = _clMalloc(edge_list_size * sizeof(int), h_graph_edges); d_graph_mask = _clMallocRW(no_of_nodes * sizeof(char), h_graph_mask); - d_updating_graph_mask = - _clMallocRW(no_of_nodes * sizeof(char), h_updating_graph_mask); + d_updating_graph_mask = _clMallocRW(no_of_nodes * sizeof(char), h_updating_graph_mask); d_graph_visited = _clMallocRW(no_of_nodes * sizeof(char), h_graph_visited); d_cost = _clMallocRW(no_of_nodes * sizeof(int), h_cost); @@ -94,8 +95,7 @@ void run_bfs_gpu(int no_of_nodes, Node *h_graph_nodes, int edge_list_size, _clMemcpyH2D(d_graph_nodes, no_of_nodes * sizeof(Node), h_graph_nodes); _clMemcpyH2D(d_graph_edges, edge_list_size * sizeof(int), h_graph_edges); _clMemcpyH2D(d_graph_mask, no_of_nodes * sizeof(char), h_graph_mask); - _clMemcpyH2D(d_updating_graph_mask, no_of_nodes * sizeof(char), - h_updating_graph_mask); + _clMemcpyH2D(d_updating_graph_mask, no_of_nodes * sizeof(char), h_updating_graph_mask); _clMemcpyH2D(d_graph_visited, no_of_nodes * sizeof(char), h_graph_visited); _clMemcpyH2D(d_cost, no_of_nodes * sizeof(int), h_cost); @@ -106,6 +106,7 @@ void run_bfs_gpu(int no_of_nodes, Node *h_graph_nodes, int edge_list_size, kernel_timer.reset(); kernel_timer.start(); #endif + do { h_over = false; _clMemcpyH2D(d_over, sizeof(char), &h_over); @@ -136,9 +137,8 @@ void run_bfs_gpu(int no_of_nodes, Node *h_graph_nodes, int edge_list_size, _clInvokeKernel(kernel_id, no_of_nodes, work_group_size); _clMemcpyD2H(d_over, sizeof(char), &h_over); - } while (h_over); + } while (h_over); - _clFinish(); #ifdef PROFILING kernel_timer.stop(); kernel_time = kernel_timer.getTimeInSeconds(); diff --git a/benchmarks/opencl/bfs/util.h b/benchmarks/opencl/bfs/util.h index 425edfba..b67abc0d 100755 --- a/benchmarks/opencl/bfs/util.h +++ b/benchmarks/opencl/bfs/util.h @@ -60,10 +60,10 @@ void compare_results(const datatype *cpu_results, const datatype *gpu_results, c } } if (passed){ - std::cout << "--cambine:passed:-)" << endl; + std::cout << "--cambine: passed: -)" << endl; } else{ - std::cout << "--cambine: failed:-(" << endl; + std::cout << "--cambine: failed :-(" << endl; } return ; } diff --git a/benchmarks/opencl/guassian/clutils.cpp b/benchmarks/opencl/guassian/clutils.cpp index 37cabb7d..c977477a 100755 --- a/benchmarks/opencl/guassian/clutils.cpp +++ b/benchmarks/opencl/guassian/clutils.cpp @@ -69,7 +69,7 @@ static cl_uint numPlatforms; //! All discoverable OpenCL devices (one pointer per platform) static cl_device_id* devices = NULL; -static cl_uint* numDevices; +static cl_uint* numDevices = NULL; //! The chosen OpenCL platform static cl_platform_id platform = NULL; @@ -88,7 +88,6 @@ static cl_command_queue commandQueueNoProf = NULL; //! Global status of events static bool eventsEnabled = false; - //------------------------------------------------------- // Initialization and Cleanup //------------------------------------------------------- @@ -239,14 +238,34 @@ static bool eventsEnabled = false; return context; }*/ +static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { + if (nullptr == filename || nullptr == data || 0 == size) + return -1; + + FILE* fp = fopen(filename, "r"); + if (NULL == fp) { + fprintf(stderr, "Failed to load kernel."); + return -1; + } + fseek(fp , 0 , SEEK_END); + long fsize = ftell(fp); + rewind(fp); + + *data = (uint8_t*)malloc(fsize); + *size = fread(*data, 1, fsize, fp); + + fclose(fp); + + return 0; +} + + cl_context cl_init_context(int platform, int dev,int quiet) { int printInfo=1; if (platform >= 0 && dev >= 0) printInfo = 0; cl_int status; // Used to iterate through the platforms and devices, respectively - cl_uint numPlatforms; - cl_uint numDevices; - + // These will hold the platform and device we select (can potentially be // multiple, but we're just doing one for now) // cl_platform_id platform = NULL; @@ -376,23 +395,24 @@ cl_context cl_init_context(int platform, int dev,int quiet) { // Getting platform and device information numPlatforms = 1; - numDevices = 1; - int platform_touse = 0; - int device_touse = 0; platforms = (cl_platform_id*)malloc(numPlatforms * sizeof(cl_platform_id)); - devices = (cl_device_id*)malloc(sizeof(cl_device_id)*numDevices); - status = clGetPlatformIDs(1, platforms, NULL); + numDevices = (cl_uint*)malloc(sizeof(cl_uint)*numPlatforms); + numDevices[0] = 1; + devices = (cl_device_id*)malloc(sizeof(cl_device_id)*numDevices[0]); + + int platform_touse = 0; + int device_touse = 0; + + status = clGetPlatformIDs(numPlatforms, platforms, NULL); cl_errChk(status, "Oops!", true); - status = clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_DEFAULT, 1, devices, NULL); + status = clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_DEFAULT, numDevices[0], devices, NULL); cl_errChk(status, "Oops!", true); - context = clCreateContext(NULL, 1, devices, NULL, NULL, &status); + context = clCreateContext(NULL, numDevices[0], devices, NULL, NULL, &status); cl_errChk(status, "Oops!", true); device=devices[device_touse]; -#define PROFILING - #ifdef PROFILING commandQueue = clCreateCommandQueue(context, @@ -400,7 +420,7 @@ cl_context cl_init_context(int platform, int dev,int quiet) { #else - clCommandQueue = clCreateCommandQueue(clGPUContext, + commandQueue = clCreateCommandQueue(context, devices[device_touse], NULL, &status); #endif // PROFILING @@ -413,22 +433,34 @@ cl_context cl_init_context(int platform, int dev,int quiet) { /*! Release all resources that the user doesn't have access to. */ -void cl_cleanup() +void cl_cleanup() { + cl_int status; + // Free the command queue - if(commandQueue) { - clReleaseCommandQueue(commandQueue); + if (commandQueue) { + status = clReleaseCommandQueue(commandQueue); + cl_errChk(status, "Oops!", true); + printf("clReleaseCommandQueue()\n"); } // Free the context - if(context) { - clReleaseContext(context); + if (context) { + status = clReleaseContext(context); + cl_errChk(status, "Oops!", true); + printf("clReleaseContext()\n"); + } + + for (int p = 0; p < numPlatforms; ++p) { + for (int d = 0; d < numDevices[p]; ++d) { + status = clReleaseDevice(devices[d]); + cl_errChk(status, "Oops!", true); + printf("clReleaseDevice()\n"); + } } free(devices); free(numDevices); - - // Free the platforms free(platforms); } @@ -443,6 +475,7 @@ void cl_freeKernel(cl_kernel kernel) if(kernel != NULL) { status = clReleaseKernel(kernel); cl_errChk(status, "Releasing kernel object", true); + printf("clReleaseKernel()\n"); } } @@ -457,6 +490,7 @@ void cl_freeMem(cl_mem mem) if(mem != NULL) { status = clReleaseMemObject(mem); cl_errChk(status, "Releasing mem object", true); + printf("clReleaseMemObject()\n"); } } @@ -471,6 +505,7 @@ void cl_freeProgram(cl_program program) if(program != NULL) { status = clReleaseProgram(program); cl_errChk(status, "Releasing program object", true); + printf("clReleaseProgram()\n"); } } @@ -782,27 +817,6 @@ void cl_writeToZCBuffer(cl_mem mem, void* data, size_t size) cl_unmapBuffer(mem, ptr); } -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return -1; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return 0; -} - //------------------------------------------------------- // Program and kernels //------------------------------------------------------- @@ -858,17 +872,17 @@ cl_program cl_compileProgram(char* kernelPath, char* compileoptions, bool verbos fread(source, 1, size, fp); source[size] = '\0';*/ - // Create the program object - //cl_program clProgramReturn = clCreateProgramWithSource(context, 1, (const char **)&source, NULL, &status); - //cl_program clProgramReturn = clCreateProgramWithBuiltInKernels(context, 1, &device, "Fan1;Fan2", &status); - // read kernel binary from file + // read kernel binary from file uint8_t *kernel_bin = NULL; size_t kernel_size; - cl_int binary_status = 0; - status = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); - cl_errChk(status, "read_kernel_file", true); + cl_int binary_status = 0; + int err = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); + cl_errChk(err, "read_kernel_file", true); + + // Create the program object + //cl_program clProgramReturn = clCreateProgramWithSource(context, 1, (const char **)&source, NULL, &status); cl_program clProgramReturn = clCreateProgramWithBinary( - context, 1, &device, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &status); + context, 1, devices, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &status); free(kernel_bin); cl_errChk(status, "Creating program", true); @@ -1440,4 +1454,4 @@ char* itoa_portable(int value, char* result, int base) { } return result; -} +} \ No newline at end of file diff --git a/benchmarks/opencl/guassian/main.cc b/benchmarks/opencl/guassian/main.cc index 4972a253..d7e235eb 100755 --- a/benchmarks/opencl/guassian/main.cc +++ b/benchmarks/opencl/guassian/main.cc @@ -76,6 +76,9 @@ int main(int argc, char *argv[]) { free(b); free(finalVec); // OpenClGaussianElimination(context,timing); + + cl_cleanup(); + printf("Passed!\n"); return 0; } @@ -142,7 +145,8 @@ void ForwardSub(cl_context context, float *a, float *b, float *m, int size, writeTime += eventTime(writeEvent, command_queue); clReleaseEvent(writeEvent); - error = clEnqueueWriteBuffer(command_queue, m_dev, + error = clEnqueueWriteBuffer(command_queue, + m_dev, 1, // change to 0 for nonblocking write 0, // offset sizeof(float) * size * size, m, 0, NULL, @@ -258,6 +262,13 @@ void ForwardSub(cl_context context, float *a, float *b, float *m, int size, printf("%f\n\n", writeTime + kernelTime + readTime); } + + cl_freeMem(a_dev); + cl_freeMem(b_dev); + cl_freeMem(m_dev); + cl_freeKernel(fan1_kernel); + cl_freeKernel(fan2_kernel); + cl_freeProgram(gaussianElim_program); } float eventTime(cl_event event, cl_command_queue command_queue) { diff --git a/benchmarks/opencl/nearn/clutils.cpp b/benchmarks/opencl/nearn/clutils.cpp index 3c433c0c..c977477a 100755 --- a/benchmarks/opencl/nearn/clutils.cpp +++ b/benchmarks/opencl/nearn/clutils.cpp @@ -69,7 +69,7 @@ static cl_uint numPlatforms; //! All discoverable OpenCL devices (one pointer per platform) static cl_device_id* devices = NULL; -static cl_uint* numDevices; +static cl_uint* numDevices = NULL; //! The chosen OpenCL platform static cl_platform_id platform = NULL; @@ -265,9 +265,7 @@ cl_context cl_init_context(int platform, int dev,int quiet) { if (platform >= 0 && dev >= 0) printInfo = 0; cl_int status; // Used to iterate through the platforms and devices, respectively - cl_uint numPlatforms; - cl_uint numDevices; - + // These will hold the platform and device we select (can potentially be // multiple, but we're just doing one for now) // cl_platform_id platform = NULL; @@ -397,23 +395,24 @@ cl_context cl_init_context(int platform, int dev,int quiet) { // Getting platform and device information numPlatforms = 1; - numDevices = 1; - int platform_touse = 0; - int device_touse = 0; platforms = (cl_platform_id*)malloc(numPlatforms * sizeof(cl_platform_id)); - devices = (cl_device_id*)malloc(sizeof(cl_device_id)*numDevices); - status = clGetPlatformIDs(1, platforms, NULL); + numDevices = (cl_uint*)malloc(sizeof(cl_uint)*numPlatforms); + numDevices[0] = 1; + devices = (cl_device_id*)malloc(sizeof(cl_device_id)*numDevices[0]); + + int platform_touse = 0; + int device_touse = 0; + + status = clGetPlatformIDs(numPlatforms, platforms, NULL); cl_errChk(status, "Oops!", true); - status = clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_DEFAULT, 1, devices, NULL); + status = clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_DEFAULT, numDevices[0], devices, NULL); cl_errChk(status, "Oops!", true); - context = clCreateContext(NULL, 1, devices, NULL, NULL, &status); + context = clCreateContext(NULL, numDevices[0], devices, NULL, NULL, &status); cl_errChk(status, "Oops!", true); device=devices[device_touse]; -#define PROFILING - #ifdef PROFILING commandQueue = clCreateCommandQueue(context, @@ -421,7 +420,7 @@ cl_context cl_init_context(int platform, int dev,int quiet) { #else - clCommandQueue = clCreateCommandQueue(clGPUContext, + commandQueue = clCreateCommandQueue(context, devices[device_touse], NULL, &status); #endif // PROFILING @@ -434,22 +433,34 @@ cl_context cl_init_context(int platform, int dev,int quiet) { /*! Release all resources that the user doesn't have access to. */ -void cl_cleanup() +void cl_cleanup() { + cl_int status; + // Free the command queue - if(commandQueue) { - clReleaseCommandQueue(commandQueue); + if (commandQueue) { + status = clReleaseCommandQueue(commandQueue); + cl_errChk(status, "Oops!", true); + printf("clReleaseCommandQueue()\n"); } // Free the context - if(context) { - clReleaseContext(context); + if (context) { + status = clReleaseContext(context); + cl_errChk(status, "Oops!", true); + printf("clReleaseContext()\n"); + } + + for (int p = 0; p < numPlatforms; ++p) { + for (int d = 0; d < numDevices[p]; ++d) { + status = clReleaseDevice(devices[d]); + cl_errChk(status, "Oops!", true); + printf("clReleaseDevice()\n"); + } } free(devices); free(numDevices); - - // Free the platforms free(platforms); } @@ -464,6 +475,7 @@ void cl_freeKernel(cl_kernel kernel) if(kernel != NULL) { status = clReleaseKernel(kernel); cl_errChk(status, "Releasing kernel object", true); + printf("clReleaseKernel()\n"); } } @@ -478,6 +490,7 @@ void cl_freeMem(cl_mem mem) if(mem != NULL) { status = clReleaseMemObject(mem); cl_errChk(status, "Releasing mem object", true); + printf("clReleaseMemObject()\n"); } } @@ -492,6 +505,7 @@ void cl_freeProgram(cl_program program) if(program != NULL) { status = clReleaseProgram(program); cl_errChk(status, "Releasing program object", true); + printf("clReleaseProgram()\n"); } } diff --git a/benchmarks/opencl/nearn/main.cc b/benchmarks/opencl/nearn/main.cc index 62d08c58..43ce1634 100755 --- a/benchmarks/opencl/nearn/main.cc +++ b/benchmarks/opencl/nearn/main.cc @@ -49,25 +49,27 @@ int main(int argc, char *argv[]) { printf("%s --> Distance=%f\n", records[i].recString, records[i].distance); } free(recordDistances); + + cl_cleanup(); + printf("Passed!\n"); + return 0; } float *OpenClFindNearestNeighbors(cl_context context, int numRecords, std::vector &locations, float lat, float lng, int timing) { - - // 1. set up kernel - cl_kernel NN_kernel; cl_int status; + + // 1. set up kernel + cl_kernel NN_kernel; cl_program cl_NN_program; cl_NN_program = cl_compileProgram((char *)"nearestNeighbor_kernel.cl", NULL); NN_kernel = clCreateKernel(cl_NN_program, "NearestNeighbor", &status); - status = - cl_errChk(status, (char *)"Error Creating Nearest Neighbor kernel", true); - if (status) - exit(1); + cl_errChk(status, (char *)"Error Creating Nearest Neighbor kernel", true); + // 2. set up memory on device and send ipts data to device // copy ipts(1,2) to device // also need to alloate memory for the distancePoints @@ -78,9 +80,11 @@ float *OpenClFindNearestNeighbors(cl_context context, int numRecords, d_locations = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(LatLong) * numRecords, NULL, &error); + cl_errChk(error, "ERROR: clCreateBuffer() failed", true); d_distances = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float) * numRecords, NULL, &error); + cl_errChk(error, "ERROR: clCreateBuffer() failed", true); cl_command_queue command_queue = cl_getCommandQueue(); cl_event writeEvent, kernelEvent, readEvent; @@ -89,6 +93,7 @@ float *OpenClFindNearestNeighbors(cl_context context, int numRecords, 0, // offset sizeof(LatLong) * numRecords, &locations[0], 0, NULL, &writeEvent); + cl_errChk(error, "ERROR: clEnqueueWriteBuffer() failed", true); // 3. send arguments to device cl_int argchk; @@ -124,8 +129,10 @@ float *OpenClFindNearestNeighbors(cl_context context, int numRecords, &readEvent); cl_errChk(error, "ERROR with clEnqueueReadBuffer", true); - if (timing) { - clFinish(command_queue); + + clFinish(command_queue); + + if (timing) { cl_ulong eventStart, eventEnd, totalTime = 0; printf("# Records\tWrite(s) [size]\t\tKernel(s)\tRead(s) " "[size]\t\tTotal(s)\n"); @@ -166,8 +173,14 @@ float *OpenClFindNearestNeighbors(cl_context context, int numRecords, printf("%f\n\n", (float)(totalTime / 1e9)); } // 6. return finalized data and release buffers - clReleaseMemObject(d_locations); - clReleaseMemObject(d_distances); + clReleaseEvent(writeEvent); + clReleaseEvent(kernelEvent); + clReleaseEvent(readEvent); + cl_freeMem(d_locations); + cl_freeMem(d_distances); + cl_freeKernel(NN_kernel); + cl_freeProgram(cl_NN_program); + return distances; } diff --git a/benchmarks/opencl/saxpy/main.cc b/benchmarks/opencl/saxpy/main.cc index d4076d70..cf090486 100644 --- a/benchmarks/opencl/saxpy/main.cc +++ b/benchmarks/opencl/saxpy/main.cc @@ -157,7 +157,7 @@ int main(int argc, char **argv) { context = CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, &pfn_notify, NULL, &_err)); cl_command_queue queue; - queue = CL_CHECK_ERR(clCreateCommandQueue(context, device_id, CL_QUEUE_PROFILING_ENABLE, &_err)); + queue = CL_CHECK_ERR(clCreateCommandQueue(context, device_id, NULL, &_err)); cl_kernel kernel = 0; cl_mem memObjects[2] = {0, 0}; From 64c27b159b837fb7db3aa4665d90a0bd2f6fdee3 Mon Sep 17 00:00:00 2001 From: Liam Paul Cooper Date: Mon, 19 Apr 2021 00:32:46 -0400 Subject: [PATCH 03/55] added csv generating scripts --- evaluation/scripts/README.txt | 59 +++++++++++++++++++++++++--- evaluation/scripts/export_csv.sh | 33 ++++++++++++++++ evaluation/scripts/export_ipc_csv.sh | 32 +++++++++++++++ 3 files changed, 119 insertions(+), 5 deletions(-) create mode 100755 evaluation/scripts/export_csv.sh create mode 100755 evaluation/scripts/export_ipc_csv.sh diff --git a/evaluation/scripts/README.txt b/evaluation/scripts/README.txt index 908b0147..dbf20831 100644 --- a/evaluation/scripts/README.txt +++ b/evaluation/scripts/README.txt @@ -5,19 +5,16 @@ Description: Makes the build in the opae directory with the specified core exists, a make clean command is ran before the build. Script waits until the inteldev script or quartus program is finished running. -Usage: ./build.sh -c [1|2|4|8|16] [-p perf] [-w wait] +Usage: ./build.sh -c [1|2|4|8|16] [-p [y|n]] Options: -c Core count (1, 2, 4, 8, or 16). -p - Performance profiling enable. Changes the source file in the + Performance profiling enable (y or n). Changes the source file in the opae directory to include/exclude "+define+PERF_ENABLE". - -w - Wait for the build to complete - _______________________________________________________________________________ @@ -27,6 +24,7 @@ Description: Runs build.sh with performance profiling enabled for all valid core configurations. _______________________________________________________________________________ +_______________________________________________________________________________ -program_fpga.sh- @@ -41,6 +39,7 @@ Options: Core count (1, 2, 4, 8, or 16). _______________________________________________________________________________ +_______________________________________________________________________________ -gather_perf_results.sh- @@ -65,3 +64,53 @@ _______________________________________________________________________________ Description: Programs fpga and runs gather_perf_results.sh for all valid core configurations. All builds should already be made before running this. + +_______________________________________________________________________________ +_______________________________________________________________________________ + + +-export_csv.sh- + +Description: Creates specified .csv output file from an input directory, file, +and parameter. The .csv file contains two columns: cores, and the input +parameter. The output file is located within the directory specified with -d. + +Usage: ./export_csv.sh -c [cores] -d [directory] -i [input filename] -o + [output filename] -p '[parameter]' + +Example: ./export_csv.sh -c 16 -d perf_2021_03_07 -i sgemm.result -o output.csv + -p 'PERF: scoreboard stalls' + +Options: + -c + Upper limit of cores to be read in. Core directories should exist in + the directory specified by -d e.g. 1c, 2c, 4c for -c 4. + + -d + The directory of the form perf_{date} located in the evaluation + directory. + + -i + The input filename located in each core directory within the + directory specified by -d. + + -o + The output filename to be created within the directory specified + by -d. + + -p + The parameter corresponding to the core count in the .csv file. The + full name of the parameter from the start of the line should be + inputted to avoid the parameter name being matched multiple times. + +_______________________________________________________________________________ + + +-export_ipc_csv.sh- + +Description: Runs export_csv.sh for the parameter IPC. + +Usage: ./export_csv.sh -c [cores] -d [directory] -i [input filename] -o + [output filename] + +Example: ./export_ipc.sh -c 16 -d perf_2021_03_07 -i sgemm.result -o output.csv diff --git a/evaluation/scripts/export_csv.sh b/evaluation/scripts/export_csv.sh new file mode 100755 index 00000000..8f95a71b --- /dev/null +++ b/evaluation/scripts/export_csv.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +while getopts c:d:i:o:p: flag +do + case "${flag}" in + c) cores=${OPTARG};; #1, 2, 4, 8, 16 + d) dir=${OPTARG};; #directory name (e.g. perf_2021_03_07) + i) ifile=${OPTARG};; #input filename + o) ofile=${OPTARG};; #output filename + p) param=${OPTARG};; #parameter to be made into csv + esac +done + +if [[ ! "$cores" =~ ^(1|2|4|8|16)$ ]]; then + echo 'Invalid parameter for argument -c (1, 2, 4, 8, or 16 expected)' + exit 1 +fi + +if [ -z "$ifile" ]; then + echo 'No input filename given for argument -f' + exit 1 +fi + +if [ -z "$dir" ]; then + echo 'No directory given for argument -d' + exit 1 +fi + +printf "cores,${param}\n" > "../${dir}/${ofile}" +for ((i=1; i<=$cores; i=i*2)); do + printf "${i}," >> "../${dir}/${ofile}" + (sed -n "s/${param}=\(.*\)/\1/p" < "../${dir}/${i}c/${ifile}") >> "../${dir}/${ofile}" +done diff --git a/evaluation/scripts/export_ipc_csv.sh b/evaluation/scripts/export_ipc_csv.sh new file mode 100755 index 00000000..f698525b --- /dev/null +++ b/evaluation/scripts/export_ipc_csv.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +while getopts c:d:f:o: flag +do + case "${flag}" in + c) cores=${OPTARG};; #1, 2, 4, 8, 16 + d) dir=${OPTARG};; #directory name (e.g. perf_2021_03_07) + i) ifile=${OPTARG};; #input filename + o) ofile=${OPTARG};; #output filename + esac +done + +if [[ ! "$cores" =~ ^(1|2|4|8|16)$ ]]; then + echo 'Invalid parameter for argument -c (1, 2, 4, 8, or 16 expected)' + exit 1 +fi + +if [ -z "$ifile" ]; then + echo 'No input filename given for argument -f' + exit 1 +fi + +if [ -z "$dir" ]; then + echo 'No directory given for argument -d' + exit 1 +fi + +printf "cores,IPC" > "../${dir}/${ofile}" +for ((i=1; i<=$cores; i=i*2)); do + printf "${i}," >> "../${dir}/${ofile}" + (sed -n "s/IPC=\(.*\)/\1/p" < "../${dir}/${i}c/${ifile}" | awk 'END {print $NF}') >> "../${dir}/${ofile}" +done From aff5903a224458d6a9c75a3a6f8943f73700b412 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 19 Apr 2021 20:53:13 -0700 Subject: [PATCH 04/55] minor ibuffer critical path optimization. --- hw/rtl/VX_ibuffer.v | 24 +++++++++++------------ hw/rtl/VX_issue.v | 1 - hw/rtl/VX_scoreboard.v | 6 +++--- hw/rtl/cache/VX_bank.v | 8 ++++---- hw/rtl/cache/VX_cache.v | 4 +++- hw/rtl/cache/VX_cache_core_req_bank_sel.v | 4 +++- hw/rtl/cache/VX_cache_core_rsp_merge.v | 2 ++ hw/rtl/cache/VX_shared_mem.v | 1 + hw/rtl/libs/VX_scope.v | 10 +++++----- hw/syn/opae/README | 3 +++ 10 files changed, 35 insertions(+), 28 deletions(-) diff --git a/hw/rtl/VX_ibuffer.v b/hw/rtl/VX_ibuffer.v index 9de55ab2..8a7bb4aa 100644 --- a/hw/rtl/VX_ibuffer.v +++ b/hw/rtl/VX_ibuffer.v @@ -7,7 +7,6 @@ module VX_ibuffer #( input wire reset, // inputs - input wire freeze, // keep current warp VX_decode_if ibuf_enq_if, // outputs @@ -117,18 +116,9 @@ module VX_ibuffer #( deq_valid_n = 0; deq_wid_n = 'x; deq_instr_n = 'x; - schedule_table_n = 'x; - - if ((0 == num_warps) - || (1 == num_warps && deq_fire && q_alm_empty[deq_wid])) begin - deq_valid_n = enq_fire; - deq_wid_n = ibuf_enq_if.wid; - deq_instr_n = q_data_in; - end else if ((1 == num_warps) || freeze) begin - deq_valid_n = 1; - deq_wid_n = deq_wid; - deq_instr_n = deq_fire ? q_data_prev[deq_wid] : q_data_out[deq_wid]; - end else begin + schedule_table_n = 'x; + + if (num_warps > 1) begin deq_valid_n = (| schedule_table); schedule_table_n = schedule_table; for (integer i = 0; i < `NUM_WARPS; i++) begin @@ -139,6 +129,14 @@ module VX_ibuffer #( break; end end + end else if (1 == num_warps && !(deq_fire && q_alm_empty[deq_wid])) begin + deq_valid_n = 1; + deq_wid_n = deq_wid; + deq_instr_n = deq_fire ? q_data_prev[deq_wid] : q_data_out[deq_wid]; + end else begin + deq_valid_n = enq_fire; + deq_wid_n = ibuf_enq_if.wid; + deq_instr_n = q_data_in; end end diff --git a/hw/rtl/VX_issue.v b/hw/rtl/VX_issue.v index 9ea7093b..269f0956 100644 --- a/hw/rtl/VX_issue.v +++ b/hw/rtl/VX_issue.v @@ -33,7 +33,6 @@ module VX_issue #( ) ibuffer ( .clk (clk), .reset (reset), - .freeze (1'b0), .ibuf_enq_if (decode_if), .ibuf_deq_if (ibuf_deq_if) ); diff --git a/hw/rtl/VX_scoreboard.v b/hw/rtl/VX_scoreboard.v index a1cc2078..139f0aa1 100644 --- a/hw/rtl/VX_scoreboard.v +++ b/hw/rtl/VX_scoreboard.v @@ -31,7 +31,7 @@ module VX_scoreboard #( if (release_reg) begin inuse_regs[writeback_if.wid][writeback_if.rd] <= 0; assert(inuse_regs[writeback_if.wid][writeback_if.rd] != 0) - else $error("*** %t: core%0d: invalid writeback register: wid=%0d, PC=%0h, rd=%0d", + else $error("%t: *** core%0d: invalid writeback register: wid=%0d, PC=%0h, rd=%0d", $time, CORE_ID, writeback_if.wid, writeback_if.PC, writeback_if.rd); end end @@ -40,7 +40,7 @@ module VX_scoreboard #( `ifdef DBG_PRINT_PIPELINE always @(posedge clk) begin if (ibuf_deq_if.valid && ~ibuf_deq_if.ready) begin - $display("%t: core%0d-stall: wid=%0d, PC=%0h, rd=%0d, wb=%0d, inuse=%b%b%b%b", + $display("%t: *** core%0d-stall: wid=%0d, PC=%0h, rd=%0d, wb=%0d, inuse=%b%b%b%b", $time, CORE_ID, ibuf_deq_if.wid, ibuf_deq_if.PC, ibuf_deq_if.rd, ibuf_deq_if.wb, deq_inuse_regs[ibuf_deq_if.rd], deq_inuse_regs[ibuf_deq_if.rs1], deq_inuse_regs[ibuf_deq_if.rs2], deq_inuse_regs[ibuf_deq_if.rs3]); end @@ -54,7 +54,7 @@ module VX_scoreboard #( deadlock_ctr <= 0; end else if (ibuf_deq_if.valid && ~ibuf_deq_if.ready) begin deadlock_ctr <= deadlock_ctr + 1; - assert(deadlock_ctr < deadlock_timeout) else $error("*** %t: core%0d-deadlock: wid=%0d, PC=%0h, rd=%0d, wb=%0d, inuse=%b%b%b%b", + assert(deadlock_ctr < deadlock_timeout) else $error("%t: *** core%0d-deadlock: wid=%0d, PC=%0h, rd=%0d, wb=%0d, inuse=%b%b%b%b", $time, CORE_ID, ibuf_deq_if.wid, ibuf_deq_if.PC, ibuf_deq_if.rd, ibuf_deq_if.wb, deq_inuse_regs[ibuf_deq_if.rd], deq_inuse_regs[ibuf_deq_if.rs1], deq_inuse_regs[ibuf_deq_if.rs2], deq_inuse_regs[ibuf_deq_if.rs3]); end else if (ibuf_deq_if.valid && ibuf_deq_if.ready) begin diff --git a/hw/rtl/cache/VX_bank.v b/hw/rtl/cache/VX_bank.v index 5e62ab26..81df57ad 100644 --- a/hw/rtl/cache/VX_bank.v +++ b/hw/rtl/cache/VX_bank.v @@ -558,11 +558,11 @@ module VX_bank #( `ifdef DBG_PRINT_CACHE_BANK always @(posedge clk) begin - /*if (valid_st1 && pmask_st1 == {NUM_PORTS{1'b1}}) begin - $display("%t: cache%0d:%0d full bank multi-porting - addr=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID)); - end*/ + /*if (crsq_in_fire && (NUM_PORTS > 1) && $countones(crsq_pmask) > 1) begin + $display("%t: *** cache%0d:%0d multi-port-out: pmask=%b, addr=%0h, tag=%0h", $time, CACHE_ID, BANK_ID, crsq_pmask, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID), crsq_tag); + end */ if (valid_st1 && !is_fill_st1 && miss_st1 && incoming_fill_qual_st1) begin - $display("%t: cache%0d:%0d miss with incoming fill - addr=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID)); + $display("%t: *** cache%0d:%0d miss with incoming fill - addr=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID)); assert(!is_mshr_st1); end if (crsq_in_stall || dreq_alm_full || mshr_alm_full) begin diff --git a/hw/rtl/cache/VX_cache.v b/hw/rtl/cache/VX_cache.v index f0bf1d9d..7a419512 100644 --- a/hw/rtl/cache/VX_cache.v +++ b/hw/rtl/cache/VX_cache.v @@ -88,7 +88,7 @@ module VX_cache #( ); `STATIC_ASSERT(NUM_BANKS <= NUM_REQS, ("invalid value")) - + wire [NUM_BANKS-1:0][NUM_PORTS-1:0] per_bank_core_req_valid; wire [NUM_BANKS-1:0][NUM_PORTS-1:0][`UP(`WORD_SELECT_BITS)-1:0] per_bank_core_req_wsel; wire [NUM_BANKS-1:0][NUM_PORTS-1:0][WORD_SIZE-1:0] per_bank_core_req_byteen; @@ -176,6 +176,7 @@ module VX_cache #( /////////////////////////////////////////////////////////////////////////// VX_cache_core_req_bank_sel #( + .CACHE_ID (CACHE_ID), .CACHE_LINE_SIZE (CACHE_LINE_SIZE), .NUM_BANKS (NUM_BANKS), .NUM_PORTS (NUM_PORTS), @@ -351,6 +352,7 @@ module VX_cache #( end VX_cache_core_rsp_merge #( + .CACHE_ID (CACHE_ID), .NUM_BANKS (NUM_BANKS), .NUM_PORTS (NUM_PORTS), .WORD_SIZE (WORD_SIZE), diff --git a/hw/rtl/cache/VX_cache_core_req_bank_sel.v b/hw/rtl/cache/VX_cache_core_req_bank_sel.v index 183ff6c2..16fb01df 100644 --- a/hw/rtl/cache/VX_cache_core_req_bank_sel.v +++ b/hw/rtl/cache/VX_cache_core_req_bank_sel.v @@ -1,6 +1,8 @@ `include "VX_cache_config.vh" module VX_cache_core_req_bank_sel #( + parameter CACHE_ID = 0, + // Size of line inside a bank in bytes parameter CACHE_LINE_SIZE = 64, // Size of a word in bytes @@ -148,7 +150,7 @@ module VX_cache_core_req_bank_sel #( end end end - + end else begin always @(*) begin diff --git a/hw/rtl/cache/VX_cache_core_rsp_merge.v b/hw/rtl/cache/VX_cache_core_rsp_merge.v index 4bed779d..5427a7a9 100644 --- a/hw/rtl/cache/VX_cache_core_rsp_merge.v +++ b/hw/rtl/cache/VX_cache_core_rsp_merge.v @@ -1,6 +1,8 @@ `include "VX_cache_config.vh" module VX_cache_core_rsp_merge #( + parameter CACHE_ID = 0, + // Number of Word requests per cycle parameter NUM_REQS = 1, // Number of banks diff --git a/hw/rtl/cache/VX_shared_mem.v b/hw/rtl/cache/VX_shared_mem.v index 4d9eee57..fc412772 100644 --- a/hw/rtl/cache/VX_shared_mem.v +++ b/hw/rtl/cache/VX_shared_mem.v @@ -71,6 +71,7 @@ module VX_shared_mem #( wire per_bank_core_req_ready_unqual; VX_cache_core_req_bank_sel #( + .CACHE_ID (CACHE_ID), .CACHE_LINE_SIZE (WORD_SIZE), .NUM_BANKS (NUM_BANKS), .NUM_PORTS (1), diff --git a/hw/rtl/libs/VX_scope.v b/hw/rtl/libs/VX_scope.v index 8cf69211..88045ceb 100644 --- a/hw/rtl/libs/VX_scope.v +++ b/hw/rtl/libs/VX_scope.v @@ -94,13 +94,13 @@ module VX_scope #( delay_val <= $bits(delay_val)'(cmd_data); cmd_start <= 1; `ifdef DBG_PRINT_SCOPE - $display("*** scope:CMD_SET_START: delay_val=%0d", $bits(delay_val)'(cmd_data)); + $display("%t: *** scope: CMD_SET_START: delay_val=%0d", $time, $bits(delay_val)'(cmd_data)); `endif end CMD_SET_STOP: begin waddr_end <= $bits(waddr)'(cmd_data); `ifdef DBG_PRINT_SCOPE - $display("*** scope:CMD_SET_STOP: waddr_end=%0d", $bits(waddr)'(cmd_data)); + $display("%t: *** scope: CMD_SET_STOP: waddr_end=%0d", $time, $bits(waddr)'(cmd_data)); `endif end default:; @@ -117,7 +117,7 @@ module VX_scope #( delay_cntr <= 0; start_time <= timestamp; `ifdef DBG_PRINT_SCOPE - $display("*** scope: recording start - start_time=%0d", timestamp); + $display("%t: *** scope: recording start - start_time=%0d", $time, timestamp); `endif end else begin start_wait <= 1; @@ -133,7 +133,7 @@ module VX_scope #( delta <= 0; start_time <= timestamp; `ifdef DBG_PRINT_SCOPE - $display("*** scope: recording start - start_time=%0d", timestamp); + $display("%t: *** scope: recording start - start_time=%0d", $time, timestamp); `endif end end @@ -162,7 +162,7 @@ module VX_scope #( if (stop || (waddr >= waddr_end)) begin `ifdef DBG_PRINT_SCOPE - $display("*** scope: recording stop - waddr=(%0d, %0d)", waddr, waddr_end); + $display("%t: *** scope: recording stop - waddr=(%0d, %0d)", $time, waddr, waddr_end); `endif waddr <= waddr; // keep last address recording <= 0; diff --git a/hw/syn/opae/README b/hw/syn/opae/README index ade3474b..03233d0b 100644 --- a/hw/syn/opae/README +++ b/hw/syn/opae/README @@ -44,6 +44,9 @@ fpgaconf vortex_afu.gbs # If this says Multiple ports. Then use --bus with fpgaconf. #bus info can be found by fpgainfo port fpgaconf --bus 0xaf vortex_afu.gbs +# get portid +fpgainfo port + # Running the Test case cd /driver/tests/basic make run-fpga From 2f5ccdcf454d6eea110f08da5455c48091d1506d Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 19 Apr 2021 21:29:39 -0700 Subject: [PATCH 05/55] quartus synthesis build update --- hw/syn/quartus/Makefile | 50 ++++++++++++++++++++++++-------- hw/syn/quartus/cache/Makefile | 12 ++++---- hw/syn/quartus/core/Makefile | 18 +++++++----- hw/syn/quartus/pipeline/Makefile | 18 +++++++++--- hw/syn/quartus/top1/Makefile | 22 +++++++------- hw/syn/quartus/top16/Makefile | 22 +++++++------- hw/syn/quartus/top2/Makefile | 22 +++++++------- hw/syn/quartus/top32/Makefile | 22 +++++++------- hw/syn/quartus/top4/Makefile | 22 +++++++------- hw/syn/quartus/top64/Makefile | 22 +++++++------- hw/syn/quartus/top8/Makefile | 22 +++++++------- hw/syn/quartus/unittest/Makefile | 18 ++++++++---- hw/syn/quartus/vortex/Makefile | 20 ++++++------- 13 files changed, 167 insertions(+), 123 deletions(-) diff --git a/hw/syn/quartus/Makefile b/hw/syn/quartus/Makefile index 66d95034..4dd40a40 100644 --- a/hw/syn/quartus/Makefile +++ b/hw/syn/quartus/Makefile @@ -1,37 +1,63 @@ +BUILDIR ?= build + .PHONY: unittest pipeline cache core vortex top1 top2 top4 top8 top16 top32 top64 unittest: - $(MAKE) -C unittest clean && $(MAKE) -C unittest > unittest/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C unittest/$(BUILDIR) clean && $(MAKE) -C unittest/$(BUILDIR) > unittest//$(BUILDIR)build.log 2>&1 & pipeline: - $(MAKE) -C pipeline clean && $(MAKE) -C pipeline > pipeline/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C pipeline/$(BUILDIR) clean && $(MAKE) -C pipeline/$(BUILDIR) > pipeline/$(BUILDIR)/build.log 2>&1 & cache: - $(MAKE) -C cache clean && $(MAKE) -C cache > cache/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C cache/$(BUILDIR) clean && $(MAKE) -C cache/$(BUILDIR) > cache/$(BUILDIR)/build.log 2>&1 & core: - $(MAKE) -C core clean && $(MAKE) -C core > core/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C core/$(BUILDIR) clean && $(MAKE) -C core/$(BUILDIR) > core/$(BUILDIR)/build.log 2>&1 & vortex: - $(MAKE) -C vortex clean && $(MAKE) -C vortex > vortex/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C vortex/$(BUILDIR) clean && $(MAKE) -C vortex/$(BUILDIR) > vortex/$(BUILDIR)/build.log 2>&1 & top1: - $(MAKE) -C top1 clean && $(MAKE) -C top1 > top1/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C top1/$(BUILDIR) clean && $(MAKE) -C top1/$(BUILDIR) > top1/$(BUILDIR)/build.log 2>&1 & top2: - $(MAKE) -C top2 clean && $(MAKE) -C top2 > top2/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C top2/$(BUILDIR) clean && $(MAKE) -C top2/$(BUILDIR) > top2/$(BUILDIR)/build.log 2>&1 & top4: - $(MAKE) -C top4 clean && $(MAKE) -C top4 > top4/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C top4/$(BUILDIR) clean && $(MAKE) -C top4/$(BUILDIR) > top4/$(BUILDIR)/build.log 2>&1 & top8: - $(MAKE) -C top8 clean && $(MAKE) -C top8 > top8/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C top8/$(BUILDIR) clean && $(MAKE) -C top8/$(BUILDIR) > top8/$(BUILDIR)/build.log 2>&1 & top16: - $(MAKE) -C top16 clean && $(MAKE) -C top16 > top16/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C top16/$(BUILDIR) clean && $(MAKE) -C top16/$(BUILDIR) > top16/$(BUILDIR)build.log 2>&1 & top32: - $(MAKE) -C top32 clean && $(MAKE) -C top32 > top32/build.log 2>&1 & + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C top32/$(BUILDIR) clean && $(MAKE) -C top32/$(BUILDIR) > top32/$(BUILDIR)/build.log 2>&1 & top64: - $(MAKE) -C top64 clean && $(MAKE) -C top64 > top64/build.log 2>&1 & \ No newline at end of file + mkdir -p core/$(BUILDIR) + cp core/Makefile core/$(BUILDIR) + $(MAKE) -C top64/$(BUILDIR) clean && $(MAKE) -C top64/$(BUILDIR) > top64/$(BUILDIR)/build.log 2>&1 & \ No newline at end of file diff --git a/hw/syn/quartus/cache/Makefile b/hw/syn/quartus/cache/Makefile index 34ffd29c..d28d9b18 100755 --- a/hw/syn/quartus/cache/Makefile +++ b/hw/syn/quartus/cache/Makefile @@ -1,14 +1,12 @@ -# Part, Family -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG - PROJECT = VX_cache TOP_LEVEL_ENTITY = VX_cache SRC_FILE = VX_cache.v +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG -RTL_DIR=../../../rtl RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache - PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf # Executable Configuration @@ -53,7 +51,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src $(SRC_FILE) -sdc ../project.sdc -inc "$(RTL_INCLUDE)" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src $(SRC_FILE) -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/core/Makefile b/hw/syn/quartus/core/Makefile index 03d89e3f..37e42df0 100644 --- a/hw/syn/quartus/core/Makefile +++ b/hw/syn/quartus/core/Makefile @@ -1,13 +1,17 @@ -# Part, Family -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG - PROJECT = Core TOP_LEVEL_ENTITY = VX_core SRC_FILE = VX_core.v +RTL_DIR = ../../../../rtl -RTL_DIR=../../../rtl -FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(RTL_DIR)/fp_cores/altera/arria10;$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 + +FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -54,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/pipeline/Makefile b/hw/syn/quartus/pipeline/Makefile index 095e19ce..bd259697 100644 --- a/hw/syn/quartus/pipeline/Makefile +++ b/hw/syn/quartus/pipeline/Makefile @@ -1,8 +1,18 @@ PROJECT = VX_pipeline TOP_LEVEL_ENTITY = VX_pipeline SRC_FILE = VX_pipeline.v -FPU_INCLUDE = ../../../rtl/fp_cores;../../../rtl/fp_cores/altera/arria10;../../../rtl/fp_cores/fpnew/src;../../../rtl/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;../../../rtl/fp_cores/fpnew/src/common_cells/include;../../../rtl/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(FPU_INCLUDE);../../../rtl;../../../rtl/libs;../../../rtl/interfaces +RTL_DIR = ../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 + +FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src +RTL_INCLUDE = $(FPU_INCLUDE);$(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf # Part, Family @@ -51,7 +61,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" syn.chg: $(STAMP) syn.chg @@ -66,7 +76,7 @@ asm.chg: $(STAMP) asm.chg timing: $(PROJECT_FILES) - quartus_sh -t ../timing-html.tcl -project $(PROJECT) + quartus_sh -t ../../timing-html.tcl -project $(PROJECT) program: $(PROJECT).sof quartus_pgm --no_banner --mode=jtag -o "$(PROJECT).sof" diff --git a/hw/syn/quartus/top1/Makefile b/hw/syn/quartus/top1/Makefile index eec14202..465cb192 100644 --- a/hw/syn/quartus/top1/Makefile +++ b/hw/syn/quartus/top1/Makefile @@ -1,18 +1,18 @@ -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -#FAMILY = "Stratix 10" -#DEVICE = 1SX280HN2F43E2VG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = vortex_afu TOP_LEVEL_ENTITY = vortex_afu SRC_FILE = vortex_afu.sv +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;../../../rtl/afu;../../../rtl/afu/ccip;$(FPU_INCLUDE) +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(RTL_DIR)/afu;$(RTL_DIR)/afu/ccip;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=1" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=1" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/top16/Makefile b/hw/syn/quartus/top16/Makefile index 28e02490..bd31b20a 100644 --- a/hw/syn/quartus/top16/Makefile +++ b/hw/syn/quartus/top16/Makefile @@ -1,18 +1,18 @@ -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -#FAMILY = "Stratix 10" -#DEVICE = 1SX280HN2F43E2VG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = vortex_afu TOP_LEVEL_ENTITY = vortex_afu SRC_FILE = vortex_afu.sv +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;../../../rtl/afu;../../../rtl/afu/ccip;$(FPU_INCLUDE) +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(RTL_DIR)/afu;$(RTL_DIR)/afu/ccip;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" -set "NUM_CLUSTERS=4" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" -set "NUM_CLUSTERS=4" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/top2/Makefile b/hw/syn/quartus/top2/Makefile index 0de5492d..31234939 100644 --- a/hw/syn/quartus/top2/Makefile +++ b/hw/syn/quartus/top2/Makefile @@ -1,18 +1,18 @@ -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -#FAMILY = "Stratix 10" -#DEVICE = 1SX280HN2F43E2VG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = vortex_afu TOP_LEVEL_ENTITY = vortex_afu SRC_FILE = vortex_afu.sv +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH=$(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;../../../rtl/afu;../../../rtl/afu/ccip;$(FPU_INCLUDE) +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(RTL_DIR)/afu;$(RTL_DIR)/afu/ccip;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=2" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=2" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/top32/Makefile b/hw/syn/quartus/top32/Makefile index 75bd55b3..558359e5 100644 --- a/hw/syn/quartus/top32/Makefile +++ b/hw/syn/quartus/top32/Makefile @@ -1,18 +1,18 @@ -#FAMILY = "Arria 10" -#DEVICE = 10AX115N3F40E2SG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -FAMILY = "Stratix 10" -DEVICE = 1SX280HN2F43E2VG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = vortex_afu TOP_LEVEL_ENTITY = vortex_afu SRC_FILE = vortex_afu.sv +RTL_DIR = ../../../../rtl + +#FAMILY = "Arria 10" +#DEVICE = 10AX115N3F40E2SG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +FAMILY = "Stratix 10" +DEVICE = 1SX280HN2F43E2VG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;../../../rtl/afu;../../../rtl/afu/ccip;$(FPU_INCLUDE) +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(RTL_DIR)/afu;$(RTL_DIR)/afu/ccip;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" -set "NUM_CLUSTERS=8" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" -set "NUM_CLUSTERS=8" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/top4/Makefile b/hw/syn/quartus/top4/Makefile index 55e25c01..2bdd4f1d 100644 --- a/hw/syn/quartus/top4/Makefile +++ b/hw/syn/quartus/top4/Makefile @@ -1,18 +1,18 @@ -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -#FAMILY = "Stratix 10" -#DEVICE = 1SX280HN2F43E2VG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = vortex_afu TOP_LEVEL_ENTITY = vortex_afu SRC_FILE = vortex_afu.sv +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;../../../rtl/afu;../../../rtl/afu/ccip;$(FPU_INCLUDE) +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(RTL_DIR)/afu;$(RTL_DIR)/afu/ccip;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/top64/Makefile b/hw/syn/quartus/top64/Makefile index e3c44b2a..89e23aa4 100644 --- a/hw/syn/quartus/top64/Makefile +++ b/hw/syn/quartus/top64/Makefile @@ -1,18 +1,18 @@ -#FAMILY = "Arria 10" -#DEVICE = 10AX115N3F40E2SG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -FAMILY = "Stratix 10" -DEVICE = 1SX280HN2F43E2VG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = vortex_afu TOP_LEVEL_ENTITY = vortex_afu SRC_FILE = vortex_afu.sv +RTL_DIR=../../../../rtl + +#FAMILY = "Arria 10" +#DEVICE = 10AX115N3F40E2SG +#FPU_CORE_PATH=$(RTL_DIR)/fp_cores/altera/arria10 + +FAMILY = "Stratix 10" +DEVICE = 1SX280HN2F43E2VG +FPU_CORE_PATH=$(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;../../../rtl/afu;../../../rtl/afu/ccip;$(FPU_INCLUDE) +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(RTL_DIR)/afu;$(RTL_DIR)/afu/ccip;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=8" -set "NUM_CLUSTERS=8" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=8" -set "NUM_CLUSTERS=8" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/top8/Makefile b/hw/syn/quartus/top8/Makefile index 9caa490b..07605567 100644 --- a/hw/syn/quartus/top8/Makefile +++ b/hw/syn/quartus/top8/Makefile @@ -1,18 +1,18 @@ -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -#FAMILY = "Stratix 10" -#DEVICE = 1SX280HN2F43E2VG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = vortex_afu TOP_LEVEL_ENTITY = vortex_afu SRC_FILE = vortex_afu.sv +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;../../../rtl/afu;../../../rtl/afu/ccip;$(FPU_INCLUDE) +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(RTL_DIR)/afu;$(RTL_DIR)/afu/ccip;$(FPU_INCLUDE) PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" -set "NUM_CLUSTERS=2" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" -set "NOPAE" -set "NUM_CORES=4" -set "NUM_CLUSTERS=2" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/unittest/Makefile b/hw/syn/quartus/unittest/Makefile index 9644cf52..43d17d0f 100644 --- a/hw/syn/quartus/unittest/Makefile +++ b/hw/syn/quartus/unittest/Makefile @@ -1,13 +1,19 @@ PROJECT = Unittest TOP_LEVEL_ENTITY = VX_cache_core_req_bank_sel SRC_FILE = VX_cache_core_req_bank_sel.v -FPU_INCLUDE = ../../../rtl/fp_cores;../../../rtl/fp_cores/altera/arria10;../../../rtl/fp_cores/fpnew/src;../../../rtl/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;../../../rtl/fp_cores/fpnew/src/common_cells/include;../../../rtl/fp_cores/fpnew/src/common_cells/src -RTL_INCLUDE = $(FPU_INCLUDE);../../../rtl;../../../rtl/libs;../../../rtl/interfaces;../../../rtl/cache -PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf +RTL_DIR = ../../../../rtl -# Part, Family FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 + +FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src +RTL_INCLUDE = $(FPU_INCLUDE);$(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache +PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf # Executable Configuration SYN_ARGS = --parallel --read_settings_files=on @@ -51,7 +57,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" syn.chg: $(STAMP) syn.chg diff --git a/hw/syn/quartus/vortex/Makefile b/hw/syn/quartus/vortex/Makefile index b2e90b31..48e40608 100644 --- a/hw/syn/quartus/vortex/Makefile +++ b/hw/syn/quartus/vortex/Makefile @@ -1,16 +1,16 @@ -FAMILY = "Arria 10" -DEVICE = 10AX115N3F40E2SG -FPU_CORE_PATH=../../../rtl/fp_cores/altera/arria10 - -#FAMILY = "Stratix 10" -#DEVICE = 1SX280HN2F43E2VG -#FPU_CORE_PATH=../../../rtl/fp_cores/altera/stratix10 - PROJECT = Vortex TOP_LEVEL_ENTITY = Vortex SRC_FILE = Vortex.sv +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG +FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/arria10 + +#FAMILY = "Stratix 10" +#DEVICE = 1SX280HN2F43E2VG +#FPU_CORE_PATH = $(RTL_DIR)/fp_cores/altera/stratix10 -RTL_DIR=../../../rtl FPU_INCLUDE = $(RTL_DIR)/fp_cores;$(FPU_CORE_PATH);$(RTL_DIR)/fp_cores/fpnew/src;$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include;$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache;$(FPU_INCLUDE) @@ -58,7 +58,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): - quartus_sh -t ../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../project.sdc -inc "$(RTL_INCLUDE)" + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" syn.chg: $(STAMP) syn.chg From 2c908b4a072f94ea5648e3f25c4f206c637c9841 Mon Sep 17 00:00:00 2001 From: MalikBurton <42877662+MalikBurton@users.noreply.github.com> Date: Fri, 23 Apr 2021 14:45:44 -0400 Subject: [PATCH 06/55] Vortex Microarchitecture image Pushed to the git repo to embed in micro-architecture .md file. --- doc/vortex_microarchitecture_v2.png | Bin 0 -> 529641 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/vortex_microarchitecture_v2.png diff --git a/doc/vortex_microarchitecture_v2.png b/doc/vortex_microarchitecture_v2.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e85891867a3e5dbe28a16ed913d54f6efe17f1 GIT binary patch literal 529641 zcmagFdHB;*`aX<`f*^_;I1Y$9f}()wnifG#(j-mOv`v$?Nl~#)lQd1*bV<{+EaHkY zIIbWr2%-a{3k)jisL011P!z=l7X}q%6PNcy=R2dne_pO!{Uj$RXL-)E+|PXu ze@-RHA%jjF)URK^AyhPy?$>X?-hTZKy>j4TpyUUcU)8T4#9O#vRUJh$2?>#Y;?j|C-2 zy>7@kxkziEcOu|}C-{P(_zXJAGx5=04BQ)y*d#du+WEwz$z=RM7H1s~Ti$K#ZsX$?beKS~m1*hb@BjLJ@y3 z3#JFIEQ@muJ2ggH+(GfZM!;@0 z!5!mI2D9ES5Bp1A!jplz0^iBS>!bjb3r&aGSq&(w+X@QQf)IjoujTD^9XKAgOR`by z7HpU>wo>u;pzl zUM?lZ4Sze^$l{heSw4pklaH;KSDm|ZM2^wsBB6?c0Tdr6v zMX%;E0dEtImMU<7E>=suj=$pzDo(Lo4tuPS9ZSP$sN}eeTffk_B`IZF)KdrPLA{a@_0V!r&{~6>dJIG?)-?MjCo4 z)2k_p-S#_P-#{VJ8YT) zZ;~mFWsyh>DaRu$&{8znF{D_ui?b3=)X{bnDO2GZ2~L~Xg(=` z4}xYZth9>`TmvOlUoPg@zIH(f$K4eHGAt+4WxI$td=b1)d1@h71#OQlb#0_%g-c2T zJeOo8m8gIZx<#O-ga^o*=+?n=2HdEYD;!r@J-womciXA8s?m5gMWROJ}RLymgXbx!yQlWg@ zUF)Llq?BBy%Xbo z(P69vMq$C_cvL8RjX*pAr5fh{z(5?_#tl{BrX4UZv2 z#1`ST6R?>JXuU>TmgG*PTgXLY7$$Wyp#rJ1IjL1W(BF(d8RZPcU1 z{Dz(<)NF?8m=&Yj_VaPFUK8U1!k0^OB96xCX3S`^)kKl2R!i}At)<#J&{VVvoE}D+*f!lOo_+Gak2;JPHgP1vmiB1^HORpRU)8 zE-+Ok7D(EjfGQF#@D9|^1{y81+l>|_JC&^}WRwmYWEzWPjl5AwbJa>z;!xG@^$<8! z3b}3}B2|c3HfR%F2CL-@i0*ME8^D`^vZm8Po3(QipDWse&#!vmUcJ*CN-s)+_Mt#M45j^iAuPx}IVkHrQ%Q7FIEXiX3rU5m z>7pdSt>rB`$rjv9xO}l}YU{y^mpnj~Jj$EZP=~4-wQ@yd z!1x%ANRpsuDoWRdUe>`_9&g|jmBSkeKSo!HIMtx_W(X4$j_Q!fnw)oxifFkCi(45T z5zU@MRqEksMre!@EXORZXR$X2^q=Bhh>~$&ghmXlFaYP`=PMA#bak z-~w2}{VX1dpk}ob<5MaQYdsK^E0K;=@qjf!$v8!ZC7}>%C3BLPG}Ts#tI{4$4TU?Q zTDw?@6rVu^ZZgrAYjx<>%p|+s9Kja~h469PORum(pP(gF}wnkB? zi@BT_mMK)in5<=>KvtAeL51P6FpGnAN3*V_hlnIiK|G2@D%l89)npdxwQB9If#{~> z6m%aN>u{-bxd9t`2cd%gdOHyghq;&pPyxXkjBRBahy><}!ucG6<%{8X!PcBcn`St- z5I_;vGl5?Tv%4u?bAfZlbT)xLwLmki;@9I!5+=-ygkg6u|OoS??QK}Z~1@)2{O(ope zU~8NdEF=|4B_hoRmC0%0G-#+;=e+G2CF)rsQl+YDQRJ9JGTQd#vs9D^oj^vy

id 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�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

  • TvdpjVnv15QvP5O6=_SaWQO+BS;&sFGY1v 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%0ABdp4L;W-M%5;)sH$TaEbs>a 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 literal 0 HcmV?d00001 diff --git a/doc/Images/vortex_cache_top_module.png b/doc/Images/vortex_cache_top_module.png new file mode 100644 index 0000000000000000000000000000000000000000..ecb8be985bcd16488bea588019f5c9a40059c507 GIT binary patch literal 68415 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 mPtferpKxBmtiPx@~F literal 0 HcmV?d00001 From 04a1c0e9ebadc416125962cb87c6ae848066b188 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 1 May 2021 13:44:08 -0700 Subject: [PATCH 25/55] IN_ORDER_MEM feature doesn't work becasue when cache bank's mem-req-queue is full, we need to schedule the mem response and skip the mshr --- hw/rtl/VX_mem_unit.v | 6 ++---- hw/rtl/cache/VX_bank.v | 36 ++++++++++++------------------------ hw/rtl/cache/VX_cache.v | 8 ++------ 3 files changed, 16 insertions(+), 34 deletions(-) diff --git a/hw/rtl/VX_mem_unit.v b/hw/rtl/VX_mem_unit.v index 6b09af6d..945a41d1 100644 --- a/hw/rtl/VX_mem_unit.v +++ b/hw/rtl/VX_mem_unit.v @@ -101,8 +101,7 @@ module VX_mem_unit # ( .WRITE_ENABLE (0), .CORE_TAG_WIDTH (`ICORE_TAG_WIDTH), .CORE_TAG_ID_BITS (`ICORE_TAG_ID_BITS), - .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH), - .IN_ORDER_MEM (!(`L2_ENABLE || `L3_ENABLE)) + .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH) ) icache ( `SCOPE_BIND_VX_mem_unit_icache @@ -161,8 +160,7 @@ module VX_mem_unit # ( .WRITE_ENABLE (1), .CORE_TAG_WIDTH (`DCORE_TAG_WIDTH), .CORE_TAG_ID_BITS (`DCORE_TAG_ID_BITS), - .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH), - .IN_ORDER_MEM (!(`L2_ENABLE || `L3_ENABLE)) + .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH) ) dcache ( `SCOPE_BIND_VX_mem_unit_dcache diff --git a/hw/rtl/cache/VX_bank.v b/hw/rtl/cache/VX_bank.v index 34c6308c..d5764519 100644 --- a/hw/rtl/cache/VX_bank.v +++ b/hw/rtl/cache/VX_bank.v @@ -35,10 +35,7 @@ module VX_bank #( parameter CORE_TAG_ID_BITS = 0, // bank offset from beginning of index range - parameter BANK_ADDR_OFFSET = 0, - - // in-order DRAN - parameter IN_ORDER_MEM = 0 + parameter BANK_ADDR_OFFSET = 0 ) ( `SCOPE_IO_VX_bank @@ -192,7 +189,7 @@ module VX_bank #( wire is_miss_st1 = valid_st1 && (miss_st1 || force_miss_st1); assign mshr_pop = mshr_pop_unqual - && !(!IN_ORDER_MEM && is_miss_st1 && is_mshr_st1) // do not schedule another mshr request if the previous one missed + && !(is_miss_st1 && is_mshr_st1) // do not schedule another mshr request if the previous one missed && !crsq_in_stall; // ensure core response ready assign mrsq_pop = mrsq_pop_unqual @@ -237,15 +234,7 @@ module VX_bank #( end else begin assign creq_line_data = creq_data; end - - wire [`LINE_ADDR_WIDTH-1:0] mem_rsp_addr_qual; - if (IN_ORDER_MEM) begin - `UNUSED_VAR (mem_rsp_addr) - assign mem_rsp_addr_qual = mshr_addr; - end else begin - assign mem_rsp_addr_qual = mem_rsp_addr; - end - + VX_pipe_register #( .DATAW (1 + 1 + 1 + 1 + `LINE_ADDR_WIDTH + `CACHE_LINE_WIDTH + (`UP(`WORD_SELECT_BITS) + WORD_SIZE + `REQS_BITS + 1) * NUM_PORTS + CORE_TAG_WIDTH + 1 + 1), .RESETW (1) @@ -259,7 +248,7 @@ module VX_bank #( mshr_pop_unqual, mrsq_pop_unqual || flush_enable, mshr_pop_unqual ? 1'b0 : creq_rw, - mshr_pop_unqual ? mshr_addr : (mem_rsp_valid ? mem_rsp_addr_qual : (flush_enable ? `LINE_ADDR_WIDTH'(flush_addr) : creq_addr)), + mshr_pop_unqual ? mshr_addr : (mem_rsp_valid ? mem_rsp_addr : (flush_enable ? `LINE_ADDR_WIDTH'(flush_addr) : creq_addr)), mem_rsp_valid ? mem_rsp_data : creq_line_data, mshr_pop_unqual ? mshr_wsel : creq_wsel, mshr_pop_unqual ? mshr_byteen : creq_byteen, @@ -307,7 +296,7 @@ module VX_bank #( ); // redundant fills - wire is_redundant_fill_st0 = !IN_ORDER_MEM && is_fill_st0 && tag_match_st0; + wire is_redundant_fill_st0 = is_fill_st0 && tag_match_st0; // we had a miss with prior request for the current address assign prev_miss_dep_st0 = is_miss_st1 && (addr_st0 == addr_st1); @@ -322,9 +311,9 @@ module VX_bank #( assign writeen_unqual_st0 = (WRITE_ENABLE && !is_fill_st0 && tag_match_st0 && mem_rw_st0) || (is_fill_st0 && !is_redundant_fill_st0); - assign incoming_fill_st0 = mem_rsp_valid && (addr_st0 == mem_rsp_addr_qual); + assign incoming_fill_st0 = mem_rsp_valid && (addr_st0 == mem_rsp_addr); - assign fill_req_unqual_st0 = !mem_rw_st0 && (!force_miss_st0 || (!IN_ORDER_MEM && is_mshr_st0 && !prev_miss_dep_st0)); + assign fill_req_unqual_st0 = !mem_rw_st0 && (!force_miss_st0 || (is_mshr_st0 && !prev_miss_dep_st0)); VX_pipe_register #( .DATAW (1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + `LINE_ADDR_WIDTH + `CACHE_LINE_WIDTH + (`UP(`WORD_SELECT_BITS) + WORD_SIZE + `REQS_BITS + 1) * NUM_PORTS + CORE_TAG_WIDTH), @@ -351,7 +340,7 @@ module VX_bank #( wire mshr_push_st1 = !is_fill_st1 && !mem_rw_st1 && (miss_st1 || force_miss_st1); - wire incoming_fill_qual_st1 = (mem_rsp_valid && (addr_st1 == mem_rsp_addr_qual)) + wire incoming_fill_qual_st1 = (mem_rsp_valid && (addr_st1 == mem_rsp_addr)) || incoming_fill_st1; wire do_writeback_st1 = !is_fill_st1 && mem_rw_st1; @@ -408,15 +397,14 @@ module VX_bank #( assign mshr_push = valid_st1 && mshr_push_st1; wire mshr_dequeue = valid_st1 && is_mshr_st1 && !mshr_push_st1 && crsq_in_ready; - wire mshr_restore = !IN_ORDER_MEM && is_mshr_st1; - `RUNTIME_ASSERT(!IN_ORDER_MEM || !(mshr_push && mshr_restore), ("Oops!")) + wire mshr_restore = is_mshr_st1; // push a missed request as 'ready' if it was a forced miss that actually had a hit // or the fill request for this block is comming wire mshr_init_ready_state = !miss_st1 || incoming_fill_qual_st1; // use memory rsp or core req address to lookup the mshr - wire [`LINE_ADDR_WIDTH-1:0] lookup_addr = mem_rsp_valid ? mem_rsp_addr_qual : creq_addr; + wire [`LINE_ADDR_WIDTH-1:0] lookup_addr = mem_rsp_valid ? mem_rsp_addr : creq_addr; VX_miss_resrv #( .BANK_ID (BANK_ID), @@ -525,7 +513,7 @@ module VX_bank #( .reset (reset), .push (mreq_push), .pop (mreq_pop), - .data_in ({mreq_rw, mreq_byteen, mreq_addr, mreq_data}), + .data_in ({mreq_rw, mreq_byteen, mreq_addr, mreq_data}), .data_out ({mem_req_rw, mem_req_byteen, mem_req_addr, mem_req_data}), .empty (mreq_empty), .alm_full (mreq_alm_full), @@ -572,7 +560,7 @@ module VX_bank #( $display("%t: cache%0d:%0d flush: addr=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(flush_addr, BANK_ID)); end if (mrsq_pop) begin - $display("%t: cache%0d:%0d fill-rsp: addr=%0h, data=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mem_rsp_addr_qual, BANK_ID), mem_rsp_data); + $display("%t: cache%0d:%0d fill-rsp: addr=%0h, data=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mem_rsp_addr, BANK_ID), mem_rsp_data); end if (mshr_pop) begin $display("%t: cache%0d:%0d mshr-rd-req: addr=%0h, tag=%0h, pmask=%0b, tid=%0d, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mshr_addr, BANK_ID), mshr_tag, mshr_pmask, mshr_tid, mshr_byteen, debug_wid_sel, debug_pc_sel); diff --git a/hw/rtl/cache/VX_cache.v b/hw/rtl/cache/VX_cache.v index 20bbc0ab..bbb658ea 100644 --- a/hw/rtl/cache/VX_cache.v +++ b/hw/rtl/cache/VX_cache.v @@ -39,10 +39,7 @@ module VX_cache #( parameter MEM_TAG_WIDTH = (32 - $clog2(CACHE_LINE_SIZE)), // bank offset from beginning of index range - parameter BANK_ADDR_OFFSET = 0, - - // in-order DRAN - parameter IN_ORDER_MEM = 0 + parameter BANK_ADDR_OFFSET = 0 ) ( `SCOPE_IO_VX_cache @@ -298,8 +295,7 @@ module VX_cache #( .WRITE_ENABLE (WRITE_ENABLE), .CORE_TAG_WIDTH (CORE_TAG_WIDTH), .CORE_TAG_ID_BITS (CORE_TAG_ID_BITS), - .BANK_ADDR_OFFSET (BANK_ADDR_OFFSET), - .IN_ORDER_MEM (IN_ORDER_MEM) + .BANK_ADDR_OFFSET (BANK_ADDR_OFFSET) ) bank ( `SCOPE_BIND_VX_cache_bank(i) From f31e0e3dca929e6d1fb610a691ea70c854f3d2e8 Mon Sep 17 00:00:00 2001 From: Malik Aki Burton Date: Sat, 1 May 2021 17:13:35 -0400 Subject: [PATCH 26/55] Added Cache_Subsystem guide --- doc/Cache_Subsystem.md | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 doc/Cache_Subsystem.md diff --git a/doc/Cache_Subsystem.md b/doc/Cache_Subsystem.md new file mode 100644 index 00000000..8aa768d7 --- /dev/null +++ b/doc/Cache_Subsystem.md @@ -0,0 +1,70 @@ +# Vortex Cache Sub-System + +The Vortex Cache Sub-system has the following main properties: + +- High-bandwidth with bank parallelism +- Snoop protocol to flush data for CPU access +- Generic design: Dcache, Icache, Shared Memory, L2 cache, L3 cache + +### Cache Hierarchy + +![Image of Cache Hierarchy](./Images/cache_hierarchy.png) + +- Cache can be configured to be any level in the hierarchy +- Caches communicate via snooping +- Cache flush from AFU is passed down the hierarchy​ + +### VX_cache.v (Top Module) + +VX.cache.v is the top module of the cache verilog code located in the `/hw/rtl/cache` directory. + +![Image of Vortex Cache](./Images/vortex_cache_top_module.png) + +- Configurable (Cache size, number of banks, bank line size, etc.) +- I/O signals + - Core Request + - Core Rsp + - DRAM Req + - DRAM Rsp + - Snoop Rsp + - Snoop Rsp + - Snoop Forwarding Out + - Snoop Forwarding In +- Bank Select + - Assigns valid and ready signals for each bank +- Snoop Forwarder +- DRAM Request Arbiter + - Prepares cache response for communication with DRAM +- Snoop Response Arbiter + - Sends snoop response +- Core Response Merge + - Cache accesses one line at a time. As a result, each request may not come back in the same response. This module tries to recombine the responses by thread ID. + +### VX_bank.v + +VX_bank.v is the verilog code that handles cache bank functionality and is located in the `/hw/rtl/cache` directory. + +![Image of Vortex Cache Bank](./Images/vortex_bank.png) + +- Allows for high throughput​ +- Each bank contains queues to hold requests to the cache​ +- I/O signals + - Core request​ + - Core Response​ + - DRAM Fill Requests​ + - DRAM Fill Response​ + - DRAM WB Requests​ + - Snp Request​ + - Snp Response +- Request Priority: DRAM fill, miss reserve, core request, snoop request​ +- Snoop Request Queue​ +- DRAM Fill Queue​ +- Core Req Arbiter​ + - Requests to be processed by the bank +- Tag Data Store​ + - Registers for valid, dirty, dirtyb, tag, and data​ + - Length of registers determined by lines in the bank​ +- Tag Data Access:​ + - I/O: stall, snoop info, force request miss + - Writes to cache or sends read response; hit or miss determined here + - A missed request goes to the miss reserve if it is not a snoop request or DRAM fill \ No newline at end of file From a6c943142615214cb1be1db8a6dfc7116e3a0824 Mon Sep 17 00:00:00 2001 From: Malik Aki Burton Date: Sat, 1 May 2021 17:15:29 -0400 Subject: [PATCH 27/55] Added Vortex cacache link --- doc/Vortex.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Vortex.md b/doc/Vortex.md index f1d410a6..d08dcbc9 100644 --- a/doc/Vortex.md +++ b/doc/Vortex.md @@ -4,6 +4,7 @@ - [Vortex Codebase Layout](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Codebase.md) - [Vortex Microarchitecture and Extended RISC-V ISA](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Microarchitecture.md) +- [Vortex Cache Sub-system](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Cache_Subsystem.md) - Vortex Software - [Vortex Simulation](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Simulation.md) - [FPGA Configuration, Program and Test](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Flubber_FPGA_Startup_Guide.md) From 30972c792a34668ebb7d5d55c7412c179334cc0d Mon Sep 17 00:00:00 2001 From: Malik Aki Burton Date: Sat, 1 May 2021 17:17:07 -0400 Subject: [PATCH 28/55] Edit Vortex and Cache guide --- doc/Cache_Subsystem.md | 2 +- doc/Vortex.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Cache_Subsystem.md b/doc/Cache_Subsystem.md index 8aa768d7..9de9aef7 100644 --- a/doc/Cache_Subsystem.md +++ b/doc/Cache_Subsystem.md @@ -1,4 +1,4 @@ -# Vortex Cache Sub-System +# Vortex Cache Subsystem The Vortex Cache Sub-system has the following main properties: diff --git a/doc/Vortex.md b/doc/Vortex.md index d08dcbc9..97ff40a2 100644 --- a/doc/Vortex.md +++ b/doc/Vortex.md @@ -4,7 +4,7 @@ - [Vortex Codebase Layout](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Codebase.md) - [Vortex Microarchitecture and Extended RISC-V ISA](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Microarchitecture.md) -- [Vortex Cache Sub-system](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Cache_Subsystem.md) +- [Vortex Cache Subsystem](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Cache_Subsystem.md) - Vortex Software - [Vortex Simulation](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Simulation.md) - [FPGA Configuration, Program and Test](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Flubber_FPGA_Startup_Guide.md) From bac53e4ae118fe0424f86ec656f48b69870ea8b0 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 2 May 2021 11:05:49 -0700 Subject: [PATCH 29/55] minor update --- ci/regression.sh | 24 ++++++++++++++++++------ hw/rtl/afu/VX_to_mem.v | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/ci/regression.sh b/ci/regression.sh index 8adb5427..b6fa3c4f 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -11,15 +11,27 @@ make -s ./ci/test_opencl.sh ./ci/test_driver.sh ./ci/test_simx.sh -./ci/test_compiler.sh +#./ci/test_compiler.sh -# Blackbox tests +# warp/threads configurations +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=2 --threads=2 --app=demo +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=2 --threads=8 --app=demo +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=8 --threads=2 --app=demo + +# cores clustering +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=1 --clusters=1 --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=1 --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=demo --args="-n1" + +# L2/L3 +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l3cache --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=demo --args="-n1" + +# build flags ./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --perf --app=demo --args="-n1" ./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --debug --app=demo --args="-n1" ./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --scope --app=basic --args="-t0 -n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=demo --args="-n1" # disabling M extension CONFIGS=-DEXT_M_DISABLE make -C hw/simulate @@ -31,7 +43,7 @@ CONFIGS=-DEXT_F_DISABLE make -C hw/simulate CONFIGS=-DSM_ENABLE=0 make -C hw/simulate # using FPNEW core -FPU_CORE=FPU_FPNEW ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=demo +FPU_CORE=FPU_FPNEW ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=dogfood # test 128-bit MEM block CONFIGS=-DMEM_BLOCK_SIZE=16 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo diff --git a/hw/rtl/afu/VX_to_mem.v b/hw/rtl/afu/VX_to_mem.v index 7e786e50..901aaa36 100644 --- a/hw/rtl/afu/VX_to_mem.v +++ b/hw/rtl/afu/VX_to_mem.v @@ -72,7 +72,7 @@ module VX_to_mem #( assign mem_req_valid_out = mem_req_valid_in; assign mem_req_rw_out = mem_req_rw_in; assign mem_req_byteen_out = DST_DATA_SIZE'(mem_req_byteen_in) << ((DST_LDATAW-3)'(req_idx) << (SRC_LDATAW-3)); - assign mem_req_data_out = DST_DATA_WIDTH'(mem_req_data_in) << ((DST_LDATAW'(req_idx)) << DST_LDATAW); + assign mem_req_data_out = DST_DATA_WIDTH'(mem_req_data_in) << ((DST_LDATAW'(req_idx)) << SRC_LDATAW); assign mem_req_tag_out = DST_TAG_WIDTH'({mem_req_tag_in, req_idx}); assign mem_req_ready_in = mem_req_ready_out; From fc7c8e1639b7d489a7b7bc6c8cd2a42b7d7bf4c1 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 2 May 2021 12:12:59 -0700 Subject: [PATCH 30/55] driver tests updates --- driver/tests/basic/Makefile | 2 +- driver/tests/basic/{basic.cpp => main.cpp} | 0 driver/tests/demo/Makefile | 2 +- driver/tests/demo/{demo.cpp => main.cpp} | 0 driver/tests/dogfood/Makefile | 2 +- driver/tests/dogfood/{dogfood.cpp => main.cpp} | 0 6 files changed, 3 insertions(+), 3 deletions(-) rename driver/tests/basic/{basic.cpp => main.cpp} (100%) rename driver/tests/demo/{demo.cpp => main.cpp} (100%) rename driver/tests/dogfood/{dogfood.cpp => main.cpp} (100%) diff --git a/driver/tests/basic/Makefile b/driver/tests/basic/Makefile index 621a0901..c0676952 100644 --- a/driver/tests/basic/Makefile +++ b/driver/tests/basic/Makefile @@ -24,7 +24,7 @@ LDFLAGS += PROJECT = basic -SRCS = basic.cpp +SRCS = main.cpp all: $(PROJECT) kernel.bin kernel.dump diff --git a/driver/tests/basic/basic.cpp b/driver/tests/basic/main.cpp similarity index 100% rename from driver/tests/basic/basic.cpp rename to driver/tests/basic/main.cpp diff --git a/driver/tests/demo/Makefile b/driver/tests/demo/Makefile index 8ca0c6c8..e0cee958 100644 --- a/driver/tests/demo/Makefile +++ b/driver/tests/demo/Makefile @@ -22,7 +22,7 @@ CXXFLAGS += -I../../include PROJECT = demo -SRCS = demo.cpp +SRCS = main.cpp all: $(PROJECT) kernel.bin kernel.dump diff --git a/driver/tests/demo/demo.cpp b/driver/tests/demo/main.cpp similarity index 100% rename from driver/tests/demo/demo.cpp rename to driver/tests/demo/main.cpp diff --git a/driver/tests/dogfood/Makefile b/driver/tests/dogfood/Makefile index 74d86837..e8ba0530 100644 --- a/driver/tests/dogfood/Makefile +++ b/driver/tests/dogfood/Makefile @@ -24,7 +24,7 @@ CXXFLAGS += -I../../include -I../../../hw PROJECT = dogfood -SRCS = dogfood.cpp +SRCS = main.cpp all: $(PROJECT) kernel.bin kernel.dump diff --git a/driver/tests/dogfood/dogfood.cpp b/driver/tests/dogfood/main.cpp similarity index 100% rename from driver/tests/dogfood/dogfood.cpp rename to driver/tests/dogfood/main.cpp From c1f40e081daefe603025c825be4c0bdb718cab0a Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 3 May 2021 03:37:28 -0700 Subject: [PATCH 31/55] adding stress test --- driver/tests/stress/Makefile | 67 ++++++++++ driver/tests/stress/common.h | 17 +++ driver/tests/stress/kernel.c | 29 +++++ driver/tests/stress/main.cpp | 241 +++++++++++++++++++++++++++++++++++ 4 files changed, 354 insertions(+) create mode 100644 driver/tests/stress/Makefile create mode 100644 driver/tests/stress/common.h create mode 100644 driver/tests/stress/kernel.c create mode 100644 driver/tests/stress/main.cpp diff --git a/driver/tests/stress/Makefile b/driver/tests/stress/Makefile new file mode 100644 index 00000000..59fd181b --- /dev/null +++ b/driver/tests/stress/Makefile @@ -0,0 +1,67 @@ +RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain +VORTEX_RT_PATH ?= $(wildcard ../../../runtime) + +OPTS ?= -n64 + +VX_CC = $(RISCV_TOOLCHAIN_PATH)/bin/riscv32-unknown-elf-gcc +VX_CXX = $(RISCV_TOOLCHAIN_PATH)/bin/riscv32-unknown-elf-g++ +VX_DP = $(RISCV_TOOLCHAIN_PATH)/bin/riscv32-unknown-elf-objdump +VX_CP = $(RISCV_TOOLCHAIN_PATH)/bin/riscv32-unknown-elf-objcopy + +VX_CFLAGS += -march=rv32imf -mabi=ilp32f -O3 -Wstack-usage=1024 -ffreestanding -nostartfiles -fdata-sections -ffunction-sections +VX_CFLAGS += -I$(VORTEX_RT_PATH)/include -I$(VORTEX_RT_PATH)/../hw + +VX_LDFLAGS += -Wl,-Bstatic,-T,$(VORTEX_RT_PATH)/linker/vx_link.ld -Wl,--gc-sections $(VORTEX_RT_PATH)/libvortexrt.a + +VX_SRCS = kernel.c + +#CXXFLAGS += -std=c++11 -O2 -Wall -Wextra -pedantic -Wfatal-errors +CXXFLAGS += -std=c++11 -O0 -g -Wall -Wextra -pedantic -Wfatal-errors + +CXXFLAGS += -I../../include + +PROJECT = stress + +SRCS = main.cpp + +all: $(PROJECT) kernel.bin kernel.dump + +kernel.dump: kernel.elf + $(VX_DP) -D kernel.elf > kernel.dump + +kernel.bin: kernel.elf + $(VX_CP) -O binary kernel.elf kernel.bin + +kernel.elf: $(VX_SRCS) + $(VX_CC) $(VX_CFLAGS) $(VX_SRCS) $(VX_LDFLAGS) -o kernel.elf + +$(PROJECT): $(SRCS) + $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -L../../stub -lvortex -o $@ + +run-fpga: $(PROJECT) + LD_LIBRARY_PATH=../../opae:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) + +run-asesim: $(PROJECT) + ASE_LOG=0 LD_LIBRARY_PATH=../../opae/ase:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) + +run-vlsim: $(PROJECT) + LD_LIBRARY_PATH=../../opae/vlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) + +run-rtlsim: $(PROJECT) + LD_LIBRARY_PATH=../../rtlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) + +run-simx: $(PROJECT) + LD_LIBRARY_PATH=../../simx:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) + +.depend: $(SRCS) + $(CXX) $(CXXFLAGS) -MM $^ > .depend; + +clean: + rm -rf $(PROJECT) *.o .depend + +clean-all: clean + rm -rf *.elf *.bin *.dump + +ifneq ($(MAKECMDGOALS),clean) + -include .depend +endif \ No newline at end of file diff --git a/driver/tests/stress/common.h b/driver/tests/stress/common.h new file mode 100644 index 00000000..41a7cc1f --- /dev/null +++ b/driver/tests/stress/common.h @@ -0,0 +1,17 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#define KERNEL_ARG_DEV_MEM_ADDR 0x7ffff000 + +#define NUM_LOADS 2 + +struct kernel_arg_t { + uint32_t num_tasks; + uint32_t size; + uint32_t stride; + uint32_t src0_ptr; + uint32_t src1_ptr; + uint32_t dst_ptr; +}; + +#endif \ No newline at end of file diff --git a/driver/tests/stress/kernel.c b/driver/tests/stress/kernel.c new file mode 100644 index 00000000..abcc46e2 --- /dev/null +++ b/driver/tests/stress/kernel.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include "common.h" + +void kernel_body(int task_id, void* arg) { + struct kernel_arg_t* _arg = (struct kernel_arg_t*)(arg); + uint32_t stride = _arg->stride; + int32_t* src0_ptr = (int32_t*)_arg->src0_ptr; + uint32_t* src1_ptr = (uint32_t*)_arg->src1_ptr; + int32_t* dst_ptr = (int32_t*)_arg->dst_ptr; + + uint32_t offset = task_id * stride; + + for (uint32_t i = 0; i < stride; ++i) { + int value = 0; + for (uint32_t j = 0; j < NUM_LOADS; ++j) { + uint32_t addr = offset + i + j; + uint32_t index = src1_ptr[addr]; + value += src0_ptr[index]; + } + dst_ptr[offset+i] = value; + } +} + +void main() { + struct kernel_arg_t* arg = (struct kernel_arg_t*)KERNEL_ARG_DEV_MEM_ADDR; + vx_spawn_tasks(arg->num_tasks, kernel_body, arg); +} \ No newline at end of file diff --git a/driver/tests/stress/main.cpp b/driver/tests/stress/main.cpp new file mode 100644 index 00000000..e6952ba2 --- /dev/null +++ b/driver/tests/stress/main.cpp @@ -0,0 +1,241 @@ +#include +#include +#include +#include +#include "common.h" +#include +#include + +#define RT_CHECK(_expr) \ + do { \ + int _ret = _expr; \ + if (0 == _ret) \ + break; \ + printf("Error: '%s' returned %d!\n", #_expr, (int)_ret); \ + cleanup(); \ + exit(-1); \ + } while (false) + +/////////////////////////////////////////////////////////////////////////////// + +const char* kernel_file = "kernel.bin"; +uint32_t count = 0; + +std::vector test_data; +std::vector addr_table; + +vx_device_h device = nullptr; +vx_buffer_h staging_buf = nullptr; + +static void show_usage() { + std::cout << "Vortex Driver Test." << std::endl; + std::cout << "Usage: [-k: kernel] [-n words] [-h: help]" << std::endl; +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "n:k:h?")) != -1) { + switch (c) { + case 'n': + count = atoi(optarg); + break; + case 'k': + kernel_file = optarg; + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } +} + +void cleanup() { + if (staging_buf) { + vx_buf_release(staging_buf); + } + if (device) { + vx_dev_close(device); + } +} + +void gen_input_data(uint32_t num_points) { + test_data.resize(num_points); + addr_table.resize(num_points + NUM_LOADS - 1); + + for (uint32_t i = 0; i < test_data.size(); ++i) { + test_data[i] = std::rand(); + } + + for (uint32_t i = 0; i < addr_table.size(); ++i) { + float r = static_cast(std::rand()) / RAND_MAX; + uint32_t index = static_cast(r * num_points); + assert(index < num_points); + addr_table[i] = index; + } +} + +int run_test(const kernel_arg_t& kernel_arg, + uint32_t buf_size, + uint32_t num_points) { + // start device + std::cout << "start device" << std::endl; + RT_CHECK(vx_start(device)); + + // wait for completion + std::cout << "wait for completion" << std::endl; + RT_CHECK(vx_ready_wait(device, -1)); + + // download destination staging_buf + std::cout << "download destination staging_buf" << std::endl; + RT_CHECK(vx_copy_from_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); + + // verify result + std::cout << "verify result" << std::endl; + { + int errors = 0; + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); + + uint32_t size_m1 = num_points - 1; + + for (uint32_t i = 0; i < num_points; ++i) { + + int ref = 0; + for (uint32_t j = 0; j < NUM_LOADS; ++j) { + uint32_t addr = i + j; + uint32_t index = addr_table.at(addr); + int value = test_data.at(index); + printf("*** [%d] addr=%d, index=%d, value=%d\n", i, addr, index, value); + ref += value; + } + + int cur = buf_ptr[i]; + if (cur != ref) { + std::cout << "error at result #" << std::dec << i + << ": actual " << cur << ", expected " << ref << std::endl; + ++errors; + } + } + + if (errors != 0) { + std::cout << "Found " << std::dec << errors << " errors!" << std::endl; + std::cout << "FAILED!" << std::endl; + return 1; + } + } + + return 0; +} + +int main(int argc, char *argv[]) { + size_t value; + kernel_arg_t kernel_arg; + + // parse command arguments + parse_args(argc, argv); + + if (count == 0) { + count = 1; + } + + std::srand(50); + + // open device connection + std::cout << "open device connection" << std::endl; + RT_CHECK(vx_dev_open(&device)); + + unsigned max_cores, max_warps, max_threads; + RT_CHECK(vx_dev_caps(device, VX_CAPS_MAX_CORES, &max_cores)); + RT_CHECK(vx_dev_caps(device, VX_CAPS_MAX_WARPS, &max_warps)); + RT_CHECK(vx_dev_caps(device, VX_CAPS_MAX_THREADS, &max_threads)); + + uint32_t num_tasks = max_cores * max_warps * max_threads; + uint32_t num_points = count * num_tasks; + uint32_t buf_size = num_points * sizeof(uint32_t); + + std::cout << "number of points: " << num_points << std::endl; + std::cout << "staging_buf size: " << buf_size << " bytes" << std::endl; + + // generate input data + gen_input_data(num_points); + + // upload program + std::cout << "upload program" << std::endl; + RT_CHECK(vx_upload_kernel_file(device, kernel_file)); + + // allocate device memory + std::cout << "allocate device memory" << std::endl; + + RT_CHECK(vx_alloc_dev_mem(device, buf_size, &value)); + kernel_arg.src0_ptr = value; + RT_CHECK(vx_alloc_dev_mem(device, buf_size, &value)); + kernel_arg.src1_ptr = value; + RT_CHECK(vx_alloc_dev_mem(device, buf_size, &value)); + kernel_arg.dst_ptr = value; + + kernel_arg.num_tasks = num_tasks; + kernel_arg.stride = count; + + std::cout << "dev_src0=" << std::hex << kernel_arg.src0_ptr << std::endl; + std::cout << "dev_src1=" << std::hex << kernel_arg.src1_ptr << std::endl; + std::cout << "dev_dst=" << std::hex << kernel_arg.dst_ptr << std::endl; + + // allocate shared memory + std::cout << "allocate shared memory" << std::endl; + uint32_t alloc_size = std::max(buf_size, sizeof(kernel_arg_t)); + RT_CHECK(vx_alloc_shared_mem(device, alloc_size, &staging_buf)); + + // upload kernel argument + std::cout << "upload kernel argument" << std::endl; + { + auto buf_ptr = (int*)vx_host_ptr(staging_buf); + memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(staging_buf, KERNEL_ARG_DEV_MEM_ADDR, sizeof(kernel_arg_t), 0)); + } + + // upload source buffer0 + { + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); + for (uint32_t i = 0; i < num_points; ++i) { + buf_ptr[i] = test_data.at(i); + } + } + std::cout << "upload source buffer0" << std::endl; + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src0_ptr, buf_size, 0)); + + // upload source buffer1 + { + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); + for (uint32_t i = 0; i < num_points; ++i) { + buf_ptr[i] = addr_table.at(i); + } + } + std::cout << "upload source buffer1" << std::endl; + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src1_ptr, buf_size, 0)); + + // clear destination staging_buf + { + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); + for (uint32_t i = 0; i < num_points; ++i) { + buf_ptr[i] = 0xdeadbeef; + } + } + std::cout << "clear destination staging_buf" << std::endl; + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); + + // run tests + std::cout << "run tests" << std::endl; + RT_CHECK(run_test(kernel_arg, buf_size, num_points)); + + // cleanup + std::cout << "cleanup" << std::endl; + cleanup(); + + std::cout << "PASSED!" << std::endl; + + return 0; +} \ No newline at end of file From 962e19356384a16c2559f23fba00c7c2f3b47024 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 3 May 2021 07:45:39 -0700 Subject: [PATCH 32/55] blackbox update --- ci/blackbox.sh | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/ci/blackbox.sh b/ci/blackbox.sh index 322f46fc..002ba500 100755 --- a/ci/blackbox.sh +++ b/ci/blackbox.sh @@ -120,20 +120,16 @@ case $DRIVER in ;; esac -case $APP in - basic) - APP_PATH=$VORTEX_HOME/driver/tests/basic - ;; - demo) - APP_PATH=$VORTEX_HOME/driver/tests/demo - ;; - dogfood) - APP_PATH=$VORTEX_HOME/driver/tests/dogfood - ;; - *) - APP_PATH=$VORTEX_HOME/benchmarks/opencl/$APP - ;; -esac +if [ -d "$VORTEX_HOME/driver/tests/$APP" ]; +then + APP_PATH=$VORTEX_HOME/driver/tests/$APP +elif [ -d "$VORTEX_HOME/benchmarks/opencl/$APP" ]; +then + APP_PATH=$VORTEX_HOME/benchmarks/opencl/$APP +else + echo "Application folder found: $APP" + exit -1 +fi CONFIGS="-DNUM_CLUSTERS=$CLUSTERS -DNUM_CORES=$CORES -DNUM_WARPS=$WARPS -DNUM_THREADS=$THREADS -DL2_ENABLE=$L2 -DL3_ENABLE=$L3 $PERF_FLAG $CONFIGS" From ba16e88eab1f704c21c8723a5d296a461706c2dc Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 3 May 2021 12:24:41 -0700 Subject: [PATCH 33/55] stress test update --- driver/tests/Makefile | 4 ++ driver/tests/basic/main.cpp | 52 +++++++++++++------------- driver/tests/demo/main.cpp | 30 +++++++-------- driver/tests/stress/common.h | 6 +-- driver/tests/stress/kernel.c | 8 ++-- driver/tests/stress/main.cpp | 72 +++++++++++++++++++----------------- hw/syn/opae/README | 7 +--- 7 files changed, 91 insertions(+), 88 deletions(-) diff --git a/driver/tests/Makefile b/driver/tests/Makefile index 5e4b3382..40394bc9 100644 --- a/driver/tests/Makefile +++ b/driver/tests/Makefile @@ -2,19 +2,23 @@ all: $(MAKE) -C basic $(MAKE) -C demo $(MAKE) -C dogfood + $(MAKE) -C stress run: $(MAKE) -C basic run-vlsim $(MAKE) -C demo run-vlsim $(MAKE) -C dogfood run-vlsim + $(MAKE) -C stress run-vlsim clean: $(MAKE) -C basic clean $(MAKE) -C demo clean $(MAKE) -C dogfood clean + $(MAKE) -C stress clean clean-all: $(MAKE) -C basic clean-all $(MAKE) -C demo clean-all $(MAKE) -C dogfood clean-all + $(MAKE) -C stress clean-all diff --git a/driver/tests/basic/main.cpp b/driver/tests/basic/main.cpp index fb232c7c..586173eb 100755 --- a/driver/tests/basic/main.cpp +++ b/driver/tests/basic/main.cpp @@ -23,7 +23,7 @@ int test = -1; uint32_t count = 0; vx_device_h device = nullptr; -vx_buffer_h buffer = nullptr; +vx_buffer_h staging_buf = nullptr; static void show_usage() { std::cout << "Vortex Driver Test." << std::endl; @@ -56,8 +56,8 @@ static void parse_args(int argc, char **argv) { } void cleanup() { - if (buffer) { - vx_buf_release(buffer); + if (staging_buf) { + vx_buf_release(staging_buf); } if (device) { vx_dev_close(device); @@ -77,38 +77,38 @@ int run_memcopy_test(uint32_t dev_addr, uint64_t value, int num_blocks) { // update source buffer for (int i = 0; i < num_blocks_8; ++i) { - ((uint64_t*)vx_host_ptr(buffer))[i] = shuffle(i, value); + ((uint64_t*)vx_host_ptr(staging_buf))[i] = shuffle(i, value); } /*for (int i = 0; i < num_blocks; ++i) { std::cout << "data[" << i << "]=0x"; for (int j = 7; j >= 0; --j) { - std::cout << std::hex << ((uint64_t*)vx_host_ptr(buffer))[i * 8 +j]; + std::cout << std::hex << ((uint64_t*)vx_host_ptr(staging_buf))[i * 8 +j]; } std::cout << std::endl; }*/ - // write buffer to local memory - std::cout << "write buffer to local memory" << std::endl; + // write source buffer to local memory + std::cout << "write source buffer to local memory" << std::endl; auto t0 = std::chrono::high_resolution_clock::now(); - RT_CHECK(vx_copy_to_dev(buffer, dev_addr, 64 * num_blocks, 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, dev_addr, 64 * num_blocks, 0)); auto t1 = std::chrono::high_resolution_clock::now(); // clear destination buffer for (int i = 0; i < num_blocks_8; ++i) { - ((uint64_t*)vx_host_ptr(buffer))[i] = 0; + ((uint64_t*)vx_host_ptr(staging_buf))[i] = 0; } - // read buffer from local memory - std::cout << "read buffer from local memory" << std::endl; + // read destination buffer from local memory + std::cout << "read destination buffer from local memory" << std::endl; auto t2 = std::chrono::high_resolution_clock::now(); - RT_CHECK(vx_copy_from_dev(buffer, dev_addr, 64 * num_blocks, 0)); + RT_CHECK(vx_copy_from_dev(staging_buf, dev_addr, 64 * num_blocks, 0)); auto t3 = std::chrono::high_resolution_clock::now(); // verify result std::cout << "verify result" << std::endl; for (int i = 0; i < num_blocks_8; ++i) { - auto curr = ((uint64_t*)vx_host_ptr(buffer))[i]; + auto curr = ((uint64_t*)vx_host_ptr(staging_buf))[i]; auto ref = shuffle(i, value); if (curr != ref) { std::cout << "error at 0x" << std::hex << (dev_addr + 8 * i) @@ -145,25 +145,25 @@ int run_kernel_test(const kernel_arg_t& kernel_arg, // update source buffer { - auto buf_ptr = (int32_t*)vx_host_ptr(buffer); + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); for (uint32_t i = 0; i < num_points; ++i) { buf_ptr[i] = i; } } std::cout << "upload source buffer" << std::endl; auto t0 = std::chrono::high_resolution_clock::now(); - RT_CHECK(vx_copy_to_dev(buffer, kernel_arg.src_ptr, buf_size, 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src_ptr, buf_size, 0)); auto t1 = std::chrono::high_resolution_clock::now(); // clear destination buffer { - auto buf_ptr = (int32_t*)vx_host_ptr(buffer); + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); for (uint32_t i = 0; i < num_points; ++i) { buf_ptr[i] = 0xdeadbeef; } } std::cout << "clear destination buffer" << std::endl; - RT_CHECK(vx_copy_to_dev(buffer, kernel_arg.dst_ptr, buf_size, 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); // start device std::cout << "start execution" << std::endl; @@ -172,17 +172,17 @@ int run_kernel_test(const kernel_arg_t& kernel_arg, RT_CHECK(vx_ready_wait(device, -1)); auto t3 = std::chrono::high_resolution_clock::now(); - // read buffer from local memory - std::cout << "read buffer from local memory" << std::endl; + // read destination buffer from local memory + std::cout << "read destination buffer from local memory" << std::endl; auto t4 = std::chrono::high_resolution_clock::now(); - RT_CHECK(vx_copy_from_dev(buffer, kernel_arg.dst_ptr, buf_size, 0)); + RT_CHECK(vx_copy_from_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); auto t5 = std::chrono::high_resolution_clock::now(); // verify result std::cout << "verify result" << std::endl; for (uint32_t i = 0; i < num_points; ++i) { - int32_t curr = ((int32_t*)vx_host_ptr(buffer))[i]; + int32_t curr = ((int32_t*)vx_host_ptr(staging_buf))[i]; int32_t ref = i; if (curr != ref) { std::cout << "error at result #" << i @@ -233,8 +233,8 @@ int main(int argc, char *argv[]) { unsigned max_cores; RT_CHECK(vx_dev_caps(device, VX_CAPS_MAX_CORES, &max_cores)); uint32_t num_points = 1 * count; - uint32_t num_blocks = (num_points * sizeof(uint32_t) + 63) / 64; - uint32_t buf_size = num_blocks * 64; + uint32_t num_blocks = (num_points * sizeof(int32_t) + 63) / 64; + uint32_t buf_size = num_blocks * 64; std::cout << "number of points: " << num_points << std::endl; std::cout << "buffer size: " << buf_size << " bytes" << std::endl; @@ -253,7 +253,7 @@ int main(int argc, char *argv[]) { // allocate shared memory std::cout << "allocate shared memory" << std::endl; uint32_t alloc_size = std::max(buf_size, sizeof(kernel_arg_t)); - RT_CHECK(vx_alloc_shared_mem(device, alloc_size, &buffer)); + RT_CHECK(vx_alloc_shared_mem(device, alloc_size, &staging_buf)); // run tests if (0 == test || -1 == test) { @@ -269,9 +269,9 @@ int main(int argc, char *argv[]) { // upload kernel argument std::cout << "upload kernel argument" << std::endl; { - auto buf_ptr = (void*)vx_host_ptr(buffer); + auto buf_ptr = (void*)vx_host_ptr(staging_buf); memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(buffer, KERNEL_ARG_DEV_MEM_ADDR, sizeof(kernel_arg_t), 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, KERNEL_ARG_DEV_MEM_ADDR, sizeof(kernel_arg_t), 0)); } std::cout << "run kernel test" << std::endl; diff --git a/driver/tests/demo/main.cpp b/driver/tests/demo/main.cpp index 41483458..7261869c 100644 --- a/driver/tests/demo/main.cpp +++ b/driver/tests/demo/main.cpp @@ -20,7 +20,7 @@ const char* kernel_file = "kernel.bin"; uint32_t count = 0; vx_device_h device = nullptr; -vx_buffer_h buffer = nullptr; +vx_buffer_h staging_buf = nullptr; static void show_usage() { std::cout << "Vortex Driver Test." << std::endl; @@ -50,8 +50,8 @@ static void parse_args(int argc, char **argv) { } void cleanup() { - if (buffer) { - vx_buf_release(buffer); + if (staging_buf) { + vx_buf_release(staging_buf); } if (device) { vx_dev_close(device); @@ -71,13 +71,13 @@ int run_test(const kernel_arg_t& kernel_arg, // download destination buffer std::cout << "download destination buffer" << std::endl; - RT_CHECK(vx_copy_from_dev(buffer, kernel_arg.dst_ptr, buf_size, 0)); + RT_CHECK(vx_copy_from_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); // verify result std::cout << "verify result" << std::endl; { int errors = 0; - auto buf_ptr = (int32_t*)vx_host_ptr(buffer); + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); for (uint32_t i = 0; i < num_points; ++i) { int ref = i + i; int cur = buf_ptr[i]; @@ -119,7 +119,7 @@ int main(int argc, char *argv[]) { uint32_t num_tasks = max_cores * max_warps * max_threads; uint32_t num_points = count * num_tasks; - uint32_t buf_size = num_points * sizeof(uint32_t); + uint32_t buf_size = num_points * sizeof(int32_t); std::cout << "number of points: " << num_points << std::endl; std::cout << "buffer size: " << buf_size << " bytes" << std::endl; @@ -148,45 +148,45 @@ int main(int argc, char *argv[]) { // allocate shared memory std::cout << "allocate shared memory" << std::endl; uint32_t alloc_size = std::max(buf_size, sizeof(kernel_arg_t)); - RT_CHECK(vx_alloc_shared_mem(device, alloc_size, &buffer)); + RT_CHECK(vx_alloc_shared_mem(device, alloc_size, &staging_buf)); // upload kernel argument std::cout << "upload kernel argument" << std::endl; { - auto buf_ptr = (int*)vx_host_ptr(buffer); + auto buf_ptr = (int*)vx_host_ptr(staging_buf); memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(buffer, KERNEL_ARG_DEV_MEM_ADDR, sizeof(kernel_arg_t), 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, KERNEL_ARG_DEV_MEM_ADDR, sizeof(kernel_arg_t), 0)); } // upload source buffer0 { - auto buf_ptr = (int32_t*)vx_host_ptr(buffer); + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); for (uint32_t i = 0; i < num_points; ++i) { buf_ptr[i] = i-1; } } std::cout << "upload source buffer0" << std::endl; - RT_CHECK(vx_copy_to_dev(buffer, kernel_arg.src0_ptr, buf_size, 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src0_ptr, buf_size, 0)); // upload source buffer1 { - auto buf_ptr = (int32_t*)vx_host_ptr(buffer); + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); for (uint32_t i = 0; i < num_points; ++i) { buf_ptr[i] = i+1; } } std::cout << "upload source buffer1" << std::endl; - RT_CHECK(vx_copy_to_dev(buffer, kernel_arg.src1_ptr, buf_size, 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src1_ptr, buf_size, 0)); // clear destination buffer { - auto buf_ptr = (int32_t*)vx_host_ptr(buffer); + auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); for (uint32_t i = 0; i < num_points; ++i) { buf_ptr[i] = 0xdeadbeef; } } std::cout << "clear destination buffer" << std::endl; - RT_CHECK(vx_copy_to_dev(buffer, kernel_arg.dst_ptr, buf_size, 0)); + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); // run tests std::cout << "run tests" << std::endl; diff --git a/driver/tests/stress/common.h b/driver/tests/stress/common.h index 41a7cc1f..55c6dbab 100644 --- a/driver/tests/stress/common.h +++ b/driver/tests/stress/common.h @@ -8,9 +8,9 @@ struct kernel_arg_t { uint32_t num_tasks; uint32_t size; - uint32_t stride; - uint32_t src0_ptr; - uint32_t src1_ptr; + uint32_t stride; + uint32_t addr_ptr; + uint32_t src_ptr; uint32_t dst_ptr; }; diff --git a/driver/tests/stress/kernel.c b/driver/tests/stress/kernel.c index abcc46e2..277935fc 100644 --- a/driver/tests/stress/kernel.c +++ b/driver/tests/stress/kernel.c @@ -6,8 +6,8 @@ void kernel_body(int task_id, void* arg) { struct kernel_arg_t* _arg = (struct kernel_arg_t*)(arg); uint32_t stride = _arg->stride; - int32_t* src0_ptr = (int32_t*)_arg->src0_ptr; - uint32_t* src1_ptr = (uint32_t*)_arg->src1_ptr; + uint32_t* addr_ptr = (uint32_t*)_arg->addr_ptr; + int32_t* src_ptr = (int32_t*)_arg->src_ptr; int32_t* dst_ptr = (int32_t*)_arg->dst_ptr; uint32_t offset = task_id * stride; @@ -16,8 +16,8 @@ void kernel_body(int task_id, void* arg) { int value = 0; for (uint32_t j = 0; j < NUM_LOADS; ++j) { uint32_t addr = offset + i + j; - uint32_t index = src1_ptr[addr]; - value += src0_ptr[index]; + uint32_t index = addr_ptr[addr]; + value += src_ptr[index]; } dst_ptr[offset+i] = value; } diff --git a/driver/tests/stress/main.cpp b/driver/tests/stress/main.cpp index e6952ba2..02c9b664 100644 --- a/driver/tests/stress/main.cpp +++ b/driver/tests/stress/main.cpp @@ -80,7 +80,7 @@ void gen_input_data(uint32_t num_points) { } int run_test(const kernel_arg_t& kernel_arg, - uint32_t buf_size, + uint32_t dst_buf_size, uint32_t num_points) { // start device std::cout << "start device" << std::endl; @@ -90,17 +90,15 @@ int run_test(const kernel_arg_t& kernel_arg, std::cout << "wait for completion" << std::endl; RT_CHECK(vx_ready_wait(device, -1)); - // download destination staging_buf - std::cout << "download destination staging_buf" << std::endl; - RT_CHECK(vx_copy_from_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); + // download destination buffer + std::cout << "download destination buffer" << std::endl; + RT_CHECK(vx_copy_from_dev(staging_buf, kernel_arg.dst_ptr, dst_buf_size, 0)); // verify result std::cout << "verify result" << std::endl; { int errors = 0; auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); - - uint32_t size_m1 = num_points - 1; for (uint32_t i = 0; i < num_points; ++i) { @@ -109,7 +107,7 @@ int run_test(const kernel_arg_t& kernel_arg, uint32_t addr = i + j; uint32_t index = addr_table.at(addr); int value = test_data.at(index); - printf("*** [%d] addr=%d, index=%d, value=%d\n", i, addr, index, value); + //printf("*** [%d] addr=%d, index=%d, value=%d\n", i, addr, index, value); ref += value; } @@ -155,14 +153,17 @@ int main(int argc, char *argv[]) { uint32_t num_tasks = max_cores * max_warps * max_threads; uint32_t num_points = count * num_tasks; - uint32_t buf_size = num_points * sizeof(uint32_t); - - std::cout << "number of points: " << num_points << std::endl; - std::cout << "staging_buf size: " << buf_size << " bytes" << std::endl; // generate input data gen_input_data(num_points); + uint32_t addr_buf_size = addr_table.size() * sizeof(int32_t); + uint32_t src_buf_size = test_data.size() * sizeof(int32_t); + uint32_t dst_buf_size = test_data.size() * sizeof(int32_t); + + std::cout << "number of points: " << num_points << std::endl; + std::cout << "buffer size: " << dst_buf_size << " bytes" << std::endl; + // upload program std::cout << "upload program" << std::endl; RT_CHECK(vx_upload_kernel_file(device, kernel_file)); @@ -170,24 +171,27 @@ int main(int argc, char *argv[]) { // allocate device memory std::cout << "allocate device memory" << std::endl; - RT_CHECK(vx_alloc_dev_mem(device, buf_size, &value)); - kernel_arg.src0_ptr = value; - RT_CHECK(vx_alloc_dev_mem(device, buf_size, &value)); - kernel_arg.src1_ptr = value; - RT_CHECK(vx_alloc_dev_mem(device, buf_size, &value)); + RT_CHECK(vx_alloc_dev_mem(device, addr_buf_size, &value)); + kernel_arg.addr_ptr = value; + RT_CHECK(vx_alloc_dev_mem(device, src_buf_size, &value)); + kernel_arg.src_ptr = value; + RT_CHECK(vx_alloc_dev_mem(device, dst_buf_size, &value)); kernel_arg.dst_ptr = value; kernel_arg.num_tasks = num_tasks; kernel_arg.stride = count; - std::cout << "dev_src0=" << std::hex << kernel_arg.src0_ptr << std::endl; - std::cout << "dev_src1=" << std::hex << kernel_arg.src1_ptr << std::endl; - std::cout << "dev_dst=" << std::hex << kernel_arg.dst_ptr << std::endl; + std::cout << "dev_addr=" << std::hex << kernel_arg.addr_ptr << std::endl; + std::cout << "dev_src=" << std::hex << kernel_arg.src_ptr << std::endl; + std::cout << "dev_dst=" << std::hex << kernel_arg.dst_ptr << std::endl; // allocate shared memory std::cout << "allocate shared memory" << std::endl; - uint32_t alloc_size = std::max(buf_size, sizeof(kernel_arg_t)); - RT_CHECK(vx_alloc_shared_mem(device, alloc_size, &staging_buf)); + uint32_t staging_buf_size = std::max(src_buf_size, + std::max(addr_buf_size, + std::max(dst_buf_size, + sizeof(kernel_arg_t)))); + RT_CHECK(vx_alloc_shared_mem(device, staging_buf_size, &staging_buf)); // upload kernel argument std::cout << "upload kernel argument" << std::endl; @@ -200,36 +204,36 @@ int main(int argc, char *argv[]) { // upload source buffer0 { auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); - for (uint32_t i = 0; i < num_points; ++i) { - buf_ptr[i] = test_data.at(i); + for (uint32_t i = 0; i < addr_table.size(); ++i) { + buf_ptr[i] = addr_table.at(i); } } - std::cout << "upload source buffer0" << std::endl; - RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src0_ptr, buf_size, 0)); + std::cout << "upload address buffer" << std::endl; + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.addr_ptr, addr_buf_size, 0)); // upload source buffer1 { auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); - for (uint32_t i = 0; i < num_points; ++i) { - buf_ptr[i] = addr_table.at(i); + for (uint32_t i = 0; i < test_data.size(); ++i) { + buf_ptr[i] = test_data.at(i); } } - std::cout << "upload source buffer1" << std::endl; - RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src1_ptr, buf_size, 0)); + std::cout << "upload source buffer" << std::endl; + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.src_ptr, src_buf_size, 0)); - // clear destination staging_buf + // clear destination buffer { auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); - for (uint32_t i = 0; i < num_points; ++i) { + for (uint32_t i = 0; i < test_data.size(); ++i) { buf_ptr[i] = 0xdeadbeef; } } - std::cout << "clear destination staging_buf" << std::endl; - RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.dst_ptr, buf_size, 0)); + std::cout << "clear destination buffer" << std::endl; + RT_CHECK(vx_copy_to_dev(staging_buf, kernel_arg.dst_ptr, dst_buf_size, 0)); // run tests std::cout << "run tests" << std::endl; - RT_CHECK(run_test(kernel_arg, buf_size, num_points)); + RT_CHECK(run_test(kernel_arg, dst_buf_size, num_points)); // cleanup std::cout << "cleanup" << std::endl; diff --git a/hw/syn/opae/README b/hw/syn/opae/README index c85981c7..9e0bd4bf 100644 --- a/hw/syn/opae/README +++ b/hw/syn/opae/README @@ -80,14 +80,9 @@ run -all tar -zcvf output_files_1c.tar.gz `find ./build_fpga_1c -type f \( -iname \*.rpt -o -iname \*.txt -o -iname \*summary -o -iname \*.log \)` # compress VCD trace -tar -zcvf trace.vcd.tar.gz ./build_ase_1c/work/trace.vcd -tar -zcvf trace.vcd.tar.gz obj_dir/trace.vcd -tar -zcvf trace.fst.tar.gz trace.fst run.log tar -zcvf run.log.tar.gz run.log -tar -zcvf vx_scope.vcd.tar.gz vx_scope.vcd tar -cvjf vx_scope.vcd.tar.bz2 vx_scope.vcd -tar -cvjf trace.fst.tar.bz2 trace.fst run.log -tar -cvjf trace.vcd.tar.bz2 driver/tests/basic/trace.vcd run.log +tar -cvjf trace.vcd.tar.bz2 trace.vcd run.log tar -cvjf trace.vcd.tar.bz2 build_ase_1c/work/run.log build_ase_1c/work/trace.vcd # decompress VCD trace From 228aee1ec749706fc6a596338d6fe5bc410b4a45 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 3 May 2021 12:25:44 -0700 Subject: [PATCH 34/55] lsu_unit pending queue bug fix --- hw/rtl/VX_lsu_unit.v | 67 +++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/hw/rtl/VX_lsu_unit.v b/hw/rtl/VX_lsu_unit.v index d3a96ade..79059f30 100644 --- a/hw/rtl/VX_lsu_unit.v +++ b/hw/rtl/VX_lsu_unit.v @@ -44,10 +44,6 @@ module VX_lsu_unit #( end wire is_dup_load = lsu_req_if.wb && lsu_req_if.tmask[0] && (& addr_matches); -`IGNORE_WARNINGS_BEGIN - reg [`LSUQ_SIZE-1:0][`DCORE_TAG_ID_BITS-1:0] pending_tags; -`IGNORE_WARNINGS_END - wire ready_in; wire stall_in = ~ready_in && req_valid; @@ -79,7 +75,7 @@ module VX_lsu_unit #( wire [`NUM_THREADS-1:0] rsp_tmask; reg [`NUM_THREADS-1:0] req_sent_mask; - wire sent_all_ready; + wire req_ready_all; wire [`DCORE_TAG_ID_BITS-1:0] mbuf_waddr, mbuf_raddr; wire mbuf_full; @@ -118,7 +114,7 @@ module VX_lsu_unit #( `UNUSED_PIN (empty) ); - assign sent_all_ready = &(dcache_req_if.ready | req_sent_mask); + assign req_ready_all = &(dcache_req_if.ready | req_sent_mask | ~req_tmask); wire [`NUM_THREADS-1:0] req_sent_dup = {{(`NUM_THREADS-1){dcache_req_fire[0] && req_is_dup}}, 1'b0}; @@ -126,19 +122,20 @@ module VX_lsu_unit #( if (reset) begin req_sent_mask <= 0; end else begin - if (sent_all_ready) + if (req_ready_all) req_sent_mask <= 0; else req_sent_mask <= req_sent_mask | dcache_req_fire | req_sent_dup; end end + wire is_req_start = (0 == req_sent_mask); + // need to hold the acquired tag index until the full request is submitted reg [`DCORE_TAG_ID_BITS-1:0] req_tag_hold; - wire [`DCORE_TAG_ID_BITS-1:0] req_tag = (0 == req_sent_mask) ? mbuf_waddr : req_tag_hold; + wire [`DCORE_TAG_ID_BITS-1:0] req_tag = is_req_start ? mbuf_waddr : req_tag_hold; always @(posedge clk) begin if (mbuf_push) begin - pending_tags[mbuf_waddr] <= req_tag; req_tag_hold <= mbuf_waddr; end end @@ -156,7 +153,8 @@ module VX_lsu_unit #( end end - wire req_ready_dep = (req_wb && ~mbuf_full) + // ensure all dependencies for the requests are resolved + wire req_dep_ready = (req_wb && (~mbuf_full || ~is_req_start)) || (~req_wb && st_commit_if.ready); // DCache Request @@ -189,7 +187,7 @@ module VX_lsu_unit #( end end - assign dcache_req_if.valid = {`NUM_THREADS{req_valid && req_ready_dep}} & req_tmask_dup & ~req_sent_mask; + assign dcache_req_if.valid = {`NUM_THREADS{req_valid && req_dep_ready}} & req_tmask_dup & ~req_sent_mask; assign dcache_req_if.rw = {`NUM_THREADS{~req_wb}}; assign dcache_req_if.addr = mem_req_addr; assign dcache_req_if.byteen = mem_req_byteen; @@ -201,11 +199,11 @@ module VX_lsu_unit #( assign dcache_req_if.tag = {`NUM_THREADS{req_tag}}; `endif - assign ready_in = req_ready_dep && sent_all_ready; + assign ready_in = req_dep_ready && req_ready_all; // send store commit - wire is_store_rsp = req_valid && ~req_wb && sent_all_ready; + wire is_store_rsp = req_valid && ~req_wb && req_ready_all; assign st_commit_if.valid = is_store_rsp; assign st_commit_if.wid = req_wid; @@ -276,23 +274,46 @@ module VX_lsu_unit #( `SCOPE_ASSIGN (dcache_rsp_tag, mbuf_raddr); `ifdef DBG_PRINT_CORE_DCACHE +`IGNORE_WARNINGS_BEGIN + reg [`LSUQ_SIZE-1:0][`DCORE_TAG_WIDTH:0] pending_reqs; +`IGNORE_WARNINGS_END + + always @(posedge clk) begin + if (reset) begin + pending_reqs <= '0; + end else if (mbuf_push) begin + pending_reqs[mbuf_waddr] <= {dcache_req_if.tag[0], 1'b1}; + end else if (mbuf_pop) begin + pending_reqs[mbuf_raddr] <= '0; + end + end + always @(posedge clk) begin if ((| dcache_req_fire)) begin - if ((| dcache_req_if.rw)) - $display("%t: D$%0d Wr Req: wid=%0d, PC=%0h, tmask=%b, addr=%0h, tag=%0h, byteen=%0h, data=%0h", - $time, CORE_ID, req_wid, req_pc, dcache_req_fire, req_addr, dcache_req_if.tag, dcache_req_if.byteen, dcache_req_if.data); - else - $display("%t: D$%0d Rd Req: wid=%0d, PC=%0h, tmask=%b, addr=%0h, tag=%0h, byteen=%0h, rd=%0d, is_dup=%b", - $time, CORE_ID, req_wid, req_pc, dcache_req_fire, req_addr, dcache_req_if.tag, dcache_req_if.byteen, req_rd, req_is_dup); + if (dcache_req_if.rw[0]) begin + $write("%t: D$%0d Wr Req: wid=%0d, PC=%0h, tmask=%b, addr=", $time, CORE_ID, req_wid, req_pc, dcache_req_fire); + `PRINT_ARRAY1D(req_addr, `NUM_THREADS); + $write(", tag=%0h, byteen=%0h, data=", dcache_req_if.tag[0], dcache_req_if.byteen); + `PRINT_ARRAY1D(dcache_req_if.data, `NUM_THREADS); + $write("\n"); + end else begin + $write("%t: D$%0d Rd Req: wid=%0d, PC=%0h, tmask=%b, addr=", $time, CORE_ID, req_wid, req_pc, dcache_req_fire); + `PRINT_ARRAY1D(req_addr, `NUM_THREADS); + $write(", tag=%0h, byteen=%0h, rd=%0d, is_dup=%b\n", dcache_req_if.tag[0], dcache_req_if.byteen, req_rd, req_is_dup); + end end if (dcache_rsp_fire) begin - $display("%t: D$%0d Rsp: valid=%b, wid=%0d, PC=%0h, tag=%0h, rd=%0d, data=%0h, is_dup=%b", - $time, CORE_ID, dcache_rsp_if.valid, rsp_wid, rsp_pc, dcache_rsp_if.tag, rsp_rd, dcache_rsp_if.data, rsp_is_dup); + $write("%t: D$%0d Rsp: valid=%b, wid=%0d, PC=%0h, tag=%0h, rd=%0d, data=", + $time, CORE_ID, dcache_rsp_if.valid, rsp_wid, rsp_pc, dcache_rsp_if.tag, rsp_rd); + `PRINT_ARRAY1D(dcache_rsp_if.data, `NUM_THREADS); + $write("is_dup=%b\n", rsp_is_dup); end if (mbuf_full) begin - $write("%t: D$%0d queue-full:", $time, CORE_ID); + $write("%t: *** D$%0d queue-full:", $time, CORE_ID); for (integer j = 0; j < `LSUQ_SIZE; j++) begin - $write(" tag%0d=%0h", j, pending_tags[j]); + if (pending_reqs[j][0]) begin + $write(" %0d->%0h", j, pending_reqs[j][1 +: `DCORE_TAG_WIDTH]); + end end $write("\n"); end From 76f5531b5883fdae6d4b169da90f7244b1fd6997 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 3 May 2021 12:44:36 -0700 Subject: [PATCH 35/55] adding stress test pre-built kernel --- driver/tests/stress/kernel.bin | Bin 0 -> 6980 bytes driver/tests/stress/kernel.dump | 564 ++++++++++++++++++++++++++++++++ driver/tests/stress/kernel.elf | Bin 0 -> 9036 bytes 3 files changed, 564 insertions(+) create mode 100755 driver/tests/stress/kernel.bin create mode 100644 driver/tests/stress/kernel.dump create mode 100755 driver/tests/stress/kernel.elf diff --git a/driver/tests/stress/kernel.bin b/driver/tests/stress/kernel.bin new file mode 100755 index 0000000000000000000000000000000000000000..63d2f799d4b47d9cd2bcca2a315a6f59334085bd GIT binary patch literal 6980 zcmeHLU1%It6h3$6&fMLmwA;?w-HOn(v)O6V(jTT6d|Nf81Vj`>@I@&@RfrP8LhF;= zIJ?@Sz1t?T0EKdt~n3$;{+IwrC+|M$n@5%+zA* zfvL1bQ|Tntya9_!7G;2ERMy}Q0s9bV?(jI-9~H~$o#_?e4wKDqqmC^6 zxZ;ajip{4RYj(Im&Wj1=j&O1>b^sSAgGXr|=a#n>*1XTRQ&%QTZu1qUCVH8hc$}%N zjJd5>2=yuJ_-nwg0KWqK3h=AIuP!E=Yw6vQS~@{BS%V=e%;~6Z^g~=VM1-8_OJpB; zNOi8xZFH{BZ}9q->-Lj36fdNbGq6ndu^WmXI!69@zhd9&SDb6S$ACwy*;IpyuH`G$FtX`mW8;JmE~>mOTL;rhYCJa@S%VY-ryszQ~BEb zZ{3w2?-e_nVxeNM2 z9&g%8IT@}1L*35i$+b9n+1qu4kJlT$Kg-upBcVn@jk4Elz1NN0X7f%abGL6t9fJ25 z;c$-~UP;N^@(kmJ))Y8a49etCAyiRvWl^YyWmoc}=u z?|si>?JF`xiHbVnVMPrdR^;%oq6!ZyD)6u(gNGFf9wu{oOG}%*fgJfaW^lJ?OnT^H zS0zN-c?2j^Yrvh-H2P{ z=$c}?f|-f2kb5Z~H{_gbnhtDX6h>>|=9y5XXA#ebFHE@c_ zsF|onyDKlPy2F$4dvW$0IKc1!#v59tzOIQo5}&yjcf-eG6xzW2Z&B3NQ^?n=Ko5$! z?;tbVo@M6lqqy68fU}p$88n)p`L|&kBIJcDbvMyT26X5=0d2mYAfKNjC)>o`k&cLy zIiVT+cHPU4*UQ@u)u96g`c$A#oW&H(AXD3LN3{XR9^6rTpkLgn(5@hG(0A*ZeHM2?$=jcs}Q#bPa(FGe5so=LP0NZ=Of-a6?LL{R?b>0<$m$IQ4oz;cCD}D zxGzJtjDJLc!zS53`CrZ4Re(RgYUH%_wex>a@B|D53: +80000000: 00000597 auipc a1,0x0 +80000004: 0f058593 addi a1,a1,240 # 800000f0 +80000008: fc102573 csrr a0,0xfc1 +8000000c: 00b5106b 0xb5106b +80000010: 0e0000ef jal ra,800000f0 +80000014: 00100513 li a0,1 +80000018: 0005006b 0x5006b +8000001c: 00002517 auipc a0,0x2 +80000020: b2850513 addi a0,a0,-1240 # 80001b44 +80000024: 00002617 auipc a2,0x2 +80000028: ba060613 addi a2,a2,-1120 # 80001bc4 <__BSS_END__> +8000002c: 40a60633 sub a2,a2,a0 +80000030: 00000593 li a1,0 +80000034: 440000ef jal ra,80000474 +80000038: 00000517 auipc a0,0x0 +8000003c: 34450513 addi a0,a0,836 # 8000037c <__libc_fini_array> +80000040: 2f4000ef jal ra,80000334 +80000044: 394000ef jal ra,800003d8 <__libc_init_array> +80000048: 008000ef jal ra,80000050

    +8000004c: 2fc0006f j 80000348 + +Disassembly of section .text: + +80000050
    : +80000050: 7ffff7b7 lui a5,0x7ffff +80000054: 0007a503 lw a0,0(a5) # 7ffff000 <__stack_size+0x7fffec00> +80000058: 800005b7 lui a1,0x80000 +8000005c: 7ffff637 lui a2,0x7ffff +80000060: 08058593 addi a1,a1,128 # 80000080 <__stack_top+0x81000080> +80000064: 1880006f j 800001ec + +80000068 : +80000068: 00000793 li a5,0 +8000006c: 00078863 beqz a5,8000007c +80000070: 80000537 lui a0,0x80000 +80000074: 37c50513 addi a0,a0,892 # 8000037c <__stack_top+0x8100037c> +80000078: 2bc0006f j 80000334 +8000007c: 00008067 ret + +80000080 : +80000080: 0085a783 lw a5,8(a1) +80000084: 00c5a683 lw a3,12(a1) +80000088: 0105a803 lw a6,16(a1) +8000008c: 02f50533 mul a0,a0,a5 +80000090: 0145a703 lw a4,20(a1) +80000094: 04078863 beqz a5,800000e4 +80000098: 00a785b3 add a1,a5,a0 +8000009c: 00259593 slli a1,a1,0x2 +800000a0: 00251793 slli a5,a0,0x2 +800000a4: 00d787b3 add a5,a5,a3 +800000a8: 00d585b3 add a1,a1,a3 +800000ac: 40d70533 sub a0,a4,a3 +800000b0: 0007a683 lw a3,0(a5) +800000b4: 0047a703 lw a4,4(a5) +800000b8: 00f50633 add a2,a0,a5 +800000bc: 00269693 slli a3,a3,0x2 +800000c0: 00271713 slli a4,a4,0x2 +800000c4: 00d806b3 add a3,a6,a3 +800000c8: 00e80733 add a4,a6,a4 +800000cc: 0006a683 lw a3,0(a3) +800000d0: 00072703 lw a4,0(a4) +800000d4: 00478793 addi a5,a5,4 +800000d8: 00d70733 add a4,a4,a3 +800000dc: 00e62023 sw a4,0(a2) # 7ffff000 <__stack_size+0x7fffec00> +800000e0: fcf598e3 bne a1,a5,800000b0 +800000e4: 00008067 ret + +800000e8 <_exit>: +800000e8: 00000513 li a0,0 +800000ec: 0005006b 0x5006b + +800000f0 : +800000f0: fc002573 csrr a0,0xfc0 +800000f4: 0005006b 0x5006b +800000f8: 00002197 auipc gp,0x2 +800000fc: e2018193 addi gp,gp,-480 # 80001f18 <__global_pointer> +80000100: 7f000117 auipc sp,0x7f000 +80000104: f0010113 addi sp,sp,-256 # ff000000 <__stack_top> +80000108: 40000593 li a1,1024 +8000010c: cc102673 csrr a2,0xcc1 +80000110: 02c585b3 mul a1,a1,a2 +80000114: 40b10133 sub sp,sp,a1 +80000118: cc3026f3 csrr a3,0xcc3 +8000011c: 00068663 beqz a3,80000128 +80000120: 00000513 li a0,0 +80000124: 0005006b 0x5006b + +80000128 : +80000128: 00008067 ret + +8000012c : +8000012c: fe010113 addi sp,sp,-32 +80000130: 00112e23 sw ra,28(sp) +80000134: 00812c23 sw s0,24(sp) +80000138: 00912a23 sw s1,20(sp) +8000013c: 01212823 sw s2,16(sp) +80000140: 01312623 sw s3,12(sp) +80000144: fc0027f3 csrr a5,0xfc0 +80000148: 0007806b 0x7806b +8000014c: cc5027f3 csrr a5,0xcc5 +80000150: cc3029f3 csrr s3,0xcc3 +80000154: cc002773 csrr a4,0xcc0 +80000158: fc002673 csrr a2,0xfc0 +8000015c: 00279693 slli a3,a5,0x2 +80000160: 800027b7 lui a5,0x80002 +80000164: b4478793 addi a5,a5,-1212 # 80001b44 <__stack_top+0x81001b44> +80000168: 00d787b3 add a5,a5,a3 +8000016c: 0007a483 lw s1,0(a5) +80000170: 0104a403 lw s0,16(s1) +80000174: 00c4a683 lw a3,12(s1) +80000178: 0089a933 slt s2,s3,s0 +8000017c: 00040793 mv a5,s0 +80000180: 00d90933 add s2,s2,a3 +80000184: 03368433 mul s0,a3,s3 +80000188: 00f9d463 bge s3,a5,80000190 +8000018c: 00098793 mv a5,s3 +80000190: 00f40433 add s0,s0,a5 +80000194: 0084a683 lw a3,8(s1) +80000198: 02c40433 mul s0,s0,a2 +8000019c: 02e907b3 mul a5,s2,a4 +800001a0: 00d40433 add s0,s0,a3 +800001a4: 00f40433 add s0,s0,a5 +800001a8: 00890933 add s2,s2,s0 +800001ac: 01245e63 bge s0,s2,800001c8 +800001b0: 0004a783 lw a5,0(s1) +800001b4: 0044a583 lw a1,4(s1) +800001b8: 00040513 mv a0,s0 +800001bc: 00140413 addi s0,s0,1 +800001c0: 000780e7 jalr a5 +800001c4: fe8916e3 bne s2,s0,800001b0 +800001c8: 0019b993 seqz s3,s3 +800001cc: 0009806b 0x9806b +800001d0: 01c12083 lw ra,28(sp) +800001d4: 01812403 lw s0,24(sp) +800001d8: 01412483 lw s1,20(sp) +800001dc: 01012903 lw s2,16(sp) +800001e0: 00c12983 lw s3,12(sp) +800001e4: 02010113 addi sp,sp,32 +800001e8: 00008067 ret + +800001ec : +800001ec: fc010113 addi sp,sp,-64 +800001f0: 02112e23 sw ra,60(sp) +800001f4: 02812c23 sw s0,56(sp) +800001f8: 02912a23 sw s1,52(sp) +800001fc: 03212823 sw s2,48(sp) +80000200: 03312623 sw s3,44(sp) +80000204: fc2026f3 csrr a3,0xfc2 +80000208: fc102873 csrr a6,0xfc1 +8000020c: fc002473 csrr s0,0xfc0 +80000210: cc5027f3 csrr a5,0xcc5 +80000214: 01f00713 li a4,31 +80000218: 0cf74463 blt a4,a5,800002e0 +8000021c: 030408b3 mul a7,s0,a6 +80000220: 00100713 li a4,1 +80000224: 00a8d463 bge a7,a0,8000022c +80000228: 03154733 div a4,a0,a7 +8000022c: 0ce6c863 blt a3,a4,800002fc +80000230: 0ae7d863 bge a5,a4,800002e0 +80000234: fff68693 addi a3,a3,-1 +80000238: 02e54333 div t1,a0,a4 +8000023c: 00030893 mv a7,t1 +80000240: 00f69663 bne a3,a5,8000024c +80000244: 02e56533 rem a0,a0,a4 +80000248: 006508b3 add a7,a0,t1 +8000024c: 0288c4b3 div s1,a7,s0 +80000250: 0288e933 rem s2,a7,s0 +80000254: 0b04ca63 blt s1,a6,80000308 +80000258: 00100693 li a3,1 +8000025c: 0304c733 div a4,s1,a6 +80000260: 00070663 beqz a4,8000026c +80000264: 00070693 mv a3,a4 +80000268: 0304e733 rem a4,s1,a6 +8000026c: 800029b7 lui s3,0x80002 +80000270: b4498993 addi s3,s3,-1212 # 80001b44 <__stack_top+0x81001b44> +80000274: 00e12e23 sw a4,28(sp) +80000278: 00c10713 addi a4,sp,12 +8000027c: 00b12623 sw a1,12(sp) +80000280: 00c12823 sw a2,16(sp) +80000284: 00d12c23 sw a3,24(sp) +80000288: 02f30333 mul t1,t1,a5 +8000028c: 00279793 slli a5,a5,0x2 +80000290: 00f987b3 add a5,s3,a5 +80000294: 00e7a023 sw a4,0(a5) +80000298: 00612a23 sw t1,20(sp) +8000029c: 06904c63 bgtz s1,80000314 +800002a0: 04090063 beqz s2,800002e0 +800002a4: 02848433 mul s0,s1,s0 +800002a8: 00812a23 sw s0,20(sp) +800002ac: 0009006b 0x9006b +800002b0: cc5027f3 csrr a5,0xcc5 +800002b4: cc202573 csrr a0,0xcc2 +800002b8: 00279793 slli a5,a5,0x2 +800002bc: 00f989b3 add s3,s3,a5 +800002c0: 0009a783 lw a5,0(s3) +800002c4: 0087a683 lw a3,8(a5) +800002c8: 0007a703 lw a4,0(a5) +800002cc: 0047a583 lw a1,4(a5) +800002d0: 00d50533 add a0,a0,a3 +800002d4: 000700e7 jalr a4 +800002d8: 00100793 li a5,1 +800002dc: 0007806b 0x7806b +800002e0: 03c12083 lw ra,60(sp) +800002e4: 03812403 lw s0,56(sp) +800002e8: 03412483 lw s1,52(sp) +800002ec: 03012903 lw s2,48(sp) +800002f0: 02c12983 lw s3,44(sp) +800002f4: 04010113 addi sp,sp,64 +800002f8: 00008067 ret +800002fc: 00068713 mv a4,a3 +80000300: f2e7cae3 blt a5,a4,80000234 +80000304: fddff06f j 800002e0 +80000308: 00000713 li a4,0 +8000030c: 00100693 li a3,1 +80000310: f5dff06f j 8000026c +80000314: 00048713 mv a4,s1 +80000318: 00985463 bge a6,s1,80000320 +8000031c: 00080713 mv a4,a6 +80000320: 800007b7 lui a5,0x80000 +80000324: 12c78793 addi a5,a5,300 # 8000012c <__stack_top+0x8100012c> +80000328: 00f7106b 0xf7106b +8000032c: e01ff0ef jal ra,8000012c +80000330: f71ff06f j 800002a0 + +80000334 : +80000334: 00050593 mv a1,a0 +80000338: 00000693 li a3,0 +8000033c: 00000613 li a2,0 +80000340: 00000513 li a0,0 +80000344: 20c0006f j 80000550 <__register_exitproc> + +80000348 : +80000348: ff010113 addi sp,sp,-16 +8000034c: 00000593 li a1,0 +80000350: 00812423 sw s0,8(sp) +80000354: 00112623 sw ra,12(sp) +80000358: 00050413 mv s0,a0 +8000035c: 290000ef jal ra,800005ec <__call_exitprocs> +80000360: 800027b7 lui a5,0x80002 +80000364: b407a503 lw a0,-1216(a5) # 80001b40 <__stack_top+0x81001b40> +80000368: 03c52783 lw a5,60(a0) +8000036c: 00078463 beqz a5,80000374 +80000370: 000780e7 jalr a5 +80000374: 00040513 mv a0,s0 +80000378: d71ff0ef jal ra,800000e8 <_exit> + +8000037c <__libc_fini_array>: +8000037c: ff010113 addi sp,sp,-16 +80000380: 00812423 sw s0,8(sp) +80000384: 800017b7 lui a5,0x80001 +80000388: 80001437 lui s0,0x80001 +8000038c: 71440413 addi s0,s0,1812 # 80001714 <__stack_top+0x81001714> +80000390: 71478793 addi a5,a5,1812 # 80001714 <__stack_top+0x81001714> +80000394: 408787b3 sub a5,a5,s0 +80000398: 00912223 sw s1,4(sp) +8000039c: 00112623 sw ra,12(sp) +800003a0: 4027d493 srai s1,a5,0x2 +800003a4: 02048063 beqz s1,800003c4 <__libc_fini_array+0x48> +800003a8: ffc78793 addi a5,a5,-4 +800003ac: 00878433 add s0,a5,s0 +800003b0: 00042783 lw a5,0(s0) +800003b4: fff48493 addi s1,s1,-1 +800003b8: ffc40413 addi s0,s0,-4 +800003bc: 000780e7 jalr a5 +800003c0: fe0498e3 bnez s1,800003b0 <__libc_fini_array+0x34> +800003c4: 00c12083 lw ra,12(sp) +800003c8: 00812403 lw s0,8(sp) +800003cc: 00412483 lw s1,4(sp) +800003d0: 01010113 addi sp,sp,16 +800003d4: 00008067 ret + +800003d8 <__libc_init_array>: +800003d8: ff010113 addi sp,sp,-16 +800003dc: 00812423 sw s0,8(sp) +800003e0: 01212023 sw s2,0(sp) +800003e4: 80001437 lui s0,0x80001 +800003e8: 80001937 lui s2,0x80001 +800003ec: 71040793 addi a5,s0,1808 # 80001710 <__stack_top+0x81001710> +800003f0: 71090913 addi s2,s2,1808 # 80001710 <__stack_top+0x81001710> +800003f4: 40f90933 sub s2,s2,a5 +800003f8: 00112623 sw ra,12(sp) +800003fc: 00912223 sw s1,4(sp) +80000400: 40295913 srai s2,s2,0x2 +80000404: 02090063 beqz s2,80000424 <__libc_init_array+0x4c> +80000408: 71040413 addi s0,s0,1808 +8000040c: 00000493 li s1,0 +80000410: 00042783 lw a5,0(s0) +80000414: 00148493 addi s1,s1,1 +80000418: 00440413 addi s0,s0,4 +8000041c: 000780e7 jalr a5 +80000420: fe9918e3 bne s2,s1,80000410 <__libc_init_array+0x38> +80000424: 80001437 lui s0,0x80001 +80000428: 80001937 lui s2,0x80001 +8000042c: 71040793 addi a5,s0,1808 # 80001710 <__stack_top+0x81001710> +80000430: 71490913 addi s2,s2,1812 # 80001714 <__stack_top+0x81001714> +80000434: 40f90933 sub s2,s2,a5 +80000438: 40295913 srai s2,s2,0x2 +8000043c: 02090063 beqz s2,8000045c <__libc_init_array+0x84> +80000440: 71040413 addi s0,s0,1808 +80000444: 00000493 li s1,0 +80000448: 00042783 lw a5,0(s0) +8000044c: 00148493 addi s1,s1,1 +80000450: 00440413 addi s0,s0,4 +80000454: 000780e7 jalr a5 +80000458: fe9918e3 bne s2,s1,80000448 <__libc_init_array+0x70> +8000045c: 00c12083 lw ra,12(sp) +80000460: 00812403 lw s0,8(sp) +80000464: 00412483 lw s1,4(sp) +80000468: 00012903 lw s2,0(sp) +8000046c: 01010113 addi sp,sp,16 +80000470: 00008067 ret + +80000474 : +80000474: 00f00313 li t1,15 +80000478: 00050713 mv a4,a0 +8000047c: 02c37e63 bgeu t1,a2,800004b8 +80000480: 00f77793 andi a5,a4,15 +80000484: 0a079063 bnez a5,80000524 +80000488: 08059263 bnez a1,8000050c +8000048c: ff067693 andi a3,a2,-16 +80000490: 00f67613 andi a2,a2,15 +80000494: 00e686b3 add a3,a3,a4 +80000498: 00b72023 sw a1,0(a4) +8000049c: 00b72223 sw a1,4(a4) +800004a0: 00b72423 sw a1,8(a4) +800004a4: 00b72623 sw a1,12(a4) +800004a8: 01070713 addi a4,a4,16 +800004ac: fed766e3 bltu a4,a3,80000498 +800004b0: 00061463 bnez a2,800004b8 +800004b4: 00008067 ret +800004b8: 40c306b3 sub a3,t1,a2 +800004bc: 00269693 slli a3,a3,0x2 +800004c0: 00000297 auipc t0,0x0 +800004c4: 005686b3 add a3,a3,t0 +800004c8: 00c68067 jr 12(a3) +800004cc: 00b70723 sb a1,14(a4) +800004d0: 00b706a3 sb a1,13(a4) +800004d4: 00b70623 sb a1,12(a4) +800004d8: 00b705a3 sb a1,11(a4) +800004dc: 00b70523 sb a1,10(a4) +800004e0: 00b704a3 sb a1,9(a4) +800004e4: 00b70423 sb a1,8(a4) +800004e8: 00b703a3 sb a1,7(a4) +800004ec: 00b70323 sb a1,6(a4) +800004f0: 00b702a3 sb a1,5(a4) +800004f4: 00b70223 sb a1,4(a4) +800004f8: 00b701a3 sb a1,3(a4) +800004fc: 00b70123 sb a1,2(a4) +80000500: 00b700a3 sb a1,1(a4) +80000504: 00b70023 sb a1,0(a4) +80000508: 00008067 ret +8000050c: 0ff5f593 andi a1,a1,255 +80000510: 00859693 slli a3,a1,0x8 +80000514: 00d5e5b3 or a1,a1,a3 +80000518: 01059693 slli a3,a1,0x10 +8000051c: 00d5e5b3 or a1,a1,a3 +80000520: f6dff06f j 8000048c +80000524: 00279693 slli a3,a5,0x2 +80000528: 00000297 auipc t0,0x0 +8000052c: 005686b3 add a3,a3,t0 +80000530: 00008293 mv t0,ra +80000534: fa0680e7 jalr -96(a3) +80000538: 00028093 mv ra,t0 +8000053c: ff078793 addi a5,a5,-16 +80000540: 40f70733 sub a4,a4,a5 +80000544: 00f60633 add a2,a2,a5 +80000548: f6c378e3 bgeu t1,a2,800004b8 +8000054c: f3dff06f j 80000488 + +80000550 <__register_exitproc>: +80000550: 800027b7 lui a5,0x80002 +80000554: b407a703 lw a4,-1216(a5) # 80001b40 <__stack_top+0x81001b40> +80000558: 14872783 lw a5,328(a4) +8000055c: 04078c63 beqz a5,800005b4 <__register_exitproc+0x64> +80000560: 0047a703 lw a4,4(a5) +80000564: 01f00813 li a6,31 +80000568: 06e84e63 blt a6,a4,800005e4 <__register_exitproc+0x94> +8000056c: 00271813 slli a6,a4,0x2 +80000570: 02050663 beqz a0,8000059c <__register_exitproc+0x4c> +80000574: 01078333 add t1,a5,a6 +80000578: 08c32423 sw a2,136(t1) +8000057c: 1887a883 lw a7,392(a5) +80000580: 00100613 li a2,1 +80000584: 00e61633 sll a2,a2,a4 +80000588: 00c8e8b3 or a7,a7,a2 +8000058c: 1917a423 sw a7,392(a5) +80000590: 10d32423 sw a3,264(t1) +80000594: 00200693 li a3,2 +80000598: 02d50463 beq a0,a3,800005c0 <__register_exitproc+0x70> +8000059c: 00170713 addi a4,a4,1 +800005a0: 00e7a223 sw a4,4(a5) +800005a4: 010787b3 add a5,a5,a6 +800005a8: 00b7a423 sw a1,8(a5) +800005ac: 00000513 li a0,0 +800005b0: 00008067 ret +800005b4: 14c70793 addi a5,a4,332 +800005b8: 14f72423 sw a5,328(a4) +800005bc: fa5ff06f j 80000560 <__register_exitproc+0x10> +800005c0: 18c7a683 lw a3,396(a5) +800005c4: 00170713 addi a4,a4,1 +800005c8: 00e7a223 sw a4,4(a5) +800005cc: 00c6e633 or a2,a3,a2 +800005d0: 18c7a623 sw a2,396(a5) +800005d4: 010787b3 add a5,a5,a6 +800005d8: 00b7a423 sw a1,8(a5) +800005dc: 00000513 li a0,0 +800005e0: 00008067 ret +800005e4: fff00513 li a0,-1 +800005e8: 00008067 ret + +800005ec <__call_exitprocs>: +800005ec: fd010113 addi sp,sp,-48 +800005f0: 800027b7 lui a5,0x80002 +800005f4: 01412c23 sw s4,24(sp) +800005f8: b407aa03 lw s4,-1216(a5) # 80001b40 <__stack_top+0x81001b40> +800005fc: 03212023 sw s2,32(sp) +80000600: 02112623 sw ra,44(sp) +80000604: 148a2903 lw s2,328(s4) +80000608: 02812423 sw s0,40(sp) +8000060c: 02912223 sw s1,36(sp) +80000610: 01312e23 sw s3,28(sp) +80000614: 01512a23 sw s5,20(sp) +80000618: 01612823 sw s6,16(sp) +8000061c: 01712623 sw s7,12(sp) +80000620: 01812423 sw s8,8(sp) +80000624: 04090063 beqz s2,80000664 <__call_exitprocs+0x78> +80000628: 00050b13 mv s6,a0 +8000062c: 00058b93 mv s7,a1 +80000630: 00100a93 li s5,1 +80000634: fff00993 li s3,-1 +80000638: 00492483 lw s1,4(s2) +8000063c: fff48413 addi s0,s1,-1 +80000640: 02044263 bltz s0,80000664 <__call_exitprocs+0x78> +80000644: 00249493 slli s1,s1,0x2 +80000648: 009904b3 add s1,s2,s1 +8000064c: 040b8463 beqz s7,80000694 <__call_exitprocs+0xa8> +80000650: 1044a783 lw a5,260(s1) +80000654: 05778063 beq a5,s7,80000694 <__call_exitprocs+0xa8> +80000658: fff40413 addi s0,s0,-1 +8000065c: ffc48493 addi s1,s1,-4 +80000660: ff3416e3 bne s0,s3,8000064c <__call_exitprocs+0x60> +80000664: 02c12083 lw ra,44(sp) +80000668: 02812403 lw s0,40(sp) +8000066c: 02412483 lw s1,36(sp) +80000670: 02012903 lw s2,32(sp) +80000674: 01c12983 lw s3,28(sp) +80000678: 01812a03 lw s4,24(sp) +8000067c: 01412a83 lw s5,20(sp) +80000680: 01012b03 lw s6,16(sp) +80000684: 00c12b83 lw s7,12(sp) +80000688: 00812c03 lw s8,8(sp) +8000068c: 03010113 addi sp,sp,48 +80000690: 00008067 ret +80000694: 00492783 lw a5,4(s2) +80000698: 0044a683 lw a3,4(s1) +8000069c: fff78793 addi a5,a5,-1 +800006a0: 04878e63 beq a5,s0,800006fc <__call_exitprocs+0x110> +800006a4: 0004a223 sw zero,4(s1) +800006a8: fa0688e3 beqz a3,80000658 <__call_exitprocs+0x6c> +800006ac: 18892783 lw a5,392(s2) +800006b0: 008a9733 sll a4,s5,s0 +800006b4: 00492c03 lw s8,4(s2) +800006b8: 00f777b3 and a5,a4,a5 +800006bc: 02079263 bnez a5,800006e0 <__call_exitprocs+0xf4> +800006c0: 000680e7 jalr a3 +800006c4: 00492703 lw a4,4(s2) +800006c8: 148a2783 lw a5,328(s4) +800006cc: 01871463 bne a4,s8,800006d4 <__call_exitprocs+0xe8> +800006d0: f92784e3 beq a5,s2,80000658 <__call_exitprocs+0x6c> +800006d4: f80788e3 beqz a5,80000664 <__call_exitprocs+0x78> +800006d8: 00078913 mv s2,a5 +800006dc: f5dff06f j 80000638 <__call_exitprocs+0x4c> +800006e0: 18c92783 lw a5,396(s2) +800006e4: 0844a583 lw a1,132(s1) +800006e8: 00f77733 and a4,a4,a5 +800006ec: 00071c63 bnez a4,80000704 <__call_exitprocs+0x118> +800006f0: 000b0513 mv a0,s6 +800006f4: 000680e7 jalr a3 +800006f8: fcdff06f j 800006c4 <__call_exitprocs+0xd8> +800006fc: 00892223 sw s0,4(s2) +80000700: fa9ff06f j 800006a8 <__call_exitprocs+0xbc> +80000704: 00058513 mv a0,a1 +80000708: 000680e7 jalr a3 +8000070c: fb9ff06f j 800006c4 <__call_exitprocs+0xd8> + +Disassembly of section .init_array: + +80001710 <__init_array_start>: +80001710: 0068 addi a0,sp,12 +80001712: 8000 0x8000 + +Disassembly of section .data: + +80001718 : +80001718: 0000 unimp +8000171a: 0000 unimp +8000171c: 1a04 addi s1,sp,304 +8000171e: 8000 0x8000 +80001720: 1a6c addi a1,sp,316 +80001722: 8000 0x8000 +80001724: 1ad4 addi a3,sp,372 +80001726: 8000 0x8000 + ... +800017c0: 0001 nop +800017c2: 0000 unimp +800017c4: 0000 unimp +800017c6: 0000 unimp +800017c8: 330e fld ft6,224(sp) +800017ca: abcd j 80001dbc <__BSS_END__+0x1f8> +800017cc: 1234 addi a3,sp,296 +800017ce: e66d bnez a2,800018b8 +800017d0: deec sw a1,124(a3) +800017d2: 0005 c.nop 1 +800017d4: 0000000b 0xb + ... + +Disassembly of section .sdata: + +80001b40 <_global_impure_ptr>: +80001b40: 1718 addi a4,sp,928 +80001b42: 8000 0x8000 + +Disassembly of section .bss: + +80001b44 : + ... + +Disassembly of section .comment: + +00000000 <.comment>: + 0: 3a434347 fmsub.d ft6,ft6,ft4,ft7,rmm + 4: 2820 fld fs0,80(s0) + 6: 29554e47 fmsub.s ft8,fa0,fs5,ft5,rmm + a: 3120 fld fs0,96(a0) + c: 2e30 fld fa2,88(a2) + e: 2e32 fld ft8,264(sp) + 10: 0030 addi a2,sp,8 + +Disassembly of section .riscv.attributes: + +00000000 <.riscv.attributes>: + 0: 2941 jal 490 <__stack_size+0x90> + 2: 0000 unimp + 4: 7200 flw fs0,32(a2) + 6: 7369 lui t1,0xffffa + 8: 01007663 bgeu zero,a6,14 <__stack_usage+0x14> + c: 001f 0000 1004 0x10040000001f + 12: 7205 lui tp,0xfffe1 + 14: 3376 fld ft6,376(sp) + 16: 6932 flw fs2,12(sp) + 18: 7032 flw ft0,44(sp) + 1a: 5f30 lw a2,120(a4) + 1c: 326d jal fffff9c6 <__stack_top+0xfff9c6> + 1e: 3070 fld fa2,224(s0) + 20: 665f 7032 0030 0x307032665f + 26: 0108 addi a0,sp,128 + 28: 0b0a slli s6,s6,0x2 diff --git a/driver/tests/stress/kernel.elf b/driver/tests/stress/kernel.elf new file mode 100755 index 0000000000000000000000000000000000000000..6c688f2fb9bc21e0b72cd66c38562dd3a4283de9 GIT binary patch literal 9036 zcmeHNU2GKB6+ZK~v$hdgGY&RMRZM2_+JH8Ov5HdlVIg)MOOZtbM5a5Q_{$Nr~pBws%dLs6BP+J#&)3&+waWo zV6#!BJVkxjYu`EZ-E;1_=boRt-WeZjdHJh?AduTcnxg`;nlRYCfk*^xqFT^;T16Fk zzR#Iq;cEF*BJK(gVVvjts-13uT1_(11$0k=&!p5!9w>RB}`3 zct%4ufSjBi8YBBh8_9+d+00GK4&5L_xfx22 zsw9oIlHr*r`&1oi)d9+SZjqthfgTS@0hR0w`07p4Yo}@I%={9sqrqO@Q*t9MF+Gjv z8uozjk7|LAX@W3|eT9;BzRB#+710ph3(eIvPMXI(kLNi$1mTe$tR#KQ0O^~4KzjWK zL9g2?%mtv+QfV%*YjUokaWWa8$z&ZZ*{1?D9v}<$T;M&V&%yR{vXCB~AmeAlWUDe6 zWq&4P@Jo_;{Q>MQBSXHAeGGz5h*|X`(U7k@V@BC9ncwsa=`oqo?>56OnKZeIX0Yzm z+Tlm`Z`M(lRYvLBOM>Jd5Yqk~g47@g>4r;${fPzpmtemL`$gC*vX6eOfZ#pI&9&nkl!BFXW6DZ;Q59BJI526t0s7jz8+*LOO6o zG6z*BUK~5sK;~8CEe--R+&gWLm+mD`{-{#E!Eb~^{1>Y~*Ce6aP3Yo887VX1}WWK4En{O#z z`;aH69a^C5@oCiVIP63Bqt}f?UKOVH-+W|Nd5HIy^;`~d{h!9e$?Wl0G4^}X)o~i} zKpuTW0Yx8?LD5GfQ1lTI6n#VhMIRwhbk=Fl&p&0K8lvp&8#r4OfhqD~f$P{^$NnzC zFP?|CC8A!{oS`m;49@~h9l5*!**PcPV;t{HmHCD$^I4^NQBUo6JX%eFOphWOX;sku zm%ZupnHr7jWbHI%@4Qd?x$1Sg|C-PC)RHOR5H+=$^s_Ul3CN#=50GDuo$A#p-M?5B zpAA1uk6x{D<&0_g0JvCQQ)Y98ocM(8)3@Mk__=xkxqy)onS&K_daT)JT89-) zzMr!PCvsD3n{vnl5&0=1Ke3h|q6P(N6V9kjuwygMsLjYwhOZs!epzl1?hLpnCJO4R==h;+f@-t+0qhCjN$Nt|aKWpc< z+W6xyn%4A8-~FqCC-kLO@<7Q0pN9u(@Y&t^;)`Fdt#57L+fci;F}N+*NIM#^b|RKE z50S7Qx3W)395S}Ww)HiJd-$>+7xD__|Ep9jwq2rpb?+*iNs{v>F8^LF&zG1G+rU&J ze1M~co^>%kFwmMGW9JQ=GsYJQejn4x6Y1#{6PW+SA{+$f zGqeU&#LriX_^rTOpzmUV-(AG-EyCX@!e$Zvb`d^UgkJ|{|J1`ZLcu?-2-|-WpsL_M z_Q;Qm@Gpz-?|}K8CJ35D*Kl2lr;G3s@LlZpC4_Pf{88Z^*er+j*D;1|+!)sZbG$6z zO1v>`0(Rr+!}peE;F|UM^;v#zfzK)`!9M_eOCswhz`WjTz~2F8KQev;7%j&ao__{- z7V%=t{IkG!@g2<%%J^1Z-a-xn3zP-k1-`5QD)2-hzkIOw8nByhj6VcU$z=Vdpnsa@ z7xIJk{}Z?g_Ei=59|ODj?1N(j{C&5qPoYzgTe)5t_%C5TzpG|_Uf??`_Olw;!Y^{t z;nSfb;bbb3NCkHXuz@7J`SbmhZzHB#?W7zBpA52C%qmNNC_F9xW!-w;d zkwj+_tliB!_Us7nY-w$44~Ky}yW<^^?r>i`)(h{DiwoQ9OJOM79qTYxnD34(ZyF&Vr=K`-Qkw@X2+b4WHKLA>WTIwqbcf%#Cj52A2%sKsokyI)X>o}N-CXs)iwLJ?#lmV*8X%_!a1=pY3n8$4cx+}*uwF`0=R~+$t zCU6U&^Eu9+7JOErlgq=9bI;g7XMHTkHHc1pZo17|xOoAT Date: Mon, 3 May 2021 12:53:15 -0700 Subject: [PATCH 36/55] minor update --- driver/Makefile | 8 +- driver/tests/stress/common.h | 2 +- driver/tests/stress/kernel.bin | Bin 6980 -> 7100 bytes driver/tests/stress/kernel.dump | 970 ++++++++++++++++---------------- driver/tests/stress/kernel.elf | Bin 9036 -> 9156 bytes 5 files changed, 507 insertions(+), 473 deletions(-) diff --git a/driver/Makefile b/driver/Makefile index 58de93a2..e015fbf5 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -1,4 +1,4 @@ -all: stub rtlsim simx opae +all: stub rtlsim simx opae tests stub: $(MAKE) -C stub @@ -12,10 +12,14 @@ rtlsim: simx: $(MAKE) -C simx +tests: + $(MAKE) -C tests + clean: $(MAKE) clean -C stub $(MAKE) clean -C opae $(MAKE) clean -C rtlsim $(MAKE) clean -C simx + $(MAKE) clean -C tests -.PHONY: all stub opae rtlsim simx clean \ No newline at end of file +.PHONY: all stub opae rtlsim simx tests clean \ No newline at end of file diff --git a/driver/tests/stress/common.h b/driver/tests/stress/common.h index 55c6dbab..843a4a4c 100644 --- a/driver/tests/stress/common.h +++ b/driver/tests/stress/common.h @@ -3,7 +3,7 @@ #define KERNEL_ARG_DEV_MEM_ADDR 0x7ffff000 -#define NUM_LOADS 2 +#define NUM_LOADS 8 struct kernel_arg_t { uint32_t num_tasks; diff --git a/driver/tests/stress/kernel.bin b/driver/tests/stress/kernel.bin index 63d2f799d4b47d9cd2bcca2a315a6f59334085bd..537c5f79445c1395dbcf43896358b20cefbbdf2a 100755 GIT binary patch delta 502 zcmZ9IziSjh9L3-4-0bG$IPMs78%_yFmc83FS`6fhfUZT(LW`6tVsl^uDJ-c#N<;T&%64 zVH}`4aL^WrrC7K@6SWirdMg3n-h&Nk5$B@%kA>9^~?J!j?vuv$= zQ@3nzzXR>}!M%Oxz-DHn1v%-12OXx85wi3b%qt)InjpRdzUuc`mVAVi9{4)}r5_Ps zpP9{oARO7C#^h80y*)vX&zKt6>>n`C#~08X$bCV12{}u@$W5Cp>;6Mmf0m{9gfXY>%DcWZUTPYO2=lIH|^cXqz93C z$?s41B3XP9sp9X@YgXaS3?c8$hFugbS?EQkRG6vdmBWk5f1@e$pztSW-W9LOvUAa> ZmY&rSeLmq)PZy7~@mV8&hY7I2XdDet zm|1{Pzh~OAb^YGayRMMFbc&{IMoSwLxOtiF2{?}MkZ)I0r`!?-P&+eFpx}%S3zDqY zInWGzG`mA+w^VWHRMmo#B0UoN0mOM0LcR=JBZU4d96EBFT?1NBhNDj*E^II}hfsfm zV|>aT9a_$SXi092kV${wy)&KF#lEtlD&K-D2Wq(=j+LmQR{G*g?Ws>majosBMqi9I zTQ7R@))O(Zw@f@1iFi)r$IaLYWLDc?yK8O@5tR|*i2: 80000000: 00000597 auipc a1,0x0 -80000004: 0f058593 addi a1,a1,240 # 800000f0 +80000004: 16858593 addi a1,a1,360 # 80000168 80000008: fc102573 csrr a0,0xfc1 8000000c: 00b5106b 0xb5106b -80000010: 0e0000ef jal ra,800000f0 +80000010: 158000ef jal ra,80000168 80000014: 00100513 li a0,1 80000018: 0005006b 0x5006b 8000001c: 00002517 auipc a0,0x2 -80000020: b2850513 addi a0,a0,-1240 # 80001b44 +80000020: ba050513 addi a0,a0,-1120 # 80001bbc 80000024: 00002617 auipc a2,0x2 -80000028: ba060613 addi a2,a2,-1120 # 80001bc4 <__BSS_END__> +80000028: c1860613 addi a2,a2,-1000 # 80001c3c <__BSS_END__> 8000002c: 40a60633 sub a2,a2,a0 80000030: 00000593 li a1,0 -80000034: 440000ef jal ra,80000474 +80000034: 4b8000ef jal ra,800004ec 80000038: 00000517 auipc a0,0x0 -8000003c: 34450513 addi a0,a0,836 # 8000037c <__libc_fini_array> -80000040: 2f4000ef jal ra,80000334 -80000044: 394000ef jal ra,800003d8 <__libc_init_array> +8000003c: 3bc50513 addi a0,a0,956 # 800003f4 <__libc_fini_array> +80000040: 36c000ef jal ra,800003ac +80000044: 40c000ef jal ra,80000450 <__libc_init_array> 80000048: 008000ef jal ra,80000050
    -8000004c: 2fc0006f j 80000348 +8000004c: 3740006f j 800003c0 Disassembly of section .text: @@ -34,502 +34,532 @@ Disassembly of section .text: 80000058: 800005b7 lui a1,0x80000 8000005c: 7ffff637 lui a2,0x7ffff 80000060: 08058593 addi a1,a1,128 # 80000080 <__stack_top+0x81000080> -80000064: 1880006f j 800001ec +80000064: 2000006f j 80000264 80000068 : 80000068: 00000793 li a5,0 8000006c: 00078863 beqz a5,8000007c 80000070: 80000537 lui a0,0x80000 -80000074: 37c50513 addi a0,a0,892 # 8000037c <__stack_top+0x8100037c> -80000078: 2bc0006f j 80000334 +80000074: 3f450513 addi a0,a0,1012 # 800003f4 <__stack_top+0x810003f4> +80000078: 3340006f j 800003ac 8000007c: 00008067 ret 80000080 : 80000080: 0085a783 lw a5,8(a1) -80000084: 00c5a683 lw a3,12(a1) -80000088: 0105a803 lw a6,16(a1) -8000008c: 02f50533 mul a0,a0,a5 -80000090: 0145a703 lw a4,20(a1) -80000094: 04078863 beqz a5,800000e4 -80000098: 00a785b3 add a1,a5,a0 -8000009c: 00259593 slli a1,a1,0x2 -800000a0: 00251793 slli a5,a0,0x2 -800000a4: 00d787b3 add a5,a5,a3 -800000a8: 00d585b3 add a1,a1,a3 -800000ac: 40d70533 sub a0,a4,a3 -800000b0: 0007a683 lw a3,0(a5) -800000b4: 0047a703 lw a4,4(a5) -800000b8: 00f50633 add a2,a0,a5 -800000bc: 00269693 slli a3,a3,0x2 -800000c0: 00271713 slli a4,a4,0x2 -800000c4: 00d806b3 add a3,a6,a3 -800000c8: 00e80733 add a4,a6,a4 -800000cc: 0006a683 lw a3,0(a3) -800000d0: 00072703 lw a4,0(a4) -800000d4: 00478793 addi a5,a5,4 -800000d8: 00d70733 add a4,a4,a3 -800000dc: 00e62023 sw a4,0(a2) # 7ffff000 <__stack_size+0x7fffec00> -800000e0: fcf598e3 bne a1,a5,800000b0 -800000e4: 00008067 ret +80000084: 00c5a803 lw a6,12(a1) +80000088: 0105a683 lw a3,16(a1) +8000008c: 02f50733 mul a4,a0,a5 +80000090: 0145ae83 lw t4,20(a1) +80000094: 0c078463 beqz a5,8000015c +80000098: 00e78e33 add t3,a5,a4 +8000009c: 002e1e13 slli t3,t3,0x2 +800000a0: 00271713 slli a4,a4,0x2 +800000a4: 01070633 add a2,a4,a6 +800000a8: 010e0e33 add t3,t3,a6 +800000ac: 410e8eb3 sub t4,t4,a6 +800000b0: 00062783 lw a5,0(a2) # 7ffff000 <__stack_size+0x7fffec00> +800000b4: 00462503 lw a0,4(a2) +800000b8: 00862583 lw a1,8(a2) +800000bc: 00c62303 lw t1,12(a2) +800000c0: 01062883 lw a7,16(a2) +800000c4: 00279793 slli a5,a5,0x2 +800000c8: 00251513 slli a0,a0,0x2 +800000cc: 01462803 lw a6,20(a2) +800000d0: 00a68533 add a0,a3,a0 +800000d4: 00f687b3 add a5,a3,a5 +800000d8: 00259593 slli a1,a1,0x2 +800000dc: 00052f83 lw t6,0(a0) +800000e0: 0007a783 lw a5,0(a5) +800000e4: 01862503 lw a0,24(a2) +800000e8: 00b685b3 add a1,a3,a1 +800000ec: 00231313 slli t1,t1,0x2 +800000f0: 0005af03 lw t5,0(a1) +800000f4: 00668333 add t1,a3,t1 +800000f8: 01c62583 lw a1,28(a2) +800000fc: 00289893 slli a7,a7,0x2 +80000100: 00032303 lw t1,0(t1) +80000104: 011688b3 add a7,a3,a7 +80000108: 00281813 slli a6,a6,0x2 +8000010c: 0008a883 lw a7,0(a7) +80000110: 01f787b3 add a5,a5,t6 +80000114: 01068833 add a6,a3,a6 +80000118: 00251513 slli a0,a0,0x2 +8000011c: 00082803 lw a6,0(a6) +80000120: 01e787b3 add a5,a5,t5 +80000124: 00a68533 add a0,a3,a0 +80000128: 00259593 slli a1,a1,0x2 +8000012c: 00052503 lw a0,0(a0) +80000130: 006787b3 add a5,a5,t1 +80000134: 00b685b3 add a1,a3,a1 +80000138: 0005a583 lw a1,0(a1) +8000013c: 011787b3 add a5,a5,a7 +80000140: 010787b3 add a5,a5,a6 +80000144: 00a787b3 add a5,a5,a0 +80000148: 00ce8733 add a4,t4,a2 +8000014c: 00f587b3 add a5,a1,a5 +80000150: 00460613 addi a2,a2,4 +80000154: 00f72023 sw a5,0(a4) +80000158: f4ce1ce3 bne t3,a2,800000b0 +8000015c: 00008067 ret -800000e8 <_exit>: -800000e8: 00000513 li a0,0 -800000ec: 0005006b 0x5006b +80000160 <_exit>: +80000160: 00000513 li a0,0 +80000164: 0005006b 0x5006b -800000f0 : -800000f0: fc002573 csrr a0,0xfc0 -800000f4: 0005006b 0x5006b -800000f8: 00002197 auipc gp,0x2 -800000fc: e2018193 addi gp,gp,-480 # 80001f18 <__global_pointer> -80000100: 7f000117 auipc sp,0x7f000 -80000104: f0010113 addi sp,sp,-256 # ff000000 <__stack_top> -80000108: 40000593 li a1,1024 -8000010c: cc102673 csrr a2,0xcc1 -80000110: 02c585b3 mul a1,a1,a2 -80000114: 40b10133 sub sp,sp,a1 -80000118: cc3026f3 csrr a3,0xcc3 -8000011c: 00068663 beqz a3,80000128 -80000120: 00000513 li a0,0 -80000124: 0005006b 0x5006b +80000168 : +80000168: fc002573 csrr a0,0xfc0 +8000016c: 0005006b 0x5006b +80000170: 00002197 auipc gp,0x2 +80000174: e2018193 addi gp,gp,-480 # 80001f90 <__global_pointer> +80000178: 7f000117 auipc sp,0x7f000 +8000017c: e8810113 addi sp,sp,-376 # ff000000 <__stack_top> +80000180: 40000593 li a1,1024 +80000184: cc102673 csrr a2,0xcc1 +80000188: 02c585b3 mul a1,a1,a2 +8000018c: 40b10133 sub sp,sp,a1 +80000190: cc3026f3 csrr a3,0xcc3 +80000194: 00068663 beqz a3,800001a0 +80000198: 00000513 li a0,0 +8000019c: 0005006b 0x5006b -80000128 : -80000128: 00008067 ret +800001a0 : +800001a0: 00008067 ret -8000012c : -8000012c: fe010113 addi sp,sp,-32 -80000130: 00112e23 sw ra,28(sp) -80000134: 00812c23 sw s0,24(sp) -80000138: 00912a23 sw s1,20(sp) -8000013c: 01212823 sw s2,16(sp) -80000140: 01312623 sw s3,12(sp) -80000144: fc0027f3 csrr a5,0xfc0 -80000148: 0007806b 0x7806b -8000014c: cc5027f3 csrr a5,0xcc5 -80000150: cc3029f3 csrr s3,0xcc3 -80000154: cc002773 csrr a4,0xcc0 -80000158: fc002673 csrr a2,0xfc0 -8000015c: 00279693 slli a3,a5,0x2 -80000160: 800027b7 lui a5,0x80002 -80000164: b4478793 addi a5,a5,-1212 # 80001b44 <__stack_top+0x81001b44> -80000168: 00d787b3 add a5,a5,a3 -8000016c: 0007a483 lw s1,0(a5) -80000170: 0104a403 lw s0,16(s1) -80000174: 00c4a683 lw a3,12(s1) -80000178: 0089a933 slt s2,s3,s0 -8000017c: 00040793 mv a5,s0 -80000180: 00d90933 add s2,s2,a3 -80000184: 03368433 mul s0,a3,s3 -80000188: 00f9d463 bge s3,a5,80000190 -8000018c: 00098793 mv a5,s3 -80000190: 00f40433 add s0,s0,a5 -80000194: 0084a683 lw a3,8(s1) -80000198: 02c40433 mul s0,s0,a2 -8000019c: 02e907b3 mul a5,s2,a4 -800001a0: 00d40433 add s0,s0,a3 -800001a4: 00f40433 add s0,s0,a5 -800001a8: 00890933 add s2,s2,s0 -800001ac: 01245e63 bge s0,s2,800001c8 -800001b0: 0004a783 lw a5,0(s1) -800001b4: 0044a583 lw a1,4(s1) -800001b8: 00040513 mv a0,s0 -800001bc: 00140413 addi s0,s0,1 -800001c0: 000780e7 jalr a5 -800001c4: fe8916e3 bne s2,s0,800001b0 -800001c8: 0019b993 seqz s3,s3 -800001cc: 0009806b 0x9806b -800001d0: 01c12083 lw ra,28(sp) -800001d4: 01812403 lw s0,24(sp) -800001d8: 01412483 lw s1,20(sp) -800001dc: 01012903 lw s2,16(sp) -800001e0: 00c12983 lw s3,12(sp) -800001e4: 02010113 addi sp,sp,32 -800001e8: 00008067 ret +800001a4 : +800001a4: fe010113 addi sp,sp,-32 +800001a8: 00112e23 sw ra,28(sp) +800001ac: 00812c23 sw s0,24(sp) +800001b0: 00912a23 sw s1,20(sp) +800001b4: 01212823 sw s2,16(sp) +800001b8: 01312623 sw s3,12(sp) +800001bc: fc0027f3 csrr a5,0xfc0 +800001c0: 0007806b 0x7806b +800001c4: cc5027f3 csrr a5,0xcc5 +800001c8: cc3029f3 csrr s3,0xcc3 +800001cc: cc002773 csrr a4,0xcc0 +800001d0: fc002673 csrr a2,0xfc0 +800001d4: 00279693 slli a3,a5,0x2 +800001d8: 800027b7 lui a5,0x80002 +800001dc: bbc78793 addi a5,a5,-1092 # 80001bbc <__stack_top+0x81001bbc> +800001e0: 00d787b3 add a5,a5,a3 +800001e4: 0007a483 lw s1,0(a5) +800001e8: 0104a403 lw s0,16(s1) +800001ec: 00c4a683 lw a3,12(s1) +800001f0: 0089a933 slt s2,s3,s0 +800001f4: 00040793 mv a5,s0 +800001f8: 00d90933 add s2,s2,a3 +800001fc: 03368433 mul s0,a3,s3 +80000200: 00f9d463 bge s3,a5,80000208 +80000204: 00098793 mv a5,s3 +80000208: 00f40433 add s0,s0,a5 +8000020c: 0084a683 lw a3,8(s1) +80000210: 02c40433 mul s0,s0,a2 +80000214: 02e907b3 mul a5,s2,a4 +80000218: 00d40433 add s0,s0,a3 +8000021c: 00f40433 add s0,s0,a5 +80000220: 00890933 add s2,s2,s0 +80000224: 01245e63 bge s0,s2,80000240 +80000228: 0004a783 lw a5,0(s1) +8000022c: 0044a583 lw a1,4(s1) +80000230: 00040513 mv a0,s0 +80000234: 00140413 addi s0,s0,1 +80000238: 000780e7 jalr a5 +8000023c: fe8916e3 bne s2,s0,80000228 +80000240: 0019b993 seqz s3,s3 +80000244: 0009806b 0x9806b +80000248: 01c12083 lw ra,28(sp) +8000024c: 01812403 lw s0,24(sp) +80000250: 01412483 lw s1,20(sp) +80000254: 01012903 lw s2,16(sp) +80000258: 00c12983 lw s3,12(sp) +8000025c: 02010113 addi sp,sp,32 +80000260: 00008067 ret -800001ec : -800001ec: fc010113 addi sp,sp,-64 -800001f0: 02112e23 sw ra,60(sp) -800001f4: 02812c23 sw s0,56(sp) -800001f8: 02912a23 sw s1,52(sp) -800001fc: 03212823 sw s2,48(sp) -80000200: 03312623 sw s3,44(sp) -80000204: fc2026f3 csrr a3,0xfc2 -80000208: fc102873 csrr a6,0xfc1 -8000020c: fc002473 csrr s0,0xfc0 -80000210: cc5027f3 csrr a5,0xcc5 -80000214: 01f00713 li a4,31 -80000218: 0cf74463 blt a4,a5,800002e0 -8000021c: 030408b3 mul a7,s0,a6 -80000220: 00100713 li a4,1 -80000224: 00a8d463 bge a7,a0,8000022c -80000228: 03154733 div a4,a0,a7 -8000022c: 0ce6c863 blt a3,a4,800002fc -80000230: 0ae7d863 bge a5,a4,800002e0 -80000234: fff68693 addi a3,a3,-1 -80000238: 02e54333 div t1,a0,a4 -8000023c: 00030893 mv a7,t1 -80000240: 00f69663 bne a3,a5,8000024c -80000244: 02e56533 rem a0,a0,a4 -80000248: 006508b3 add a7,a0,t1 -8000024c: 0288c4b3 div s1,a7,s0 -80000250: 0288e933 rem s2,a7,s0 -80000254: 0b04ca63 blt s1,a6,80000308 -80000258: 00100693 li a3,1 -8000025c: 0304c733 div a4,s1,a6 -80000260: 00070663 beqz a4,8000026c -80000264: 00070693 mv a3,a4 -80000268: 0304e733 rem a4,s1,a6 -8000026c: 800029b7 lui s3,0x80002 -80000270: b4498993 addi s3,s3,-1212 # 80001b44 <__stack_top+0x81001b44> -80000274: 00e12e23 sw a4,28(sp) -80000278: 00c10713 addi a4,sp,12 -8000027c: 00b12623 sw a1,12(sp) -80000280: 00c12823 sw a2,16(sp) -80000284: 00d12c23 sw a3,24(sp) -80000288: 02f30333 mul t1,t1,a5 -8000028c: 00279793 slli a5,a5,0x2 -80000290: 00f987b3 add a5,s3,a5 -80000294: 00e7a023 sw a4,0(a5) -80000298: 00612a23 sw t1,20(sp) -8000029c: 06904c63 bgtz s1,80000314 -800002a0: 04090063 beqz s2,800002e0 -800002a4: 02848433 mul s0,s1,s0 -800002a8: 00812a23 sw s0,20(sp) -800002ac: 0009006b 0x9006b -800002b0: cc5027f3 csrr a5,0xcc5 -800002b4: cc202573 csrr a0,0xcc2 -800002b8: 00279793 slli a5,a5,0x2 -800002bc: 00f989b3 add s3,s3,a5 -800002c0: 0009a783 lw a5,0(s3) -800002c4: 0087a683 lw a3,8(a5) -800002c8: 0007a703 lw a4,0(a5) -800002cc: 0047a583 lw a1,4(a5) -800002d0: 00d50533 add a0,a0,a3 -800002d4: 000700e7 jalr a4 -800002d8: 00100793 li a5,1 -800002dc: 0007806b 0x7806b -800002e0: 03c12083 lw ra,60(sp) -800002e4: 03812403 lw s0,56(sp) -800002e8: 03412483 lw s1,52(sp) -800002ec: 03012903 lw s2,48(sp) -800002f0: 02c12983 lw s3,44(sp) -800002f4: 04010113 addi sp,sp,64 -800002f8: 00008067 ret -800002fc: 00068713 mv a4,a3 -80000300: f2e7cae3 blt a5,a4,80000234 -80000304: fddff06f j 800002e0 -80000308: 00000713 li a4,0 -8000030c: 00100693 li a3,1 -80000310: f5dff06f j 8000026c -80000314: 00048713 mv a4,s1 -80000318: 00985463 bge a6,s1,80000320 -8000031c: 00080713 mv a4,a6 -80000320: 800007b7 lui a5,0x80000 -80000324: 12c78793 addi a5,a5,300 # 8000012c <__stack_top+0x8100012c> -80000328: 00f7106b 0xf7106b -8000032c: e01ff0ef jal ra,8000012c -80000330: f71ff06f j 800002a0 +80000264 : +80000264: fc010113 addi sp,sp,-64 +80000268: 02112e23 sw ra,60(sp) +8000026c: 02812c23 sw s0,56(sp) +80000270: 02912a23 sw s1,52(sp) +80000274: 03212823 sw s2,48(sp) +80000278: 03312623 sw s3,44(sp) +8000027c: fc2026f3 csrr a3,0xfc2 +80000280: fc102873 csrr a6,0xfc1 +80000284: fc002473 csrr s0,0xfc0 +80000288: cc5027f3 csrr a5,0xcc5 +8000028c: 01f00713 li a4,31 +80000290: 0cf74463 blt a4,a5,80000358 +80000294: 030408b3 mul a7,s0,a6 +80000298: 00100713 li a4,1 +8000029c: 00a8d463 bge a7,a0,800002a4 +800002a0: 03154733 div a4,a0,a7 +800002a4: 0ce6c863 blt a3,a4,80000374 +800002a8: 0ae7d863 bge a5,a4,80000358 +800002ac: fff68693 addi a3,a3,-1 +800002b0: 02e54333 div t1,a0,a4 +800002b4: 00030893 mv a7,t1 +800002b8: 00f69663 bne a3,a5,800002c4 +800002bc: 02e56533 rem a0,a0,a4 +800002c0: 006508b3 add a7,a0,t1 +800002c4: 0288c4b3 div s1,a7,s0 +800002c8: 0288e933 rem s2,a7,s0 +800002cc: 0b04ca63 blt s1,a6,80000380 +800002d0: 00100693 li a3,1 +800002d4: 0304c733 div a4,s1,a6 +800002d8: 00070663 beqz a4,800002e4 +800002dc: 00070693 mv a3,a4 +800002e0: 0304e733 rem a4,s1,a6 +800002e4: 800029b7 lui s3,0x80002 +800002e8: bbc98993 addi s3,s3,-1092 # 80001bbc <__stack_top+0x81001bbc> +800002ec: 00e12e23 sw a4,28(sp) +800002f0: 00c10713 addi a4,sp,12 +800002f4: 00b12623 sw a1,12(sp) +800002f8: 00c12823 sw a2,16(sp) +800002fc: 00d12c23 sw a3,24(sp) +80000300: 02f30333 mul t1,t1,a5 +80000304: 00279793 slli a5,a5,0x2 +80000308: 00f987b3 add a5,s3,a5 +8000030c: 00e7a023 sw a4,0(a5) +80000310: 00612a23 sw t1,20(sp) +80000314: 06904c63 bgtz s1,8000038c +80000318: 04090063 beqz s2,80000358 +8000031c: 02848433 mul s0,s1,s0 +80000320: 00812a23 sw s0,20(sp) +80000324: 0009006b 0x9006b +80000328: cc5027f3 csrr a5,0xcc5 +8000032c: cc202573 csrr a0,0xcc2 +80000330: 00279793 slli a5,a5,0x2 +80000334: 00f989b3 add s3,s3,a5 +80000338: 0009a783 lw a5,0(s3) +8000033c: 0087a683 lw a3,8(a5) +80000340: 0007a703 lw a4,0(a5) +80000344: 0047a583 lw a1,4(a5) +80000348: 00d50533 add a0,a0,a3 +8000034c: 000700e7 jalr a4 +80000350: 00100793 li a5,1 +80000354: 0007806b 0x7806b +80000358: 03c12083 lw ra,60(sp) +8000035c: 03812403 lw s0,56(sp) +80000360: 03412483 lw s1,52(sp) +80000364: 03012903 lw s2,48(sp) +80000368: 02c12983 lw s3,44(sp) +8000036c: 04010113 addi sp,sp,64 +80000370: 00008067 ret +80000374: 00068713 mv a4,a3 +80000378: f2e7cae3 blt a5,a4,800002ac +8000037c: fddff06f j 80000358 +80000380: 00000713 li a4,0 +80000384: 00100693 li a3,1 +80000388: f5dff06f j 800002e4 +8000038c: 00048713 mv a4,s1 +80000390: 00985463 bge a6,s1,80000398 +80000394: 00080713 mv a4,a6 +80000398: 800007b7 lui a5,0x80000 +8000039c: 1a478793 addi a5,a5,420 # 800001a4 <__stack_top+0x810001a4> +800003a0: 00f7106b 0xf7106b +800003a4: e01ff0ef jal ra,800001a4 +800003a8: f71ff06f j 80000318 -80000334 : -80000334: 00050593 mv a1,a0 -80000338: 00000693 li a3,0 -8000033c: 00000613 li a2,0 -80000340: 00000513 li a0,0 -80000344: 20c0006f j 80000550 <__register_exitproc> +800003ac : +800003ac: 00050593 mv a1,a0 +800003b0: 00000693 li a3,0 +800003b4: 00000613 li a2,0 +800003b8: 00000513 li a0,0 +800003bc: 20c0006f j 800005c8 <__register_exitproc> -80000348 : -80000348: ff010113 addi sp,sp,-16 -8000034c: 00000593 li a1,0 -80000350: 00812423 sw s0,8(sp) -80000354: 00112623 sw ra,12(sp) -80000358: 00050413 mv s0,a0 -8000035c: 290000ef jal ra,800005ec <__call_exitprocs> -80000360: 800027b7 lui a5,0x80002 -80000364: b407a503 lw a0,-1216(a5) # 80001b40 <__stack_top+0x81001b40> -80000368: 03c52783 lw a5,60(a0) -8000036c: 00078463 beqz a5,80000374 -80000370: 000780e7 jalr a5 -80000374: 00040513 mv a0,s0 -80000378: d71ff0ef jal ra,800000e8 <_exit> +800003c0 : +800003c0: ff010113 addi sp,sp,-16 +800003c4: 00000593 li a1,0 +800003c8: 00812423 sw s0,8(sp) +800003cc: 00112623 sw ra,12(sp) +800003d0: 00050413 mv s0,a0 +800003d4: 290000ef jal ra,80000664 <__call_exitprocs> +800003d8: 800027b7 lui a5,0x80002 +800003dc: bb87a503 lw a0,-1096(a5) # 80001bb8 <__stack_top+0x81001bb8> +800003e0: 03c52783 lw a5,60(a0) +800003e4: 00078463 beqz a5,800003ec +800003e8: 000780e7 jalr a5 +800003ec: 00040513 mv a0,s0 +800003f0: d71ff0ef jal ra,80000160 <_exit> -8000037c <__libc_fini_array>: -8000037c: ff010113 addi sp,sp,-16 -80000380: 00812423 sw s0,8(sp) -80000384: 800017b7 lui a5,0x80001 -80000388: 80001437 lui s0,0x80001 -8000038c: 71440413 addi s0,s0,1812 # 80001714 <__stack_top+0x81001714> -80000390: 71478793 addi a5,a5,1812 # 80001714 <__stack_top+0x81001714> -80000394: 408787b3 sub a5,a5,s0 -80000398: 00912223 sw s1,4(sp) -8000039c: 00112623 sw ra,12(sp) -800003a0: 4027d493 srai s1,a5,0x2 -800003a4: 02048063 beqz s1,800003c4 <__libc_fini_array+0x48> -800003a8: ffc78793 addi a5,a5,-4 -800003ac: 00878433 add s0,a5,s0 -800003b0: 00042783 lw a5,0(s0) -800003b4: fff48493 addi s1,s1,-1 -800003b8: ffc40413 addi s0,s0,-4 -800003bc: 000780e7 jalr a5 -800003c0: fe0498e3 bnez s1,800003b0 <__libc_fini_array+0x34> -800003c4: 00c12083 lw ra,12(sp) -800003c8: 00812403 lw s0,8(sp) -800003cc: 00412483 lw s1,4(sp) -800003d0: 01010113 addi sp,sp,16 -800003d4: 00008067 ret +800003f4 <__libc_fini_array>: +800003f4: ff010113 addi sp,sp,-16 +800003f8: 00812423 sw s0,8(sp) +800003fc: 800017b7 lui a5,0x80001 +80000400: 80001437 lui s0,0x80001 +80000404: 78c40413 addi s0,s0,1932 # 8000178c <__stack_top+0x8100178c> +80000408: 78c78793 addi a5,a5,1932 # 8000178c <__stack_top+0x8100178c> +8000040c: 408787b3 sub a5,a5,s0 +80000410: 00912223 sw s1,4(sp) +80000414: 00112623 sw ra,12(sp) +80000418: 4027d493 srai s1,a5,0x2 +8000041c: 02048063 beqz s1,8000043c <__libc_fini_array+0x48> +80000420: ffc78793 addi a5,a5,-4 +80000424: 00878433 add s0,a5,s0 +80000428: 00042783 lw a5,0(s0) +8000042c: fff48493 addi s1,s1,-1 +80000430: ffc40413 addi s0,s0,-4 +80000434: 000780e7 jalr a5 +80000438: fe0498e3 bnez s1,80000428 <__libc_fini_array+0x34> +8000043c: 00c12083 lw ra,12(sp) +80000440: 00812403 lw s0,8(sp) +80000444: 00412483 lw s1,4(sp) +80000448: 01010113 addi sp,sp,16 +8000044c: 00008067 ret -800003d8 <__libc_init_array>: -800003d8: ff010113 addi sp,sp,-16 -800003dc: 00812423 sw s0,8(sp) -800003e0: 01212023 sw s2,0(sp) -800003e4: 80001437 lui s0,0x80001 -800003e8: 80001937 lui s2,0x80001 -800003ec: 71040793 addi a5,s0,1808 # 80001710 <__stack_top+0x81001710> -800003f0: 71090913 addi s2,s2,1808 # 80001710 <__stack_top+0x81001710> -800003f4: 40f90933 sub s2,s2,a5 -800003f8: 00112623 sw ra,12(sp) -800003fc: 00912223 sw s1,4(sp) -80000400: 40295913 srai s2,s2,0x2 -80000404: 02090063 beqz s2,80000424 <__libc_init_array+0x4c> -80000408: 71040413 addi s0,s0,1808 -8000040c: 00000493 li s1,0 -80000410: 00042783 lw a5,0(s0) -80000414: 00148493 addi s1,s1,1 -80000418: 00440413 addi s0,s0,4 -8000041c: 000780e7 jalr a5 -80000420: fe9918e3 bne s2,s1,80000410 <__libc_init_array+0x38> -80000424: 80001437 lui s0,0x80001 -80000428: 80001937 lui s2,0x80001 -8000042c: 71040793 addi a5,s0,1808 # 80001710 <__stack_top+0x81001710> -80000430: 71490913 addi s2,s2,1812 # 80001714 <__stack_top+0x81001714> -80000434: 40f90933 sub s2,s2,a5 -80000438: 40295913 srai s2,s2,0x2 -8000043c: 02090063 beqz s2,8000045c <__libc_init_array+0x84> -80000440: 71040413 addi s0,s0,1808 -80000444: 00000493 li s1,0 -80000448: 00042783 lw a5,0(s0) -8000044c: 00148493 addi s1,s1,1 -80000450: 00440413 addi s0,s0,4 -80000454: 000780e7 jalr a5 -80000458: fe9918e3 bne s2,s1,80000448 <__libc_init_array+0x70> -8000045c: 00c12083 lw ra,12(sp) -80000460: 00812403 lw s0,8(sp) -80000464: 00412483 lw s1,4(sp) -80000468: 00012903 lw s2,0(sp) -8000046c: 01010113 addi sp,sp,16 -80000470: 00008067 ret +80000450 <__libc_init_array>: +80000450: ff010113 addi sp,sp,-16 +80000454: 00812423 sw s0,8(sp) +80000458: 01212023 sw s2,0(sp) +8000045c: 80001437 lui s0,0x80001 +80000460: 80001937 lui s2,0x80001 +80000464: 78840793 addi a5,s0,1928 # 80001788 <__stack_top+0x81001788> +80000468: 78890913 addi s2,s2,1928 # 80001788 <__stack_top+0x81001788> +8000046c: 40f90933 sub s2,s2,a5 +80000470: 00112623 sw ra,12(sp) +80000474: 00912223 sw s1,4(sp) +80000478: 40295913 srai s2,s2,0x2 +8000047c: 02090063 beqz s2,8000049c <__libc_init_array+0x4c> +80000480: 78840413 addi s0,s0,1928 +80000484: 00000493 li s1,0 +80000488: 00042783 lw a5,0(s0) +8000048c: 00148493 addi s1,s1,1 +80000490: 00440413 addi s0,s0,4 +80000494: 000780e7 jalr a5 +80000498: fe9918e3 bne s2,s1,80000488 <__libc_init_array+0x38> +8000049c: 80001437 lui s0,0x80001 +800004a0: 80001937 lui s2,0x80001 +800004a4: 78840793 addi a5,s0,1928 # 80001788 <__stack_top+0x81001788> +800004a8: 78c90913 addi s2,s2,1932 # 8000178c <__stack_top+0x8100178c> +800004ac: 40f90933 sub s2,s2,a5 +800004b0: 40295913 srai s2,s2,0x2 +800004b4: 02090063 beqz s2,800004d4 <__libc_init_array+0x84> +800004b8: 78840413 addi s0,s0,1928 +800004bc: 00000493 li s1,0 +800004c0: 00042783 lw a5,0(s0) +800004c4: 00148493 addi s1,s1,1 +800004c8: 00440413 addi s0,s0,4 +800004cc: 000780e7 jalr a5 +800004d0: fe9918e3 bne s2,s1,800004c0 <__libc_init_array+0x70> +800004d4: 00c12083 lw ra,12(sp) +800004d8: 00812403 lw s0,8(sp) +800004dc: 00412483 lw s1,4(sp) +800004e0: 00012903 lw s2,0(sp) +800004e4: 01010113 addi sp,sp,16 +800004e8: 00008067 ret -80000474 : -80000474: 00f00313 li t1,15 -80000478: 00050713 mv a4,a0 -8000047c: 02c37e63 bgeu t1,a2,800004b8 -80000480: 00f77793 andi a5,a4,15 -80000484: 0a079063 bnez a5,80000524 -80000488: 08059263 bnez a1,8000050c -8000048c: ff067693 andi a3,a2,-16 -80000490: 00f67613 andi a2,a2,15 -80000494: 00e686b3 add a3,a3,a4 -80000498: 00b72023 sw a1,0(a4) -8000049c: 00b72223 sw a1,4(a4) -800004a0: 00b72423 sw a1,8(a4) -800004a4: 00b72623 sw a1,12(a4) -800004a8: 01070713 addi a4,a4,16 -800004ac: fed766e3 bltu a4,a3,80000498 -800004b0: 00061463 bnez a2,800004b8 -800004b4: 00008067 ret -800004b8: 40c306b3 sub a3,t1,a2 -800004bc: 00269693 slli a3,a3,0x2 -800004c0: 00000297 auipc t0,0x0 -800004c4: 005686b3 add a3,a3,t0 -800004c8: 00c68067 jr 12(a3) -800004cc: 00b70723 sb a1,14(a4) -800004d0: 00b706a3 sb a1,13(a4) -800004d4: 00b70623 sb a1,12(a4) -800004d8: 00b705a3 sb a1,11(a4) -800004dc: 00b70523 sb a1,10(a4) -800004e0: 00b704a3 sb a1,9(a4) -800004e4: 00b70423 sb a1,8(a4) -800004e8: 00b703a3 sb a1,7(a4) -800004ec: 00b70323 sb a1,6(a4) -800004f0: 00b702a3 sb a1,5(a4) -800004f4: 00b70223 sb a1,4(a4) -800004f8: 00b701a3 sb a1,3(a4) -800004fc: 00b70123 sb a1,2(a4) -80000500: 00b700a3 sb a1,1(a4) -80000504: 00b70023 sb a1,0(a4) -80000508: 00008067 ret -8000050c: 0ff5f593 andi a1,a1,255 -80000510: 00859693 slli a3,a1,0x8 -80000514: 00d5e5b3 or a1,a1,a3 -80000518: 01059693 slli a3,a1,0x10 -8000051c: 00d5e5b3 or a1,a1,a3 -80000520: f6dff06f j 8000048c -80000524: 00279693 slli a3,a5,0x2 -80000528: 00000297 auipc t0,0x0 -8000052c: 005686b3 add a3,a3,t0 -80000530: 00008293 mv t0,ra -80000534: fa0680e7 jalr -96(a3) -80000538: 00028093 mv ra,t0 -8000053c: ff078793 addi a5,a5,-16 -80000540: 40f70733 sub a4,a4,a5 -80000544: 00f60633 add a2,a2,a5 -80000548: f6c378e3 bgeu t1,a2,800004b8 -8000054c: f3dff06f j 80000488 +800004ec : +800004ec: 00f00313 li t1,15 +800004f0: 00050713 mv a4,a0 +800004f4: 02c37e63 bgeu t1,a2,80000530 +800004f8: 00f77793 andi a5,a4,15 +800004fc: 0a079063 bnez a5,8000059c +80000500: 08059263 bnez a1,80000584 +80000504: ff067693 andi a3,a2,-16 +80000508: 00f67613 andi a2,a2,15 +8000050c: 00e686b3 add a3,a3,a4 +80000510: 00b72023 sw a1,0(a4) +80000514: 00b72223 sw a1,4(a4) +80000518: 00b72423 sw a1,8(a4) +8000051c: 00b72623 sw a1,12(a4) +80000520: 01070713 addi a4,a4,16 +80000524: fed766e3 bltu a4,a3,80000510 +80000528: 00061463 bnez a2,80000530 +8000052c: 00008067 ret +80000530: 40c306b3 sub a3,t1,a2 +80000534: 00269693 slli a3,a3,0x2 +80000538: 00000297 auipc t0,0x0 +8000053c: 005686b3 add a3,a3,t0 +80000540: 00c68067 jr 12(a3) +80000544: 00b70723 sb a1,14(a4) +80000548: 00b706a3 sb a1,13(a4) +8000054c: 00b70623 sb a1,12(a4) +80000550: 00b705a3 sb a1,11(a4) +80000554: 00b70523 sb a1,10(a4) +80000558: 00b704a3 sb a1,9(a4) +8000055c: 00b70423 sb a1,8(a4) +80000560: 00b703a3 sb a1,7(a4) +80000564: 00b70323 sb a1,6(a4) +80000568: 00b702a3 sb a1,5(a4) +8000056c: 00b70223 sb a1,4(a4) +80000570: 00b701a3 sb a1,3(a4) +80000574: 00b70123 sb a1,2(a4) +80000578: 00b700a3 sb a1,1(a4) +8000057c: 00b70023 sb a1,0(a4) +80000580: 00008067 ret +80000584: 0ff5f593 andi a1,a1,255 +80000588: 00859693 slli a3,a1,0x8 +8000058c: 00d5e5b3 or a1,a1,a3 +80000590: 01059693 slli a3,a1,0x10 +80000594: 00d5e5b3 or a1,a1,a3 +80000598: f6dff06f j 80000504 +8000059c: 00279693 slli a3,a5,0x2 +800005a0: 00000297 auipc t0,0x0 +800005a4: 005686b3 add a3,a3,t0 +800005a8: 00008293 mv t0,ra +800005ac: fa0680e7 jalr -96(a3) +800005b0: 00028093 mv ra,t0 +800005b4: ff078793 addi a5,a5,-16 +800005b8: 40f70733 sub a4,a4,a5 +800005bc: 00f60633 add a2,a2,a5 +800005c0: f6c378e3 bgeu t1,a2,80000530 +800005c4: f3dff06f j 80000500 -80000550 <__register_exitproc>: -80000550: 800027b7 lui a5,0x80002 -80000554: b407a703 lw a4,-1216(a5) # 80001b40 <__stack_top+0x81001b40> -80000558: 14872783 lw a5,328(a4) -8000055c: 04078c63 beqz a5,800005b4 <__register_exitproc+0x64> -80000560: 0047a703 lw a4,4(a5) -80000564: 01f00813 li a6,31 -80000568: 06e84e63 blt a6,a4,800005e4 <__register_exitproc+0x94> -8000056c: 00271813 slli a6,a4,0x2 -80000570: 02050663 beqz a0,8000059c <__register_exitproc+0x4c> -80000574: 01078333 add t1,a5,a6 -80000578: 08c32423 sw a2,136(t1) -8000057c: 1887a883 lw a7,392(a5) -80000580: 00100613 li a2,1 -80000584: 00e61633 sll a2,a2,a4 -80000588: 00c8e8b3 or a7,a7,a2 -8000058c: 1917a423 sw a7,392(a5) -80000590: 10d32423 sw a3,264(t1) -80000594: 00200693 li a3,2 -80000598: 02d50463 beq a0,a3,800005c0 <__register_exitproc+0x70> -8000059c: 00170713 addi a4,a4,1 -800005a0: 00e7a223 sw a4,4(a5) -800005a4: 010787b3 add a5,a5,a6 -800005a8: 00b7a423 sw a1,8(a5) -800005ac: 00000513 li a0,0 -800005b0: 00008067 ret -800005b4: 14c70793 addi a5,a4,332 -800005b8: 14f72423 sw a5,328(a4) -800005bc: fa5ff06f j 80000560 <__register_exitproc+0x10> -800005c0: 18c7a683 lw a3,396(a5) -800005c4: 00170713 addi a4,a4,1 -800005c8: 00e7a223 sw a4,4(a5) -800005cc: 00c6e633 or a2,a3,a2 -800005d0: 18c7a623 sw a2,396(a5) -800005d4: 010787b3 add a5,a5,a6 -800005d8: 00b7a423 sw a1,8(a5) -800005dc: 00000513 li a0,0 -800005e0: 00008067 ret -800005e4: fff00513 li a0,-1 -800005e8: 00008067 ret +800005c8 <__register_exitproc>: +800005c8: 800027b7 lui a5,0x80002 +800005cc: bb87a703 lw a4,-1096(a5) # 80001bb8 <__stack_top+0x81001bb8> +800005d0: 14872783 lw a5,328(a4) +800005d4: 04078c63 beqz a5,8000062c <__register_exitproc+0x64> +800005d8: 0047a703 lw a4,4(a5) +800005dc: 01f00813 li a6,31 +800005e0: 06e84e63 blt a6,a4,8000065c <__register_exitproc+0x94> +800005e4: 00271813 slli a6,a4,0x2 +800005e8: 02050663 beqz a0,80000614 <__register_exitproc+0x4c> +800005ec: 01078333 add t1,a5,a6 +800005f0: 08c32423 sw a2,136(t1) +800005f4: 1887a883 lw a7,392(a5) +800005f8: 00100613 li a2,1 +800005fc: 00e61633 sll a2,a2,a4 +80000600: 00c8e8b3 or a7,a7,a2 +80000604: 1917a423 sw a7,392(a5) +80000608: 10d32423 sw a3,264(t1) +8000060c: 00200693 li a3,2 +80000610: 02d50463 beq a0,a3,80000638 <__register_exitproc+0x70> +80000614: 00170713 addi a4,a4,1 +80000618: 00e7a223 sw a4,4(a5) +8000061c: 010787b3 add a5,a5,a6 +80000620: 00b7a423 sw a1,8(a5) +80000624: 00000513 li a0,0 +80000628: 00008067 ret +8000062c: 14c70793 addi a5,a4,332 +80000630: 14f72423 sw a5,328(a4) +80000634: fa5ff06f j 800005d8 <__register_exitproc+0x10> +80000638: 18c7a683 lw a3,396(a5) +8000063c: 00170713 addi a4,a4,1 +80000640: 00e7a223 sw a4,4(a5) +80000644: 00c6e633 or a2,a3,a2 +80000648: 18c7a623 sw a2,396(a5) +8000064c: 010787b3 add a5,a5,a6 +80000650: 00b7a423 sw a1,8(a5) +80000654: 00000513 li a0,0 +80000658: 00008067 ret +8000065c: fff00513 li a0,-1 +80000660: 00008067 ret -800005ec <__call_exitprocs>: -800005ec: fd010113 addi sp,sp,-48 -800005f0: 800027b7 lui a5,0x80002 -800005f4: 01412c23 sw s4,24(sp) -800005f8: b407aa03 lw s4,-1216(a5) # 80001b40 <__stack_top+0x81001b40> -800005fc: 03212023 sw s2,32(sp) -80000600: 02112623 sw ra,44(sp) -80000604: 148a2903 lw s2,328(s4) -80000608: 02812423 sw s0,40(sp) -8000060c: 02912223 sw s1,36(sp) -80000610: 01312e23 sw s3,28(sp) -80000614: 01512a23 sw s5,20(sp) -80000618: 01612823 sw s6,16(sp) -8000061c: 01712623 sw s7,12(sp) -80000620: 01812423 sw s8,8(sp) -80000624: 04090063 beqz s2,80000664 <__call_exitprocs+0x78> -80000628: 00050b13 mv s6,a0 -8000062c: 00058b93 mv s7,a1 -80000630: 00100a93 li s5,1 -80000634: fff00993 li s3,-1 -80000638: 00492483 lw s1,4(s2) -8000063c: fff48413 addi s0,s1,-1 -80000640: 02044263 bltz s0,80000664 <__call_exitprocs+0x78> -80000644: 00249493 slli s1,s1,0x2 -80000648: 009904b3 add s1,s2,s1 -8000064c: 040b8463 beqz s7,80000694 <__call_exitprocs+0xa8> -80000650: 1044a783 lw a5,260(s1) -80000654: 05778063 beq a5,s7,80000694 <__call_exitprocs+0xa8> -80000658: fff40413 addi s0,s0,-1 -8000065c: ffc48493 addi s1,s1,-4 -80000660: ff3416e3 bne s0,s3,8000064c <__call_exitprocs+0x60> -80000664: 02c12083 lw ra,44(sp) -80000668: 02812403 lw s0,40(sp) -8000066c: 02412483 lw s1,36(sp) -80000670: 02012903 lw s2,32(sp) -80000674: 01c12983 lw s3,28(sp) -80000678: 01812a03 lw s4,24(sp) -8000067c: 01412a83 lw s5,20(sp) -80000680: 01012b03 lw s6,16(sp) -80000684: 00c12b83 lw s7,12(sp) -80000688: 00812c03 lw s8,8(sp) -8000068c: 03010113 addi sp,sp,48 -80000690: 00008067 ret -80000694: 00492783 lw a5,4(s2) -80000698: 0044a683 lw a3,4(s1) -8000069c: fff78793 addi a5,a5,-1 -800006a0: 04878e63 beq a5,s0,800006fc <__call_exitprocs+0x110> -800006a4: 0004a223 sw zero,4(s1) -800006a8: fa0688e3 beqz a3,80000658 <__call_exitprocs+0x6c> -800006ac: 18892783 lw a5,392(s2) -800006b0: 008a9733 sll a4,s5,s0 -800006b4: 00492c03 lw s8,4(s2) -800006b8: 00f777b3 and a5,a4,a5 -800006bc: 02079263 bnez a5,800006e0 <__call_exitprocs+0xf4> -800006c0: 000680e7 jalr a3 -800006c4: 00492703 lw a4,4(s2) -800006c8: 148a2783 lw a5,328(s4) -800006cc: 01871463 bne a4,s8,800006d4 <__call_exitprocs+0xe8> -800006d0: f92784e3 beq a5,s2,80000658 <__call_exitprocs+0x6c> -800006d4: f80788e3 beqz a5,80000664 <__call_exitprocs+0x78> -800006d8: 00078913 mv s2,a5 -800006dc: f5dff06f j 80000638 <__call_exitprocs+0x4c> -800006e0: 18c92783 lw a5,396(s2) -800006e4: 0844a583 lw a1,132(s1) -800006e8: 00f77733 and a4,a4,a5 -800006ec: 00071c63 bnez a4,80000704 <__call_exitprocs+0x118> -800006f0: 000b0513 mv a0,s6 -800006f4: 000680e7 jalr a3 -800006f8: fcdff06f j 800006c4 <__call_exitprocs+0xd8> -800006fc: 00892223 sw s0,4(s2) -80000700: fa9ff06f j 800006a8 <__call_exitprocs+0xbc> -80000704: 00058513 mv a0,a1 -80000708: 000680e7 jalr a3 -8000070c: fb9ff06f j 800006c4 <__call_exitprocs+0xd8> +80000664 <__call_exitprocs>: +80000664: fd010113 addi sp,sp,-48 +80000668: 800027b7 lui a5,0x80002 +8000066c: 01412c23 sw s4,24(sp) +80000670: bb87aa03 lw s4,-1096(a5) # 80001bb8 <__stack_top+0x81001bb8> +80000674: 03212023 sw s2,32(sp) +80000678: 02112623 sw ra,44(sp) +8000067c: 148a2903 lw s2,328(s4) +80000680: 02812423 sw s0,40(sp) +80000684: 02912223 sw s1,36(sp) +80000688: 01312e23 sw s3,28(sp) +8000068c: 01512a23 sw s5,20(sp) +80000690: 01612823 sw s6,16(sp) +80000694: 01712623 sw s7,12(sp) +80000698: 01812423 sw s8,8(sp) +8000069c: 04090063 beqz s2,800006dc <__call_exitprocs+0x78> +800006a0: 00050b13 mv s6,a0 +800006a4: 00058b93 mv s7,a1 +800006a8: 00100a93 li s5,1 +800006ac: fff00993 li s3,-1 +800006b0: 00492483 lw s1,4(s2) +800006b4: fff48413 addi s0,s1,-1 +800006b8: 02044263 bltz s0,800006dc <__call_exitprocs+0x78> +800006bc: 00249493 slli s1,s1,0x2 +800006c0: 009904b3 add s1,s2,s1 +800006c4: 040b8463 beqz s7,8000070c <__call_exitprocs+0xa8> +800006c8: 1044a783 lw a5,260(s1) +800006cc: 05778063 beq a5,s7,8000070c <__call_exitprocs+0xa8> +800006d0: fff40413 addi s0,s0,-1 +800006d4: ffc48493 addi s1,s1,-4 +800006d8: ff3416e3 bne s0,s3,800006c4 <__call_exitprocs+0x60> +800006dc: 02c12083 lw ra,44(sp) +800006e0: 02812403 lw s0,40(sp) +800006e4: 02412483 lw s1,36(sp) +800006e8: 02012903 lw s2,32(sp) +800006ec: 01c12983 lw s3,28(sp) +800006f0: 01812a03 lw s4,24(sp) +800006f4: 01412a83 lw s5,20(sp) +800006f8: 01012b03 lw s6,16(sp) +800006fc: 00c12b83 lw s7,12(sp) +80000700: 00812c03 lw s8,8(sp) +80000704: 03010113 addi sp,sp,48 +80000708: 00008067 ret +8000070c: 00492783 lw a5,4(s2) +80000710: 0044a683 lw a3,4(s1) +80000714: fff78793 addi a5,a5,-1 +80000718: 04878e63 beq a5,s0,80000774 <__call_exitprocs+0x110> +8000071c: 0004a223 sw zero,4(s1) +80000720: fa0688e3 beqz a3,800006d0 <__call_exitprocs+0x6c> +80000724: 18892783 lw a5,392(s2) +80000728: 008a9733 sll a4,s5,s0 +8000072c: 00492c03 lw s8,4(s2) +80000730: 00f777b3 and a5,a4,a5 +80000734: 02079263 bnez a5,80000758 <__call_exitprocs+0xf4> +80000738: 000680e7 jalr a3 +8000073c: 00492703 lw a4,4(s2) +80000740: 148a2783 lw a5,328(s4) +80000744: 01871463 bne a4,s8,8000074c <__call_exitprocs+0xe8> +80000748: f92784e3 beq a5,s2,800006d0 <__call_exitprocs+0x6c> +8000074c: f80788e3 beqz a5,800006dc <__call_exitprocs+0x78> +80000750: 00078913 mv s2,a5 +80000754: f5dff06f j 800006b0 <__call_exitprocs+0x4c> +80000758: 18c92783 lw a5,396(s2) +8000075c: 0844a583 lw a1,132(s1) +80000760: 00f77733 and a4,a4,a5 +80000764: 00071c63 bnez a4,8000077c <__call_exitprocs+0x118> +80000768: 000b0513 mv a0,s6 +8000076c: 000680e7 jalr a3 +80000770: fcdff06f j 8000073c <__call_exitprocs+0xd8> +80000774: 00892223 sw s0,4(s2) +80000778: fa9ff06f j 80000720 <__call_exitprocs+0xbc> +8000077c: 00058513 mv a0,a1 +80000780: 000680e7 jalr a3 +80000784: fb9ff06f j 8000073c <__call_exitprocs+0xd8> Disassembly of section .init_array: -80001710 <__init_array_start>: -80001710: 0068 addi a0,sp,12 -80001712: 8000 0x8000 +80001788 <__init_array_start>: +80001788: 0068 addi a0,sp,12 +8000178a: 8000 0x8000 Disassembly of section .data: -80001718 : -80001718: 0000 unimp -8000171a: 0000 unimp -8000171c: 1a04 addi s1,sp,304 -8000171e: 8000 0x8000 -80001720: 1a6c addi a1,sp,316 -80001722: 8000 0x8000 -80001724: 1ad4 addi a3,sp,372 -80001726: 8000 0x8000 +80001790 : +80001790: 0000 unimp +80001792: 0000 unimp +80001794: 1a7c addi a5,sp,316 +80001796: 8000 0x8000 +80001798: 1ae4 addi s1,sp,380 +8000179a: 8000 0x8000 +8000179c: 1b4c addi a1,sp,436 +8000179e: 8000 0x8000 ... -800017c0: 0001 nop -800017c2: 0000 unimp -800017c4: 0000 unimp -800017c6: 0000 unimp -800017c8: 330e fld ft6,224(sp) -800017ca: abcd j 80001dbc <__BSS_END__+0x1f8> -800017cc: 1234 addi a3,sp,296 -800017ce: e66d bnez a2,800018b8 -800017d0: deec sw a1,124(a3) -800017d2: 0005 c.nop 1 -800017d4: 0000000b 0xb +80001838: 0001 nop +8000183a: 0000 unimp +8000183c: 0000 unimp +8000183e: 0000 unimp +80001840: 330e fld ft6,224(sp) +80001842: abcd j 80001e34 <__BSS_END__+0x1f8> +80001844: 1234 addi a3,sp,296 +80001846: e66d bnez a2,80001930 +80001848: deec sw a1,124(a3) +8000184a: 0005 c.nop 1 +8000184c: 0000000b 0xb ... Disassembly of section .sdata: -80001b40 <_global_impure_ptr>: -80001b40: 1718 addi a4,sp,928 -80001b42: 8000 0x8000 +80001bb8 <_global_impure_ptr>: +80001bb8: 1790 addi a2,sp,992 +80001bba: 8000 0x8000 Disassembly of section .bss: -80001b44 : +80001bbc : ... Disassembly of section .comment: diff --git a/driver/tests/stress/kernel.elf b/driver/tests/stress/kernel.elf index 6c688f2fb9bc21e0b72cd66c38562dd3a4283de9..4be84fc82c023874a05274861639e6d1abd3aeb4 100755 GIT binary patch delta 1099 zcmZ8g-%Aux6h3!mXVwkbX1%&Ay6)-@<8Cj8jAT&c3TaS5_7GG=R9XrW5)~{FI5z5T z5VCUmA=E=enGa#qP(&IjXeNX&{s9GP76?*kRtRL3 zccQ?H43J}u%3Ip9>mWZ>z_ia1!8?WnF(Q${N%WkfF8h&K2bhy|lRXAAIYW4b`qBt``6_%4&Mb=q za_S2%Y9&(FSIqOBl%__UHs2N|O^@KEg6Gn{5{&UZQgQ^_c%?d#z~oc{Z}Q`z?gaN- zPne$HalO(9dZZutv2F2Y@JQU%oxuFUh+m{kXHqtWit$9@AHjLF=mAa6T2VR6zghy; z9NEEAu==|OoUwo^>U7L+l}5 z4t5aFd@y|GMz&65-lhDFcz6?jOE|Z$$e-PWzih&5gj*y$S5|d+l;l_heV{@O-QAo# zjpXemoDQ$c)!_TzBiXn(h>zlJgqvJo-6LE85?mp?jPqsT0*VOIjQ0U~TU7LiLe=l- z!se2v$h|w5BUfRTun;54G!pZX@FJcKh0i{b!79v>{UC3yqZ+t?NgJyaxJ`K*Sv?dV zqxza`eIDUc8^n1DTlD|rdJEfL}~VtiPtHboWhj~T@fPESQgPeqGM#> t!V3|OCnEWZIL0WRk3`uh-lFFWzMA>*_{|ADY@`V5Z delta 959 zcmZ9KPe>F|7{I?bvv0-~v)P@^9a3lA8QkrUB(e+ArRK0^N{}523N|tc1r1sB5D_#X zo1G&0P=pLZ$n6y5*r6~oP`q>qEc8+dfq5{rz(cT5-&=QM@y&d^`F;QAdvCG*!i6{cP1ZOLtLnn_M>gA0SO(2QML&0W_(D%bNsg;ox(&X-!rbiCIE7|CT} zWM&EE=bR<@t|aH$82S0UYz}a|5s+$nqpRR$KSP4AIwLbG$hme%D7%0YG0?+t@RT)3 zsGF2W0XeP$j*?wn1-oGbzEAGvdodk|N^A$+z*VVz&RY*uGO1$@w}P|MauA>DrzCX_ z*Y%i^%1~?ut3p>yUq<))GYS76$BqTSw#GoeeAMXyzoh$o8JrIpI2Ed_5pEp?w{o*L z9||&&^y8sv+PvYK23F-e4DJBQCz7#ylh|Zcc#d&PW(K~l9crNipm_ku^oV8rXJ3Jx z+LFC+Y>>iq-D!3NpVXaaP585Jkn*JKBiBR4IFacwMV9l6ef*BNR9E<~?Bk7noG0F5 z__hATg%q{p5(YqlBwe6Vdm7!76tNN6YgdC`e=ip8;zt5x?;~E5!JQ%wf&{mT?_k=D z1b1LBN@%A^yT$RLX|{CHttmM#lX|f@3yq4e5Q}Cg7u{tAz7Y@O7c+7rNhLzX62D1X zny3aoU{ZM$hY9j4&*~@pS&B~<<12_a%bKeucIoZ&x+6a%X+gnG%j9B~8s4;QE@~M# zPG4d$4!*T)zvz+#Tzqfon71^R!UJ}kUn1QxjFRr0tuYtVc3j#q@xC47l~I6e!t@U? CfWYwp From bde6a69ea012db14a22f1f84c2dd3b39a987dfe0 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 4 May 2021 07:32:03 -0700 Subject: [PATCH 37/55] adding support for multi-banks memory bus --- driver/opae/vlsim/opae_sim.cpp | 157 +++++++++++---------- driver/opae/vlsim/opae_sim.h | 7 +- driver/opae/vlsim/verilated_stub.h | 126 ----------------- driver/opae/vlsim/vortex_afu_shim.sv | 23 ++- hw/rtl/afu/VX_avs_wrapper.v | 203 ++++++++++++++++----------- hw/rtl/afu/ccip_std_afu.sv | 96 ++++--------- hw/rtl/afu/vortex_afu.sv | 24 ++-- hw/rtl/tex_unit/VX_tex_mgr.v | 19 --- hw/rtl/tex_unit/VX_tex_unit.v | 50 ------- hw/syn/opae/Makefile | 4 +- hw/syn/quartus/Makefile | 44 +++--- 11 files changed, 276 insertions(+), 477 deletions(-) delete mode 100644 driver/opae/vlsim/verilated_stub.h delete mode 100644 hw/rtl/tex_unit/VX_tex_mgr.v delete mode 100644 hw/rtl/tex_unit/VX_tex_unit.v diff --git a/driver/opae/vlsim/opae_sim.cpp b/driver/opae/vlsim/opae_sim.cpp index d62319a5..98a52ce6 100644 --- a/driver/opae/vlsim/opae_sim.cpp +++ b/driver/opae/vlsim/opae_sim.cpp @@ -137,16 +137,19 @@ void opae_sim::flush() { void opae_sim::reset() { - host_buffers_.clear(); - mem_reads_.clear(); + host_buffers_.clear(); cci_reads_.clear(); cci_writes_.clear(); vortex_afu_->vcp2af_sRxPort_c0_rspValid = 0; vortex_afu_->vcp2af_sRxPort_c1_rspValid = 0; vortex_afu_->vcp2af_sRxPort_c0_TxAlmFull = 0; vortex_afu_->vcp2af_sRxPort_c1_TxAlmFull = 0; - vortex_afu_->avs_readdatavalid = 0; - vortex_afu_->avs_waitrequest = 0; + + for (int b = 0; b < PLATFORM_PARAM_LOCAL_MEMORY_BANKS; ++b) { + mem_reads_[b].clear(); + vortex_afu_->avs_readdatavalid[b] = 0; + vortex_afu_->avs_waitrequest[b] = 0; + } vortex_afu_->reset = 1; @@ -268,79 +271,29 @@ void opae_sim::sTxPort_bus() { } void opae_sim::avs_bus() { - // update memory responses schedule - for (auto& rsp : mem_reads_) { - if (rsp.cycles_left > 0) - rsp.cycles_left -= 1; - } - - // schedule memory responses in FIFO order - std::list::iterator mem_rd_it(mem_reads_.end()); - if (!mem_reads_.empty() - && (0 == mem_reads_.begin()->cycles_left)) { - mem_rd_it = mem_reads_.begin(); - } - - // send memory response - vortex_afu_->avs_readdatavalid = 0; - if (mem_rd_it != mem_reads_.end()) { - vortex_afu_->avs_readdatavalid = 1; - memcpy(vortex_afu_->avs_readdata, mem_rd_it->data.data(), MEM_BLOCK_SIZE); - uint32_t addr = mem_rd_it->addr; - mem_reads_.erase(mem_rd_it); - /*printf("%0ld: [sim] MEM Rd Rsp: addr=%x, pending={", timestamp, addr * MEM_BLOCK_SIZE); - for (auto& req : mem_reads_) { - if (req.cycles_left != 0) - printf(" !%0x", req.addr * MEM_BLOCK_SIZE); - else - printf(" %0x", req.addr * MEM_BLOCK_SIZE); + for (int b = 0; b < PLATFORM_PARAM_LOCAL_MEMORY_BANKS; ++b) { + // update memory responses schedule + for (auto& rsp : mem_reads_[b]) { + if (rsp.cycles_left > 0) + rsp.cycles_left -= 1; } - printf("}\n");*/ - } - // handle memory stalls - bool mem_stalled = false; -#ifdef ENABLE_MEM_STALLS - if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) { - mem_stalled = true; - } else - if (mem_reads_.size() >= MEM_RQ_SIZE) { - mem_stalled = true; - } -#endif - - // process memory requests - if (!mem_stalled) { - assert(!vortex_afu_->avs_read || !vortex_afu_->avs_write); - if (vortex_afu_->avs_write) { - uint64_t byteen = vortex_afu_->avs_byteenable; - unsigned base_addr = vortex_afu_->avs_address * MEM_BLOCK_SIZE; - uint8_t* data = (uint8_t*)(vortex_afu_->avs_writedata); - for (int i = 0; i < MEM_BLOCK_SIZE; i++) { - if ((byteen >> i) & 0x1) { - ram_[base_addr + i] = data[i]; - } - } - /*printf("%0ld: [sim] MEM Wr Req: addr=%x, data=", timestamp, base_addr); - for (int i = 0; i < MEM_BLOCK_SIZE; i++) { - printf("%0x", data[(MEM_BLOCK_SIZE-1)-i]); - } - printf("\n");*/ + // schedule memory responses in FIFO order + std::list::iterator mem_rd_it(mem_reads_[b].end()); + if (!mem_reads_[b].empty() + && (0 == mem_reads_[b].begin()->cycles_left)) { + mem_rd_it = mem_reads_[b].begin(); } - if (vortex_afu_->avs_read) { - mem_rd_req_t mem_req; - mem_req.addr = vortex_afu_->avs_address; - ram_.read(vortex_afu_->avs_address * MEM_BLOCK_SIZE, MEM_BLOCK_SIZE, mem_req.data.data()); - mem_req.cycles_left = MEM_LATENCY; - for (auto& rsp : mem_reads_) { - if (mem_req.addr == rsp.addr) { - mem_req.cycles_left = rsp.cycles_left; - break; - } - } - mem_reads_.emplace_back(mem_req); - /*printf("%0ld: [sim] MEM Rd Req: addr=%x, pending={", timestamp, mem_req.addr * MEM_BLOCK_SIZE); - for (auto& req : mem_reads_) { + + // send memory response + vortex_afu_->avs_readdatavalid[b] = 0; + if (mem_rd_it != mem_reads_[b].end()) { + vortex_afu_->avs_readdatavalid[b] = 1; + memcpy(vortex_afu_->avs_readdata[b], mem_rd_it->data.data(), MEM_BLOCK_SIZE); + uint32_t addr = mem_rd_it->addr; + mem_reads_[b].erase(mem_rd_it); + /*printf("%0ld: [sim] MEM Rd Rsp: addr=%x, pending={", timestamp, addr * MEM_BLOCK_SIZE); + for (auto& req : mem_reads_[b]) { if (req.cycles_left != 0) printf(" !%0x", req.addr * MEM_BLOCK_SIZE); else @@ -348,7 +301,59 @@ void opae_sim::avs_bus() { } printf("}\n");*/ } - } - vortex_afu_->avs_waitrequest = mem_stalled; + // handle memory stalls + bool mem_stalled = false; + #ifdef ENABLE_MEM_STALLS + if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) { + mem_stalled = true; + } else + if (mem_reads_[b].size() >= MEM_RQ_SIZE) { + mem_stalled = true; + } + #endif + + // process memory requests + if (!mem_stalled) { + assert(!vortex_afu_->avs_read[b] || !vortex_afu_->avs_write[b]); + if (vortex_afu_->avs_write[b]) { + uint64_t byteen = vortex_afu_->avs_byteenable[b]; + unsigned base_addr = vortex_afu_->avs_address[b] * MEM_BLOCK_SIZE; + uint8_t* data = (uint8_t*)(vortex_afu_->avs_writedata[b]); + for (int i = 0; i < MEM_BLOCK_SIZE; i++) { + if ((byteen >> i) & 0x1) { + ram_[base_addr + i] = data[i]; + } + } + /*printf("%0ld: [sim] MEM Wr Req: addr=%x, data=", timestamp, base_addr); + for (int i = 0; i < MEM_BLOCK_SIZE; i++) { + printf("%0x", data[(MEM_BLOCK_SIZE-1)-i]); + } + printf("\n");*/ + } + if (vortex_afu_->avs_read[b]) { + mem_rd_req_t mem_req; + mem_req.addr = vortex_afu_->avs_address[b]; + ram_.read(vortex_afu_->avs_address[b] * MEM_BLOCK_SIZE, MEM_BLOCK_SIZE, mem_req.data.data()); + mem_req.cycles_left = MEM_LATENCY; + for (auto& rsp : mem_reads_[b]) { + if (mem_req.addr == rsp.addr) { + mem_req.cycles_left = rsp.cycles_left; + break; + } + } + mem_reads_[b].emplace_back(mem_req); + /*printf("%0ld: [sim] MEM Rd Req: addr=%x, pending={", timestamp, mem_req.addr * MEM_BLOCK_SIZE); + for (auto& req : mem_reads_[b]) { + if (req.cycles_left != 0) + printf(" !%0x", req.addr * MEM_BLOCK_SIZE); + else + printf(" %0x", req.addr * MEM_BLOCK_SIZE); + } + printf("}\n");*/ + } + } + + vortex_afu_->avs_waitrequest[b] = mem_stalled; + } } \ No newline at end of file diff --git a/driver/opae/vlsim/opae_sim.h b/driver/opae/vlsim/opae_sim.h index 1d9bef54..e8ecd4a3 100644 --- a/driver/opae/vlsim/opae_sim.h +++ b/driver/opae/vlsim/opae_sim.h @@ -1,8 +1,7 @@ #pragma once #include "verilated.h" -#include "verilated_stub.h" - +//#include "verilated_stub.h" #include "Vvortex_afu_shim.h" #include "Vvortex_afu_shim__Syms.h" @@ -20,7 +19,7 @@ #include #undef MEM_BLOCK_SIZE -#define MEM_BLOCK_SIZE (Vvortex_afu_shim::VL_BITS_avs_writedata / 8) +#define MEM_BLOCK_SIZE (PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH / 8) #define CACHE_BLOCK_SIZE 64 @@ -83,7 +82,7 @@ private: std::unordered_map host_buffers_; - std::list mem_reads_; + std::list mem_reads_ [PLATFORM_PARAM_LOCAL_MEMORY_BANKS]; std::list cci_reads_; diff --git a/driver/opae/vlsim/verilated_stub.h b/driver/opae/vlsim/verilated_stub.h deleted file mode 100644 index ad79adac..00000000 --- a/driver/opae/vlsim/verilated_stub.h +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#undef VL_ST_SIG8 -#define VL_ST_SIG8(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - CData name - -#undef VL_ST_SIG16 -#define VL_ST_SIG16(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - SData name - -#undef VL_ST_SIG64 -#define VL_ST_SIG64(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - QData name - -#undef VL_ST_SIG -#define VL_ST_SIG(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - IData name - -#undef VL_ST_SIGW -#define VL_ST_SIGW(name, msb, lsb, words) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - WData name[words] - -#undef VL_SIG8 -#define VL_SIG8(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - CData name - -#undef VL_SIG16 -#define VL_SIG16(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - SData name - -#undef VL_SIG64 -#define VL_SIG64(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - QData name - -#undef VL_SIG -#define VL_SIG(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - IData name - -#undef VL_SIGW -#define VL_SIGW(name, msb, lsb, words) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - WData name[words] - -#undef VL_IN8 -#define VL_IN8(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - CData name - -#undef VL_IN16 -#define VL_IN16(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - SData name - -#undef VL_IN64 -#define VL_IN64(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - QData name - -#undef VL_IN -#define VL_IN(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - IData name - -#undef VL_INW -#define VL_INW(name, msb, lsb, words) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - WData name[words] - -#undef VL_INOUT8 -#define VL_INOUT8(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - CData name - -#undef VL_INOUT16 -#define VL_INOUT16(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - SData name - -#undef VL_INOUT64 -#define VL_INOUT64(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - QData name - -#undef VL_INOUT -#define VL_INOUT(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - IData name - -#undef VL_INOUTW -#define VL_INOUTW(name, msb, lsb, words) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - WData name[words] - -#undef VL_OUT8 -#define VL_OUT8(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - CData name - -#undef VL_OUT16 -#define VL_OUT16(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - SData name - -#undef VL_OUT64 -#define VL_OUT64(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - QData name - -#undef VL_OUT -#define VL_OUT(name, msb, lsb) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - IData name - -#undef VL_OUTW -#define VL_OUTW(name, msb, lsb, words) \ - enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ - WData name[words] diff --git a/driver/opae/vlsim/vortex_afu_shim.sv b/driver/opae/vlsim/vortex_afu_shim.sv index ed7537c5..9255bfaa 100644 --- a/driver/opae/vlsim/vortex_afu_shim.sv +++ b/driver/opae/vlsim/vortex_afu_shim.sv @@ -72,17 +72,15 @@ module vortex_afu_shim ( output t_ccip_mmioData af2cp_sTxPort_c2_data, // Avalon signals for local memory access - output t_local_mem_data avs_writedata, - input t_local_mem_data avs_readdata, - output t_local_mem_addr avs_address, - input logic avs_waitrequest, - output logic avs_write, - output logic avs_read, - output t_local_mem_byte_mask avs_byteenable, - output t_local_mem_burst_cnt avs_burstcount, - input avs_readdatavalid, - - output logic [$clog2(`PLATFORM_PARAM_LOCAL_MEMORY_BANKS)-1:0] mem_bank_select + output t_local_mem_data avs_writedata [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + input t_local_mem_data avs_readdata [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + output t_local_mem_addr avs_address [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + input logic avs_waitrequest [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + output logic avs_write [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + output logic avs_read [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + output t_local_mem_byte_mask avs_byteenable [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + output t_local_mem_burst_cnt avs_burstcount [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS], + input avs_readdatavalid [`PLATFORM_PARAM_LOCAL_MEMORY_BANKS] ); t_if_ccip_Rx cp2af_sRxPort; @@ -103,8 +101,7 @@ vortex_afu #( .avs_read(avs_read), .avs_byteenable(avs_byteenable), .avs_burstcount(avs_burstcount), - .avs_readdatavalid(avs_readdatavalid), - .mem_bank_select(mem_bank_select) + .avs_readdatavalid(avs_readdatavalid) ); t_if_ccip_c0_RxHdr c0_RxHdr; diff --git a/hw/rtl/afu/VX_avs_wrapper.v b/hw/rtl/afu/VX_avs_wrapper.v index ff7d1dd1..81dc78bc 100644 --- a/hw/rtl/afu/VX_avs_wrapper.v +++ b/hw/rtl/afu/VX_avs_wrapper.v @@ -1,6 +1,7 @@ `include "VX_define.vh" module VX_avs_wrapper #( + parameter NUM_BANKS = 1, parameter AVS_DATA_WIDTH = 1, parameter AVS_ADDR_WIDTH = 1, parameter AVS_BURST_WIDTH = 1, @@ -31,103 +32,141 @@ module VX_avs_wrapper #( input wire mem_rsp_ready, // AVS bus - output wire [AVS_DATA_WIDTH-1:0] avs_writedata, - input wire [AVS_DATA_WIDTH-1:0] avs_readdata, - output wire [AVS_ADDR_WIDTH-1:0] avs_address, - input wire avs_waitrequest, - output wire avs_write, - output wire avs_read, - output wire [AVS_BYTEENW-1:0] avs_byteenable, - output wire [AVS_BURST_WIDTH-1:0] avs_burstcount, - input avs_readdatavalid, - output wire [AVS_BANKS_BITS-1:0] avs_bankselect + output wire [AVS_DATA_WIDTH-1:0] avs_writedata [NUM_BANKS], + input wire [AVS_DATA_WIDTH-1:0] avs_readdata [NUM_BANKS], + output wire [AVS_ADDR_WIDTH-1:0] avs_address [NUM_BANKS], + input wire avs_waitrequest [NUM_BANKS], + output wire avs_write [NUM_BANKS], + output wire avs_read [NUM_BANKS], + output wire [AVS_BYTEENW-1:0] avs_byteenable [NUM_BANKS], + output wire [AVS_BURST_WIDTH-1:0] avs_burstcount [NUM_BANKS], + input avs_readdatavalid [NUM_BANKS] ); - reg [AVS_BANKS_BITS-1:0] avs_bankselect_r; - reg [AVS_BURST_WIDTH-1:0] avs_burstcount_r; - wire avs_reqq_push = mem_req_valid && mem_req_ready && !mem_req_rw; - wire avs_reqq_pop = mem_rsp_valid && mem_rsp_ready; + localparam BANK_ADDRW = $clog2(NUM_BANKS); - wire avs_rspq_push = avs_readdatavalid; - wire avs_rspq_pop = avs_reqq_pop; - wire avs_rspq_empty; + // Requests handling - wire rsp_queue_going_full; - wire [RD_QUEUE_ADDR_WIDTH-1:0] rsp_queue_size; - VX_pending_size #( - .SIZE (RD_QUEUE_SIZE) - ) pending_size ( - .clk (clk), - .reset (reset), - .push (avs_reqq_push), - .pop (avs_rspq_pop), - `UNUSED_PIN (empty), - .full (rsp_queue_going_full), - .size (rsp_queue_size) - ); - `UNUSED_VAR (rsp_queue_size) - - always @(posedge clk) begin - avs_burstcount_r <= 1; - avs_bankselect_r <= 0; - end + reg [AVS_BURST_WIDTH-1:0] avs_burstcount_r; - VX_fifo_queue #( - .DATAW (REQ_TAG_WIDTH), - .SIZE (RD_QUEUE_SIZE) - ) rd_req_queue ( - .clk (clk), - .reset (reset), - .push (avs_reqq_push), - .pop (avs_reqq_pop), - .data_in (mem_req_tag), - .data_out (mem_rsp_tag), - `UNUSED_PIN (empty), - `UNUSED_PIN (full), - `UNUSED_PIN (alm_empty), - `UNUSED_PIN (alm_full), - `UNUSED_PIN (size) + wire [NUM_BANKS-1:0] avs_reqq_pop; + wire [NUM_BANKS-1:0] req_queue_going_full; + wire [NUM_BANKS-1:0][RD_QUEUE_ADDR_WIDTH-1:0] req_queue_size; + wire [NUM_BANKS-1:0][REQ_TAG_WIDTH-1:0] avs_reqq_data_out; + + wire [BANK_ADDRW-1:0] req_bank_sel = mem_req_addr [BANK_ADDRW-1:0]; + + wire avs_reqq_push = mem_req_valid && !mem_req_rw && mem_req_ready; + + for (genvar i = 0; i < NUM_BANKS; i++) begin + + VX_pending_size #( + .SIZE (RD_QUEUE_SIZE) + ) pending_size ( + .clk (clk), + .reset (reset), + .push (avs_reqq_push && (req_bank_sel == i)), + .pop (avs_reqq_pop[i]), + `UNUSED_PIN (empty), + .full (req_queue_going_full[i]), + .size (req_queue_size[i]) + ); + `UNUSED_VAR (req_queue_size) + + always @(posedge clk) begin + avs_burstcount_r <= 1; + end + + VX_fifo_queue #( + .DATAW (REQ_TAG_WIDTH), + .SIZE (RD_QUEUE_SIZE) + ) rd_req_queue ( + .clk (clk), + .reset (reset), + .push (avs_reqq_push && (req_bank_sel == i)), + .pop (avs_reqq_pop[i]), + .data_in (mem_req_tag), + .data_out (avs_reqq_data_out[i]), + `UNUSED_PIN (empty), + `UNUSED_PIN (full), + `UNUSED_PIN (alm_empty), + `UNUSED_PIN (alm_full), + `UNUSED_PIN (size) + ); + end + + for (genvar i = 0; i < NUM_BANKS; i++) begin + assign avs_read[i] = mem_req_valid && !mem_req_rw && !req_queue_going_full[i] && (req_bank_sel == i); + assign avs_write[i] = mem_req_valid && mem_req_rw && !req_queue_going_full[i] && (req_bank_sel == i); + assign avs_address[i] = mem_req_addr; + assign avs_byteenable[i] = mem_req_byteen; + assign avs_writedata[i] = mem_req_data; + assign avs_burstcount[i] = avs_burstcount_r; + end + + assign mem_req_ready = !(avs_waitrequest[req_bank_sel] || req_queue_going_full[req_bank_sel]); + + // Responses handling + + wire [NUM_BANKS-1:0] rsp_arb_valid_in; + wire [NUM_BANKS-1:0][AVS_DATA_WIDTH+REQ_TAG_WIDTH-1:0] rsp_arb_data_in; + wire [NUM_BANKS-1:0] rsp_arb_ready_in; + + wire [NUM_BANKS-1:0][AVS_DATA_WIDTH-1:0] avs_rspq_data_out; + wire [NUM_BANKS-1:0] avs_rspq_empty; + + for (genvar i = 0; i < NUM_BANKS; i++) begin + + VX_fifo_queue #( + .DATAW (AVS_DATA_WIDTH), + .SIZE (RD_QUEUE_SIZE) + ) rd_rsp_queue ( + .clk (clk), + .reset (reset), + .push (avs_readdatavalid[i]), + .pop (avs_reqq_pop[i]), + .data_in (avs_readdata[i]), + .data_out (avs_rspq_data_out[i]), + .empty (avs_rspq_empty[i]), + `UNUSED_PIN (full), + `UNUSED_PIN (alm_empty), + `UNUSED_PIN (alm_full), + `UNUSED_PIN (size) + ); + + end + + for (genvar i = 0; i < NUM_BANKS; i++) begin + assign rsp_arb_valid_in[i] = !avs_rspq_empty[i]; + assign rsp_arb_data_in[i] = {avs_rspq_data_out[i], avs_reqq_data_out[i]}; + assign avs_reqq_pop[i] = rsp_arb_valid_in[i] && rsp_arb_ready_in[i]; + end + + VX_stream_arbiter #( + .NUM_REQS (NUM_BANKS), + .DATAW (AVS_DATA_WIDTH+REQ_TAG_WIDTH), + .BUFFERED (0) + ) rsp_arb ( + .clk (clk), + .reset (reset), + .valid_in (rsp_arb_valid_in), + .data_in (rsp_arb_data_in), + .ready_in (rsp_arb_ready_in), + .valid_out (mem_rsp_valid), + .data_out ({mem_rsp_data, mem_rsp_tag}), + .ready_out (mem_rsp_ready) ); - VX_fifo_queue #( - .DATAW (AVS_DATA_WIDTH), - .SIZE (RD_QUEUE_SIZE) - ) rd_rsp_queue ( - .clk (clk), - .reset (reset), - .push (avs_rspq_push), - .pop (avs_rspq_pop), - .data_in (avs_readdata), - .data_out (mem_rsp_data), - .empty (avs_rspq_empty), - `UNUSED_PIN (full), - `UNUSED_PIN (alm_empty), - `UNUSED_PIN (alm_full), - `UNUSED_PIN (size) - ); - - assign avs_read = mem_req_valid && !mem_req_rw && !rsp_queue_going_full; - assign avs_write = mem_req_valid && mem_req_rw && !rsp_queue_going_full; - assign avs_address = mem_req_addr; - assign avs_byteenable = mem_req_byteen; - assign avs_writedata = mem_req_data; - assign avs_burstcount = avs_burstcount_r; - assign avs_bankselect = avs_bankselect_r; - - assign mem_req_ready = !avs_waitrequest && !rsp_queue_going_full; - - assign mem_rsp_valid = !avs_rspq_empty; - `ifdef DBG_PRINT_AVS always @(posedge clk) begin if (mem_req_valid && mem_req_ready) begin if (mem_req_rw) $display("%t: AVS Wr Req: addr=%0h, byteen=%0h, tag=%0h, data=%0h", $time, `TO_FULL_ADDR(mem_req_addr), mem_req_byteen, mem_req_tag, mem_req_data); else - $display("%t: AVS Rd Req: addr=%0h, byteen=%0h, tag=%0h, pending=%0d", $time, `TO_FULL_ADDR(mem_req_addr), mem_req_byteen, mem_req_tag, rsp_queue_size); + $display("%t: AVS Rd Req: addr=%0h, byteen=%0h, tag=%0h, pending=%0d", $time, `TO_FULL_ADDR(mem_req_addr), mem_req_byteen, mem_req_tag, req_queue_size); end if (mem_rsp_valid && mem_rsp_ready) begin - $display("%t: AVS Rd Rsp: tag=%0h, data=%0h, pending=%0d", $time, mem_rsp_tag, mem_rsp_data, rsp_queue_size); + $display("%t: AVS Rd Rsp: tag=%0h, data=%0h, pending=%0d", $time, mem_rsp_tag, mem_rsp_data, req_queue_size); end end `endif diff --git a/hw/rtl/afu/ccip_std_afu.sv b/hw/rtl/afu/ccip_std_afu.sv index 4534d40c..2adea591 100644 --- a/hw/rtl/afu/ccip_std_afu.sv +++ b/hw/rtl/afu/ccip_std_afu.sv @@ -77,30 +77,28 @@ module ccip_std_afu #( // User AFU goes here // ==================================================================== - // - // vortex_afu depends on CCI-P and local memory being in the same - // clock domain. This is accomplished by choosing a common clock - // in the AFU's JSON description. The platform instantiates clock- - // crossing shims automatically, as needed. - // + t_local_mem_byte_mask avs_byteenable [NUM_LOCAL_MEM_BANKS]; + logic avs_waitrequest [NUM_LOCAL_MEM_BANKS]; + t_local_mem_data avs_readdata [NUM_LOCAL_MEM_BANKS]; + logic avs_readdatavalid [NUM_LOCAL_MEM_BANKS]; + t_local_mem_burst_cnt avs_burstcount [NUM_LOCAL_MEM_BANKS]; + t_local_mem_data avs_writedata [NUM_LOCAL_MEM_BANKS]; + t_local_mem_addr avs_address [NUM_LOCAL_MEM_BANKS]; + logic avs_write [NUM_LOCAL_MEM_BANKS]; + logic avs_read [NUM_LOCAL_MEM_BANKS]; - // - // Memory banks are used very simply here. Only bank is active at - // a time, selected by mem_bank_select. mem_bank_select is set - // by a CSR from the host. - // - t_local_mem_byte_mask avs_byteenable; - logic avs_waitrequest; - t_local_mem_data avs_readdata; - logic avs_readdatavalid; - t_local_mem_burst_cnt avs_burstcount; - t_local_mem_data avs_writedata; - t_local_mem_addr avs_address; - logic avs_write; - logic avs_read; - - // choose which memory bank to test - logic [$clog2(NUM_LOCAL_MEM_BANKS)-1:0] mem_bank_select; + for (genvar b = 0; b < NUM_LOCAL_MEM_BANKS; b++) begin + assign local_mem[b].burstcount = avs_burstcount[b]; + assign local_mem[b].writedata = avs_writedata[b]; + assign local_mem[b].address = avs_address[b]; + assign local_mem[b].byteenable = avs_byteenable[b]; + assign local_mem[b].write = avs_write[b]; + assign local_mem[b].read = avs_read[b]; + + assign avs_waitrequest[b] = local_mem[b].waitrequest; + assign avs_readdata[b] = local_mem[b].readdata; + assign avs_readdatavalid[b] = local_mem[b].readdatavalid; + end vortex_afu #( .NUM_LOCAL_MEM_BANKS(NUM_LOCAL_MEM_BANKS) @@ -108,6 +106,9 @@ module ccip_std_afu #( .clk (clk), .reset (reset_T1), + .cp2af_sRxPort (cp2af_sRx_T1), + .af2cp_sTxPort (af2cp_sTx_T0), + .avs_writedata (avs_writedata), .avs_readdata (avs_readdata), .avs_address (avs_address), @@ -116,52 +117,7 @@ module ccip_std_afu #( .avs_read (avs_read), .avs_byteenable (avs_byteenable), .avs_burstcount (avs_burstcount), - .avs_readdatavalid (avs_readdatavalid), - .mem_bank_select (mem_bank_select), - - .cp2af_sRxPort (cp2af_sRx_T1), - .af2cp_sTxPort (af2cp_sTx_T0) - ); - - // - // Export the local memory interface signals as vectors so that bank - // selection can use array syntax. - // - logic avs_waitrequest_v[NUM_LOCAL_MEM_BANKS]; - t_local_mem_data avs_readdata_v[NUM_LOCAL_MEM_BANKS]; - logic avs_readdatavalid_v[NUM_LOCAL_MEM_BANKS]; - - genvar b; - generate - for (b = 0; b < NUM_LOCAL_MEM_BANKS; b = b + 1) - begin : lmb - always_comb - begin - // Local memory to AFU signals - avs_waitrequest_v[b] = local_mem[b].waitrequest; - avs_readdata_v[b] = local_mem[b].readdata; - avs_readdatavalid_v[b] = local_mem[b].readdatavalid; - - // Replicate address and write data to all banks. Only - // the request signals have to be bank-specific. - local_mem[b].burstcount = avs_burstcount; - local_mem[b].writedata = avs_writedata; - local_mem[b].address = avs_address; - local_mem[b].byteenable = avs_byteenable; - - // Request a write to this bank? - local_mem[b].write = avs_write && - ($bits(mem_bank_select)'(b) == mem_bank_select); - - // Request a read from this bank? - local_mem[b].read = avs_read && - ($bits(mem_bank_select)'(b) == mem_bank_select); - end - end - endgenerate - - assign avs_waitrequest = avs_waitrequest_v[mem_bank_select]; - assign avs_readdata = avs_readdata_v[mem_bank_select]; - assign avs_readdatavalid = avs_readdatavalid_v[mem_bank_select]; + .avs_readdatavalid (avs_readdatavalid) + ); endmodule diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 392c775d..2ac0f075 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -26,17 +26,15 @@ module vortex_afu #( output t_if_ccip_Tx af2cp_sTxPort, // Avalon signals for local memory access - output t_local_mem_data avs_writedata, - input t_local_mem_data avs_readdata, - output t_local_mem_addr avs_address, - input logic avs_waitrequest, - output logic avs_write, - output logic avs_read, - output t_local_mem_byte_mask avs_byteenable, - output t_local_mem_burst_cnt avs_burstcount, - input avs_readdatavalid, - - output logic [$clog2(NUM_LOCAL_MEM_BANKS)-1:0] mem_bank_select + output t_local_mem_data avs_writedata [NUM_LOCAL_MEM_BANKS], + input t_local_mem_data avs_readdata [NUM_LOCAL_MEM_BANKS], + output t_local_mem_addr avs_address [NUM_LOCAL_MEM_BANKS], + input logic avs_waitrequest [NUM_LOCAL_MEM_BANKS], + output logic avs_write [NUM_LOCAL_MEM_BANKS], + output logic avs_read [NUM_LOCAL_MEM_BANKS], + output t_local_mem_byte_mask avs_byteenable [NUM_LOCAL_MEM_BANKS], + output t_local_mem_burst_cnt avs_burstcount [NUM_LOCAL_MEM_BANKS], + input avs_readdatavalid [NUM_LOCAL_MEM_BANKS] ); localparam RESET_DELAY = 3; @@ -636,6 +634,7 @@ VX_mem_arb #( //-- VX_avs_wrapper #( + .NUM_BANKS (NUM_LOCAL_MEM_BANKS), .AVS_DATA_WIDTH (LMEM_LINE_WIDTH), .AVS_ADDR_WIDTH (LMEM_ADDR_WIDTH), .AVS_BURST_WIDTH (LMEM_BURST_CTRW), @@ -670,8 +669,7 @@ VX_avs_wrapper #( .avs_read (avs_read), .avs_byteenable (avs_byteenable), .avs_burstcount (avs_burstcount), - .avs_readdatavalid(avs_readdatavalid), - .avs_bankselect (mem_bank_select) + .avs_readdatavalid(avs_readdatavalid) ); // CCI-P Read Request /////////////////////////////////////////////////////////// diff --git a/hw/rtl/tex_unit/VX_tex_mgr.v b/hw/rtl/tex_unit/VX_tex_mgr.v deleted file mode 100644 index a7de9180..00000000 --- a/hw/rtl/tex_unit/VX_tex_mgr.v +++ /dev/null @@ -1,19 +0,0 @@ -`include "VX_platform.vh" - -module VX_tex_mgr ( - input wire clk, - input wire reset -); - - //-- - -endmodule - - - - - - - - - diff --git a/hw/rtl/tex_unit/VX_tex_unit.v b/hw/rtl/tex_unit/VX_tex_unit.v deleted file mode 100644 index a7c38cfe..00000000 --- a/hw/rtl/tex_unit/VX_tex_unit.v +++ /dev/null @@ -1,50 +0,0 @@ -`include "VX_platform.vh" - -module VX_tex_unit #( - parameter TADDRW = 32, - parameter MADDRW = 32, - parameter DATAW = 32, - parameter MAXWTW = 8, - parameter MAXHTW = 8, - parameter MAXFTW = 2, - parameter MAXFMW = 1, - parameter MAXAMW = 2, - parameter TAGW = 16, - - parameter NUMCRQS = 32 -) ( - input wire clk, - input wire reset, - - // Texture Request - input wire tex_req_valid, - input wire [TADDRW-1:0] tex_req_u, - input wire [TADDRW-1:0] tex_req_v, - input wire [MADDRW-1:0] tex_req_addr, - input wire [MAXWTW-1:0] tex_req_width, - input wire [MAXHTW-1:0] tex_req_height, - input wire [MAXFTW-1:0] tex_req_format, - input wire [MAXFMW-1:0] tex_req_filter, - input wire [MAXAMW-1:0] tex_req_clamp, - input wire [TAGW-1:0] tex_req_tag, - output wire tex_req_ready, - - // Texture Response - output wire tex_rsp_valid, - output wire [TAGW-1:0] tex_rsp_tag, - input wire [DATAW-1:0] tex_rsp_data, - input wire tex_rsp_ready, - - // Cache Request - output wire [NUMCRQS-1:0] cache_req_valids, - output wire [NUMCRQS-1:0][MADDRW-1:0] cache_req_addrs, - input wire cache_req_ready, - - // Cache Response - input wire cache_rsp_valid, - input wire [MADDRW-1:0] cache_rsp_addr, - input wire [DATAW-1:0] cache_rsp_data, - output wire cache_rsp_ready -); - -endmodule \ No newline at end of file diff --git a/hw/syn/opae/Makefile b/hw/syn/opae/Makefile index 38f21fba..d820df9a 100644 --- a/hw/syn/opae/Makefile +++ b/hw/syn/opae/Makefile @@ -1,6 +1,6 @@ -ASE_BUILD_DIR ?= build_ase -FPGA_BUILD_DIR ?= build_fpga DEVICE_FAMILY ?= arria10 +ASE_BUILD_DIR ?= build_ase_$(DEVICE_FAMILY) +FPGA_BUILD_DIR ?= build_fpga_$(DEVICE_FAMILY) RTL_DIR=../../rtl ifeq ($(shell which qsub-synth),) diff --git a/hw/syn/quartus/Makefile b/hw/syn/quartus/Makefile index 4dd40a40..fa002563 100644 --- a/hw/syn/quartus/Makefile +++ b/hw/syn/quartus/Makefile @@ -3,18 +3,18 @@ BUILDIR ?= build .PHONY: unittest pipeline cache core vortex top1 top2 top4 top8 top16 top32 top64 unittest: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p unittest/$(BUILDIR) + cp core/Makefile unittest/$(BUILDIR) $(MAKE) -C unittest/$(BUILDIR) clean && $(MAKE) -C unittest/$(BUILDIR) > unittest//$(BUILDIR)build.log 2>&1 & pipeline: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p pipeline/$(BUILDIR) + cp core/Makefile pipeline/$(BUILDIR) $(MAKE) -C pipeline/$(BUILDIR) clean && $(MAKE) -C pipeline/$(BUILDIR) > pipeline/$(BUILDIR)/build.log 2>&1 & cache: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p cache/$(BUILDIR) + cp core/Makefile cache/$(BUILDIR) $(MAKE) -C cache/$(BUILDIR) clean && $(MAKE) -C cache/$(BUILDIR) > cache/$(BUILDIR)/build.log 2>&1 & core: @@ -23,41 +23,41 @@ core: $(MAKE) -C core/$(BUILDIR) clean && $(MAKE) -C core/$(BUILDIR) > core/$(BUILDIR)/build.log 2>&1 & vortex: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p vortex/$(BUILDIR) + cp core/Makefile vortex/$(BUILDIR) $(MAKE) -C vortex/$(BUILDIR) clean && $(MAKE) -C vortex/$(BUILDIR) > vortex/$(BUILDIR)/build.log 2>&1 & top1: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p top1/$(BUILDIR) + cp core/Makefile top1/$(BUILDIR) $(MAKE) -C top1/$(BUILDIR) clean && $(MAKE) -C top1/$(BUILDIR) > top1/$(BUILDIR)/build.log 2>&1 & top2: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p top2/$(BUILDIR) + cp core/Makefile top2/$(BUILDIR) $(MAKE) -C top2/$(BUILDIR) clean && $(MAKE) -C top2/$(BUILDIR) > top2/$(BUILDIR)/build.log 2>&1 & top4: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p top4/$(BUILDIR) + cp core/Makefile top4/$(BUILDIR) $(MAKE) -C top4/$(BUILDIR) clean && $(MAKE) -C top4/$(BUILDIR) > top4/$(BUILDIR)/build.log 2>&1 & top8: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p top8/$(BUILDIR) + cp core/Makefile top8/$(BUILDIR) $(MAKE) -C top8/$(BUILDIR) clean && $(MAKE) -C top8/$(BUILDIR) > top8/$(BUILDIR)/build.log 2>&1 & top16: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p top16/$(BUILDIR) + cp core/Makefile top16/$(BUILDIR) $(MAKE) -C top16/$(BUILDIR) clean && $(MAKE) -C top16/$(BUILDIR) > top16/$(BUILDIR)build.log 2>&1 & top32: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p top32/$(BUILDIR) + cp core/Makefile top32/$(BUILDIR) $(MAKE) -C top32/$(BUILDIR) clean && $(MAKE) -C top32/$(BUILDIR) > top32/$(BUILDIR)/build.log 2>&1 & top64: - mkdir -p core/$(BUILDIR) - cp core/Makefile core/$(BUILDIR) + mkdir -p top64/$(BUILDIR) + cp core/Makefile top64/$(BUILDIR) $(MAKE) -C top64/$(BUILDIR) clean && $(MAKE) -C top64/$(BUILDIR) > top64/$(BUILDIR)/build.log 2>&1 & \ No newline at end of file From 8f451aa74cdf3b8416d2b8a5348bb7e8bdc27574 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 4 May 2021 08:01:49 -0700 Subject: [PATCH 38/55] minor update --- hw/rtl/afu/vortex_afu.sv | 15 +++++++-------- hw/scripts/scope.json | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 2ac0f075..6cdb14b9 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -1017,14 +1017,13 @@ Vortex #() vortex ( `SCOPE_ASSIGN (cci_sTxPort_c2_mmioRdValid, af2cp_sTxPort.c2.mmioRdValid); `SCOPE_ASSIGN (cci_sRxPort_c0TxAlmFull, cp2af_sRxPort.c0TxAlmFull); `SCOPE_ASSIGN (cci_sRxPort_c1TxAlmFull, cp2af_sRxPort.c1TxAlmFull); -`SCOPE_ASSIGN (avs_address, avs_address); -`SCOPE_ASSIGN (avs_waitrequest, avs_waitrequest); -`SCOPE_ASSIGN (avs_write_fire, avs_write && !avs_waitrequest); -`SCOPE_ASSIGN (avs_read_fire, avs_read && !avs_waitrequest); -`SCOPE_ASSIGN (avs_byteenable, avs_byteenable); -`SCOPE_ASSIGN (avs_burstcount, avs_burstcount); -`SCOPE_ASSIGN (avs_readdatavalid, avs_readdatavalid); -`SCOPE_ASSIGN (mem_bank_select, mem_bank_select); +`SCOPE_ASSIGN (avs_address, avs_address[0]); +`SCOPE_ASSIGN (avs_waitrequest, avs_waitrequest[0]); +`SCOPE_ASSIGN (avs_write_fire, avs_write[0] && !avs_waitrequest[0]); +`SCOPE_ASSIGN (avs_read_fire, avs_read[0] && !avs_waitrequest[0]); +`SCOPE_ASSIGN (avs_byteenable, avs_byteenable[0]); +`SCOPE_ASSIGN (avs_burstcount, avs_burstcount[0]); +`SCOPE_ASSIGN (avs_readdatavalid, avs_readdatavalid[0]); `SCOPE_ASSIGN (cci_mem_rd_req_ctr, cci_mem_rd_req_ctr); `SCOPE_ASSIGN (cci_mem_wr_req_ctr, cci_mem_wr_req_ctr); `SCOPE_ASSIGN (cci_rd_req_ctr, cci_rd_req_ctr); diff --git a/hw/scripts/scope.json b/hw/scripts/scope.json index 6290a622..f97e6af0 100644 --- a/hw/scripts/scope.json +++ b/hw/scripts/scope.json @@ -97,7 +97,6 @@ "avs_byteenable":64, "avs_burstcount":4, "avs_readdatavalid":1, - "mem_bank_select":1, "cci_mem_rd_req_ctr":26, "cci_mem_wr_req_ctr":26, "cci_rd_req_ctr":26, From 6107bf8247915b4ea5b5939f8d8d1f250c4831ea Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 4 May 2021 11:05:07 -0700 Subject: [PATCH 39/55] minor fix --- ci/regression.sh | 8 ++++---- hw/rtl/afu/VX_avs_wrapper.v | 12 +++--------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/ci/regression.sh b/ci/regression.sh index b6fa3c4f..27649975 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -48,11 +48,11 @@ FPU_CORE=FPU_FPNEW ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=dogfood # test 128-bit MEM block CONFIGS=-DMEM_BLOCK_SIZE=16 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo -# test 128-bit DRAM block -CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo - # test 128-bit MEM and DRAM block CONFIGS="-DMEM_BLOCK_SIZE=16 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo # test 27-bit DRAM address -CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo \ No newline at end of file +CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo + +# test 128-bit DRAM block +CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo \ No newline at end of file diff --git a/hw/rtl/afu/VX_avs_wrapper.v b/hw/rtl/afu/VX_avs_wrapper.v index 81dc78bc..74f5b48d 100644 --- a/hw/rtl/afu/VX_avs_wrapper.v +++ b/hw/rtl/afu/VX_avs_wrapper.v @@ -43,18 +43,16 @@ module VX_avs_wrapper #( input avs_readdatavalid [NUM_BANKS] ); - localparam BANK_ADDRW = $clog2(NUM_BANKS); + localparam BANK_ADDRW = `LOG2UP(NUM_BANKS); // Requests handling - - reg [AVS_BURST_WIDTH-1:0] avs_burstcount_r; wire [NUM_BANKS-1:0] avs_reqq_pop; wire [NUM_BANKS-1:0] req_queue_going_full; wire [NUM_BANKS-1:0][RD_QUEUE_ADDR_WIDTH-1:0] req_queue_size; wire [NUM_BANKS-1:0][REQ_TAG_WIDTH-1:0] avs_reqq_data_out; - wire [BANK_ADDRW-1:0] req_bank_sel = mem_req_addr [BANK_ADDRW-1:0]; + wire [BANK_ADDRW-1:0] req_bank_sel = (NUM_BANKS >= 2) ? mem_req_addr [BANK_ADDRW-1:0] : 1'b0; wire avs_reqq_push = mem_req_valid && !mem_req_rw && mem_req_ready; @@ -72,10 +70,6 @@ module VX_avs_wrapper #( .size (req_queue_size[i]) ); `UNUSED_VAR (req_queue_size) - - always @(posedge clk) begin - avs_burstcount_r <= 1; - end VX_fifo_queue #( .DATAW (REQ_TAG_WIDTH), @@ -101,7 +95,7 @@ module VX_avs_wrapper #( assign avs_address[i] = mem_req_addr; assign avs_byteenable[i] = mem_req_byteen; assign avs_writedata[i] = mem_req_data; - assign avs_burstcount[i] = avs_burstcount_r; + assign avs_burstcount[i] = AVS_BURST_WIDTH'(1); end assign mem_req_ready = !(avs_waitrequest[req_bank_sel] || req_queue_going_full[req_bank_sel]); From 3e88a7180131f58c2b2106dfd16747ff7add187b Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 6 May 2021 08:55:46 -0700 Subject: [PATCH 40/55] minor update --- driver/tests/stress/kernel.bin | Bin 7100 -> 7108 bytes driver/tests/stress/kernel.c | 8 +- driver/tests/stress/kernel.dump | 994 ++++++++++++++++---------------- driver/tests/stress/kernel.elf | Bin 9156 -> 9164 bytes driver/tests/stress/main.cpp | 66 ++- hw/rtl/afu/VX_avs_wrapper.v | 2 +- 6 files changed, 560 insertions(+), 510 deletions(-) diff --git a/driver/tests/stress/kernel.bin b/driver/tests/stress/kernel.bin index 537c5f79445c1395dbcf43896358b20cefbbdf2a..9aec10635f9f5ae18b54a794e3114b05d5a345a3 100755 GIT binary patch delta 501 zcmYj~F-RLx9LB$Qckf*z8O}b;1q(%#T-y1DI0&9lBZA=2E-i%)4h{|u3UX5puDN6l zkG2kl79p3;eUyUSAkrj`g$!{N99)Drs6lY>U9i>R&jz zMfy;r0_iU;a_@6tGg4gN(&G;KS3DX@vuZfyWbGItDvz?Gt(~D&{656#-VbOZeD zOK%MsjT?q95+g6Z8e_Q>TOMJLZJ8KPNm}}s?kSPmY-&9FaT39~x;M`dh=#c I?Ai$K09MbJ8vpPLlHT zp!8?8^bzNXCj~EI6&zjw2+luyHRDcqPdbB8o4)Bh@Qe$7aQ_@%?iq#V4$lzwm%VjV zwF|U+E}9&%;0tqRAXj2Q4HK~K1E>Kf>0Vmu{Q|W+?zr4Ig_yYm;ng7>mt?U>*+y|* z)g7>)1r>C`{6naQLwd6gF&Th0S|pPJvh*kPn*i!AH+&atJ?K)Fe1Z@@*bawOPYmFY z^j5<_7_wfOM5O_>eZxGyBH453A283S*U%iu0&emOa+Z3RpFPS_*Jucto|t@Tw$g%M zy~6ifCl~n#MZV3aG(|6TN{_9hQFcaSWF3$6h4q0J^^nb3=}4cknzJA2^eECd?ME}6 zNEBX1vhXYPYZLHi`w$Orhiw!rVRs_^%APIfmE-Hmf1`^2X8+EaU-?^O*_ustride; uint32_t* addr_ptr = (uint32_t*)_arg->addr_ptr; - int32_t* src_ptr = (int32_t*)_arg->src_ptr; - int32_t* dst_ptr = (int32_t*)_arg->dst_ptr; + float* src_ptr = (float*)_arg->src_ptr; + float* dst_ptr = (float*)_arg->dst_ptr; uint32_t offset = task_id * stride; for (uint32_t i = 0; i < stride; ++i) { - int value = 0; + float value = 0.0f; for (uint32_t j = 0; j < NUM_LOADS; ++j) { uint32_t addr = offset + i + j; uint32_t index = addr_ptr[addr]; - value += src_ptr[index]; + value *= src_ptr[index]; } dst_ptr[offset+i] = value; } diff --git a/driver/tests/stress/kernel.dump b/driver/tests/stress/kernel.dump index 53bad0ae..21e810bf 100644 --- a/driver/tests/stress/kernel.dump +++ b/driver/tests/stress/kernel.dump @@ -6,25 +6,25 @@ Disassembly of section .init: 80000000 <_start>: 80000000: 00000597 auipc a1,0x0 -80000004: 16858593 addi a1,a1,360 # 80000168 +80000004: 17058593 addi a1,a1,368 # 80000170 80000008: fc102573 csrr a0,0xfc1 8000000c: 00b5106b 0xb5106b -80000010: 158000ef jal ra,80000168 +80000010: 160000ef jal ra,80000170 80000014: 00100513 li a0,1 80000018: 0005006b 0x5006b 8000001c: 00002517 auipc a0,0x2 -80000020: ba050513 addi a0,a0,-1120 # 80001bbc +80000020: ba850513 addi a0,a0,-1112 # 80001bc4 80000024: 00002617 auipc a2,0x2 -80000028: c1860613 addi a2,a2,-1000 # 80001c3c <__BSS_END__> +80000028: c2060613 addi a2,a2,-992 # 80001c44 <__BSS_END__> 8000002c: 40a60633 sub a2,a2,a0 80000030: 00000593 li a1,0 -80000034: 4b8000ef jal ra,800004ec +80000034: 4c0000ef jal ra,800004f4 80000038: 00000517 auipc a0,0x0 -8000003c: 3bc50513 addi a0,a0,956 # 800003f4 <__libc_fini_array> -80000040: 36c000ef jal ra,800003ac -80000044: 40c000ef jal ra,80000450 <__libc_init_array> +8000003c: 3c450513 addi a0,a0,964 # 800003fc <__libc_fini_array> +80000040: 374000ef jal ra,800003b4 +80000044: 414000ef jal ra,80000458 <__libc_init_array> 80000048: 008000ef jal ra,80000050
    -8000004c: 3740006f j 800003c0 +8000004c: 37c0006f j 800003c8 Disassembly of section .text: @@ -34,532 +34,534 @@ Disassembly of section .text: 80000058: 800005b7 lui a1,0x80000 8000005c: 7ffff637 lui a2,0x7ffff 80000060: 08058593 addi a1,a1,128 # 80000080 <__stack_top+0x81000080> -80000064: 2000006f j 80000264 +80000064: 2080006f j 8000026c 80000068 : 80000068: 00000793 li a5,0 8000006c: 00078863 beqz a5,8000007c 80000070: 80000537 lui a0,0x80000 -80000074: 3f450513 addi a0,a0,1012 # 800003f4 <__stack_top+0x810003f4> -80000078: 3340006f j 800003ac +80000074: 3fc50513 addi a0,a0,1020 # 800003fc <__stack_top+0x810003fc> +80000078: 33c0006f j 800003b4 8000007c: 00008067 ret 80000080 : 80000080: 0085a783 lw a5,8(a1) -80000084: 00c5a803 lw a6,12(a1) -80000088: 0105a683 lw a3,16(a1) -8000008c: 02f50733 mul a4,a0,a5 -80000090: 0145ae83 lw t4,20(a1) -80000094: 0c078463 beqz a5,8000015c -80000098: 00e78e33 add t3,a5,a4 -8000009c: 002e1e13 slli t3,t3,0x2 -800000a0: 00271713 slli a4,a4,0x2 -800000a4: 01070633 add a2,a4,a6 -800000a8: 010e0e33 add t3,t3,a6 -800000ac: 410e8eb3 sub t4,t4,a6 -800000b0: 00062783 lw a5,0(a2) # 7ffff000 <__stack_size+0x7fffec00> -800000b4: 00462503 lw a0,4(a2) -800000b8: 00862583 lw a1,8(a2) -800000bc: 00c62303 lw t1,12(a2) -800000c0: 01062883 lw a7,16(a2) -800000c4: 00279793 slli a5,a5,0x2 -800000c8: 00251513 slli a0,a0,0x2 -800000cc: 01462803 lw a6,20(a2) -800000d0: 00a68533 add a0,a3,a0 -800000d4: 00f687b3 add a5,a3,a5 +80000084: 00c5a603 lw a2,12(a1) +80000088: 0105a703 lw a4,16(a1) +8000008c: 02f506b3 mul a3,a0,a5 +80000090: 0145a883 lw a7,20(a1) +80000094: 0c078863 beqz a5,80000164 +80000098: 00d78833 add a6,a5,a3 +8000009c: f0000653 fmv.w.x fa2,zero +800000a0: 00269693 slli a3,a3,0x2 +800000a4: 00281813 slli a6,a6,0x2 +800000a8: 00c686b3 add a3,a3,a2 +800000ac: 00c80833 add a6,a6,a2 +800000b0: 40c888b3 sub a7,a7,a2 +800000b4: 0006a583 lw a1,0(a3) +800000b8: 0086a603 lw a2,8(a3) +800000bc: 00c6a503 lw a0,12(a3) +800000c0: 00259593 slli a1,a1,0x2 +800000c4: 00b705b3 add a1,a4,a1 +800000c8: 0005a787 flw fa5,0(a1) +800000cc: 0046a583 lw a1,4(a3) +800000d0: 00261613 slli a2,a2,0x2 +800000d4: 10f677d3 fmul.s fa5,fa2,fa5 800000d8: 00259593 slli a1,a1,0x2 -800000dc: 00052f83 lw t6,0(a0) -800000e0: 0007a783 lw a5,0(a5) -800000e4: 01862503 lw a0,24(a2) -800000e8: 00b685b3 add a1,a3,a1 -800000ec: 00231313 slli t1,t1,0x2 -800000f0: 0005af03 lw t5,0(a1) -800000f4: 00668333 add t1,a3,t1 -800000f8: 01c62583 lw a1,28(a2) -800000fc: 00289893 slli a7,a7,0x2 -80000100: 00032303 lw t1,0(t1) -80000104: 011688b3 add a7,a3,a7 -80000108: 00281813 slli a6,a6,0x2 -8000010c: 0008a883 lw a7,0(a7) -80000110: 01f787b3 add a5,a5,t6 -80000114: 01068833 add a6,a3,a6 -80000118: 00251513 slli a0,a0,0x2 -8000011c: 00082803 lw a6,0(a6) -80000120: 01e787b3 add a5,a5,t5 -80000124: 00a68533 add a0,a3,a0 -80000128: 00259593 slli a1,a1,0x2 -8000012c: 00052503 lw a0,0(a0) -80000130: 006787b3 add a5,a5,t1 -80000134: 00b685b3 add a1,a3,a1 -80000138: 0005a583 lw a1,0(a1) -8000013c: 011787b3 add a5,a5,a7 -80000140: 010787b3 add a5,a5,a6 -80000144: 00a787b3 add a5,a5,a0 -80000148: 00ce8733 add a4,t4,a2 -8000014c: 00f587b3 add a5,a1,a5 -80000150: 00460613 addi a2,a2,4 -80000154: 00f72023 sw a5,0(a4) -80000158: f4ce1ce3 bne t3,a2,800000b0 -8000015c: 00008067 ret +800000dc: 00b705b3 add a1,a4,a1 +800000e0: 0005a687 flw fa3,0(a1) +800000e4: 00c70633 add a2,a4,a2 +800000e8: 00062707 flw fa4,0(a2) # 7ffff000 <__stack_size+0x7fffec00> +800000ec: 10d7f7d3 fmul.s fa5,fa5,fa3 +800000f0: 00251513 slli a0,a0,0x2 +800000f4: 00a70533 add a0,a4,a0 +800000f8: 0106a583 lw a1,16(a3) +800000fc: 0146a603 lw a2,20(a3) +80000100: 10e7f7d3 fmul.s fa5,fa5,fa4 +80000104: 00052707 flw fa4,0(a0) +80000108: 00259593 slli a1,a1,0x2 +8000010c: 00b705b3 add a1,a4,a1 +80000110: 0005a687 flw fa3,0(a1) +80000114: 10e7f7d3 fmul.s fa5,fa5,fa4 +80000118: 00261613 slli a2,a2,0x2 +8000011c: 00c70633 add a2,a4,a2 +80000120: 00062707 flw fa4,0(a2) +80000124: 0186a583 lw a1,24(a3) +80000128: 10d7f7d3 fmul.s fa5,fa5,fa3 +8000012c: 01c6a603 lw a2,28(a3) +80000130: 00259593 slli a1,a1,0x2 +80000134: 00b705b3 add a1,a4,a1 +80000138: 00261613 slli a2,a2,0x2 +8000013c: 10e7f7d3 fmul.s fa5,fa5,fa4 +80000140: 0005a707 flw fa4,0(a1) +80000144: 00c70633 add a2,a4,a2 +80000148: 00d887b3 add a5,a7,a3 +8000014c: 00468693 addi a3,a3,4 +80000150: 10e7f7d3 fmul.s fa5,fa5,fa4 +80000154: 00062707 flw fa4,0(a2) +80000158: 10f777d3 fmul.s fa5,fa4,fa5 +8000015c: 00f7a027 fsw fa5,0(a5) +80000160: f4d81ae3 bne a6,a3,800000b4 +80000164: 00008067 ret -80000160 <_exit>: -80000160: 00000513 li a0,0 -80000164: 0005006b 0x5006b - -80000168 : -80000168: fc002573 csrr a0,0xfc0 +80000168 <_exit>: +80000168: 00000513 li a0,0 8000016c: 0005006b 0x5006b -80000170: 00002197 auipc gp,0x2 -80000174: e2018193 addi gp,gp,-480 # 80001f90 <__global_pointer> -80000178: 7f000117 auipc sp,0x7f000 -8000017c: e8810113 addi sp,sp,-376 # ff000000 <__stack_top> -80000180: 40000593 li a1,1024 -80000184: cc102673 csrr a2,0xcc1 -80000188: 02c585b3 mul a1,a1,a2 -8000018c: 40b10133 sub sp,sp,a1 -80000190: cc3026f3 csrr a3,0xcc3 -80000194: 00068663 beqz a3,800001a0 -80000198: 00000513 li a0,0 -8000019c: 0005006b 0x5006b -800001a0 : -800001a0: 00008067 ret +80000170 : +80000170: fc002573 csrr a0,0xfc0 +80000174: 0005006b 0x5006b +80000178: 00002197 auipc gp,0x2 +8000017c: e2018193 addi gp,gp,-480 # 80001f98 <__global_pointer> +80000180: 7f000117 auipc sp,0x7f000 +80000184: e8010113 addi sp,sp,-384 # ff000000 <__stack_top> +80000188: 40000593 li a1,1024 +8000018c: cc102673 csrr a2,0xcc1 +80000190: 02c585b3 mul a1,a1,a2 +80000194: 40b10133 sub sp,sp,a1 +80000198: cc3026f3 csrr a3,0xcc3 +8000019c: 00068663 beqz a3,800001a8 +800001a0: 00000513 li a0,0 +800001a4: 0005006b 0x5006b -800001a4 : -800001a4: fe010113 addi sp,sp,-32 -800001a8: 00112e23 sw ra,28(sp) -800001ac: 00812c23 sw s0,24(sp) -800001b0: 00912a23 sw s1,20(sp) -800001b4: 01212823 sw s2,16(sp) -800001b8: 01312623 sw s3,12(sp) -800001bc: fc0027f3 csrr a5,0xfc0 -800001c0: 0007806b 0x7806b -800001c4: cc5027f3 csrr a5,0xcc5 -800001c8: cc3029f3 csrr s3,0xcc3 -800001cc: cc002773 csrr a4,0xcc0 -800001d0: fc002673 csrr a2,0xfc0 -800001d4: 00279693 slli a3,a5,0x2 -800001d8: 800027b7 lui a5,0x80002 -800001dc: bbc78793 addi a5,a5,-1092 # 80001bbc <__stack_top+0x81001bbc> -800001e0: 00d787b3 add a5,a5,a3 -800001e4: 0007a483 lw s1,0(a5) -800001e8: 0104a403 lw s0,16(s1) -800001ec: 00c4a683 lw a3,12(s1) -800001f0: 0089a933 slt s2,s3,s0 -800001f4: 00040793 mv a5,s0 -800001f8: 00d90933 add s2,s2,a3 -800001fc: 03368433 mul s0,a3,s3 -80000200: 00f9d463 bge s3,a5,80000208 -80000204: 00098793 mv a5,s3 -80000208: 00f40433 add s0,s0,a5 -8000020c: 0084a683 lw a3,8(s1) -80000210: 02c40433 mul s0,s0,a2 -80000214: 02e907b3 mul a5,s2,a4 -80000218: 00d40433 add s0,s0,a3 -8000021c: 00f40433 add s0,s0,a5 -80000220: 00890933 add s2,s2,s0 -80000224: 01245e63 bge s0,s2,80000240 -80000228: 0004a783 lw a5,0(s1) -8000022c: 0044a583 lw a1,4(s1) -80000230: 00040513 mv a0,s0 -80000234: 00140413 addi s0,s0,1 -80000238: 000780e7 jalr a5 -8000023c: fe8916e3 bne s2,s0,80000228 -80000240: 0019b993 seqz s3,s3 -80000244: 0009806b 0x9806b -80000248: 01c12083 lw ra,28(sp) -8000024c: 01812403 lw s0,24(sp) -80000250: 01412483 lw s1,20(sp) -80000254: 01012903 lw s2,16(sp) -80000258: 00c12983 lw s3,12(sp) -8000025c: 02010113 addi sp,sp,32 -80000260: 00008067 ret +800001a8 : +800001a8: 00008067 ret -80000264 : -80000264: fc010113 addi sp,sp,-64 -80000268: 02112e23 sw ra,60(sp) -8000026c: 02812c23 sw s0,56(sp) -80000270: 02912a23 sw s1,52(sp) -80000274: 03212823 sw s2,48(sp) -80000278: 03312623 sw s3,44(sp) -8000027c: fc2026f3 csrr a3,0xfc2 -80000280: fc102873 csrr a6,0xfc1 -80000284: fc002473 csrr s0,0xfc0 -80000288: cc5027f3 csrr a5,0xcc5 -8000028c: 01f00713 li a4,31 -80000290: 0cf74463 blt a4,a5,80000358 -80000294: 030408b3 mul a7,s0,a6 -80000298: 00100713 li a4,1 -8000029c: 00a8d463 bge a7,a0,800002a4 -800002a0: 03154733 div a4,a0,a7 -800002a4: 0ce6c863 blt a3,a4,80000374 -800002a8: 0ae7d863 bge a5,a4,80000358 -800002ac: fff68693 addi a3,a3,-1 -800002b0: 02e54333 div t1,a0,a4 -800002b4: 00030893 mv a7,t1 -800002b8: 00f69663 bne a3,a5,800002c4 -800002bc: 02e56533 rem a0,a0,a4 -800002c0: 006508b3 add a7,a0,t1 -800002c4: 0288c4b3 div s1,a7,s0 -800002c8: 0288e933 rem s2,a7,s0 -800002cc: 0b04ca63 blt s1,a6,80000380 -800002d0: 00100693 li a3,1 -800002d4: 0304c733 div a4,s1,a6 -800002d8: 00070663 beqz a4,800002e4 -800002dc: 00070693 mv a3,a4 -800002e0: 0304e733 rem a4,s1,a6 -800002e4: 800029b7 lui s3,0x80002 -800002e8: bbc98993 addi s3,s3,-1092 # 80001bbc <__stack_top+0x81001bbc> -800002ec: 00e12e23 sw a4,28(sp) -800002f0: 00c10713 addi a4,sp,12 -800002f4: 00b12623 sw a1,12(sp) -800002f8: 00c12823 sw a2,16(sp) -800002fc: 00d12c23 sw a3,24(sp) -80000300: 02f30333 mul t1,t1,a5 -80000304: 00279793 slli a5,a5,0x2 -80000308: 00f987b3 add a5,s3,a5 -8000030c: 00e7a023 sw a4,0(a5) -80000310: 00612a23 sw t1,20(sp) -80000314: 06904c63 bgtz s1,8000038c -80000318: 04090063 beqz s2,80000358 -8000031c: 02848433 mul s0,s1,s0 -80000320: 00812a23 sw s0,20(sp) -80000324: 0009006b 0x9006b -80000328: cc5027f3 csrr a5,0xcc5 -8000032c: cc202573 csrr a0,0xcc2 -80000330: 00279793 slli a5,a5,0x2 -80000334: 00f989b3 add s3,s3,a5 -80000338: 0009a783 lw a5,0(s3) -8000033c: 0087a683 lw a3,8(a5) -80000340: 0007a703 lw a4,0(a5) -80000344: 0047a583 lw a1,4(a5) -80000348: 00d50533 add a0,a0,a3 -8000034c: 000700e7 jalr a4 -80000350: 00100793 li a5,1 -80000354: 0007806b 0x7806b -80000358: 03c12083 lw ra,60(sp) -8000035c: 03812403 lw s0,56(sp) -80000360: 03412483 lw s1,52(sp) -80000364: 03012903 lw s2,48(sp) -80000368: 02c12983 lw s3,44(sp) -8000036c: 04010113 addi sp,sp,64 -80000370: 00008067 ret -80000374: 00068713 mv a4,a3 -80000378: f2e7cae3 blt a5,a4,800002ac -8000037c: fddff06f j 80000358 -80000380: 00000713 li a4,0 -80000384: 00100693 li a3,1 -80000388: f5dff06f j 800002e4 -8000038c: 00048713 mv a4,s1 -80000390: 00985463 bge a6,s1,80000398 -80000394: 00080713 mv a4,a6 -80000398: 800007b7 lui a5,0x80000 -8000039c: 1a478793 addi a5,a5,420 # 800001a4 <__stack_top+0x810001a4> -800003a0: 00f7106b 0xf7106b -800003a4: e01ff0ef jal ra,800001a4 -800003a8: f71ff06f j 80000318 +800001ac : +800001ac: fe010113 addi sp,sp,-32 +800001b0: 00112e23 sw ra,28(sp) +800001b4: 00812c23 sw s0,24(sp) +800001b8: 00912a23 sw s1,20(sp) +800001bc: 01212823 sw s2,16(sp) +800001c0: 01312623 sw s3,12(sp) +800001c4: fc0027f3 csrr a5,0xfc0 +800001c8: 0007806b 0x7806b +800001cc: cc5027f3 csrr a5,0xcc5 +800001d0: cc3029f3 csrr s3,0xcc3 +800001d4: cc002773 csrr a4,0xcc0 +800001d8: fc002673 csrr a2,0xfc0 +800001dc: 00279693 slli a3,a5,0x2 +800001e0: 800027b7 lui a5,0x80002 +800001e4: bc478793 addi a5,a5,-1084 # 80001bc4 <__stack_top+0x81001bc4> +800001e8: 00d787b3 add a5,a5,a3 +800001ec: 0007a483 lw s1,0(a5) +800001f0: 0104a403 lw s0,16(s1) +800001f4: 00c4a683 lw a3,12(s1) +800001f8: 0089a933 slt s2,s3,s0 +800001fc: 00040793 mv a5,s0 +80000200: 00d90933 add s2,s2,a3 +80000204: 03368433 mul s0,a3,s3 +80000208: 00f9d463 bge s3,a5,80000210 +8000020c: 00098793 mv a5,s3 +80000210: 00f40433 add s0,s0,a5 +80000214: 0084a683 lw a3,8(s1) +80000218: 02c40433 mul s0,s0,a2 +8000021c: 02e907b3 mul a5,s2,a4 +80000220: 00d40433 add s0,s0,a3 +80000224: 00f40433 add s0,s0,a5 +80000228: 00890933 add s2,s2,s0 +8000022c: 01245e63 bge s0,s2,80000248 +80000230: 0004a783 lw a5,0(s1) +80000234: 0044a583 lw a1,4(s1) +80000238: 00040513 mv a0,s0 +8000023c: 00140413 addi s0,s0,1 +80000240: 000780e7 jalr a5 +80000244: fe8916e3 bne s2,s0,80000230 +80000248: 0019b993 seqz s3,s3 +8000024c: 0009806b 0x9806b +80000250: 01c12083 lw ra,28(sp) +80000254: 01812403 lw s0,24(sp) +80000258: 01412483 lw s1,20(sp) +8000025c: 01012903 lw s2,16(sp) +80000260: 00c12983 lw s3,12(sp) +80000264: 02010113 addi sp,sp,32 +80000268: 00008067 ret -800003ac : -800003ac: 00050593 mv a1,a0 -800003b0: 00000693 li a3,0 -800003b4: 00000613 li a2,0 -800003b8: 00000513 li a0,0 -800003bc: 20c0006f j 800005c8 <__register_exitproc> +8000026c : +8000026c: fc010113 addi sp,sp,-64 +80000270: 02112e23 sw ra,60(sp) +80000274: 02812c23 sw s0,56(sp) +80000278: 02912a23 sw s1,52(sp) +8000027c: 03212823 sw s2,48(sp) +80000280: 03312623 sw s3,44(sp) +80000284: fc2026f3 csrr a3,0xfc2 +80000288: fc102873 csrr a6,0xfc1 +8000028c: fc002473 csrr s0,0xfc0 +80000290: cc5027f3 csrr a5,0xcc5 +80000294: 01f00713 li a4,31 +80000298: 0cf74463 blt a4,a5,80000360 +8000029c: 030408b3 mul a7,s0,a6 +800002a0: 00100713 li a4,1 +800002a4: 00a8d463 bge a7,a0,800002ac +800002a8: 03154733 div a4,a0,a7 +800002ac: 0ce6c863 blt a3,a4,8000037c +800002b0: 0ae7d863 bge a5,a4,80000360 +800002b4: fff68693 addi a3,a3,-1 +800002b8: 02e54333 div t1,a0,a4 +800002bc: 00030893 mv a7,t1 +800002c0: 00f69663 bne a3,a5,800002cc +800002c4: 02e56533 rem a0,a0,a4 +800002c8: 006508b3 add a7,a0,t1 +800002cc: 0288c4b3 div s1,a7,s0 +800002d0: 0288e933 rem s2,a7,s0 +800002d4: 0b04ca63 blt s1,a6,80000388 +800002d8: 00100693 li a3,1 +800002dc: 0304c733 div a4,s1,a6 +800002e0: 00070663 beqz a4,800002ec +800002e4: 00070693 mv a3,a4 +800002e8: 0304e733 rem a4,s1,a6 +800002ec: 800029b7 lui s3,0x80002 +800002f0: bc498993 addi s3,s3,-1084 # 80001bc4 <__stack_top+0x81001bc4> +800002f4: 00e12e23 sw a4,28(sp) +800002f8: 00c10713 addi a4,sp,12 +800002fc: 00b12623 sw a1,12(sp) +80000300: 00c12823 sw a2,16(sp) +80000304: 00d12c23 sw a3,24(sp) +80000308: 02f30333 mul t1,t1,a5 +8000030c: 00279793 slli a5,a5,0x2 +80000310: 00f987b3 add a5,s3,a5 +80000314: 00e7a023 sw a4,0(a5) +80000318: 00612a23 sw t1,20(sp) +8000031c: 06904c63 bgtz s1,80000394 +80000320: 04090063 beqz s2,80000360 +80000324: 02848433 mul s0,s1,s0 +80000328: 00812a23 sw s0,20(sp) +8000032c: 0009006b 0x9006b +80000330: cc5027f3 csrr a5,0xcc5 +80000334: cc202573 csrr a0,0xcc2 +80000338: 00279793 slli a5,a5,0x2 +8000033c: 00f989b3 add s3,s3,a5 +80000340: 0009a783 lw a5,0(s3) +80000344: 0087a683 lw a3,8(a5) +80000348: 0007a703 lw a4,0(a5) +8000034c: 0047a583 lw a1,4(a5) +80000350: 00d50533 add a0,a0,a3 +80000354: 000700e7 jalr a4 +80000358: 00100793 li a5,1 +8000035c: 0007806b 0x7806b +80000360: 03c12083 lw ra,60(sp) +80000364: 03812403 lw s0,56(sp) +80000368: 03412483 lw s1,52(sp) +8000036c: 03012903 lw s2,48(sp) +80000370: 02c12983 lw s3,44(sp) +80000374: 04010113 addi sp,sp,64 +80000378: 00008067 ret +8000037c: 00068713 mv a4,a3 +80000380: f2e7cae3 blt a5,a4,800002b4 +80000384: fddff06f j 80000360 +80000388: 00000713 li a4,0 +8000038c: 00100693 li a3,1 +80000390: f5dff06f j 800002ec +80000394: 00048713 mv a4,s1 +80000398: 00985463 bge a6,s1,800003a0 +8000039c: 00080713 mv a4,a6 +800003a0: 800007b7 lui a5,0x80000 +800003a4: 1ac78793 addi a5,a5,428 # 800001ac <__stack_top+0x810001ac> +800003a8: 00f7106b 0xf7106b +800003ac: e01ff0ef jal ra,800001ac +800003b0: f71ff06f j 80000320 -800003c0 : -800003c0: ff010113 addi sp,sp,-16 -800003c4: 00000593 li a1,0 -800003c8: 00812423 sw s0,8(sp) -800003cc: 00112623 sw ra,12(sp) -800003d0: 00050413 mv s0,a0 -800003d4: 290000ef jal ra,80000664 <__call_exitprocs> -800003d8: 800027b7 lui a5,0x80002 -800003dc: bb87a503 lw a0,-1096(a5) # 80001bb8 <__stack_top+0x81001bb8> -800003e0: 03c52783 lw a5,60(a0) -800003e4: 00078463 beqz a5,800003ec -800003e8: 000780e7 jalr a5 -800003ec: 00040513 mv a0,s0 -800003f0: d71ff0ef jal ra,80000160 <_exit> +800003b4 : +800003b4: 00050593 mv a1,a0 +800003b8: 00000693 li a3,0 +800003bc: 00000613 li a2,0 +800003c0: 00000513 li a0,0 +800003c4: 20c0006f j 800005d0 <__register_exitproc> -800003f4 <__libc_fini_array>: -800003f4: ff010113 addi sp,sp,-16 -800003f8: 00812423 sw s0,8(sp) -800003fc: 800017b7 lui a5,0x80001 -80000400: 80001437 lui s0,0x80001 -80000404: 78c40413 addi s0,s0,1932 # 8000178c <__stack_top+0x8100178c> -80000408: 78c78793 addi a5,a5,1932 # 8000178c <__stack_top+0x8100178c> -8000040c: 408787b3 sub a5,a5,s0 -80000410: 00912223 sw s1,4(sp) -80000414: 00112623 sw ra,12(sp) -80000418: 4027d493 srai s1,a5,0x2 -8000041c: 02048063 beqz s1,8000043c <__libc_fini_array+0x48> -80000420: ffc78793 addi a5,a5,-4 -80000424: 00878433 add s0,a5,s0 -80000428: 00042783 lw a5,0(s0) -8000042c: fff48493 addi s1,s1,-1 -80000430: ffc40413 addi s0,s0,-4 -80000434: 000780e7 jalr a5 -80000438: fe0498e3 bnez s1,80000428 <__libc_fini_array+0x34> -8000043c: 00c12083 lw ra,12(sp) -80000440: 00812403 lw s0,8(sp) -80000444: 00412483 lw s1,4(sp) -80000448: 01010113 addi sp,sp,16 -8000044c: 00008067 ret +800003c8 : +800003c8: ff010113 addi sp,sp,-16 +800003cc: 00000593 li a1,0 +800003d0: 00812423 sw s0,8(sp) +800003d4: 00112623 sw ra,12(sp) +800003d8: 00050413 mv s0,a0 +800003dc: 290000ef jal ra,8000066c <__call_exitprocs> +800003e0: 800027b7 lui a5,0x80002 +800003e4: bc07a503 lw a0,-1088(a5) # 80001bc0 <__stack_top+0x81001bc0> +800003e8: 03c52783 lw a5,60(a0) +800003ec: 00078463 beqz a5,800003f4 +800003f0: 000780e7 jalr a5 +800003f4: 00040513 mv a0,s0 +800003f8: d71ff0ef jal ra,80000168 <_exit> -80000450 <__libc_init_array>: -80000450: ff010113 addi sp,sp,-16 -80000454: 00812423 sw s0,8(sp) -80000458: 01212023 sw s2,0(sp) -8000045c: 80001437 lui s0,0x80001 -80000460: 80001937 lui s2,0x80001 -80000464: 78840793 addi a5,s0,1928 # 80001788 <__stack_top+0x81001788> -80000468: 78890913 addi s2,s2,1928 # 80001788 <__stack_top+0x81001788> -8000046c: 40f90933 sub s2,s2,a5 -80000470: 00112623 sw ra,12(sp) -80000474: 00912223 sw s1,4(sp) -80000478: 40295913 srai s2,s2,0x2 -8000047c: 02090063 beqz s2,8000049c <__libc_init_array+0x4c> -80000480: 78840413 addi s0,s0,1928 -80000484: 00000493 li s1,0 -80000488: 00042783 lw a5,0(s0) -8000048c: 00148493 addi s1,s1,1 -80000490: 00440413 addi s0,s0,4 -80000494: 000780e7 jalr a5 -80000498: fe9918e3 bne s2,s1,80000488 <__libc_init_array+0x38> -8000049c: 80001437 lui s0,0x80001 -800004a0: 80001937 lui s2,0x80001 -800004a4: 78840793 addi a5,s0,1928 # 80001788 <__stack_top+0x81001788> -800004a8: 78c90913 addi s2,s2,1932 # 8000178c <__stack_top+0x8100178c> -800004ac: 40f90933 sub s2,s2,a5 -800004b0: 40295913 srai s2,s2,0x2 -800004b4: 02090063 beqz s2,800004d4 <__libc_init_array+0x84> -800004b8: 78840413 addi s0,s0,1928 -800004bc: 00000493 li s1,0 -800004c0: 00042783 lw a5,0(s0) -800004c4: 00148493 addi s1,s1,1 -800004c8: 00440413 addi s0,s0,4 -800004cc: 000780e7 jalr a5 -800004d0: fe9918e3 bne s2,s1,800004c0 <__libc_init_array+0x70> -800004d4: 00c12083 lw ra,12(sp) -800004d8: 00812403 lw s0,8(sp) -800004dc: 00412483 lw s1,4(sp) -800004e0: 00012903 lw s2,0(sp) -800004e4: 01010113 addi sp,sp,16 -800004e8: 00008067 ret +800003fc <__libc_fini_array>: +800003fc: ff010113 addi sp,sp,-16 +80000400: 00812423 sw s0,8(sp) +80000404: 800017b7 lui a5,0x80001 +80000408: 80001437 lui s0,0x80001 +8000040c: 79440413 addi s0,s0,1940 # 80001794 <__stack_top+0x81001794> +80000410: 79478793 addi a5,a5,1940 # 80001794 <__stack_top+0x81001794> +80000414: 408787b3 sub a5,a5,s0 +80000418: 00912223 sw s1,4(sp) +8000041c: 00112623 sw ra,12(sp) +80000420: 4027d493 srai s1,a5,0x2 +80000424: 02048063 beqz s1,80000444 <__libc_fini_array+0x48> +80000428: ffc78793 addi a5,a5,-4 +8000042c: 00878433 add s0,a5,s0 +80000430: 00042783 lw a5,0(s0) +80000434: fff48493 addi s1,s1,-1 +80000438: ffc40413 addi s0,s0,-4 +8000043c: 000780e7 jalr a5 +80000440: fe0498e3 bnez s1,80000430 <__libc_fini_array+0x34> +80000444: 00c12083 lw ra,12(sp) +80000448: 00812403 lw s0,8(sp) +8000044c: 00412483 lw s1,4(sp) +80000450: 01010113 addi sp,sp,16 +80000454: 00008067 ret -800004ec : -800004ec: 00f00313 li t1,15 -800004f0: 00050713 mv a4,a0 -800004f4: 02c37e63 bgeu t1,a2,80000530 -800004f8: 00f77793 andi a5,a4,15 -800004fc: 0a079063 bnez a5,8000059c -80000500: 08059263 bnez a1,80000584 -80000504: ff067693 andi a3,a2,-16 -80000508: 00f67613 andi a2,a2,15 -8000050c: 00e686b3 add a3,a3,a4 -80000510: 00b72023 sw a1,0(a4) -80000514: 00b72223 sw a1,4(a4) -80000518: 00b72423 sw a1,8(a4) -8000051c: 00b72623 sw a1,12(a4) -80000520: 01070713 addi a4,a4,16 -80000524: fed766e3 bltu a4,a3,80000510 -80000528: 00061463 bnez a2,80000530 -8000052c: 00008067 ret -80000530: 40c306b3 sub a3,t1,a2 -80000534: 00269693 slli a3,a3,0x2 -80000538: 00000297 auipc t0,0x0 -8000053c: 005686b3 add a3,a3,t0 -80000540: 00c68067 jr 12(a3) -80000544: 00b70723 sb a1,14(a4) -80000548: 00b706a3 sb a1,13(a4) -8000054c: 00b70623 sb a1,12(a4) -80000550: 00b705a3 sb a1,11(a4) -80000554: 00b70523 sb a1,10(a4) -80000558: 00b704a3 sb a1,9(a4) -8000055c: 00b70423 sb a1,8(a4) -80000560: 00b703a3 sb a1,7(a4) -80000564: 00b70323 sb a1,6(a4) -80000568: 00b702a3 sb a1,5(a4) -8000056c: 00b70223 sb a1,4(a4) -80000570: 00b701a3 sb a1,3(a4) -80000574: 00b70123 sb a1,2(a4) -80000578: 00b700a3 sb a1,1(a4) -8000057c: 00b70023 sb a1,0(a4) -80000580: 00008067 ret -80000584: 0ff5f593 andi a1,a1,255 -80000588: 00859693 slli a3,a1,0x8 -8000058c: 00d5e5b3 or a1,a1,a3 -80000590: 01059693 slli a3,a1,0x10 +80000458 <__libc_init_array>: +80000458: ff010113 addi sp,sp,-16 +8000045c: 00812423 sw s0,8(sp) +80000460: 01212023 sw s2,0(sp) +80000464: 80001437 lui s0,0x80001 +80000468: 80001937 lui s2,0x80001 +8000046c: 79040793 addi a5,s0,1936 # 80001790 <__stack_top+0x81001790> +80000470: 79090913 addi s2,s2,1936 # 80001790 <__stack_top+0x81001790> +80000474: 40f90933 sub s2,s2,a5 +80000478: 00112623 sw ra,12(sp) +8000047c: 00912223 sw s1,4(sp) +80000480: 40295913 srai s2,s2,0x2 +80000484: 02090063 beqz s2,800004a4 <__libc_init_array+0x4c> +80000488: 79040413 addi s0,s0,1936 +8000048c: 00000493 li s1,0 +80000490: 00042783 lw a5,0(s0) +80000494: 00148493 addi s1,s1,1 +80000498: 00440413 addi s0,s0,4 +8000049c: 000780e7 jalr a5 +800004a0: fe9918e3 bne s2,s1,80000490 <__libc_init_array+0x38> +800004a4: 80001437 lui s0,0x80001 +800004a8: 80001937 lui s2,0x80001 +800004ac: 79040793 addi a5,s0,1936 # 80001790 <__stack_top+0x81001790> +800004b0: 79490913 addi s2,s2,1940 # 80001794 <__stack_top+0x81001794> +800004b4: 40f90933 sub s2,s2,a5 +800004b8: 40295913 srai s2,s2,0x2 +800004bc: 02090063 beqz s2,800004dc <__libc_init_array+0x84> +800004c0: 79040413 addi s0,s0,1936 +800004c4: 00000493 li s1,0 +800004c8: 00042783 lw a5,0(s0) +800004cc: 00148493 addi s1,s1,1 +800004d0: 00440413 addi s0,s0,4 +800004d4: 000780e7 jalr a5 +800004d8: fe9918e3 bne s2,s1,800004c8 <__libc_init_array+0x70> +800004dc: 00c12083 lw ra,12(sp) +800004e0: 00812403 lw s0,8(sp) +800004e4: 00412483 lw s1,4(sp) +800004e8: 00012903 lw s2,0(sp) +800004ec: 01010113 addi sp,sp,16 +800004f0: 00008067 ret + +800004f4 : +800004f4: 00f00313 li t1,15 +800004f8: 00050713 mv a4,a0 +800004fc: 02c37e63 bgeu t1,a2,80000538 +80000500: 00f77793 andi a5,a4,15 +80000504: 0a079063 bnez a5,800005a4 +80000508: 08059263 bnez a1,8000058c +8000050c: ff067693 andi a3,a2,-16 +80000510: 00f67613 andi a2,a2,15 +80000514: 00e686b3 add a3,a3,a4 +80000518: 00b72023 sw a1,0(a4) +8000051c: 00b72223 sw a1,4(a4) +80000520: 00b72423 sw a1,8(a4) +80000524: 00b72623 sw a1,12(a4) +80000528: 01070713 addi a4,a4,16 +8000052c: fed766e3 bltu a4,a3,80000518 +80000530: 00061463 bnez a2,80000538 +80000534: 00008067 ret +80000538: 40c306b3 sub a3,t1,a2 +8000053c: 00269693 slli a3,a3,0x2 +80000540: 00000297 auipc t0,0x0 +80000544: 005686b3 add a3,a3,t0 +80000548: 00c68067 jr 12(a3) +8000054c: 00b70723 sb a1,14(a4) +80000550: 00b706a3 sb a1,13(a4) +80000554: 00b70623 sb a1,12(a4) +80000558: 00b705a3 sb a1,11(a4) +8000055c: 00b70523 sb a1,10(a4) +80000560: 00b704a3 sb a1,9(a4) +80000564: 00b70423 sb a1,8(a4) +80000568: 00b703a3 sb a1,7(a4) +8000056c: 00b70323 sb a1,6(a4) +80000570: 00b702a3 sb a1,5(a4) +80000574: 00b70223 sb a1,4(a4) +80000578: 00b701a3 sb a1,3(a4) +8000057c: 00b70123 sb a1,2(a4) +80000580: 00b700a3 sb a1,1(a4) +80000584: 00b70023 sb a1,0(a4) +80000588: 00008067 ret +8000058c: 0ff5f593 andi a1,a1,255 +80000590: 00859693 slli a3,a1,0x8 80000594: 00d5e5b3 or a1,a1,a3 -80000598: f6dff06f j 80000504 -8000059c: 00279693 slli a3,a5,0x2 -800005a0: 00000297 auipc t0,0x0 -800005a4: 005686b3 add a3,a3,t0 -800005a8: 00008293 mv t0,ra -800005ac: fa0680e7 jalr -96(a3) -800005b0: 00028093 mv ra,t0 -800005b4: ff078793 addi a5,a5,-16 -800005b8: 40f70733 sub a4,a4,a5 -800005bc: 00f60633 add a2,a2,a5 -800005c0: f6c378e3 bgeu t1,a2,80000530 -800005c4: f3dff06f j 80000500 +80000598: 01059693 slli a3,a1,0x10 +8000059c: 00d5e5b3 or a1,a1,a3 +800005a0: f6dff06f j 8000050c +800005a4: 00279693 slli a3,a5,0x2 +800005a8: 00000297 auipc t0,0x0 +800005ac: 005686b3 add a3,a3,t0 +800005b0: 00008293 mv t0,ra +800005b4: fa0680e7 jalr -96(a3) +800005b8: 00028093 mv ra,t0 +800005bc: ff078793 addi a5,a5,-16 +800005c0: 40f70733 sub a4,a4,a5 +800005c4: 00f60633 add a2,a2,a5 +800005c8: f6c378e3 bgeu t1,a2,80000538 +800005cc: f3dff06f j 80000508 -800005c8 <__register_exitproc>: -800005c8: 800027b7 lui a5,0x80002 -800005cc: bb87a703 lw a4,-1096(a5) # 80001bb8 <__stack_top+0x81001bb8> -800005d0: 14872783 lw a5,328(a4) -800005d4: 04078c63 beqz a5,8000062c <__register_exitproc+0x64> -800005d8: 0047a703 lw a4,4(a5) -800005dc: 01f00813 li a6,31 -800005e0: 06e84e63 blt a6,a4,8000065c <__register_exitproc+0x94> -800005e4: 00271813 slli a6,a4,0x2 -800005e8: 02050663 beqz a0,80000614 <__register_exitproc+0x4c> -800005ec: 01078333 add t1,a5,a6 -800005f0: 08c32423 sw a2,136(t1) -800005f4: 1887a883 lw a7,392(a5) -800005f8: 00100613 li a2,1 -800005fc: 00e61633 sll a2,a2,a4 -80000600: 00c8e8b3 or a7,a7,a2 -80000604: 1917a423 sw a7,392(a5) -80000608: 10d32423 sw a3,264(t1) -8000060c: 00200693 li a3,2 -80000610: 02d50463 beq a0,a3,80000638 <__register_exitproc+0x70> -80000614: 00170713 addi a4,a4,1 -80000618: 00e7a223 sw a4,4(a5) -8000061c: 010787b3 add a5,a5,a6 -80000620: 00b7a423 sw a1,8(a5) -80000624: 00000513 li a0,0 -80000628: 00008067 ret -8000062c: 14c70793 addi a5,a4,332 -80000630: 14f72423 sw a5,328(a4) -80000634: fa5ff06f j 800005d8 <__register_exitproc+0x10> -80000638: 18c7a683 lw a3,396(a5) -8000063c: 00170713 addi a4,a4,1 -80000640: 00e7a223 sw a4,4(a5) -80000644: 00c6e633 or a2,a3,a2 -80000648: 18c7a623 sw a2,396(a5) -8000064c: 010787b3 add a5,a5,a6 -80000650: 00b7a423 sw a1,8(a5) -80000654: 00000513 li a0,0 -80000658: 00008067 ret -8000065c: fff00513 li a0,-1 +800005d0 <__register_exitproc>: +800005d0: 800027b7 lui a5,0x80002 +800005d4: bc07a703 lw a4,-1088(a5) # 80001bc0 <__stack_top+0x81001bc0> +800005d8: 14872783 lw a5,328(a4) +800005dc: 04078c63 beqz a5,80000634 <__register_exitproc+0x64> +800005e0: 0047a703 lw a4,4(a5) +800005e4: 01f00813 li a6,31 +800005e8: 06e84e63 blt a6,a4,80000664 <__register_exitproc+0x94> +800005ec: 00271813 slli a6,a4,0x2 +800005f0: 02050663 beqz a0,8000061c <__register_exitproc+0x4c> +800005f4: 01078333 add t1,a5,a6 +800005f8: 08c32423 sw a2,136(t1) +800005fc: 1887a883 lw a7,392(a5) +80000600: 00100613 li a2,1 +80000604: 00e61633 sll a2,a2,a4 +80000608: 00c8e8b3 or a7,a7,a2 +8000060c: 1917a423 sw a7,392(a5) +80000610: 10d32423 sw a3,264(t1) +80000614: 00200693 li a3,2 +80000618: 02d50463 beq a0,a3,80000640 <__register_exitproc+0x70> +8000061c: 00170713 addi a4,a4,1 +80000620: 00e7a223 sw a4,4(a5) +80000624: 010787b3 add a5,a5,a6 +80000628: 00b7a423 sw a1,8(a5) +8000062c: 00000513 li a0,0 +80000630: 00008067 ret +80000634: 14c70793 addi a5,a4,332 +80000638: 14f72423 sw a5,328(a4) +8000063c: fa5ff06f j 800005e0 <__register_exitproc+0x10> +80000640: 18c7a683 lw a3,396(a5) +80000644: 00170713 addi a4,a4,1 +80000648: 00e7a223 sw a4,4(a5) +8000064c: 00c6e633 or a2,a3,a2 +80000650: 18c7a623 sw a2,396(a5) +80000654: 010787b3 add a5,a5,a6 +80000658: 00b7a423 sw a1,8(a5) +8000065c: 00000513 li a0,0 80000660: 00008067 ret +80000664: fff00513 li a0,-1 +80000668: 00008067 ret -80000664 <__call_exitprocs>: -80000664: fd010113 addi sp,sp,-48 -80000668: 800027b7 lui a5,0x80002 -8000066c: 01412c23 sw s4,24(sp) -80000670: bb87aa03 lw s4,-1096(a5) # 80001bb8 <__stack_top+0x81001bb8> -80000674: 03212023 sw s2,32(sp) -80000678: 02112623 sw ra,44(sp) -8000067c: 148a2903 lw s2,328(s4) -80000680: 02812423 sw s0,40(sp) -80000684: 02912223 sw s1,36(sp) -80000688: 01312e23 sw s3,28(sp) -8000068c: 01512a23 sw s5,20(sp) -80000690: 01612823 sw s6,16(sp) -80000694: 01712623 sw s7,12(sp) -80000698: 01812423 sw s8,8(sp) -8000069c: 04090063 beqz s2,800006dc <__call_exitprocs+0x78> -800006a0: 00050b13 mv s6,a0 -800006a4: 00058b93 mv s7,a1 -800006a8: 00100a93 li s5,1 -800006ac: fff00993 li s3,-1 -800006b0: 00492483 lw s1,4(s2) -800006b4: fff48413 addi s0,s1,-1 -800006b8: 02044263 bltz s0,800006dc <__call_exitprocs+0x78> -800006bc: 00249493 slli s1,s1,0x2 -800006c0: 009904b3 add s1,s2,s1 -800006c4: 040b8463 beqz s7,8000070c <__call_exitprocs+0xa8> -800006c8: 1044a783 lw a5,260(s1) -800006cc: 05778063 beq a5,s7,8000070c <__call_exitprocs+0xa8> -800006d0: fff40413 addi s0,s0,-1 -800006d4: ffc48493 addi s1,s1,-4 -800006d8: ff3416e3 bne s0,s3,800006c4 <__call_exitprocs+0x60> -800006dc: 02c12083 lw ra,44(sp) -800006e0: 02812403 lw s0,40(sp) -800006e4: 02412483 lw s1,36(sp) -800006e8: 02012903 lw s2,32(sp) -800006ec: 01c12983 lw s3,28(sp) -800006f0: 01812a03 lw s4,24(sp) -800006f4: 01412a83 lw s5,20(sp) -800006f8: 01012b03 lw s6,16(sp) -800006fc: 00c12b83 lw s7,12(sp) -80000700: 00812c03 lw s8,8(sp) -80000704: 03010113 addi sp,sp,48 -80000708: 00008067 ret -8000070c: 00492783 lw a5,4(s2) -80000710: 0044a683 lw a3,4(s1) -80000714: fff78793 addi a5,a5,-1 -80000718: 04878e63 beq a5,s0,80000774 <__call_exitprocs+0x110> -8000071c: 0004a223 sw zero,4(s1) -80000720: fa0688e3 beqz a3,800006d0 <__call_exitprocs+0x6c> -80000724: 18892783 lw a5,392(s2) -80000728: 008a9733 sll a4,s5,s0 -8000072c: 00492c03 lw s8,4(s2) -80000730: 00f777b3 and a5,a4,a5 -80000734: 02079263 bnez a5,80000758 <__call_exitprocs+0xf4> -80000738: 000680e7 jalr a3 -8000073c: 00492703 lw a4,4(s2) -80000740: 148a2783 lw a5,328(s4) -80000744: 01871463 bne a4,s8,8000074c <__call_exitprocs+0xe8> -80000748: f92784e3 beq a5,s2,800006d0 <__call_exitprocs+0x6c> -8000074c: f80788e3 beqz a5,800006dc <__call_exitprocs+0x78> -80000750: 00078913 mv s2,a5 -80000754: f5dff06f j 800006b0 <__call_exitprocs+0x4c> -80000758: 18c92783 lw a5,396(s2) -8000075c: 0844a583 lw a1,132(s1) -80000760: 00f77733 and a4,a4,a5 -80000764: 00071c63 bnez a4,8000077c <__call_exitprocs+0x118> -80000768: 000b0513 mv a0,s6 -8000076c: 000680e7 jalr a3 -80000770: fcdff06f j 8000073c <__call_exitprocs+0xd8> -80000774: 00892223 sw s0,4(s2) -80000778: fa9ff06f j 80000720 <__call_exitprocs+0xbc> -8000077c: 00058513 mv a0,a1 -80000780: 000680e7 jalr a3 -80000784: fb9ff06f j 8000073c <__call_exitprocs+0xd8> +8000066c <__call_exitprocs>: +8000066c: fd010113 addi sp,sp,-48 +80000670: 800027b7 lui a5,0x80002 +80000674: 01412c23 sw s4,24(sp) +80000678: bc07aa03 lw s4,-1088(a5) # 80001bc0 <__stack_top+0x81001bc0> +8000067c: 03212023 sw s2,32(sp) +80000680: 02112623 sw ra,44(sp) +80000684: 148a2903 lw s2,328(s4) +80000688: 02812423 sw s0,40(sp) +8000068c: 02912223 sw s1,36(sp) +80000690: 01312e23 sw s3,28(sp) +80000694: 01512a23 sw s5,20(sp) +80000698: 01612823 sw s6,16(sp) +8000069c: 01712623 sw s7,12(sp) +800006a0: 01812423 sw s8,8(sp) +800006a4: 04090063 beqz s2,800006e4 <__call_exitprocs+0x78> +800006a8: 00050b13 mv s6,a0 +800006ac: 00058b93 mv s7,a1 +800006b0: 00100a93 li s5,1 +800006b4: fff00993 li s3,-1 +800006b8: 00492483 lw s1,4(s2) +800006bc: fff48413 addi s0,s1,-1 +800006c0: 02044263 bltz s0,800006e4 <__call_exitprocs+0x78> +800006c4: 00249493 slli s1,s1,0x2 +800006c8: 009904b3 add s1,s2,s1 +800006cc: 040b8463 beqz s7,80000714 <__call_exitprocs+0xa8> +800006d0: 1044a783 lw a5,260(s1) +800006d4: 05778063 beq a5,s7,80000714 <__call_exitprocs+0xa8> +800006d8: fff40413 addi s0,s0,-1 +800006dc: ffc48493 addi s1,s1,-4 +800006e0: ff3416e3 bne s0,s3,800006cc <__call_exitprocs+0x60> +800006e4: 02c12083 lw ra,44(sp) +800006e8: 02812403 lw s0,40(sp) +800006ec: 02412483 lw s1,36(sp) +800006f0: 02012903 lw s2,32(sp) +800006f4: 01c12983 lw s3,28(sp) +800006f8: 01812a03 lw s4,24(sp) +800006fc: 01412a83 lw s5,20(sp) +80000700: 01012b03 lw s6,16(sp) +80000704: 00c12b83 lw s7,12(sp) +80000708: 00812c03 lw s8,8(sp) +8000070c: 03010113 addi sp,sp,48 +80000710: 00008067 ret +80000714: 00492783 lw a5,4(s2) +80000718: 0044a683 lw a3,4(s1) +8000071c: fff78793 addi a5,a5,-1 +80000720: 04878e63 beq a5,s0,8000077c <__call_exitprocs+0x110> +80000724: 0004a223 sw zero,4(s1) +80000728: fa0688e3 beqz a3,800006d8 <__call_exitprocs+0x6c> +8000072c: 18892783 lw a5,392(s2) +80000730: 008a9733 sll a4,s5,s0 +80000734: 00492c03 lw s8,4(s2) +80000738: 00f777b3 and a5,a4,a5 +8000073c: 02079263 bnez a5,80000760 <__call_exitprocs+0xf4> +80000740: 000680e7 jalr a3 +80000744: 00492703 lw a4,4(s2) +80000748: 148a2783 lw a5,328(s4) +8000074c: 01871463 bne a4,s8,80000754 <__call_exitprocs+0xe8> +80000750: f92784e3 beq a5,s2,800006d8 <__call_exitprocs+0x6c> +80000754: f80788e3 beqz a5,800006e4 <__call_exitprocs+0x78> +80000758: 00078913 mv s2,a5 +8000075c: f5dff06f j 800006b8 <__call_exitprocs+0x4c> +80000760: 18c92783 lw a5,396(s2) +80000764: 0844a583 lw a1,132(s1) +80000768: 00f77733 and a4,a4,a5 +8000076c: 00071c63 bnez a4,80000784 <__call_exitprocs+0x118> +80000770: 000b0513 mv a0,s6 +80000774: 000680e7 jalr a3 +80000778: fcdff06f j 80000744 <__call_exitprocs+0xd8> +8000077c: 00892223 sw s0,4(s2) +80000780: fa9ff06f j 80000728 <__call_exitprocs+0xbc> +80000784: 00058513 mv a0,a1 +80000788: 000680e7 jalr a3 +8000078c: fb9ff06f j 80000744 <__call_exitprocs+0xd8> Disassembly of section .init_array: -80001788 <__init_array_start>: -80001788: 0068 addi a0,sp,12 -8000178a: 8000 0x8000 +80001790 <__init_array_start>: +80001790: 0068 addi a0,sp,12 +80001792: 8000 0x8000 Disassembly of section .data: -80001790 : -80001790: 0000 unimp -80001792: 0000 unimp -80001794: 1a7c addi a5,sp,316 -80001796: 8000 0x8000 -80001798: 1ae4 addi s1,sp,380 -8000179a: 8000 0x8000 -8000179c: 1b4c addi a1,sp,436 +80001798 : +80001798: 0000 unimp +8000179a: 0000 unimp +8000179c: 1a84 addi s1,sp,368 8000179e: 8000 0x8000 +800017a0: 1aec addi a1,sp,380 +800017a2: 8000 0x8000 +800017a4: 1b54 addi a3,sp,436 +800017a6: 8000 0x8000 ... -80001838: 0001 nop -8000183a: 0000 unimp -8000183c: 0000 unimp -8000183e: 0000 unimp -80001840: 330e fld ft6,224(sp) -80001842: abcd j 80001e34 <__BSS_END__+0x1f8> -80001844: 1234 addi a3,sp,296 -80001846: e66d bnez a2,80001930 -80001848: deec sw a1,124(a3) -8000184a: 0005 c.nop 1 -8000184c: 0000000b 0xb +80001840: 0001 nop +80001842: 0000 unimp +80001844: 0000 unimp +80001846: 0000 unimp +80001848: 330e fld ft6,224(sp) +8000184a: abcd j 80001e3c <__BSS_END__+0x1f8> +8000184c: 1234 addi a3,sp,296 +8000184e: e66d bnez a2,80001938 +80001850: deec sw a1,124(a3) +80001852: 0005 c.nop 1 +80001854: 0000000b 0xb ... Disassembly of section .sdata: -80001bb8 <_global_impure_ptr>: -80001bb8: 1790 addi a2,sp,992 -80001bba: 8000 0x8000 +80001bc0 <_global_impure_ptr>: +80001bc0: 1798 addi a4,sp,992 +80001bc2: 8000 0x8000 Disassembly of section .bss: -80001bbc : +80001bc4 : ... Disassembly of section .comment: diff --git a/driver/tests/stress/kernel.elf b/driver/tests/stress/kernel.elf index 4be84fc82c023874a05274861639e6d1abd3aeb4..b107e920dae8b7ba7776c8681dca30b341f62ddd 100755 GIT binary patch delta 1081 zcmZ8gT}TvB6h3!m@2o3Uv(CCJy1Kf9Yef(;f-iv^_=6xwR8WzXNEB!&7})mW#O5kN zuyRrsG74c=A0ntJqS(k{{dwp?5YiV(2(kym3QK~8I(OYQafZX4@0{=Z&Y3%RQq3Ql zqZMp@q*5=7+5tpxpi2c{v_w6bFr!a9;s;u|r>{y)cd0L61Hi3u6}pJ+sRGdW;A>BS zRz-PlD2X7F32|CIv}(NZ*aigaD2{J{2|X~4ZK`L$tU&74Ic$eI4yMLu>ZxK}F#*Dp zgCHknK%V5xQhrI{sYXV;0%LdyPAc#n#{!@g9|S8h3r5~NSi|$da9klx1myTE;Aj|Dh#i>#-M{dRNh(FH? z7T=Ir3}2P@)zH_cuK^&_Ew0!Owq@`%$;5-aeP$qq?cRDeg%7-K>@j}x_K;6|nXlts zRwtPEiN6~^*@NE_&h-`i#Xb1T9-JoJjVonGPo!uXlaLb>sHMZ3n@*+a8VJXH+taG> zQ@P$v4J^GxDX_`NjQz|{!flh3WJ4e|DZ_b+z z6k#z7SQ37yxp!2s?U?YHmlDgOjDZ# zGZXJ8Ou+nVb@Tx_U$s${^8yG{fG!Py(UJ=n%+5V*9o)39yX>5)EuYpN!&k6FT+!e(Wrs}wt|-sK zHMFWd7ed8EIf`UEUI_cL8{G3-E9PEY-^_zn{6i{(2{&f^0T|WA=b-OoEeC z8D38S51Ak*8=2KT1a9^RV801YtwQ=5L(Wlcn>o->m?foD?3BHMBCB`M*JtdkIXEJ z59G8hcqUN6E@C!tRGJ!fKLs{2X?heFOCPZ&9OiXWb`(GH8ueucvr`!i29HF$GTe7L zWBGokjG6!#dLQt^n^SGzleniVgI9ujnMj!~q^t{-<6Q8M(0miRLyOx{7H1_L6<~iL zJ5ULB-^BqpRc^~HkK>i+w$hKMIRRw4#g+fho&rCm67eFh92XeFbfk{m#=%H4yNgSa zv!s)*inU%@trM9yD1R-FtmEgz#l9kcb{&6Q$IHa+IA2xUGDg$bL;+A?8=c$YbQ(>! zmpC6=nO1{ue-Ew3#dicKevA #include "common.h" #include +#include +#include #include #define RT_CHECK(_expr) \ @@ -18,10 +20,55 @@ /////////////////////////////////////////////////////////////////////////////// +union Float_t { + float f; + int i; + struct { + uint32_t man : 23; + uint32_t exp : 8; + uint32_t sign : 1; + } parts; +}; + +inline float fround(float x, int32_t precision = 8) { + auto power_of_10 = std::pow(10, precision); + return std::round(x * power_of_10) / power_of_10; +} + +inline bool almost_equal_eps(float a, float b, int ulp = 128) { + auto eps = std::numeric_limits::epsilon() * (std::max(fabs(a), fabs(b)) * ulp); + auto d = fabs(a - b); + if (d > eps) { + std::cout << "*** almost_equal_eps: d=" << d << ", eps=" << eps << std::endl; + return false; + } + return true; +} + +inline bool almost_equal_ulp(float a, float b, int32_t ulp = 6) { + Float_t fa{a}, fb{b}; + auto d = std::abs(fa.i - fb.i); + if (d > ulp) { + std::cout << "*** almost_equal_ulp: a=" << a << ", b=" << b << ", ulp=" << d << ", ia=" << std::hex << fa.i << ", ib=" << fb.i << std::endl; + return false; + } + return true; +} + +inline bool almost_equal(float a, float b) { + if (a == b) + return true; + /*if (almost_equal_eps(a, b)) + return true;*/ + return almost_equal_ulp(a, b); +} + +/////////////////////////////////////////////////////////////////////////////// + const char* kernel_file = "kernel.bin"; uint32_t count = 0; -std::vector test_data; +std::vector test_data; std::vector addr_table; vx_device_h device = nullptr; @@ -68,7 +115,8 @@ void gen_input_data(uint32_t num_points) { addr_table.resize(num_points + NUM_LOADS - 1); for (uint32_t i = 0; i < test_data.size(); ++i) { - test_data[i] = std::rand(); + float r = static_cast(std::rand()) / RAND_MAX; + test_data[i] = r; } for (uint32_t i = 0; i < addr_table.size(); ++i) { @@ -98,21 +146,21 @@ int run_test(const kernel_arg_t& kernel_arg, std::cout << "verify result" << std::endl; { int errors = 0; - auto buf_ptr = (int32_t*)vx_host_ptr(staging_buf); + auto buf_ptr = (float*)vx_host_ptr(staging_buf); for (uint32_t i = 0; i < num_points; ++i) { - int ref = 0; + float ref = 0.0f; for (uint32_t j = 0; j < NUM_LOADS; ++j) { uint32_t addr = i + j; uint32_t index = addr_table.at(addr); - int value = test_data.at(index); - //printf("*** [%d] addr=%d, index=%d, value=%d\n", i, addr, index, value); - ref += value; + float value = test_data.at(index); + //printf("*** [%d] addr=%d, index=%d, value=%f\n", i, addr, index, value); + ref *= value; } - int cur = buf_ptr[i]; - if (cur != ref) { + float cur = buf_ptr[i]; + if (!almost_equal(cur, ref)) { std::cout << "error at result #" << std::dec << i << ": actual " << cur << ", expected " << ref << std::endl; ++errors; diff --git a/hw/rtl/afu/VX_avs_wrapper.v b/hw/rtl/afu/VX_avs_wrapper.v index 74f5b48d..16947179 100644 --- a/hw/rtl/afu/VX_avs_wrapper.v +++ b/hw/rtl/afu/VX_avs_wrapper.v @@ -52,7 +52,7 @@ module VX_avs_wrapper #( wire [NUM_BANKS-1:0][RD_QUEUE_ADDR_WIDTH-1:0] req_queue_size; wire [NUM_BANKS-1:0][REQ_TAG_WIDTH-1:0] avs_reqq_data_out; - wire [BANK_ADDRW-1:0] req_bank_sel = (NUM_BANKS >= 2) ? mem_req_addr [BANK_ADDRW-1:0] : 1'b0; + wire [BANK_ADDRW-1:0] req_bank_sel = (NUM_BANKS >= 2) ? mem_req_addr [BANK_ADDRW-1:0] : '0; wire avs_reqq_push = mem_req_valid && !mem_req_rw && mem_req_ready; From 2bdf8c9353b36d56f3e9eca3624f35fc6fdcf95b Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 18 May 2021 11:14:31 -0700 Subject: [PATCH 41/55] minor update --- benchmarks/opencl/sgemm/main.cc | 3 ++- benchmarks/opencl/vecadd/main.cc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/benchmarks/opencl/sgemm/main.cc b/benchmarks/opencl/sgemm/main.cc index f61a8727..06893876 100644 --- a/benchmarks/opencl/sgemm/main.cc +++ b/benchmarks/opencl/sgemm/main.cc @@ -220,7 +220,8 @@ int main (int argc, char **argv) { matmul(h_ref, h_a, h_b, size, size, size); for (int i = 0; i < (size * size); i++) { if (!almost_equal(h_c[i], h_ref[i])) { - printf("*** error: [%d] expected=%f, actual=%f\n", i, h_ref[i], h_c[i]); + if (errors < 100) + printf("*** error: [%d] expected=%f, actual=%f\n", i, h_ref[i], h_c[i]); ++errors; } } diff --git a/benchmarks/opencl/vecadd/main.cc b/benchmarks/opencl/vecadd/main.cc index 5b8c3a83..e38548bf 100644 --- a/benchmarks/opencl/vecadd/main.cc +++ b/benchmarks/opencl/vecadd/main.cc @@ -198,7 +198,8 @@ int main (int argc, char **argv) { for (int i = 0; i < size; ++i) { float ref = h_a[i] + h_b[i]; if (!almost_equal(h_c[i], ref)) { - printf("*** error: [%d] expected=%f, actual=%f, a=%f, b=%f\n", i, ref, h_c[i], h_a[i], h_b[i]); + if (errors < 100) + printf("*** error: [%d] expected=%f, actual=%f, a=%f, b=%f\n", i, ref, h_c[i], h_a[i], h_b[i]); ++errors; } } From 7095a460661cb80810e89862377681e6c9fa713e Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 18 May 2021 11:15:36 -0700 Subject: [PATCH 42/55] minor update --- hw/rtl/afu/vortex_afu.sv | 6 +++--- hw/syn/opae/README | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 6cdb14b9..fbd0cbfe 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -639,7 +639,7 @@ VX_avs_wrapper #( .AVS_ADDR_WIDTH (LMEM_ADDR_WIDTH), .AVS_BURST_WIDTH (LMEM_BURST_CTRW), .AVS_BANKS (NUM_LOCAL_MEM_BANKS), - .REQ_TAG_WIDTH (AVS_REQ_TAGW+1), + .REQ_TAG_WIDTH (AVS_REQ_TAGW + 1), .RD_QUEUE_SIZE (AVS_RD_QUEUE_SIZE) ) avs_wrapper ( .clk (clk), @@ -720,9 +720,9 @@ VX_pending_size #( .reset (reset), .push (cci_rd_req_fire), .pop (cci_rdq_pop), - `UNUSED_PIN (empty), .full (cci_pending_reads_full), - .size (cci_pending_reads) + .size (cci_pending_reads), + `UNUSED_PIN (empty) ); `UNUSED_VAR (cci_pending_reads) diff --git a/hw/syn/opae/README b/hw/syn/opae/README index 9e0bd4bf..1c61ca16 100644 --- a/hw/syn/opae/README +++ b/hw/syn/opae/README @@ -63,13 +63,13 @@ qsub-sim make ase # tests -./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n1 -t0 -./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n1 -t1 -./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n16 -./run_ase.sh build_ase_1c ../../../driver/tests/demo/demo -n16 -./run_ase.sh build_ase_1c ../../../driver/tests/dogfood/dogfood -n16 -./run_ase.sh build_ase_1c ../../../benchmarks/opencl/vecadd/vecadd -./run_ase.sh build_ase_1c ../../../benchmarks/opencl/sgemm/sgemm -n4 +./run_ase.sh build_ase_arria10_1c ../../../driver/tests/basic/basic -n1 -t0 +./run_ase.sh build_ase_arria10_1c ../../../driver/tests/basic/basic -n1 -t1 +./run_ase.sh build_ase_arria10_1c ../../../driver/tests/basic/basic -n16 +./run_ase.sh build_ase_arria10_1c ../../../driver/tests/demo/demo -n16 +./run_ase.sh build_ase_arria10_1c ../../../driver/tests/dogfood/dogfood -n16 +./run_ase.sh build_ase_arria10_1c ../../../benchmarks/opencl/vecadd/vecadd +./run_ase.sh build_ase_arria10_1c ../../../benchmarks/opencl/sgemm/sgemm -n4 # modify "vsim_run.tcl" to dump VCD trace vcd file trace.vcd @@ -83,7 +83,7 @@ tar -zcvf output_files_1c.tar.gz `find ./build_fpga_1c -type f \( -iname \*.rpt tar -zcvf run.log.tar.gz run.log tar -cvjf vx_scope.vcd.tar.bz2 vx_scope.vcd tar -cvjf trace.vcd.tar.bz2 trace.vcd run.log -tar -cvjf trace.vcd.tar.bz2 build_ase_1c/work/run.log build_ase_1c/work/trace.vcd +tar -cvjf trace.vcd.tar.bz2 build_ase_arria10_1c/work/run.log build_ase_arria10_1c/work/trace.vcd # decompress VCD trace tar -zxvf vortex.vcd.tar.gz From d80e1b28a313bc51089ab765b812f45ea4970082 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 20 May 2021 05:36:09 -0700 Subject: [PATCH 43/55] fixes for multi-channel memory support --- hw/rtl/afu/VX_avs_wrapper.v | 36 +++--- hw/rtl/afu/vortex_afu.sv | 220 ++++++++++++++++++------------------ 2 files changed, 130 insertions(+), 126 deletions(-) diff --git a/hw/rtl/afu/VX_avs_wrapper.v b/hw/rtl/afu/VX_avs_wrapper.v index 16947179..b3d0a5d5 100644 --- a/hw/rtl/afu/VX_avs_wrapper.v +++ b/hw/rtl/afu/VX_avs_wrapper.v @@ -47,37 +47,39 @@ module VX_avs_wrapper #( // Requests handling - wire [NUM_BANKS-1:0] avs_reqq_pop; + wire [NUM_BANKS-1:0] avs_reqq_push, avs_reqq_pop, avs_reqq_ready; wire [NUM_BANKS-1:0] req_queue_going_full; wire [NUM_BANKS-1:0][RD_QUEUE_ADDR_WIDTH-1:0] req_queue_size; wire [NUM_BANKS-1:0][REQ_TAG_WIDTH-1:0] avs_reqq_data_out; - wire [BANK_ADDRW-1:0] req_bank_sel = (NUM_BANKS >= 2) ? mem_req_addr [BANK_ADDRW-1:0] : '0; - - wire avs_reqq_push = mem_req_valid && !mem_req_rw && mem_req_ready; + wire [BANK_ADDRW-1:0] req_bank_sel = (NUM_BANKS >= 2) ? mem_req_addr[BANK_ADDRW-1:0] : '0; for (genvar i = 0; i < NUM_BANKS; i++) begin + assign avs_reqq_ready[i] = !req_queue_going_full[i] && !avs_waitrequest[i]; + assign avs_reqq_push[i] = mem_req_valid && !mem_req_rw && avs_reqq_ready[i] && (req_bank_sel == i); + end + for (genvar i = 0; i < NUM_BANKS; i++) begin VX_pending_size #( .SIZE (RD_QUEUE_SIZE) ) pending_size ( .clk (clk), .reset (reset), - .push (avs_reqq_push && (req_bank_sel == i)), - .pop (avs_reqq_pop[i]), - `UNUSED_PIN (empty), + .push (avs_reqq_push[i]), + .pop (avs_reqq_pop[i]), .full (req_queue_going_full[i]), - .size (req_queue_size[i]) + .size (req_queue_size[i]), + `UNUSED_PIN (empty) ); `UNUSED_VAR (req_queue_size) VX_fifo_queue #( - .DATAW (REQ_TAG_WIDTH), - .SIZE (RD_QUEUE_SIZE) + .DATAW (REQ_TAG_WIDTH), + .SIZE (RD_QUEUE_SIZE) ) rd_req_queue ( .clk (clk), .reset (reset), - .push (avs_reqq_push && (req_bank_sel == i)), + .push (avs_reqq_push[i]), .pop (avs_reqq_pop[i]), .data_in (mem_req_tag), .data_out (avs_reqq_data_out[i]), @@ -98,7 +100,7 @@ module VX_avs_wrapper #( assign avs_burstcount[i] = AVS_BURST_WIDTH'(1); end - assign mem_req_ready = !(avs_waitrequest[req_bank_sel] || req_queue_going_full[req_bank_sel]); + assign mem_req_ready = avs_reqq_ready[req_bank_sel]; // Responses handling @@ -110,10 +112,9 @@ module VX_avs_wrapper #( wire [NUM_BANKS-1:0] avs_rspq_empty; for (genvar i = 0; i < NUM_BANKS; i++) begin - VX_fifo_queue #( - .DATAW (AVS_DATA_WIDTH), - .SIZE (RD_QUEUE_SIZE) + .DATAW (AVS_DATA_WIDTH), + .SIZE (RD_QUEUE_SIZE) ) rd_rsp_queue ( .clk (clk), .reset (reset), @@ -127,7 +128,6 @@ module VX_avs_wrapper #( `UNUSED_PIN (alm_full), `UNUSED_PIN (size) ); - end for (genvar i = 0; i < NUM_BANKS; i++) begin @@ -138,8 +138,8 @@ module VX_avs_wrapper #( VX_stream_arbiter #( .NUM_REQS (NUM_BANKS), - .DATAW (AVS_DATA_WIDTH+REQ_TAG_WIDTH), - .BUFFERED (0) + .DATAW (AVS_DATA_WIDTH + REQ_TAG_WIDTH), + .BUFFERED (NUM_BANKS > 2) ) rsp_arb ( .clk (clk), .reset (reset), diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index fbd0cbfe..39bc970d 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -48,7 +48,10 @@ localparam CCI_LINE_SIZE = CCI_LINE_WIDTH / 8; localparam CCI_ADDR_WIDTH = 32 - $clog2(CCI_LINE_WIDTH / 8); localparam AVS_RD_QUEUE_SIZE = 16; -localparam AVS_REQ_TAGW = `MAX(`VX_MEM_TAG_WIDTH, `VX_MEM_TAG_WIDTH + ($clog2(LMEM_LINE_WIDTH) - $clog2(`VX_MEM_LINE_WIDTH))); +localparam AVS_REQ_TAGW_VX = `MAX(`VX_MEM_TAG_WIDTH, `VX_MEM_TAG_WIDTH + $clog2(LMEM_LINE_WIDTH) - $clog2(`VX_MEM_LINE_WIDTH)); +localparam AVS_REQ_TAGW_CCI = `MAX(CCI_ADDR_WIDTH, CCI_ADDR_WIDTH + $clog2(LMEM_LINE_WIDTH) - $clog2(CCI_LINE_WIDTH)); +localparam AVS_REQ_TAGW = `MAX(AVS_REQ_TAGW_VX, AVS_REQ_TAGW_CCI); + localparam CCI_RD_WINDOW_SIZE = 8; localparam CCI_RD_QUEUE_SIZE = 2 * CCI_RD_WINDOW_SIZE; @@ -448,27 +451,19 @@ end wire cci_mem_rd_req_valid; wire cci_mem_wr_req_valid; -wire [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_addr; -wire [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr; wire [CCI_RD_RQ_DATAW-1:0] cci_rdq_dout; -wire cci_mem_req_ready; wire cci_mem_req_valid; wire cci_mem_req_rw; wire [CCI_ADDR_WIDTH-1:0] cci_mem_req_addr; -wire cci_mem_req_tag = 1'b0; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_req_tag; +wire cci_mem_req_ready; wire cci_mem_rsp_valid; wire [CCI_LINE_WIDTH-1:0] cci_mem_rsp_data; -wire cci_mem_rsp_tag; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_rsp_tag; wire cci_mem_rsp_ready; -`UNUSED_VAR (cci_mem_rsp_tag) - -assign cci_mem_req_rw = (CMD_MEM_WRITE == state); -assign cci_mem_req_valid = cci_mem_req_rw ? cci_mem_wr_req_valid : cci_mem_rd_req_valid; -assign cci_mem_req_addr = cci_mem_req_rw ? cci_mem_wr_req_addr : cci_mem_rd_req_addr; - //-- wire cci_mem_req_arb_valid; @@ -489,7 +484,7 @@ VX_to_mem #( .DST_DATA_WIDTH (LMEM_LINE_WIDTH), .SRC_ADDR_WIDTH (CCI_ADDR_WIDTH), .DST_ADDR_WIDTH (LMEM_ADDR_WIDTH), - .SRC_TAG_WIDTH (1), + .SRC_TAG_WIDTH (CCI_ADDR_WIDTH), .DST_TAG_WIDTH (AVS_REQ_TAGW) ) cci_to_mem ( .clk (clk), @@ -675,13 +670,15 @@ VX_avs_wrapper #( // CCI-P Read Request /////////////////////////////////////////////////////////// reg [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_ctr; -reg [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr; -wire [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr_next; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr; reg [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr_unqual; -wire [CCI_RD_RQ_TAGW-1:0] cci_rd_req_tag, cci_rd_rsp_tag; +reg [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr; +wire [CCI_RD_RQ_TAGW-1:0] cci_rd_req_tag; +wire [CCI_RD_RQ_TAGW-1:0] cci_rd_rsp_tag; reg [CCI_RD_RQ_TAGW-1:0] cci_rd_rsp_ctr; -t_ccip_clAddr cci_rd_req_addr; +wire cci_rd_req_fire; +t_ccip_clAddr cci_rd_req_addr; reg cci_rd_req_enable, cci_rd_req_wait; wire cci_rdq_push, cci_rdq_pop; @@ -689,6 +686,7 @@ wire [CCI_RD_RQ_DATAW-1:0] cci_rdq_din; wire cci_rdq_empty; always @(*) begin + af2cp_sTxPort.c0.valid = cci_rd_req_fire; af2cp_sTxPort.c0.hdr = t_ccip_c0_ReqMemHdr'(0); af2cp_sTxPort.c0.hdr.address = cci_rd_req_addr; af2cp_sTxPort.c0.hdr.mdata = t_ccip_mdata'(cci_rd_req_tag); @@ -696,8 +694,6 @@ end wire cci_mem_wr_req_fire = cci_mem_wr_req_valid && cci_mem_req_ready; -wire cci_rd_req_fire = af2cp_sTxPort.c0.valid; - wire cci_rd_rsp_fire = (STATE_WRITE == state) && cp2af_sRxPort.c0.rspValid && (cp2af_sRxPort.c0.hdr.resp_type == eRSP_RDLINE); @@ -705,10 +701,8 @@ wire cci_rd_rsp_fire = (STATE_WRITE == state) assign cci_rd_req_tag = CCI_RD_RQ_TAGW'(cci_rd_req_ctr); assign cci_rd_rsp_tag = CCI_RD_RQ_TAGW'(cp2af_sRxPort.c0.hdr.mdata); -assign cci_rd_req_ctr_next = cci_rd_req_ctr + CCI_ADDR_WIDTH'(cci_rd_req_fire ? 1 : 0); - -assign cci_rdq_pop = cci_mem_wr_req_fire; assign cci_rdq_push = cci_rd_rsp_fire; +assign cci_rdq_pop = cci_mem_wr_req_fire; assign cci_rdq_din = {cp2af_sRxPort.c0.data, cci_rd_rsp_tag}; wire [$clog2(CCI_RD_QUEUE_SIZE+1)-1:0] cci_pending_reads; @@ -726,72 +720,72 @@ VX_pending_size #( ); `UNUSED_VAR (cci_pending_reads) +assign cci_rd_req_fire = cci_rd_req_enable && !(cci_rd_req_wait || cci_pending_reads_full); + assign cci_mem_wr_req_valid = !cci_rdq_empty; assign cci_mem_wr_req_addr = cci_mem_wr_req_addr_unqual + (CCI_ADDR_WIDTH'(CCI_RD_RQ_TAGW'(cci_rdq_dout))); -assign af2cp_sTxPort.c0.valid = cci_rd_req_enable && !(cci_rd_req_wait || cci_pending_reads_full); - assign cmd_write_done = (cci_mem_wr_req_ctr == cmd_data_size); // Send read requests to CCI always @(posedge clk) begin if (reset) begin - cci_rd_req_addr <= 0; - cci_rd_req_ctr <= 0; - cci_rd_rsp_ctr <= 0; - cci_rd_req_enable <= 0; - cci_rd_req_wait <= 0; - cci_mem_wr_req_ctr <= 0; - cci_mem_wr_req_addr_unqual <= 0; - end - else begin + cci_rd_req_enable <= 0; + cci_rd_req_wait <= 0; + end else begin if ((STATE_IDLE == state) && (CMD_MEM_WRITE == cmd_type)) begin - cci_rd_req_addr <= cmd_io_addr; - cci_rd_req_ctr <= 0; - cci_rd_rsp_ctr <= 0; - cci_rd_req_enable <= (cmd_data_size != 0); - cci_rd_req_wait <= 0; - cci_mem_wr_req_ctr <= 0; - cci_mem_wr_req_addr_unqual <= cmd_mem_addr; + cci_rd_req_enable <= (cmd_data_size != 0); + cci_rd_req_wait <= 0; end cci_rd_req_enable <= (STATE_WRITE == state) - && (cci_rd_req_ctr_next != cmd_data_size) + && (cci_rd_req_ctr != cmd_data_size) && !cp2af_sRxPort.c0TxAlmFull; - if (cci_rd_req_fire) begin - cci_rd_req_addr <= cci_rd_req_addr + 1; - cci_rd_req_ctr <= cci_rd_req_ctr_next; - if (cci_rd_req_tag == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) begin - cci_rd_req_wait <= 1; // end current request batch - end - `ifdef DBG_PRINT_OPAE - $display("%t: CCI Rd Req: addr=%0h, tag=%0h, rem=%0d, pending=%0d", $time, cci_rd_req_addr, cci_rd_req_tag, (cmd_data_size - cci_rd_req_ctr_next), cci_pending_reads); - `endif + if (cci_rd_req_fire && (cci_rd_req_tag == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1))) begin + cci_rd_req_wait <= 1; // end current request batch end - if (cci_rd_rsp_fire) begin - cci_rd_rsp_ctr <= cci_rd_rsp_ctr + CCI_RD_RQ_TAGW'(1); - if (cci_rd_rsp_ctr == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) begin - cci_rd_req_wait <= 0; // restart new request batch - end - `ifdef DBG_PRINT_OPAE - $display("%t: CCI Rd Rsp: idx=%0d, ctr=%0d, data=%0h", $time, cci_rd_rsp_tag, cci_rd_rsp_ctr, cp2af_sRxPort.c0.data); - `endif - end + if (cci_rd_rsp_fire && (cci_rd_rsp_ctr == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1))) begin + cci_rd_req_wait <= 0; // begin new request batch + end + end - /*if (cci_rdq_pop) begin - `ifdef DBG_PRINT_OPAE - $display("%t: CCI Rd Queue Pop: pending=%0d", $time, cci_pending_reads); - `endif - end*/ + if ((STATE_IDLE == state) + && (CMD_MEM_WRITE == cmd_type)) begin + cci_rd_req_addr <= cmd_io_addr; + cci_rd_req_ctr <= 0; + cci_rd_rsp_ctr <= 0; + cci_mem_wr_req_ctr <= 0; + cci_mem_wr_req_addr_unqual <= cmd_mem_addr; + end - if (cci_mem_wr_req_fire) begin - cci_mem_wr_req_addr_unqual <= cci_mem_wr_req_addr_unqual + ((CCI_RD_RQ_TAGW'(cci_mem_wr_req_ctr) == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) ? CCI_ADDR_WIDTH'(CCI_RD_WINDOW_SIZE) : CCI_ADDR_WIDTH'(0)); - cci_mem_wr_req_ctr <= cci_mem_wr_req_ctr + CCI_ADDR_WIDTH'(1); - end + if (cci_rd_req_fire) begin + cci_rd_req_addr <= cci_rd_req_addr + 1; + cci_rd_req_ctr <= cci_rd_req_ctr + 1; + `ifdef DBG_PRINT_OPAE + $display("%t: CCI Rd Req: addr=%0h, tag=%0h, rem=%0d, pending=%0d", $time, cci_rd_req_addr, cci_rd_req_tag, (cmd_data_size - cci_rd_req_ctr - 1), cci_pending_reads); + `endif + end + + if (cci_rd_rsp_fire) begin + cci_rd_rsp_ctr <= cci_rd_rsp_ctr + CCI_RD_RQ_TAGW'(1); + `ifdef DBG_PRINT_OPAE + $display("%t: CCI Rd Rsp: idx=%0d, ctr=%0d, data=%0h", $time, cci_rd_rsp_tag, cci_rd_rsp_ctr, cp2af_sRxPort.c0.data); + `endif + end + + if (cci_rdq_pop) begin + `ifdef DBG_PRINT_OPAE + $display("%t: CCI Rd Queue Pop: pending=%0d", $time, cci_pending_reads); + `endif + end + + if (cci_mem_wr_req_fire) begin + cci_mem_wr_req_addr_unqual <= cci_mem_wr_req_addr_unqual + ((CCI_RD_RQ_TAGW'(cci_mem_wr_req_ctr) == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) ? CCI_ADDR_WIDTH'(CCI_RD_WINDOW_SIZE) : CCI_ADDR_WIDTH'(0)); + cci_mem_wr_req_ctr <= cci_mem_wr_req_ctr + CCI_ADDR_WIDTH'(1); end end @@ -835,22 +829,24 @@ VX_fifo_queue #( // CCI-P Write Request ////////////////////////////////////////////////////////// reg [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_ctr; +reg [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_addr; reg [CCI_ADDR_WIDTH-1:0] cci_wr_req_ctr; -reg [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_addr_r; + +reg cci_wr_req_fire; t_ccip_clAddr cci_wr_req_addr; +t_ccip_clData cci_wr_req_data; always @(*) begin + af2cp_sTxPort.c1.valid = cci_wr_req_fire; af2cp_sTxPort.c1.hdr = t_ccip_c1_ReqMemHdr'(0); - af2cp_sTxPort.c1.hdr.address = cci_wr_req_addr; af2cp_sTxPort.c1.hdr.sop = 1; // single line write mode - af2cp_sTxPort.c1.data = t_ccip_clData'(cci_mem_rsp_data); + af2cp_sTxPort.c1.hdr.address = cci_wr_req_addr; + af2cp_sTxPort.c1.data = cci_wr_req_data; end wire cci_mem_rd_req_fire = cci_mem_rd_req_valid && cci_mem_req_ready; wire cci_mem_rd_rsp_fire = cci_mem_rsp_valid && cci_mem_rsp_ready; -wire cci_wr_req_fire = cci_mem_rd_rsp_fire; - wire cci_wr_rsp_fire = (STATE_READ == state) && cp2af_sRxPort.c1.rspValid && (cp2af_sRxPort.c1.hdr.resp_type == eRSP_WRLINE); @@ -858,12 +854,13 @@ wire cci_wr_rsp_fire = (STATE_READ == state) wire [$clog2(CCI_RW_PENDING_SIZE+1)-1:0] cci_pending_writes; wire cci_pending_writes_empty; wire cci_pending_writes_full; + VX_pending_size #( .SIZE (CCI_RW_PENDING_SIZE) ) cci_wr_pending_size ( .clk (clk), .reset (reset), - .push (cci_wr_req_fire), + .push (cci_mem_rd_rsp_fire), .pop (cci_wr_rsp_fire), .empty (cci_pending_writes_empty), .full (cci_pending_writes_full), @@ -871,54 +868,61 @@ VX_pending_size #( ); `UNUSED_VAR (cci_pending_writes) -assign cci_mem_rd_req_valid = (cci_mem_rd_req_ctr != 0); -assign cci_mem_rd_req_addr = cci_mem_rd_req_addr_r; +assign cci_mem_rd_req_valid = (STATE_READ == state) + && (cci_mem_rd_req_ctr != cmd_data_size); -assign af2cp_sTxPort.c1.valid = cci_mem_rd_rsp_fire; -assign cci_mem_rsp_ready = !cp2af_sRxPort.c1TxAlmFull && !cci_pending_writes_full; +assign cci_mem_rsp_ready = !cp2af_sRxPort.c1TxAlmFull + && !cci_pending_writes_full; -assign cmd_read_done = (0 == cci_wr_req_ctr) && cci_pending_writes_empty; +assign cmd_read_done = (0 == cci_wr_req_ctr) + && cci_pending_writes_empty; // Send write requests to CCI always @(posedge clk) begin if (reset) begin - cci_wr_req_addr <= 0; - cci_wr_req_ctr <= 0; - cci_mem_rd_req_ctr <= 0; - cci_mem_rd_req_addr_r <= 0; + cci_wr_req_fire <= 0; + end else begin + cci_wr_req_fire <= cci_mem_rd_rsp_fire; end - else begin - if ((STATE_IDLE == state) - && (CMD_MEM_READ == cmd_type)) begin - cci_wr_req_addr <= cmd_io_addr; - cci_wr_req_ctr <= cmd_data_size; - cci_mem_rd_req_ctr <= cmd_data_size; - cci_mem_rd_req_addr_r <= cmd_mem_addr; - end + + if ((STATE_IDLE == state) + && (CMD_MEM_READ == cmd_type)) begin + cci_mem_rd_req_ctr <= 0; + cci_mem_rd_req_addr <= cmd_mem_addr; + cci_wr_req_ctr <= cmd_data_size; + end - if (cci_wr_req_fire) begin - assert(cci_wr_req_ctr != 0); - cci_wr_req_addr <= cci_wr_req_addr + t_ccip_clAddr'(1); - cci_wr_req_ctr <= cci_wr_req_ctr - CCI_ADDR_WIDTH'(1); - `ifdef DBG_PRINT_OPAE - $display("%t: CCI Wr Req: addr=%0h, rem=%0d, pending=%0d, data=%0h", $time, cci_wr_req_addr, (cci_wr_req_ctr - 1), cci_pending_writes, af2cp_sTxPort.c1.data); - `endif - end + if (cci_mem_rd_req_fire) begin + cci_mem_rd_req_addr <= cci_mem_rd_req_addr + CCI_ADDR_WIDTH'(1); + cci_mem_rd_req_ctr <= cci_mem_rd_req_ctr + CCI_ADDR_WIDTH'(1); + end - /*`ifdef DBG_PRINT_OPAE - if (cci_wr_rsp_fire) begin - $display("%t: CCI Wr Rsp: pending=%0d", $time, cci_pending_writes); - end - `endif*/ + cci_wr_req_addr <= cmd_io_addr + t_ccip_clAddr'(cci_mem_rsp_tag); + cci_wr_req_data <= t_ccip_clData'(cci_mem_rsp_data); - if (cci_mem_rd_req_fire) begin - cci_mem_rd_req_addr_r <= cci_mem_rd_req_addr_r + CCI_ADDR_WIDTH'(1); - cci_mem_rd_req_ctr <= cci_mem_rd_req_ctr - CCI_ADDR_WIDTH'(1); - end + if (cci_wr_req_fire) begin + assert(cci_wr_req_ctr != 0); + cci_wr_req_ctr <= cci_wr_req_ctr - CCI_ADDR_WIDTH'(1); + `ifdef DBG_PRINT_OPAE + $display("%t: CCI Wr Req: addr=%0h, rem=%0d, pending=%0d, data=%0h", $time, cci_wr_req_addr, (cci_wr_req_ctr - 1), cci_pending_writes, af2cp_sTxPort.c1.data); + `endif + end + + if (cci_wr_rsp_fire) begin + `ifdef DBG_PRINT_OPAE + $display("%t: CCI Wr Rsp: pending=%0d", $time, cci_pending_writes); + `endif end end +//-- + +assign cci_mem_req_rw = (CMD_MEM_WRITE == state); +assign cci_mem_req_valid = cci_mem_req_rw ? cci_mem_wr_req_valid : cci_mem_rd_req_valid; +assign cci_mem_req_addr = cci_mem_req_rw ? cci_mem_wr_req_addr : cci_mem_rd_req_addr; +assign cci_mem_req_tag = cci_mem_req_rw ? cci_mem_wr_req_ctr : cci_mem_rd_req_ctr; + // CSRs /////////////////////////////////////////////////////////////////////// reg csr_io_req_sent; From b3e54e66f8569c3b0fc0ff7c00d5cf3e789712f5 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 23 May 2021 10:54:06 -0700 Subject: [PATCH 44/55] fixed compiler warnings --- driver/opae/vlsim/Makefile | 13 +++---------- driver/rtlsim/Makefile | 8 ++------ driver/simx/Makefile | 9 +++------ hw/simulate/Makefile | 2 +- simX/Makefile | 4 +--- 5 files changed, 10 insertions(+), 26 deletions(-) diff --git a/driver/opae/vlsim/Makefile b/driver/opae/vlsim/Makefile index b84c24f4..58d2fcd4 100644 --- a/driver/opae/vlsim/Makefile +++ b/driver/opae/vlsim/Makefile @@ -1,8 +1,7 @@ CFLAGS += -std=c++11 -O2 -Wall -Wextra -Wfatal-errors #CFLAGS += -std=c++11 -g -O0 -Wall -Wextra -Wfatal-errors -CFLAGS += -Wno-aligned-new -Wno-maybe-uninitialized - +CFLAGS += -DUSE_VLSIM -fPIC -Wno-maybe-uninitialized CFLAGS += -I../../../../hw # control RTL debug print states @@ -21,15 +20,9 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE DBG_FLAGS += $(DBG_PRINT_FLAGS) DBG_FLAGS += -DDBG_CACHE_REQ_INFO -#CONFIGS := -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) -#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) -#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 $(CONFIGS) -CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=1 $(CONFIGS) - -CFLAGS += -fPIC - -CFLAGS += -DUSE_VLSIM $(CONFIGS) +CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=1 +CFLAGS += $(CONFIGS) CFLAGS += -DDUMP_PERF_STATS LDFLAGS += -shared -pthread diff --git a/driver/rtlsim/Makefile b/driver/rtlsim/Makefile index b3d466f7..76e7185d 100644 --- a/driver/rtlsim/Makefile +++ b/driver/rtlsim/Makefile @@ -1,7 +1,7 @@ CFLAGS += -std=c++11 -O2 -Wall -Wextra -Wfatal-errors #CFLAGS += -std=c++11 -g -O0 -Wall -Wextra -Wfatal-errors -CFLAGS += -fPIC -Wno-aligned-new -Wno-maybe-uninitialized +CFLAGS += -DUSE_RTLSIM -fPIC -Wno-maybe-uninitialized CFLAGS += -I../../include -I../../../hw/simulate -I../../../hw # control RTL debug print states @@ -20,13 +20,9 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE DBG_FLAGS += $(DBG_PRINT_FLAGS) DBG_FLAGS += -DDBG_CACHE_REQ_INFO -#CONFIGS := -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) -#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) -#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 $(CONFIGS) -CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=1 $(CONFIGS) +CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=1 CFLAGS += $(CONFIGS) - CFLAGS += -DDUMP_PERF_STATS LDFLAGS += -shared -pthread diff --git a/driver/simx/Makefile b/driver/simx/Makefile index 2779145a..154404d0 100644 --- a/driver/simx/Makefile +++ b/driver/simx/Makefile @@ -6,16 +6,13 @@ SIMX_DIR = ../../simX CXXFLAGS += -std=c++11 -O2 -Wall -Wextra -Wfatal-errors #CXXFLAGS += -std=c++11 -g -O0 -Wall -Wextra -Wfatal-errors -CXXFLAGS += -fPIC -Wno-aligned-new -Wno-maybe-uninitialized +CXXFLAGS += -DUSE_SIMX -fPIC -Wno-maybe-uninitialized CXXFLAGS += -I../include -I../../hw -I$(SIMX_DIR) -CXXFLAGS += -DDUMP_PERF_STATS -#CONFIGS := -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) -#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) -#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 $(CONFIGS) -CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=1 $(CONFIGS) +CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=1 CXXFLAGS += $(CONFIGS) +CXXFLAGS += -DDUMP_PERF_STATS LDFLAGS += -shared -pthread #LDFLAGS += -dynamiclib -pthread diff --git a/hw/simulate/Makefile b/hw/simulate/Makefile index 192be90d..e5856b4b 100644 --- a/hw/simulate/Makefile +++ b/hw/simulate/Makefile @@ -1,7 +1,7 @@ CFLAGS += -std=c++11 -O2 -Wall -Wextra -Wfatal-errors #CFLAGS += -std=c++11 -g -O0 -Wall -Wextra -Wfatal-errors -CFLAGS += -Wno-aligned-new -Wno-maybe-uninitialized +CFLAGS += -Wno-maybe-uninitialized CFLAGS += -I../.. diff --git a/simX/Makefile b/simX/Makefile index 76fc6e7e..cc443f6a 100644 --- a/simX/Makefile +++ b/simX/Makefile @@ -1,12 +1,10 @@ #CXXFLAGS += -std=c++11 -O2 -Wall -Wextra -Wfatal-errors CXXFLAGS += -std=c++11 -g -O0 -Wall -Wextra -Wfatal-errors -CXXFLAGS += -Wno-aligned-new -Wno-maybe-uninitialized +CXXFLAGS += -Wno-maybe-uninitialized CXXFLAGS += -I. -I../hw CXXFLAGS += -DDUMP_PERF_STATS -LDFLAGS += - TOP = vx_cache_sim RTL_DIR = ../hw/rtl From d3f0a77ae50960ca8405e1aab0a8731827360768 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 23 May 2021 10:57:02 -0700 Subject: [PATCH 45/55] fixed databus arbiter bug --- hw/rtl/VX_databus_arb.v | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/rtl/VX_databus_arb.v b/hw/rtl/VX_databus_arb.v index 6a77f385..e797b75a 100644 --- a/hw/rtl/VX_databus_arb.v +++ b/hw/rtl/VX_databus_arb.v @@ -54,10 +54,11 @@ module VX_databus_arb ( if (`SM_ENABLE ) begin assign cache_req_if.valid[i] = cache_req_valid_out && ~is_smem_addr_out; assign smem_req_if.valid[i] = cache_req_valid_out && is_smem_addr_out; - assign cache_req_ready_out = is_smem_addr_out ? smem_req_if.ready[i] : cache_req_if.ready[i]; + assign cache_req_ready_out = (cache_req_if.ready[i] && ~is_smem_addr_out) + || (smem_req_if.ready[i] && is_smem_addr_out); assign smem_req_if.addr[i] = cache_req_if.addr[i]; - assign smem_req_if.rw[i] = cache_req_if.rw[i]; + assign smem_req_if.rw[i] = cache_req_if.rw[i]; assign smem_req_if.byteen[i] = cache_req_if.byteen[i]; assign smem_req_if.data[i] = cache_req_if.data[i]; assign smem_req_if.tag[i] = cache_req_if.tag[i]; From 244f4b096425e83a8dfa645e8b84ad0be56d1458 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 23 May 2021 10:57:58 -0700 Subject: [PATCH 46/55] fixed shared memory write bug --- hw/rtl/VX_lsu_unit.v | 2 +- hw/rtl/cache/VX_shared_mem.v | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/hw/rtl/VX_lsu_unit.v b/hw/rtl/VX_lsu_unit.v index 79059f30..97928cd6 100644 --- a/hw/rtl/VX_lsu_unit.v +++ b/hw/rtl/VX_lsu_unit.v @@ -306,7 +306,7 @@ module VX_lsu_unit #( $write("%t: D$%0d Rsp: valid=%b, wid=%0d, PC=%0h, tag=%0h, rd=%0d, data=", $time, CORE_ID, dcache_rsp_if.valid, rsp_wid, rsp_pc, dcache_rsp_if.tag, rsp_rd); `PRINT_ARRAY1D(dcache_rsp_if.data, `NUM_THREADS); - $write("is_dup=%b\n", rsp_is_dup); + $write(", is_dup=%b\n", rsp_is_dup); end if (mbuf_full) begin $write("%t: *** D$%0d queue-full:", $time, CORE_ID); diff --git a/hw/rtl/cache/VX_shared_mem.v b/hw/rtl/cache/VX_shared_mem.v index d2d38fad..e9b867d7 100644 --- a/hw/rtl/cache/VX_shared_mem.v +++ b/hw/rtl/cache/VX_shared_mem.v @@ -156,9 +156,14 @@ module VX_shared_mem #( `UNUSED_PIN (size) ); - wire [NUM_BANKS-1:0][`WORD_WIDTH-1:0] per_bank_core_rsp_data; + wire [NUM_BANKS-1:0][`WORD_WIDTH-1:0] per_bank_core_rsp_data; for (genvar i = 0; i < NUM_BANKS; i++) begin + + wire wren = per_bank_core_req_rw[i] + && per_bank_core_req_valid[i] + && creq_pop; + VX_sp_ram #( .DATAW (`WORD_WIDTH), .SIZE (`LINES_PER_BANK), @@ -167,7 +172,7 @@ module VX_shared_mem #( ) data ( .clk (clk), .addr (per_bank_core_req_addr[i]), - .wren (per_bank_core_req_valid[i] && per_bank_core_req_rw[i]), + .wren (wren), .byteen (per_bank_core_req_byteen[i]), .rden (1'b1), .din (per_bank_core_req_data[i]), @@ -228,10 +233,19 @@ module VX_shared_mem #( $display("%t: cache%0d pipeline-stall", $time, CACHE_ID); end if (creq_pop) begin - if (core_rsp_rw) - $display("%t: cache%0d core-wr-req: tmask=%0b, addr=%0h, tag=%0h, byteen=%b, data=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, per_bank_core_req_valid, per_bank_core_req_addr, per_bank_core_req_tag, per_bank_core_req_byteen, per_bank_core_req_data, debug_wid_st0, debug_pc_st0); - else - $display("%t: cache%0d core-rd-req: tmask=%0b, addr=%0h, tag=%0h, byteen=%b, data=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, per_bank_core_req_valid, per_bank_core_req_addr, per_bank_core_req_tag, per_bank_core_req_byteen, per_bank_core_rsp_data, debug_wid_st0, debug_pc_st0); + if (core_rsp_rw) begin + $write("%t: cache%0d core-wr-req: tmask=%0b, addr=", $time, CACHE_ID, per_bank_core_req_valid); + end else begin + $write("%t: cache%0d core-rd-req: tmask=%0b, addr=", $time, CACHE_ID, per_bank_core_req_valid); + end + `PRINT_ARRAY1D(per_bank_core_req_addr, `NUM_THREADS); + $write(", tag=%0h, byteen=%b, data=", per_bank_core_req_tag, per_bank_core_req_byteen); + if (core_rsp_rw) begin + `PRINT_ARRAY1D(per_bank_core_req_data, `NUM_THREADS); + end else begin + `PRINT_ARRAY1D(per_bank_core_rsp_data, `NUM_THREADS); + end + $write(", wid=%0d, PC=%0h\n", debug_wid_st0, debug_pc_st0); end end `endif From 6388d87ec5c85af9620a9e04cf4e26580afd1fad Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 24 May 2021 18:06:11 -0700 Subject: [PATCH 47/55] afu bug fix --- hw/rtl/afu/vortex_afu.sv | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 39bc970d..19e694ed 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -673,13 +673,14 @@ reg [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_ctr; wire [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr; reg [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr_unqual; reg [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr; +wire [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr_next; wire [CCI_RD_RQ_TAGW-1:0] cci_rd_req_tag; wire [CCI_RD_RQ_TAGW-1:0] cci_rd_rsp_tag; reg [CCI_RD_RQ_TAGW-1:0] cci_rd_rsp_ctr; wire cci_rd_req_fire; t_ccip_clAddr cci_rd_req_addr; -reg cci_rd_req_enable, cci_rd_req_wait; +reg cci_rd_req_valid, cci_rd_req_wait; wire cci_rdq_push, cci_rdq_pop; wire [CCI_RD_RQ_DATAW-1:0] cci_rdq_din; @@ -720,7 +721,9 @@ VX_pending_size #( ); `UNUSED_VAR (cci_pending_reads) -assign cci_rd_req_fire = cci_rd_req_enable && !(cci_rd_req_wait || cci_pending_reads_full); +assign cci_rd_req_ctr_next = cci_rd_req_ctr + CCI_ADDR_WIDTH'(cci_rd_req_fire ? 1 : 0); + +assign cci_rd_req_fire = cci_rd_req_valid && !(cci_rd_req_wait || cci_pending_reads_full); assign cci_mem_wr_req_valid = !cci_rdq_empty; @@ -731,18 +734,18 @@ assign cmd_write_done = (cci_mem_wr_req_ctr == cmd_data_size); // Send read requests to CCI always @(posedge clk) begin if (reset) begin - cci_rd_req_enable <= 0; - cci_rd_req_wait <= 0; + cci_rd_req_valid <= 0; + cci_rd_req_wait <= 0; end else begin if ((STATE_IDLE == state) && (CMD_MEM_WRITE == cmd_type)) begin - cci_rd_req_enable <= (cmd_data_size != 0); - cci_rd_req_wait <= 0; + cci_rd_req_valid <= (cmd_data_size != 0); + cci_rd_req_wait <= 0; end - cci_rd_req_enable <= (STATE_WRITE == state) - && (cci_rd_req_ctr != cmd_data_size) - && !cp2af_sRxPort.c0TxAlmFull; + cci_rd_req_valid <= (STATE_WRITE == state) + && (cci_rd_req_ctr_next != cmd_data_size) + && !cp2af_sRxPort.c0TxAlmFull; if (cci_rd_req_fire && (cci_rd_req_tag == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1))) begin cci_rd_req_wait <= 1; // end current request batch From c81b1173b81dff51a15f7491ff7e295cb496afca Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 24 May 2021 18:20:46 -0700 Subject: [PATCH 48/55] minor update --- .travis.yml | 1 + ci/regression.sh | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1398e3be..81950c5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ install: script: - ./ci/regression.sh + - ./ci/test_compiler.sh after_success: # Gather code coverage diff --git a/ci/regression.sh b/ci/regression.sh index 27649975..58bdfd9e 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -11,7 +11,6 @@ make -s ./ci/test_opencl.sh ./ci/test_driver.sh ./ci/test_simx.sh -#./ci/test_compiler.sh # warp/threads configurations ./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=2 --threads=2 --app=demo From 9b120e3bb4d256cb50b99a48decb6879f3a450db Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 24 May 2021 20:05:36 -0700 Subject: [PATCH 49/55] minor update --- ci/regression.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/regression.sh b/ci/regression.sh index 58bdfd9e..2a411bba 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -48,7 +48,7 @@ FPU_CORE=FPU_FPNEW ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=dogfood CONFIGS=-DMEM_BLOCK_SIZE=16 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo # test 128-bit MEM and DRAM block -CONFIGS="-DMEM_BLOCK_SIZE=16 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo +CONFIGS="-DMEM_BLOCK_SIZE=16 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28 -DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo # test 27-bit DRAM address CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo From 093008fa1e4070e95302d189ca370ea30402d939 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 25 May 2021 09:13:32 -0700 Subject: [PATCH 50/55] minor update --- hw/rtl/afu/VX_to_mem.v | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/rtl/afu/VX_to_mem.v b/hw/rtl/afu/VX_to_mem.v index 901aaa36..c9c6287c 100644 --- a/hw/rtl/afu/VX_to_mem.v +++ b/hw/rtl/afu/VX_to_mem.v @@ -87,8 +87,8 @@ module VX_to_mem #( reg [P-1:0][DST_DATA_WIDTH-1:0] mem_rsp_data_out_r, mem_rsp_data_out_n; - wire mem_req_fire_out = mem_req_valid_out && mem_req_ready_out; - wire mem_rsp_fire_in = mem_rsp_valid_in && mem_rsp_ready_in; + wire mem_req_out_fire = mem_req_valid_out && mem_req_ready_out; + wire mem_rsp_in_fire = mem_rsp_valid_in && mem_rsp_ready_in; wire [P-1:0][DST_DATA_WIDTH-1:0] mem_req_data_in_w = mem_req_data_in; wire [P-1:0][DST_DATA_SIZE-1:0] mem_req_byteen_in_w = mem_req_byteen_in; @@ -103,10 +103,10 @@ module VX_to_mem #( req_ctr <= 0; rsp_ctr <= 0; end else begin - if (mem_req_fire_out) begin + if (mem_req_out_fire) begin req_ctr <= req_ctr + 1; end - if (mem_rsp_fire_in) begin + if (mem_rsp_in_fire) begin rsp_ctr <= rsp_ctr + 1; mem_rsp_data_out_r <= mem_rsp_data_out_n; end @@ -117,7 +117,7 @@ module VX_to_mem #( wire [DST_TAG_WIDTH-1:0] mem_rsp_tag_in_w; always @(posedge clk) begin - if (mem_rsp_fire_in) begin + if (mem_rsp_in_fire) begin mem_rsp_tag_in_r <= mem_rsp_tag_in; end end From 79638c89defba2226c9d8eecdeb4ca7dfb055fbb Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 25 May 2021 22:02:42 -0700 Subject: [PATCH 51/55] adding synthesis build for shared memory --- hw/syn/quartus/.gitignore | 3 ++ hw/syn/quartus/Makefile | 29 +++++++++------ hw/syn/quartus/smem/Makefile | 72 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 12 deletions(-) create mode 100755 hw/syn/quartus/smem/Makefile diff --git a/hw/syn/quartus/.gitignore b/hw/syn/quartus/.gitignore index 0c2cba5a..7a0867fe 100644 --- a/hw/syn/quartus/.gitignore +++ b/hw/syn/quartus/.gitignore @@ -1,6 +1,9 @@ /unittest/* !/unittest/Makefile +/smem/* +!/smem/Makefile + /cache/* !/cache/Makefile diff --git a/hw/syn/quartus/Makefile b/hw/syn/quartus/Makefile index fa002563..9cf2a79b 100644 --- a/hw/syn/quartus/Makefile +++ b/hw/syn/quartus/Makefile @@ -1,20 +1,25 @@ BUILDIR ?= build -.PHONY: unittest pipeline cache core vortex top1 top2 top4 top8 top16 top32 top64 +.PHONY: unittest pipeline smem cache core vortex top1 top2 top4 top8 top16 top32 top64 unittest: mkdir -p unittest/$(BUILDIR) - cp core/Makefile unittest/$(BUILDIR) + cp unittest/Makefile unittest/$(BUILDIR) $(MAKE) -C unittest/$(BUILDIR) clean && $(MAKE) -C unittest/$(BUILDIR) > unittest//$(BUILDIR)build.log 2>&1 & pipeline: mkdir -p pipeline/$(BUILDIR) - cp core/Makefile pipeline/$(BUILDIR) + cp pipeline/Makefile pipeline/$(BUILDIR) $(MAKE) -C pipeline/$(BUILDIR) clean && $(MAKE) -C pipeline/$(BUILDIR) > pipeline/$(BUILDIR)/build.log 2>&1 & +smem: + mkdir -p smem/$(BUILDIR) + cp smem/Makefile smem/$(BUILDIR) + $(MAKE) -C smem/$(BUILDIR) clean && $(MAKE) -C smem/$(BUILDIR) > smem/$(BUILDIR)/build.log 2>&1 & + cache: mkdir -p cache/$(BUILDIR) - cp core/Makefile cache/$(BUILDIR) + cp cache/Makefile cache/$(BUILDIR) $(MAKE) -C cache/$(BUILDIR) clean && $(MAKE) -C cache/$(BUILDIR) > cache/$(BUILDIR)/build.log 2>&1 & core: @@ -24,40 +29,40 @@ core: vortex: mkdir -p vortex/$(BUILDIR) - cp core/Makefile vortex/$(BUILDIR) + cp vortex/Makefile vortex/$(BUILDIR) $(MAKE) -C vortex/$(BUILDIR) clean && $(MAKE) -C vortex/$(BUILDIR) > vortex/$(BUILDIR)/build.log 2>&1 & top1: mkdir -p top1/$(BUILDIR) - cp core/Makefile top1/$(BUILDIR) + cp top1/Makefile top1/$(BUILDIR) $(MAKE) -C top1/$(BUILDIR) clean && $(MAKE) -C top1/$(BUILDIR) > top1/$(BUILDIR)/build.log 2>&1 & top2: mkdir -p top2/$(BUILDIR) - cp core/Makefile top2/$(BUILDIR) + cp top2/Makefile top2/$(BUILDIR) $(MAKE) -C top2/$(BUILDIR) clean && $(MAKE) -C top2/$(BUILDIR) > top2/$(BUILDIR)/build.log 2>&1 & top4: mkdir -p top4/$(BUILDIR) - cp core/Makefile top4/$(BUILDIR) + cp top4/Makefile top4/$(BUILDIR) $(MAKE) -C top4/$(BUILDIR) clean && $(MAKE) -C top4/$(BUILDIR) > top4/$(BUILDIR)/build.log 2>&1 & top8: mkdir -p top8/$(BUILDIR) - cp core/Makefile top8/$(BUILDIR) + cp top8/Makefile top8/$(BUILDIR) $(MAKE) -C top8/$(BUILDIR) clean && $(MAKE) -C top8/$(BUILDIR) > top8/$(BUILDIR)/build.log 2>&1 & top16: mkdir -p top16/$(BUILDIR) - cp core/Makefile top16/$(BUILDIR) + cp top16/Makefile top16/$(BUILDIR) $(MAKE) -C top16/$(BUILDIR) clean && $(MAKE) -C top16/$(BUILDIR) > top16/$(BUILDIR)build.log 2>&1 & top32: mkdir -p top32/$(BUILDIR) - cp core/Makefile top32/$(BUILDIR) + cp top32/Makefile top32/$(BUILDIR) $(MAKE) -C top32/$(BUILDIR) clean && $(MAKE) -C top32/$(BUILDIR) > top32/$(BUILDIR)/build.log 2>&1 & top64: mkdir -p top64/$(BUILDIR) - cp core/Makefile top64/$(BUILDIR) + cp top64/Makefile top64/$(BUILDIR) $(MAKE) -C top64/$(BUILDIR) clean && $(MAKE) -C top64/$(BUILDIR) > top64/$(BUILDIR)/build.log 2>&1 & \ No newline at end of file diff --git a/hw/syn/quartus/smem/Makefile b/hw/syn/quartus/smem/Makefile new file mode 100755 index 00000000..3b0c0872 --- /dev/null +++ b/hw/syn/quartus/smem/Makefile @@ -0,0 +1,72 @@ +PROJECT = VX_shared_mem +TOP_LEVEL_ENTITY = VX_shared_mem +SRC_FILE = VX_shared_mem.v +RTL_DIR = ../../../../rtl + +FAMILY = "Arria 10" +DEVICE = 10AX115N3F40E2SG + +RTL_INCLUDE = $(RTL_DIR);$(RTL_DIR)/libs;$(RTL_DIR)/interfaces;$(RTL_DIR)/cache +PROJECT_FILES = $(PROJECT).qpf $(PROJECT).qsf + +# Executable Configuration +SYN_ARGS = --parallel --read_settings_files=on +FIT_ARGS = --parallel --part=$(DEVICE) --read_settings_files=on +ASM_ARGS = +STA_ARGS = --parallel --do_report_timing + +# Build targets +all: $(PROJECT).sta.rpt + +syn: $(PROJECT).syn.rpt + +fit: $(PROJECT).fit.rpt + +asm: $(PROJECT).asm.rpt + +sta: $(PROJECT).sta.rpt + +smart: smart.log + +# Target implementations +STAMP = echo done > + +$(PROJECT).syn.rpt: smart.log syn.chg $(SOURCE_FILES) + quartus_syn $(PROJECT) $(SYN_ARGS) + $(STAMP) fit.chg + +$(PROJECT).fit.rpt: smart.log fit.chg $(PROJECT).syn.rpt + quartus_fit $(PROJECT) $(FIT_ARGS) + $(STAMP) asm.chg + $(STAMP) sta.chg + +$(PROJECT).asm.rpt: smart.log asm.chg $(PROJECT).fit.rpt + quartus_asm $(PROJECT) $(ASM_ARGS) + +$(PROJECT).sta.rpt: smart.log sta.chg $(PROJECT).fit.rpt + quartus_sta $(PROJECT) $(STA_ARGS) + +smart.log: $(PROJECT_FILES) + quartus_sh --determine_smart_action $(PROJECT) > smart.log + +# Project initialization +$(PROJECT_FILES): + quartus_sh -t ../../project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src $(SRC_FILE) -sdc ../../project.sdc -inc "$(RTL_INCLUDE)" + +syn.chg: + $(STAMP) syn.chg + +fit.chg: + $(STAMP) fit.chg + +sta.chg: + $(STAMP) sta.chg + +asm.chg: + $(STAMP) asm.chg + +program: $(PROJECT).sof + quartus_pgm --no_banner --mode=jtag -o "$(PROJECT).sof" + +clean: + rm -rf bin *.rpt *.chg *.qsf *.qpf *.qws *.log *.htm *.eqn *.pin *.sof *.pof qdb incremental_db tmp-clearbox From c7f85b76ede28bbbabe7fe99f545f6d31155b41d Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 26 May 2021 13:36:10 -0700 Subject: [PATCH 52/55] minor update --- hw/rtl/VX_databus_arb.v | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/rtl/VX_databus_arb.v b/hw/rtl/VX_databus_arb.v index e797b75a..02704b7f 100644 --- a/hw/rtl/VX_databus_arb.v +++ b/hw/rtl/VX_databus_arb.v @@ -34,7 +34,7 @@ module VX_databus_arb ( wire is_smem_addr_in, is_smem_addr_out; // select shared memory bus - assign is_smem_addr_in = core_req_if.valid[i] && `SM_ENABLE + assign is_smem_addr_in = `SM_ENABLE && (core_req_if.addr[i][REQ_ADDRW-1:SMEM_ASHIFT-REQ_ASHIFT] >= (32-SMEM_ASHIFT)'((`SHARED_MEM_BASE_ADDR - `SMEM_SIZE) >> SMEM_ASHIFT)) && (core_req_if.addr[i][REQ_ADDRW-1:SMEM_ASHIFT-REQ_ASHIFT] < (32-SMEM_ASHIFT)'(`SHARED_MEM_BASE_ADDR >> SMEM_ASHIFT)); @@ -51,11 +51,10 @@ module VX_databus_arb ( .ready_out (cache_req_ready_out) ); - if (`SM_ENABLE ) begin + if (`SM_ENABLE) begin assign cache_req_if.valid[i] = cache_req_valid_out && ~is_smem_addr_out; assign smem_req_if.valid[i] = cache_req_valid_out && is_smem_addr_out; - assign cache_req_ready_out = (cache_req_if.ready[i] && ~is_smem_addr_out) - || (smem_req_if.ready[i] && is_smem_addr_out); + assign cache_req_ready_out = is_smem_addr_out ? smem_req_if.ready[i] : cache_req_if.ready[i]; assign smem_req_if.addr[i] = cache_req_if.addr[i]; assign smem_req_if.rw[i] = cache_req_if.rw[i]; From d8517d4d080ef8b4de4fdc7fb814e29989c220d3 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 26 May 2021 13:37:07 -0700 Subject: [PATCH 53/55] minor update --- hw/rtl/cache/VX_bank.v | 14 +++++++------- hw/rtl/cache/VX_cache_core_rsp_merge.v | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/rtl/cache/VX_bank.v b/hw/rtl/cache/VX_bank.v index d5764519..0f79f881 100644 --- a/hw/rtl/cache/VX_bank.v +++ b/hw/rtl/cache/VX_bank.v @@ -90,10 +90,10 @@ module VX_bank #( `UNUSED_PARAM (CORE_TAG_ID_BITS) `ifdef DBG_CACHE_REQ_INFO - /* verilator lint_off UNUSED */ +`IGNORE_WARNINGS_BEGIN wire [31:0] debug_pc_sel, debug_pc_st0, debug_pc_st1; wire [`NW_BITS-1:0] debug_wid_sel, debug_wid_st0, debug_wid_st1; - /* verilator lint_on UNUSED */ +`IGNORE_WARNINGS_END `endif wire creq_pop; @@ -554,7 +554,7 @@ module VX_bank #( assert(!is_mshr_st1); end if (crsq_in_stall || mreq_alm_full || mshr_alm_full) begin - $display("%t: cache%0d:%0d pipeline-stall: cwbq=%b, dwbq=%b, mshr=%b", $time, CACHE_ID, BANK_ID, crsq_in_stall, mreq_alm_full, mshr_alm_full); + $display("%t: *** cache%0d:%0d pipeline-stall: cwbq=%b, dwbq=%b, mshr=%b", $time, CACHE_ID, BANK_ID, crsq_in_stall, mreq_alm_full, mshr_alm_full); end if (flush_enable) begin $display("%t: cache%0d:%0d flush: addr=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(flush_addr, BANK_ID)); @@ -563,16 +563,16 @@ module VX_bank #( $display("%t: cache%0d:%0d fill-rsp: addr=%0h, data=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mem_rsp_addr, BANK_ID), mem_rsp_data); end if (mshr_pop) begin - $display("%t: cache%0d:%0d mshr-rd-req: addr=%0h, tag=%0h, pmask=%0b, tid=%0d, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mshr_addr, BANK_ID), mshr_tag, mshr_pmask, mshr_tid, mshr_byteen, debug_wid_sel, debug_pc_sel); + $display("%t: cache%0d:%0d mshr-rd-req: addr=%0h, tag=%0h, pmask=%b, tid=%0d, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mshr_addr, BANK_ID), mshr_tag, mshr_pmask, mshr_tid, mshr_byteen, debug_wid_sel, debug_pc_sel); end if (creq_pop) begin if (creq_rw) - $display("%t: cache%0d:%0d core-wr-req: addr=%0h, tag=%0h, pmask=%0b, tid=%0d, byteen=%b, data=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(creq_addr, BANK_ID), creq_tag, creq_pmask, creq_tid, creq_byteen, creq_data, debug_wid_sel, debug_pc_sel); + $display("%t: cache%0d:%0d core-wr-req: addr=%0h, tag=%0h, pmask=%b, tid=%0d, byteen=%b, data=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(creq_addr, BANK_ID), creq_tag, creq_pmask, creq_tid, creq_byteen, creq_data, debug_wid_sel, debug_pc_sel); else - $display("%t: cache%0d:%0d core-rd-req: addr=%0h, tag=%0h, pmask=%0b, tid=%0d, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(creq_addr, BANK_ID), creq_tag, creq_pmask, creq_tid, creq_byteen, debug_wid_sel, debug_pc_sel); + $display("%t: cache%0d:%0d core-rd-req: addr=%0h, tag=%0h, pmask=%b, tid=%0d, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(creq_addr, BANK_ID), creq_tag, creq_pmask, creq_tid, creq_byteen, debug_wid_sel, debug_pc_sel); end if (crsq_in_fire) begin - $display("%t: cache%0d:%0d core-rsp: addr=%0h, tag=%0h, pmask=%0b, tid=%0d, data=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID), crsq_tag, crsq_pmask, crsq_tid, crsq_data, debug_wid_st1, debug_pc_st1); + $display("%t: cache%0d:%0d core-rsp: addr=%0h, tag=%0h, pmask=%b, tid=%0d, data=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID), crsq_tag, crsq_pmask, crsq_tid, crsq_data, debug_wid_st1, debug_pc_st1); end if (mreq_push) begin if (do_writeback_st1) diff --git a/hw/rtl/cache/VX_cache_core_rsp_merge.v b/hw/rtl/cache/VX_cache_core_rsp_merge.v index 2713943a..e7ab960d 100644 --- a/hw/rtl/cache/VX_cache_core_rsp_merge.v +++ b/hw/rtl/cache/VX_cache_core_rsp_merge.v @@ -43,6 +43,10 @@ module VX_cache_core_rsp_merge #( if (CORE_TAG_ID_BITS != 0) begin + // The core response bus handles a single tag at the time + // We first need to select the current tag to process, + // then send all bank responses for that tag as a batch + reg [CORE_TAG_WIDTH-1:0] core_rsp_tag_unqual; wire core_rsp_ready_unqual; From 4c5104e96a783d2a48b5f6cf3fc64fcf47a92abb Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 26 May 2021 15:03:48 -0700 Subject: [PATCH 54/55] fixed shared memory multi-tag requests bug --- hw/rtl/cache/VX_shared_mem.v | 187 +++++++++++++++++++++++++---------- 1 file changed, 135 insertions(+), 52 deletions(-) diff --git a/hw/rtl/cache/VX_shared_mem.v b/hw/rtl/cache/VX_shared_mem.v index e9b867d7..3ebf485d 100644 --- a/hw/rtl/cache/VX_shared_mem.v +++ b/hw/rtl/cache/VX_shared_mem.v @@ -4,25 +4,25 @@ module VX_shared_mem #( parameter CACHE_ID = 0, // Size of cache in bytes - parameter CACHE_SIZE = 16384, + parameter CACHE_SIZE = (1024*16), // Number of banks - parameter NUM_BANKS = 4, + parameter NUM_BANKS = 2, // Size of a word in bytes parameter WORD_SIZE = 4, // Number of Word requests per cycle - parameter NUM_REQS = NUM_BANKS, + parameter NUM_REQS = 4, // Core Request Queue Size - parameter CREQ_SIZE = 4, - - // core request tag size - parameter CORE_TAG_WIDTH = 1, + parameter CREQ_SIZE = 8, // size of tag id in core request tag - parameter CORE_TAG_ID_BITS = 0, + parameter CORE_TAG_ID_BITS = 8, + + // core request tag size + parameter CORE_TAG_WIDTH = (2 + CORE_TAG_ID_BITS), // bank offset from beginning of index range - parameter BANK_ADDR_OFFSET = 0 + parameter BANK_ADDR_OFFSET = `CLOG2(256) ) ( input wire clk, input wire reset, @@ -54,13 +54,6 @@ module VX_shared_mem #( localparam CACHE_LINE_SIZE = WORD_SIZE; -`ifdef DBG_CACHE_REQ_INFO - /* verilator lint_off UNUSED */ - wire [31:0] debug_pc_st0; - wire [`NW_BITS-1:0] debug_wid_st0; - /* verilator lint_on UNUSED */ -`endif - wire [NUM_BANKS-1:0] per_bank_core_req_valid_unqual; wire [NUM_BANKS-1:0] per_bank_core_req_rw_unqual; wire [NUM_BANKS-1:0][`LINE_ADDR_WIDTH-1:0] per_bank_core_req_addr_unqual; @@ -109,20 +102,26 @@ module VX_shared_mem #( wire [NUM_BANKS-1:0][`LINE_SELECT_BITS-1:0] per_bank_core_req_addr; wire [NUM_BANKS-1:0][WORD_SIZE-1:0] per_bank_core_req_byteen; wire [NUM_BANKS-1:0][`WORD_WIDTH-1:0] per_bank_core_req_data; - wire [NUM_REQS-1:0][CORE_TAG_WIDTH-1:0] per_bank_core_req_tag; + wire [NUM_BANKS-1:0][CORE_TAG_WIDTH-1:0] per_bank_core_req_tag; wire [NUM_BANKS-1:0][`REQS_BITS-1:0] per_bank_core_req_tid; wire creq_push, creq_pop, creq_empty, creq_full; - wire crsq_in_ready; + wire crsq_in_fire_last; + + wire [NUM_BANKS-1:0] per_bank_rsp_valid = per_bank_core_req_valid & ~per_bank_core_req_rw; + + wire core_req_has_read = (| per_bank_rsp_valid); - assign creq_push = (| core_req_valid) && !creq_full; - assign creq_pop = ~creq_empty && crsq_in_ready; + assign creq_push = (| core_req_valid) && ~creq_full; + + assign creq_pop = (~creq_empty && ~core_req_has_read) + || crsq_in_fire_last; assign per_bank_core_req_ready_unqual = ~creq_full; - wire [NUM_REQS-1:0][`LINE_SELECT_BITS-1:0] per_bank_core_req_addr_qual; + wire [NUM_BANKS-1:0][`LINE_SELECT_BITS-1:0] per_bank_core_req_addr_qual; `UNUSED_VAR (per_bank_core_req_addr_unqual) - for (genvar i = 0; i < NUM_REQS; i++) begin + for (genvar i = 0; i < NUM_BANKS; i++) begin assign per_bank_core_req_addr_qual[i] = per_bank_core_req_addr_unqual[i][`LINE_SELECT_BITS-1:0]; end @@ -179,6 +178,34 @@ module VX_shared_mem #( .dout (per_bank_core_rsp_data[i]) ); end + + // The core response bus handles a single tag at the time + // We first need to select the current tag to process, + // then send all bank responses for that tag as a batch + + wire crsq_in_valid, crsq_in_ready; + + reg [NUM_BANKS-1:0] bank_rsp_sel, bank_rsp_sel_r; + + wire [NUM_BANKS-1:0] bank_rsp_sel_n = bank_rsp_sel | bank_rsp_sel_r; + + wire crsq_in_fire = crsq_in_valid && crsq_in_ready; + + assign crsq_in_fire_last = crsq_in_fire && (bank_rsp_sel_n == per_bank_rsp_valid); + + always @(posedge clk) begin + if (reset) begin + bank_rsp_sel <= 0; + end else begin + if (crsq_in_fire) begin + if (bank_rsp_sel_n == per_bank_rsp_valid) begin + bank_rsp_sel <= 0; + end else begin + bank_rsp_sel <= bank_rsp_sel_n; + end + end + end + end reg [NUM_REQS-1:0] core_rsp_valids_in; reg [NUM_REQS-1:0][`WORD_WIDTH-1:0] core_rsp_data_in; @@ -186,31 +213,30 @@ module VX_shared_mem #( always @(*) begin core_rsp_valids_in = 0; - core_rsp_data_in = 'x; + core_rsp_data_in = 'x; core_rsp_tag_in = 'x; - for (integer i = 0; i < NUM_BANKS; i++) begin - if (per_bank_core_req_valid[i]) begin - core_rsp_valids_in[per_bank_core_req_tid[i]] = 1; - core_rsp_data_in[per_bank_core_req_tid[i]] = per_bank_core_rsp_data[i]; + bank_rsp_sel_r = 0; + + for (integer i = NUM_BANKS-1; i >= 0; --i) begin + if (per_bank_rsp_valid[i] && ~bank_rsp_sel[i]) begin core_rsp_tag_in = per_bank_core_req_tag[i]; end end - end - -`ifdef DBG_CACHE_REQ_INFO - if (CORE_TAG_WIDTH != CORE_TAG_ID_BITS && CORE_TAG_ID_BITS != 0) begin - assign {debug_pc_st0, debug_wid_st0} = core_rsp_tag_in[CORE_TAG_WIDTH-1:CORE_TAG_ID_BITS]; - end else begin - assign {debug_pc_st0, debug_wid_st0} = 0; + + for (integer i = 0; i < NUM_BANKS; i++) begin + if (per_bank_core_req_valid[i] + && (core_rsp_tag_in[CORE_TAG_ID_BITS-1:0] == per_bank_core_req_tag[i][CORE_TAG_ID_BITS-1:0])) begin + core_rsp_valids_in[per_bank_core_req_tid[i]] = 1; + core_rsp_data_in[per_bank_core_req_tid[i]] = per_bank_core_rsp_data[i]; + bank_rsp_sel_r[i] = 1; + end + end end -`endif - + wire [NUM_REQS-1:0] core_rsp_valids_out; wire core_rsp_valid_out; - wire core_rsp_rw = | (per_bank_core_req_valid & per_bank_core_req_rw); - - wire crsq_in_valid = ~creq_empty && ~core_rsp_rw; + assign crsq_in_valid = ~creq_empty && core_req_has_read; VX_skid_buffer #( .DATAW (NUM_BANKS * (1 + `WORD_WIDTH) + CORE_TAG_WIDTH) @@ -227,25 +253,82 @@ module VX_shared_mem #( assign core_rsp_valid = core_rsp_valids_out & {NUM_REQS{core_rsp_valid_out}}; +`ifdef DBG_CACHE_REQ_INFO +`IGNORE_WARNINGS_BEGIN + wire [NUM_BANKS-1:0][31:0] debug_pc_st0, debug_pc_st1; + wire [NUM_BANKS-1:0][`NW_BITS-1:0] debug_wid_st0, debug_wid_st1; +`IGNORE_WARNINGS_END + + for (genvar i = 0; i < NUM_BANKS; ++i) begin + if (CORE_TAG_WIDTH != CORE_TAG_ID_BITS && CORE_TAG_ID_BITS != 0) begin + assign {debug_pc_st0[i], debug_wid_st0[i]} = per_bank_core_req_tag_unqual[i][CORE_TAG_WIDTH-1:CORE_TAG_ID_BITS]; + assign {debug_pc_st1[i], debug_wid_st1[i]} = per_bank_core_req_tag[i][CORE_TAG_WIDTH-1:CORE_TAG_ID_BITS]; + end else begin + assign {debug_pc_st0[i], debug_wid_st0[i]} = 0; + assign {debug_pc_st1[i], debug_wid_st1[i]} = 0; + end + end +`endif + `ifdef DBG_PRINT_CACHE_BANK + + reg is_multi_tag_req; +`IGNORE_WARNINGS_BEGIN + reg [CORE_TAG_WIDTH-1:0] core_req_tag_sel; +`IGNORE_WARNINGS_END + + always @(*) begin + core_req_tag_sel ='x; + for (integer i = NUM_BANKS-1; i >= 0; --i) begin + if (per_bank_core_req_valid[i]) begin + core_req_tag_sel = per_bank_core_req_tag[i]; + end + end + is_multi_tag_req = 0; + for (integer i = 0; i < NUM_BANKS; ++i) begin + if (per_bank_core_req_valid[i] + && (core_req_tag_sel[CORE_TAG_ID_BITS-1:0] != per_bank_core_req_tag[i][CORE_TAG_ID_BITS-1:0])) begin + is_multi_tag_req = !creq_empty; + end + end + end + always @(posedge clk) begin if (!crsq_in_ready) begin - $display("%t: cache%0d pipeline-stall", $time, CACHE_ID); + $display("%t: *** cache%0d pipeline-stall", $time, CACHE_ID); + end + if (is_multi_tag_req) begin + $display("%t: *** cache%0d multi-tag request!", $time, CACHE_ID); + end + if (creq_push) begin + for (integer i = 0; i < NUM_BANKS; ++i) begin + if (per_bank_core_req_valid_unqual[i]) begin + if (per_bank_core_req_rw_unqual[i]) begin + $display("%t: cache%0d:%0d core-wr-req: addr=%0h, tag=%0h, byteen=%b, data=%0h, wid=%0d, PC=%0h", + $time, CACHE_ID, i, per_bank_core_req_addr_unqual[i], per_bank_core_req_tag_unqual[i], per_bank_core_req_byteen_unqual[i], per_bank_core_req_data_unqual[i], + debug_wid_st0[i], debug_pc_st0[i]); + end else begin + $display("%t: cache%0d:%0d core-rd-req: addr=%0h, tag=%0h, byteen=%b, wid=%0d, PC=%0h", + $time, CACHE_ID, i, per_bank_core_req_addr_unqual[i], per_bank_core_req_tag_unqual[i], per_bank_core_req_byteen_unqual[i], + debug_wid_st0[i], debug_pc_st0[i]); + end + end + end end if (creq_pop) begin - if (core_rsp_rw) begin - $write("%t: cache%0d core-wr-req: tmask=%0b, addr=", $time, CACHE_ID, per_bank_core_req_valid); - end else begin - $write("%t: cache%0d core-rd-req: tmask=%0b, addr=", $time, CACHE_ID, per_bank_core_req_valid); + for (integer i = 0; i < NUM_BANKS; ++i) begin + if (per_bank_core_req_valid[i]) begin + if (per_bank_core_req_rw[i]) begin + $display("%t: cache%0d:%0d core-wr-rsp: addr=%0h, tag=%0h, byteen=%b, data=%0h, wid=%0d, PC=%0h", + $time, CACHE_ID, i, per_bank_core_req_addr[i], per_bank_core_req_tag[i], per_bank_core_req_byteen[i], per_bank_core_req_data[i], + debug_wid_st1[i], debug_pc_st1[i]); + end else begin + $display("%t: cache%0d:%0d core-rd-rsp: addr=%0h, tag=%0h, byteen=%b, wid=%0d, PC=%0h", + $time, CACHE_ID, i, per_bank_core_req_addr[i], per_bank_core_req_tag[i], per_bank_core_req_byteen[i], + debug_wid_st1[i], debug_pc_st1[i]); + end + end end - `PRINT_ARRAY1D(per_bank_core_req_addr, `NUM_THREADS); - $write(", tag=%0h, byteen=%b, data=", per_bank_core_req_tag, per_bank_core_req_byteen); - if (core_rsp_rw) begin - `PRINT_ARRAY1D(per_bank_core_req_data, `NUM_THREADS); - end else begin - `PRINT_ARRAY1D(per_bank_core_rsp_data, `NUM_THREADS); - end - $write(", wid=%0d, PC=%0h\n", debug_wid_st0, debug_pc_st0); end end `endif From df7d91d690774cdf412e6726d4e62def88488bb4 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 26 May 2021 15:29:39 -0700 Subject: [PATCH 55/55] more testing --- ci/regression.sh | 11 +++++++++-- driver/opae/vlsim/opae_sim.cpp | 15 ++++++++++++++- hw/simulate/simulator.cpp | 15 ++++++++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/ci/regression.sh b/ci/regression.sh index 2a411bba..0e0fb248 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -51,7 +51,14 @@ CONFIGS=-DMEM_BLOCK_SIZE=16 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo CONFIGS="-DMEM_BLOCK_SIZE=16 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28 -DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo # test 27-bit DRAM address -CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo +CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo # test 128-bit DRAM block -CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo \ No newline at end of file +CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo + +# test verilator reset values +CONFIGS="-DVERILATOR_RESET_VALUE=0" ./ci/blackbox.sh --driver=vlsim --cores=4 --app=sgemm +CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=vlsim --cores=4 --app=sgemm + +# test vlsim memory stress +CONFIGS="-DMEM_LATENCY=100 -DMEM_RQ_SIZE=4 -DMEM_STALLS_MODULO=4" ./ci/blackbox.sh --driver=vlsim --cores=4 --app=sgemm diff --git a/driver/opae/vlsim/opae_sim.cpp b/driver/opae/vlsim/opae_sim.cpp index 98a52ce6..9f8df01d 100644 --- a/driver/opae/vlsim/opae_sim.cpp +++ b/driver/opae/vlsim/opae_sim.cpp @@ -11,9 +11,22 @@ #define RESET_DELAY 4 #define ENABLE_MEM_STALLS + +#ifndef MEM_LATENCY #define MEM_LATENCY 24 +#endif + +#ifndef MEM_RQ_SIZE #define MEM_RQ_SIZE 16 +#endif + +#ifndef MEM_STALLS_MODULO #define MEM_STALLS_MODULO 16 +#endif + +#ifndef VERILATOR_RESET_VALUE +#define VERILATOR_RESET_VALUE 2 +#endif uint64_t timestamp = 0; @@ -23,7 +36,7 @@ double sc_time_stamp() { opae_sim::opae_sim() { // force random values for unitialized signals - Verilated::randReset(2); + Verilated::randReset(VERILATOR_RESET_VALUE); Verilated::randSeed(50); // Turn off assertion before reset diff --git a/hw/simulate/simulator.cpp b/hw/simulate/simulator.cpp index 86156b94..25ed1992 100644 --- a/hw/simulate/simulator.cpp +++ b/hw/simulate/simulator.cpp @@ -6,9 +6,22 @@ #define RESET_DELAY 4 #define ENABLE_MEM_STALLS + +#ifndef MEM_LATENCY #define MEM_LATENCY 24 +#endif + +#ifndef MEM_RQ_SIZE #define MEM_RQ_SIZE 16 +#endif + +#ifndef MEM_STALLS_MODULO #define MEM_STALLS_MODULO 16 +#endif + +#ifndef VERILATOR_RESET_VALUE +#define VERILATOR_RESET_VALUE 2 +#endif #define VL_WDATA_GETW(lwp, i, n, w) \ VL_SEL_IWII(0, n * w, 0, 0, lwp, i * w, w) @@ -21,7 +34,7 @@ double sc_time_stamp() { Simulator::Simulator() { // force random values for unitialized signals - Verilated::randReset(2); + Verilated::randReset(VERILATOR_RESET_VALUE); Verilated::randSeed(50); // Turn off assertion before reset

    U>d^?1`6ki*iWl?6o`eWy^tk3g5^H>&L5~-h} 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 Zf99>)u|jTJIGh-Oz|+;wWt~$(697W(-qZj9 literal 0 HcmV?d00001 From e3e5c178ffa5d48726ac00dacd297c8ddcf69f4a Mon Sep 17 00:00:00 2001 From: Malik Aki Burton Date: Fri, 23 Apr 2021 18:31:52 -0400 Subject: [PATCH 07/55] Added codebase and microarch guides and updated vortex and simulation guides slightly --- doc/Codebase.md | 35 +++++++++++++++ doc/Microarchitecture.md | 94 ++++++++++++++++++++++++++++++++++++++++ doc/Simulation.md | 7 ++- doc/Vortex.md | 2 +- 4 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 doc/Codebase.md create mode 100644 doc/Microarchitecture.md diff --git a/doc/Codebase.md b/doc/Codebase.md new file mode 100644 index 00000000..3d018855 --- /dev/null +++ b/doc/Codebase.md @@ -0,0 +1,35 @@ +# Vortex Codebase + +The directory/file layout of the Vortex codebase is as followed: + +- `benchmark`: contains opencl, risc-v, and vector tests + - `opencl`: contains basic kernel operation tests (i.e. vector add, transpose, dot product) + - `riscv`: contains official riscv tests which are pre-compiled into binaries + - `vector`: tests for vector instructions (not yet implemented) +- `ci`: contain tests to be run during continuous integration (Travis CI) + - driver, opencl, riscv_isa, and runtime tests +- `driver`: contains driver software implementation (software that is run on the host to communicate with the vortex processor) + - `opae`: contains code for driver that runs on FPGA + - `rtlsim`: contains code for driver that runs on local machine (driver built using verilator which converts rtl to c++ binary) + - `simx`: contains code for driver that runs on local machine (vortex) + - `include`: contains vortex.h which has the vortex API that is used by the drivers +- `runtime`: contains software used inside kernel programs to expose GPGPU capabilities + - `include`: contains vortex API needed for runtime + - `linker`: contains linker file for compiling kernels + - `src`: contains implementation of vortex API (from include folder) + - `tests`: contains runtime tests + - `simple`: contains test for GPGPU functionality allowed in vortex +- `simx`: contains simX, the cycle approximate simulator for vortex +- `miscs`: contains old code that is no longer used +- `hw`: + - `unit_tests`: contains unit test for RTL of cache and queue + - `syn`: contains all synthesis scripts (quartus and yosys) + - `quartus`: contains code to synthesis cache, core, pipeline, top, and vortex stand-alone + - `simulate`: contains RTL simulator (verilator) + - `testbench.cpp`: runs either the riscv, runtime, or opencl tests + - `opae`: contains source code for the accelerator functional unit (AFU) and code which programs the fpga + - `rtl`: contains rtl source code + - `cache`: contains cache subsystem code + - `fp_cores`: contains floating point unit code + - `interfaces`: contains code that handles communication for each of the units of the microarchitecture + - `libs`: contains general-purpose modules (i.e., buffers, encoders, arbiters, pipe registers) \ No newline at end of file diff --git a/doc/Microarchitecture.md b/doc/Microarchitecture.md new file mode 100644 index 00000000..d8892e62 --- /dev/null +++ b/doc/Microarchitecture.md @@ -0,0 +1,94 @@ +# Vortex Microarchitecture + +### Vortex GPGPU Execution Model + +Vortex uses the SIMT (Single Instruction, Multiple Threads) execution model with a single warp issued per cycle. + +- **Threads** + - Smallest unit of computation + - Each thread has its own register file (32 int + 32 fp registers) + - Threads execute in parallel +- **Warps** + - A logical clster of threads + - Each thread in a warp execute the same instruction + - The PC is shared; maintain thread mask for Writeback + - Warp's execution is time-multiplexed at log steps + - Ex. warp 0 executes at cycle 0, warp 1 executes at cycle 1 + +### Vortex RISC-V ISA Extension + +- **Thread Mask Control** + - Control the number of warps to activate during execution + - `TMC` *count*: activate count threads +- **Warp Scheduling** + - Control the number of warps to activate during execution + - `WSPAWN` *count, addr*: activate count warps and jump to addr location +- **Control-Flow Divergence** + - Control threads to activate when a branch diverges + - `SPLIT` *predicate*: apply 'taken' predicate thread mask adn save 'not-taken' into IPDOM stack + - `JOIN`: restore 'not-taken' thread mask +- **Warp Synchronization** + - `BAR` *id, count*: stall warps entering barrier *id* until count is reached + +### Vortex Pipeline/Datapath + +![Image of Vortex Microarchitecture](vortex_microarchitecture_v2.png) + +Vortex has a 5-stage pipeline: FI | ID | Issue | EX | WB. + +- **Fetch** + - Warp Scheduler + - Track stalled & active warps, resolve branches and barriers, maintain split/join IPDOM stack + - Instruction Cache + - Retrieve instruction from cache, issue I-cache requests/responses +- **Decode** + - Decode fetched instructions, notify warp scheduler when the following instructions are decoded: + - Branch, tmc, split/join, wspawn + - Precompute used_regs mask (needed for Issue stage) +- **Issue** + - Scheduling + - In-order issue (operands/execute unit ready), out-of-order commit + - IBuffer + - Store fetched instructions, separate queues per-warp, selects next warp through round-robin scheduling + - Scoreboard + - Track in-use registers + - GPRs (General-Purpose Registers) stage + - Fetch issued instruction operands and send operands to execute unit +- **Execute** + - ALU Unit + - Single-cycle operations (+,-,>>,<<,&,|,^), Branch instructions (Share ALU resources) + - MULDIV Unit + - Multiplier - done in 2 cycles + - Divider - division and remainder, done in 32 cycles + - Implements serial alogrithm (Stalls the pipeline) + - FPU Unit + - Multi-cycle operations, uses `FPnew` Library on ASIC, uses hard DSPs on FPGA + - CSR Unit + - Store constant status registers - device caps, FPU status flags, performance counters + - Handle external CSR requests (requests from host CPU) + - LSU Unit + - Handle load/store operations, issue D-cache requests, handle D-cache responses + - Commit load responses - saves storage, Scoreboard tracks completion + - GPGPU Unit + - Handle GPGPU instructions + - TMC, WSPAWN, SPLIT, BAR + - JOIN is handled by Warp Scheduler (upon SPLIT response) +- **Commit** + - Commit + - Update CSR flags, update performance counters + - Writeback + - Write result back to GPRs, notify Scoreboard (release in-use register), select candidate instruction (ALU unit has highest priority) +- **Clustering** + - Group mulitple cores into clusters (optionally share L2 cache) + - Group multiple clusters (optionally share L3 cache) + - Configurable at build time + - Default configuration: + - #Clusters = 1 + - #Cores = 4 + - #Warps = 4 + - #Threads = 4 +- **FPGA AFU Interface** + - Manage CPU-GPU comunication + - Query devices caps, load kernel instructions and resource buffers, start kernel execution, read destination buffers + - Local Memory - GPU access to local DRAM + - Reserved I/O addresses - redirect to host CPU, console output \ No newline at end of file diff --git a/doc/Simulation.md b/doc/Simulation.md index b6861628..dfd042bb 100644 --- a/doc/Simulation.md +++ b/doc/Simulation.md @@ -24,10 +24,9 @@ Running tests under specific drivers (rtlsim,simx,fpga) is done using the script - *L3cache* - used to enable the shared l3cache among the Vortex clusters. - *Driver* - used to specify which driver to run the Vortex simulation (either rtlsim, vlsim, fpga, or simx). - *Debug* - used to enable debug mode for the Vortex simulation. -- *Scope* - -- *Perf* - is used to enable the detailed performance counters within the Vortex simulation. -- *App* - is used to specify which test/benchmark to run in the Vortex simulation. The main choices are vecadd, sgemm, basic, demo, and dogfood. Other tests/benchmarks are located in the `/benchmarks/opencl` folder though not all of them work wit the current version of Vortex. -- *Args* - +- *Perf* - used to enable the detailed performance counters within the Vortex simulation. +- *App* - used to specify which test/benchmark to run in the Vortex simulation. The main choices are vecadd, sgemm, basic, demo, and dogfood. Other tests/benchmarks are located in the `/benchmarks/opencl` folder though not all of them work wit the current version of Vortex. +- *Args* - used to pass additional arguments to the application. Example use of command line arguments: Run the sgemm benchmark using the vlsim driver with a Vortex configuration of 1 cluster, 4 cores, 4 warps, and 4 threads. diff --git a/doc/Vortex.md b/doc/Vortex.md index 36846b30..16dad807 100644 --- a/doc/Vortex.md +++ b/doc/Vortex.md @@ -2,7 +2,7 @@ ### Table of Contents -- Vortex Architecture +- Vortex Microarchitecture - Vortex Software - [Vortex Simulation](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Simulation.md) - [FPGA](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Flubber_FPGA_Startup_Guide.md) From 4cb98a25a79ccd686c9c4d21dc9025054000f45d Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 24 Apr 2021 00:31:27 -0400 Subject: [PATCH 08/55] enabling 128-bit dram bus --- .travis.yml | 3 +- ci/blackbox.sh | 2 +- ci/regression.sh | 22 ++- driver/opae/vlsim/Makefile | 20 ++- driver/opae/vlsim/opae_sim.cpp | 27 +-- driver/opae/vlsim/opae_sim.h | 5 +- driver/opae/vlsim/vortex_afu_shim.sv | 6 +- driver/rtlsim/Makefile | 10 +- driver/simx/Makefile | 8 +- hw/Makefile | 6 +- hw/rtl/VX_config.vh | 6 +- hw/rtl/afu/VX_avs_wrapper.v | 26 +-- hw/rtl/afu/VX_cci_to_mem.v | 107 ++++++++++++ hw/rtl/afu/vortex_afu.sv | 192 +++++++++++++--------- hw/rtl/afu/vortex_afu.vh | 13 +- hw/rtl/cache/VX_cache_core_req_bank_sel.v | 1 + hw/rtl/cache/VX_cache_core_rsp_merge.v | 2 + hw/scripts/gen_config.py | 76 +++------ hw/simulate/Makefile | 10 +- 19 files changed, 344 insertions(+), 198 deletions(-) create mode 100644 hw/rtl/afu/VX_cci_to_mem.v diff --git a/.travis.yml b/.travis.yml index a30782e5..1398e3be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,8 +18,7 @@ install: - export RISCV_TOOLCHAIN_PATH=/opt/riscv-gnu-toolchain - export VERILATOR_ROOT=/opt/verilator - export PATH=$VERILATOR_ROOT/bin:$PATH - - make -s - + script: - ./ci/regression.sh diff --git a/ci/blackbox.sh b/ci/blackbox.sh index 8a7d3657..322f46fc 100755 --- a/ci/blackbox.sh +++ b/ci/blackbox.sh @@ -135,7 +135,7 @@ case $APP in ;; esac -CONFIGS="-DNUM_CLUSTERS=$CLUSTERS -DNUM_CORES=$CORES -DNUM_WARPS=$WARPS -DNUM_THREADS=$THREADS -DL2_ENABLE=$L2 -DL3_ENABLE=$L3 $PERF_FLAG" +CONFIGS="-DNUM_CLUSTERS=$CLUSTERS -DNUM_CORES=$CORES -DNUM_WARPS=$WARPS -DNUM_THREADS=$THREADS -DL2_ENABLE=$L2 -DL3_ENABLE=$L3 $PERF_FLAG $CONFIGS" echo "CONFIGS=$CONFIGS" diff --git a/ci/regression.sh b/ci/regression.sh index eb00b259..439b28ef 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -3,6 +3,8 @@ # exit when any command fails set -e +make -s + # Dogfood tests ./ci/test_runtime.sh ./ci/test_riscv_isa.sh @@ -11,6 +13,14 @@ set -e ./ci/test_simx.sh ./ci/test_compiler.sh +# Blackbox tests +./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --perf --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --debug --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --scope --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=demo --args="-n1" + # Build tests disabling extensions CONFIGS=-DEXT_M_DISABLE make -C hw/simulate CONFIGS=-DEXT_F_DISABLE make -C hw/simulate @@ -18,10 +28,8 @@ CONFIGS=-DEXT_F_DISABLE make -C hw/simulate # disable shared memory CONFIGS=-DSM_ENABLE=0 make -C hw/simulate -# Blackbox tests -./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --perf --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --debug --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --scope --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=demo --args="-n1" \ No newline at end of file +# test 128-bit DRAM bus +CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS=4 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo + +# test 256-bit DRAM bus +CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS=4 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo \ No newline at end of file diff --git a/driver/opae/vlsim/Makefile b/driver/opae/vlsim/Makefile index 69dabc36..64f7691d 100644 --- a/driver/opae/vlsim/Makefile +++ b/driver/opae/vlsim/Makefile @@ -21,10 +21,10 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE DBG_FLAGS += $(DBG_PRINT_FLAGS) DBG_FLAGS += -DDBG_CACHE_REQ_INFO -#CONFIGS ?= -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 -#CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 -#CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 -CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=1 +#CONFIGS := -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) +#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) +#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 $(CONFIGS) +CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=1 $(CONFIGS) CFLAGS += -fPIC @@ -47,10 +47,11 @@ FPU_INCLUDE = -I$(RTL_DIR)/fp_cores -I$(DPI_DIR) -I$(RTL_DIR)/fp_cores/fpnew/src RTL_INCLUDE = -I$(RTL_DIR) -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/cache $(FPU_INCLUDE) RTL_INCLUDE += -I$(RTL_DIR)/afu -I$(RTL_DIR)/afu/ccip -VL_FLAGS += -O2 --language 1800-2009 --assert -Wall -Wpedantic $(CONFIGS) -VL_FLAGS += -Wno-DECLFILENAME +VL_FLAGS += -O2 --language 1800-2009 --assert -Wall -Wpedantic +VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += verilator.vlt +VL_FLAGS += $(CONFIGS) # Enable Verilator multithreaded simulation #THREADS ?= $(shell python3 -c 'import multiprocessing as mp; print(max(1, mp.cpu_count() // 2))') @@ -87,10 +88,13 @@ VL_FLAGS += -DFPU_DPI PROJECT = libopae-c-vlsim.so all: $(PROJECT) + +vortex_afu.h : $(RTL_DIR)/afu/vortex_afu.vh + ../../../hw/scripts/gen_config.py -i $(RTL_DIR)/afu/vortex_afu.vh -o vortex_afu.h -$(PROJECT): $(SRCS) +$(PROJECT): $(SRCS) vortex_afu.h verilator --exe --cc $(TOP) --top-module $(TOP) $(RTL_INCLUDE) $(VL_FLAGS) $(SRCS) -CFLAGS '$(CFLAGS)' -LDFLAGS '$(LDFLAGS)' -o ../$(PROJECT) make -j -C obj_dir -f V$(TOP).mk clean: - rm -rf $(PROJECT) obj_dir ../scope-defs.h $(RTL_DIR)/scope-defs.vh + rm -rf $(PROJECT) obj_dir ../scope-defs.h $(RTL_DIR)/scope-defs.vh vortex_afu.h diff --git a/driver/opae/vlsim/opae_sim.cpp b/driver/opae/vlsim/opae_sim.cpp index 0844ee17..1aaa7e6d 100644 --- a/driver/opae/vlsim/opae_sim.cpp +++ b/driver/opae/vlsim/opae_sim.cpp @@ -285,15 +285,15 @@ void opae_sim::avs_bus() { vortex_afu_->avs_readdatavalid = 0; if (dram_rd_it != dram_reads_.end()) { vortex_afu_->avs_readdatavalid = 1; - memcpy(vortex_afu_->avs_readdata, dram_rd_it->data.data(), CACHE_BLOCK_SIZE); + memcpy(vortex_afu_->avs_readdata, dram_rd_it->data.data(), DRAM_BLOCK_SIZE); uint32_t addr = dram_rd_it->addr; dram_reads_.erase(dram_rd_it); - /*printf("%0ld: [sim] DRAM Rd Rsp: addr=%x, pending={", timestamp, addr * CACHE_BLOCK_SIZE); + /*printf("%0ld: [sim] DRAM Rd Rsp: addr=%x, pending={", timestamp, addr * DRAM_BLOCK_SIZE); for (auto& req : dram_reads_) { if (req.cycles_left != 0) - printf(" !%0x", req.addr * CACHE_BLOCK_SIZE); + printf(" !%0x", req.addr * DRAM_BLOCK_SIZE); else - printf(" %0x", req.addr * CACHE_BLOCK_SIZE); + printf(" %0x", req.addr * DRAM_BLOCK_SIZE); } printf("}\n");*/ } @@ -315,19 +315,24 @@ void opae_sim::avs_bus() { if (vortex_afu_->avs_write) { assert(0 == vortex_afu_->mem_bank_select); uint64_t byteen = vortex_afu_->avs_byteenable; - unsigned base_addr = (vortex_afu_->avs_address * CACHE_BLOCK_SIZE); + unsigned base_addr = vortex_afu_->avs_address * DRAM_BLOCK_SIZE; uint8_t* data = (uint8_t*)(vortex_afu_->avs_writedata); - for (int i = 0; i < CACHE_BLOCK_SIZE; i++) { + for (int i = 0; i < DRAM_BLOCK_SIZE; i++) { if ((byteen >> i) & 0x1) { ram_[base_addr + i] = data[i]; } } + /*printf("%0ld: [sim] DRAM Wr Req: addr=%x, data=", timestamp, base_addr); + for (int i = 0; i < DRAM_BLOCK_SIZE; i++) { + printf("%0x", data[(DRAM_BLOCK_SIZE-1)-i]); + } + printf("\n");*/ } if (vortex_afu_->avs_read) { assert(0 == vortex_afu_->mem_bank_select); dram_rd_req_t dram_req; dram_req.addr = vortex_afu_->avs_address; - ram_.read(vortex_afu_->avs_address * CACHE_BLOCK_SIZE, CACHE_BLOCK_SIZE, dram_req.data.data()); + ram_.read(vortex_afu_->avs_address * DRAM_BLOCK_SIZE, DRAM_BLOCK_SIZE, dram_req.data.data()); dram_req.cycles_left = DRAM_LATENCY; for (auto& rsp : dram_reads_) { if (dram_req.addr == rsp.addr) { @@ -336,15 +341,15 @@ void opae_sim::avs_bus() { } } dram_reads_.emplace_back(dram_req); - /*printf("%0ld: [sim] DRAM Rd Req: addr=%x, pending={", timestamp, dram_req.addr * CACHE_BLOCK_SIZE); + /*printf("%0ld: [sim] DRAM Rd Req: addr=%x, pending={", timestamp, dram_req.addr * DRAM_BLOCK_SIZE); for (auto& req : dram_reads_) { if (req.cycles_left != 0) - printf(" !%0x", req.addr * CACHE_BLOCK_SIZE); + printf(" !%0x", req.addr * DRAM_BLOCK_SIZE); else - printf(" %0x", req.addr * CACHE_BLOCK_SIZE); + printf(" %0x", req.addr * DRAM_BLOCK_SIZE); } printf("}\n");*/ - } + } } vortex_afu_->avs_waitrequest = dram_stalled; diff --git a/driver/opae/vlsim/opae_sim.h b/driver/opae/vlsim/opae_sim.h index ad08019e..15689769 100644 --- a/driver/opae/vlsim/opae_sim.h +++ b/driver/opae/vlsim/opae_sim.h @@ -9,6 +9,7 @@ #endif #include +#include "vortex_afu.h" #include "ram.h" #include @@ -16,6 +17,8 @@ #include #include +#define DRAM_BLOCK_SIZE (PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH / 8) + #define CACHE_BLOCK_SIZE 64 class opae_sim { @@ -40,7 +43,7 @@ private: typedef struct { int cycles_left; - std::array data; + std::array data; uint32_t addr; } dram_rd_req_t; diff --git a/driver/opae/vlsim/vortex_afu_shim.sv b/driver/opae/vlsim/vortex_afu_shim.sv index 0bcabd03..8d38fc53 100644 --- a/driver/opae/vlsim/vortex_afu_shim.sv +++ b/driver/opae/vlsim/vortex_afu_shim.sv @@ -1,5 +1,9 @@ -`include "VX_define.vh" +`include "VX_platform.vh" +`IGNORE_WARNINGS_BEGIN `include "vortex_afu.vh" +`IGNORE_WARNINGS_END +`include "VX_define.vh" + /* verilator lint_off IMPORTSTAR */ import ccip_if_pkg::*; import local_mem_cfg_pkg::*; diff --git a/driver/rtlsim/Makefile b/driver/rtlsim/Makefile index 2dc8e72e..3f2b22ae 100644 --- a/driver/rtlsim/Makefile +++ b/driver/rtlsim/Makefile @@ -20,10 +20,10 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE DBG_FLAGS += $(DBG_PRINT_FLAGS) DBG_FLAGS += -DDBG_CACHE_REQ_INFO -#CONFIGS ?= -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 -#CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 -#CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 -CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=1 +#CONFIGS := -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) +#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) +#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 $(CONFIGS) +CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=1 $(CONFIGS) CFLAGS += $(CONFIGS) @@ -44,7 +44,7 @@ FPU_INCLUDE = -I$(RTL_DIR)/fp_cores -I$(DPI_DIR) -I$(RTL_DIR)/fp_cores/fpnew/src RTL_INCLUDE = -I$(RTL_DIR) -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/cache $(FPU_INCLUDE) VL_FLAGS += -O2 --language 1800-2009 --assert -Wall -Wpedantic $(CONFIGS) -VL_FLAGS += -Wno-DECLFILENAME +VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += verilator.vlt diff --git a/driver/simx/Makefile b/driver/simx/Makefile index fb3a23e2..2779145a 100644 --- a/driver/simx/Makefile +++ b/driver/simx/Makefile @@ -10,10 +10,10 @@ CXXFLAGS += -fPIC -Wno-aligned-new -Wno-maybe-uninitialized CXXFLAGS += -I../include -I../../hw -I$(SIMX_DIR) CXXFLAGS += -DDUMP_PERF_STATS -#CONFIGS ?= -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 -#CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 -#CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 -CONFIGS ?= -DNUM_CLUSTERS=1 -DNUM_CORES=1 +#CONFIGS := -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) +#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 $(CONFIGS) +#CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 $(CONFIGS) +CONFIGS := -DNUM_CLUSTERS=1 -DNUM_CORES=1 $(CONFIGS) CXXFLAGS += $(CONFIGS) diff --git a/hw/Makefile b/hw/Makefile index 635b4d15..425e58d9 100644 --- a/hw/Makefile +++ b/hw/Makefile @@ -1,9 +1,9 @@ .PHONY: build_config -build_config: - ./scripts/gen_config.py --outv ./rtl/VX_user_config.vh --outc ./VX_config.h +build_config: ./rtl/VX_config.vh + ./scripts/gen_config.py -i ./rtl/VX_config.vh -o ./VX_config.h $(MAKE) -C simulate clean: - rm -f ./rtl/VX_user_config.vh ./VX_config.h + rm -f ./VX_config.h $(MAKE) -C simulate clean \ No newline at end of file diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index ae09cdc0..cf09d93c 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -36,7 +36,11 @@ `endif `ifndef GLOBAL_BLOCK_SIZE -`define GLOBAL_BLOCK_SIZE 64 +`ifdef PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH + `define GLOBAL_BLOCK_SIZE (`PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH / 8) +`else + `define GLOBAL_BLOCK_SIZE 64 +`endif `endif `ifndef L1_BLOCK_SIZE diff --git a/hw/rtl/afu/VX_avs_wrapper.v b/hw/rtl/afu/VX_avs_wrapper.v index 7c0860c0..36f0a986 100644 --- a/hw/rtl/afu/VX_avs_wrapper.v +++ b/hw/rtl/afu/VX_avs_wrapper.v @@ -15,18 +15,6 @@ module VX_avs_wrapper #( input wire clk, input wire reset, - // AVS bus - output wire [AVS_DATAW-1:0] avs_writedata, - input wire [AVS_DATAW-1:0] avs_readdata, - output wire [AVS_ADDRW-1:0] avs_address, - input wire avs_waitrequest, - output wire avs_write, - output wire avs_read, - output wire [AVS_BYTEENW-1:0] avs_byteenable, - output wire [AVS_BURSTW-1:0] avs_burstcount, - input avs_readdatavalid, - output wire [AVS_BANKS_BITS-1:0] avs_bankselect, - // DRAM request input wire dram_req_valid, input wire dram_req_rw, @@ -40,7 +28,19 @@ module VX_avs_wrapper #( output wire dram_rsp_valid, output wire [AVS_DATAW-1:0] dram_rsp_data, output wire [REQ_TAGW-1:0] dram_rsp_tag, - input wire dram_rsp_ready + input wire dram_rsp_ready, + + // AVS bus + output wire [AVS_DATAW-1:0] avs_writedata, + input wire [AVS_DATAW-1:0] avs_readdata, + output wire [AVS_ADDRW-1:0] avs_address, + input wire avs_waitrequest, + output wire avs_write, + output wire avs_read, + output wire [AVS_BYTEENW-1:0] avs_byteenable, + output wire [AVS_BURSTW-1:0] avs_burstcount, + input avs_readdatavalid, + output wire [AVS_BANKS_BITS-1:0] avs_bankselect ); reg [AVS_BANKS_BITS-1:0] avs_bankselect_r; reg [AVS_BURSTW-1:0] avs_burstcount_r; diff --git a/hw/rtl/afu/VX_cci_to_mem.v b/hw/rtl/afu/VX_cci_to_mem.v new file mode 100644 index 00000000..71eb19a7 --- /dev/null +++ b/hw/rtl/afu/VX_cci_to_mem.v @@ -0,0 +1,107 @@ +`include "VX_define.vh" + +module VX_cci_to_mem #( + parameter CCI_DATAW = 1, + parameter CCI_ADDRW = 1, + parameter AVS_DATAW = 1, + parameter AVS_ADDRW = 1, + parameter AVS_BYTEENW = (AVS_DATAW / 8), + parameter TAG_WIDTH = 1 +) ( + input wire clk, + input wire reset, + + input wire dram_req_valid_in, + input wire [CCI_ADDRW-1:0] dram_req_addr_in, + input wire dram_req_rw_in, + input wire [CCI_DATAW-1:0] dram_req_data_in, + input wire [TAG_WIDTH-1:0] dram_req_tag_in, + output wire dram_req_ready_in, + + output wire dram_req_valid_out, + output wire [AVS_ADDRW-1:0] dram_req_addr_out, + output wire dram_req_rw_out, + output wire [AVS_BYTEENW-1:0] dram_req_byteen_out, + output wire [AVS_DATAW-1:0] dram_req_data_out, + output wire [TAG_WIDTH-1:0] dram_req_tag_out, + input wire dram_req_ready_out, + + input wire dram_rsp_valid_in, + input wire [AVS_DATAW-1:0] dram_rsp_data_in, + input wire [TAG_WIDTH-1:0] dram_rsp_tag_in, + output wire dram_rsp_ready_in, + + output wire dram_rsp_valid_out, + output wire [CCI_DATAW-1:0] dram_rsp_data_out, + output wire [TAG_WIDTH-1:0] dram_rsp_tag_out, + input wire dram_rsp_ready_out +); + localparam N = AVS_ADDRW - CCI_ADDRW; + + `STATIC_ASSERT(N >= 0, ("oops!")) + + if (N == 0) begin + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + + assign dram_req_valid_out = dram_req_valid_in; + assign dram_req_addr_out = dram_req_addr_in; + assign dram_req_rw_out = dram_req_rw_in; + assign dram_req_byteen_out = {AVS_BYTEENW{1'b1}}; + assign dram_req_data_out = dram_req_data_in; + assign dram_req_tag_out = dram_req_tag_in; + assign dram_req_ready_in = dram_req_ready_out; + + assign dram_rsp_valid_out = dram_rsp_valid_in; + assign dram_rsp_data_out = dram_rsp_data_in; + assign dram_rsp_tag_out = dram_rsp_tag_in; + assign dram_rsp_ready_in = dram_rsp_ready_out; + + end else begin + + reg [N-1:0] req_ctr, rsp_ctr; + + wire [(2**N)-1:0][AVS_DATAW-1:0] dram_req_data_w_in; + + reg [(2**N)-1:0][AVS_DATAW-1:0] dram_rsp_data_r_out, dram_rsp_data_n_out; + + wire dram_req_fire_out = dram_req_valid_out && dram_req_ready_out; + wire dram_rsp_fire_in = dram_rsp_valid_in && dram_rsp_ready_in; + + assign dram_req_data_w_in = dram_req_data_in; + + always @(*) begin + dram_rsp_data_n_out = dram_rsp_data_r_out; + dram_rsp_data_n_out[rsp_ctr] = dram_rsp_data_in; + end + + always @(posedge clk) begin + if (reset) begin + req_ctr <= 0; + rsp_ctr <= 0; + end else begin + if (dram_req_fire_out) begin + req_ctr <= req_ctr + 1; + end + if (dram_rsp_fire_in) begin + rsp_ctr <= rsp_ctr + 1; + dram_rsp_data_r_out <= dram_rsp_data_n_out; + end + end + end + + assign dram_req_valid_out = dram_req_valid_in; + assign dram_req_addr_out = {dram_req_addr_in, req_ctr}; + assign dram_req_rw_out = dram_req_rw_in; + assign dram_req_byteen_out = {AVS_BYTEENW{1'b1}}; + assign dram_req_data_out = dram_req_data_w_in[req_ctr]; + assign dram_req_tag_out = dram_req_tag_in; + assign dram_req_ready_in = dram_req_ready_out && (req_ctr == (2**N-1)); + + assign dram_rsp_valid_out = dram_rsp_valid_in && (rsp_ctr == (2**N-1)); + assign dram_rsp_data_out = dram_rsp_data_n_out; + assign dram_rsp_tag_out = dram_rsp_tag_in; + assign dram_rsp_ready_in = dram_rsp_ready_out; + end + +endmodule \ No newline at end of file diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 4d6cae37..0f99530b 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -1,9 +1,13 @@ -`include "VX_define.vh" -`ifndef NOPAE -`include "afu_json_info.vh" -`else +`include "VX_platform.vh" +`ifdef NOPAE +`IGNORE_WARNINGS_BEGIN `include "vortex_afu.vh" +`IGNORE_WARNINGS_END +`else +`include "afu_json_info.vh" `endif +`include "VX_define.vh" + /* verilator lint_off IMPORTSTAR */ import ccip_if_pkg::*; import local_mem_cfg_pkg::*; @@ -36,10 +40,14 @@ module vortex_afu #( localparam RESET_DELAY = 3; -localparam DRAM_ADDR_WIDTH = $bits(t_local_mem_addr); localparam DRAM_LINE_WIDTH = $bits(t_local_mem_data); +localparam DRAM_ADDR_WIDTH = $bits(t_local_mem_addr); +localparam DRAM_BURST_CTRW = $bits(t_local_mem_burst_cnt); localparam DRAM_LINE_LW = $clog2(DRAM_LINE_WIDTH); +localparam CCI_LINE_WIDTH = $bits(t_ccip_clData); +localparam CCI_ADDR_WIDTH = 32 - $clog2(CCI_LINE_WIDTH / 8); + localparam VX_DRAM_LINE_LW = $clog2(`VX_DRAM_LINE_WIDTH); localparam VX_DRAM_LINE_IDX = (DRAM_LINE_LW - VX_DRAM_LINE_LW); @@ -74,7 +82,7 @@ localparam MMIO_CSR_DATA = `AFU_IMAGE_MMIO_CSR_DATA; localparam MMIO_CSR_READ = `AFU_IMAGE_MMIO_CSR_READ; localparam CCI_RD_RQ_TAGW = $clog2(CCI_RD_WINDOW_SIZE); -localparam CCI_RD_RQ_DATAW = $bits(t_ccip_clData) + CCI_RD_RQ_TAGW; +localparam CCI_RD_RQ_DATAW = CCI_LINE_WIDTH + CCI_RD_RQ_TAGW; localparam STATE_IDLE = 0; localparam STATE_READ = 1; @@ -128,8 +136,8 @@ reg vx_dram_en; // CMD variables ////////////////////////////////////////////////////////////// t_ccip_clAddr cmd_io_addr; -reg [DRAM_ADDR_WIDTH-1:0] cmd_mem_addr; -reg [DRAM_ADDR_WIDTH-1:0] cmd_data_size; +reg [CCI_ADDR_WIDTH-1:0] cmd_mem_addr; +reg [CCI_ADDR_WIDTH-1:0] cmd_data_size; `ifdef SCOPE wire [63:0] cmd_scope_rdata; @@ -216,9 +224,9 @@ always @(posedge clk) begin `endif end MMIO_MEM_ADDR: begin - cmd_mem_addr <= t_local_mem_addr'(cp2af_sRxPort.c0.data); + cmd_mem_addr <= $bits(cmd_mem_addr)'(cp2af_sRxPort.c0.data); `ifdef DBG_PRINT_OPAE - $display("%t: MMIO_MEM_ADDR: addr=%0h, data=0x%0h", $time, mmio_hdr.address, t_local_mem_addr'(cp2af_sRxPort.c0.data)); + $display("%t: MMIO_MEM_ADDR: addr=%0h, data=0x%0h", $time, mmio_hdr.address, $bits(cmd_mem_addr)'(cp2af_sRxPort.c0.data)); `endif end MMIO_DATA_SIZE: begin @@ -455,18 +463,18 @@ t_local_mem_data dram_rsp_data; wire [AVS_REQ_TAGW:0] dram_rsp_tag; wire dram_rsp_ready; -wire cci_dram_req_valid; -wire cci_dram_req_rw; -t_local_mem_byte_mask cci_dram_req_byteen; -t_local_mem_addr cci_dram_req_addr; -t_local_mem_data cci_dram_req_data; -wire [AVS_REQ_TAGW-1:0] cci_dram_req_tag; -wire cci_dram_req_ready; +wire cci_dram_req_tmp_valid; +wire cci_dram_req_tmp_rw; +t_local_mem_byte_mask cci_dram_req_tmp_byteen; +t_local_mem_addr cci_dram_req_tmp_addr; +t_local_mem_data cci_dram_req_tmp_data; +wire [AVS_REQ_TAGW-1:0] cci_dram_req_tmp_tag; +wire cci_dram_req_tmp_ready; -wire cci_dram_rsp_valid; -t_local_mem_data cci_dram_rsp_data; -wire [AVS_REQ_TAGW-1:0] cci_dram_rsp_tag; -wire cci_dram_rsp_ready; +wire cci_dram_rsp_tmp_valid; +t_local_mem_data cci_dram_rsp_tmp_data; +wire [AVS_REQ_TAGW-1:0] cci_dram_rsp_tmp_tag; +wire cci_dram_rsp_tmp_ready; wire vx_dram_req_valid_qual; t_local_mem_addr vx_dram_req_addr_qual; @@ -477,18 +485,55 @@ wire [AVS_REQ_TAGW-1:0] vx_dram_req_tag_qual; wire [(1 << VX_DRAM_LINE_IDX)-1:0][`VX_DRAM_LINE_WIDTH-1:0] vx_dram_rsp_data_unqual; wire [AVS_REQ_TAGW-1:0] vx_dram_rsp_tag_unqual; -wire cci_dram_rd_req_valid, cci_dram_wr_req_valid; -wire [DRAM_ADDR_WIDTH-1:0] cci_dram_rd_req_addr, cci_dram_wr_req_addr; +wire cci_dram_rd_req_valid; +wire cci_dram_wr_req_valid; +wire [CCI_ADDR_WIDTH-1:0] cci_dram_rd_req_addr; +wire [CCI_ADDR_WIDTH-1:0] cci_dram_wr_req_addr; wire [CCI_RD_RQ_DATAW-1:0] cci_rdq_dout; +wire cci_dram_req_ready; + +wire cci_dram_rsp_valid; +wire [CCI_LINE_WIDTH-1:0] cci_dram_rsp_data; +wire [AVS_REQ_TAGW-1:0] cci_dram_rsp_tag; +wire cci_dram_rsp_ready; //-- -assign cci_dram_req_valid = (CMD_MEM_WRITE == state) ? cci_dram_wr_req_valid : cci_dram_rd_req_valid; -assign cci_dram_req_addr = (CMD_MEM_WRITE == state) ? cci_dram_wr_req_addr : cci_dram_rd_req_addr; -assign cci_dram_req_rw = (CMD_MEM_WRITE == state); -assign cci_dram_req_byteen = {64{1'b1}}; -assign cci_dram_req_data = cci_rdq_dout[CCI_RD_RQ_DATAW-1:CCI_RD_RQ_TAGW]; -assign cci_dram_req_tag = AVS_REQ_TAGW'(0); +VX_cci_to_mem #( + .CCI_DATAW (CCI_LINE_WIDTH), + .CCI_ADDRW (CCI_ADDR_WIDTH), + .AVS_DATAW (DRAM_LINE_WIDTH), + .AVS_ADDRW (DRAM_ADDR_WIDTH), + .TAG_WIDTH (AVS_REQ_TAGW) +) cci_to_mem( + .clk (clk), + .reset (reset), + + .dram_req_valid_in ((CMD_MEM_WRITE == state) ? cci_dram_wr_req_valid : cci_dram_rd_req_valid), + .dram_req_addr_in ((CMD_MEM_WRITE == state) ? cci_dram_wr_req_addr : cci_dram_rd_req_addr), + .dram_req_rw_in ((CMD_MEM_WRITE == state)), + .dram_req_data_in (cci_rdq_dout[CCI_RD_RQ_DATAW-1:CCI_RD_RQ_TAGW]), + .dram_req_tag_in (AVS_REQ_TAGW'(0)), + .dram_req_ready_in (cci_dram_req_ready), + + .dram_req_valid_out (cci_dram_req_tmp_valid), + .dram_req_addr_out (cci_dram_req_tmp_addr), + .dram_req_rw_out (cci_dram_req_tmp_rw), + .dram_req_byteen_out(cci_dram_req_tmp_byteen), + .dram_req_data_out (cci_dram_req_tmp_data), + .dram_req_tag_out (cci_dram_req_tmp_tag), + .dram_req_ready_out (cci_dram_req_tmp_ready), + + .dram_rsp_valid_in (cci_dram_rsp_tmp_valid), + .dram_rsp_data_in (cci_dram_rsp_tmp_data), + .dram_rsp_tag_in (cci_dram_rsp_tmp_tag), + .dram_rsp_ready_in (cci_dram_rsp_tmp_ready), + + .dram_rsp_valid_out (cci_dram_rsp_valid), + .dram_rsp_data_out (cci_dram_rsp_data), + .dram_rsp_tag_out (cci_dram_rsp_tag), + .dram_rsp_ready_out (cci_dram_rsp_ready) +); `UNUSED_VAR (cci_dram_rsp_tag) @@ -518,8 +563,8 @@ assign vx_dram_rsp_tag = vx_dram_rsp_tag_unqual[`VX_DRAM_TAG_WIDTH+VX_DRAM_LINE_ VX_mem_arb #( .NUM_REQS (2), - .DATA_WIDTH ($bits(t_local_mem_data)), - .ADDR_WIDTH ($bits(t_local_mem_addr)), + .DATA_WIDTH (DRAM_LINE_WIDTH), + .ADDR_WIDTH (DRAM_ADDR_WIDTH), .TAG_IN_WIDTH (AVS_REQ_TAGW), .TAG_OUT_WIDTH (AVS_REQ_TAGW+1) ) dram_arb ( @@ -527,13 +572,13 @@ VX_mem_arb #( .reset (reset), // Source request - .req_valid_in ({cci_dram_req_valid, vx_dram_req_valid_qual}), - .req_rw_in ({cci_dram_req_rw, vx_dram_req_rw}), - .req_byteen_in ({cci_dram_req_byteen, vx_dram_req_byteen_qual}), - .req_addr_in ({cci_dram_req_addr, vx_dram_req_addr_qual}), - .req_data_in ({cci_dram_req_data, vx_dram_req_data_qual}), - .req_tag_in ({cci_dram_req_tag, vx_dram_req_tag_qual}), - .req_ready_in ({cci_dram_req_ready, vx_dram_req_ready}), + .req_valid_in ({cci_dram_req_tmp_valid, vx_dram_req_valid_qual}), + .req_rw_in ({cci_dram_req_tmp_rw, vx_dram_req_rw}), + .req_byteen_in ({cci_dram_req_tmp_byteen, vx_dram_req_byteen_qual}), + .req_addr_in ({cci_dram_req_tmp_addr, vx_dram_req_addr_qual}), + .req_data_in ({cci_dram_req_tmp_data, vx_dram_req_data_qual}), + .req_tag_in ({cci_dram_req_tmp_tag, vx_dram_req_tag_qual}), + .req_ready_in ({cci_dram_req_tmp_ready, vx_dram_req_ready}), // DRAM request .req_valid_out (dram_req_valid), @@ -545,10 +590,10 @@ VX_mem_arb #( .req_ready_out (dram_req_ready), // Source response - .rsp_valid_out ({cci_dram_rsp_valid, vx_dram_rsp_valid}), - .rsp_data_out ({cci_dram_rsp_data, vx_dram_rsp_data_unqual}), - .rsp_tag_out ({cci_dram_rsp_tag, vx_dram_rsp_tag_unqual}), - .rsp_ready_out ({cci_dram_rsp_ready, vx_dram_rsp_ready}), + .rsp_valid_out ({cci_dram_rsp_tmp_valid, vx_dram_rsp_valid}), + .rsp_data_out ({cci_dram_rsp_tmp_data, vx_dram_rsp_data_unqual}), + .rsp_tag_out ({cci_dram_rsp_tmp_tag, vx_dram_rsp_tag_unqual}), + .rsp_ready_out ({cci_dram_rsp_tmp_ready, vx_dram_rsp_ready}), // DRAM response .rsp_valid_in (dram_rsp_valid), @@ -560,9 +605,9 @@ VX_mem_arb #( //-- VX_avs_wrapper #( - .AVS_DATAW ($bits(t_local_mem_data)), - .AVS_ADDRW ($bits(t_local_mem_addr)), - .AVS_BURSTW ($bits(t_local_mem_burst_cnt)), + .AVS_DATAW (DRAM_LINE_WIDTH), + .AVS_ADDRW (DRAM_ADDR_WIDTH), + .AVS_BURSTW (DRAM_BURST_CTRW), .AVS_BANKS (NUM_LOCAL_MEM_BANKS), .REQ_TAGW (AVS_REQ_TAGW+1), .RD_QUEUE_SIZE (AVS_RD_QUEUE_SIZE) @@ -570,18 +615,6 @@ VX_avs_wrapper #( .clk (clk), .reset (reset), - // AVS bus - .avs_writedata (avs_writedata), - .avs_readdata (avs_readdata), - .avs_address (avs_address), - .avs_waitrequest (avs_waitrequest), - .avs_write (avs_write), - .avs_read (avs_read), - .avs_byteenable (avs_byteenable), - .avs_burstcount (avs_burstcount), - .avs_readdatavalid (avs_readdatavalid), - .avs_bankselect (mem_bank_select), - // DRAM request .dram_req_valid (dram_req_valid), .dram_req_rw (dram_req_rw), @@ -595,15 +628,27 @@ VX_avs_wrapper #( .dram_rsp_valid (dram_rsp_valid), .dram_rsp_data (dram_rsp_data), .dram_rsp_tag (dram_rsp_tag), - .dram_rsp_ready (dram_rsp_ready) + .dram_rsp_ready (dram_rsp_ready), + + // AVS bus + .avs_writedata (avs_writedata), + .avs_readdata (avs_readdata), + .avs_address (avs_address), + .avs_waitrequest (avs_waitrequest), + .avs_write (avs_write), + .avs_read (avs_read), + .avs_byteenable (avs_byteenable), + .avs_burstcount (avs_burstcount), + .avs_readdatavalid (avs_readdatavalid), + .avs_bankselect (mem_bank_select) ); // CCI-P Read Request /////////////////////////////////////////////////////////// -reg [DRAM_ADDR_WIDTH-1:0] cci_dram_wr_req_ctr; -reg [DRAM_ADDR_WIDTH-1:0] cci_rd_req_ctr; -wire [DRAM_ADDR_WIDTH-1:0] cci_rd_req_ctr_next; -reg [DRAM_ADDR_WIDTH-1:0] cci_dram_wr_req_addr_unqual; +reg [CCI_ADDR_WIDTH-1:0] cci_dram_wr_req_ctr; +reg [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr; +wire [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr_next; +reg [CCI_ADDR_WIDTH-1:0] cci_dram_wr_req_addr_unqual; wire [CCI_RD_RQ_TAGW-1:0] cci_rd_req_tag, cci_rd_rsp_tag; reg [CCI_RD_RQ_TAGW-1:0] cci_rd_rsp_ctr; t_ccip_clAddr cci_rd_req_addr; @@ -631,7 +676,7 @@ wire cci_rd_rsp_fire = (STATE_WRITE == state) assign cci_rd_req_tag = CCI_RD_RQ_TAGW'(cci_rd_req_ctr); assign cci_rd_rsp_tag = CCI_RD_RQ_TAGW'(cp2af_sRxPort.c0.hdr.mdata); -assign cci_rd_req_ctr_next = cci_rd_req_ctr + DRAM_ADDR_WIDTH'(cci_rd_req_fire ? 1 : 0); +assign cci_rd_req_ctr_next = cci_rd_req_ctr + CCI_ADDR_WIDTH'(cci_rd_req_fire ? 1 : 0); assign cci_rdq_pop = cci_dram_wr_req_fire; assign cci_rdq_push = cci_rd_rsp_fire; @@ -654,9 +699,9 @@ VX_pending_size #( assign cci_dram_wr_req_valid = !cci_rdq_empty; -assign cci_dram_wr_req_addr = cci_dram_wr_req_addr_unqual + (DRAM_ADDR_WIDTH'(CCI_RD_RQ_TAGW'(cci_rdq_dout))); +assign cci_dram_wr_req_addr = cci_dram_wr_req_addr_unqual + (CCI_ADDR_WIDTH'(CCI_RD_RQ_TAGW'(cci_rdq_dout))); -assign af2cp_sTxPort.c0.valid = cci_rd_req_enable && !cci_rd_req_wait; +assign af2cp_sTxPort.c0.valid = cci_rd_req_enable && !(cci_rd_req_wait || cci_pending_reads_full); assign cmd_write_done = (cci_dram_wr_req_ctr == cmd_data_size); @@ -685,7 +730,6 @@ always @(posedge clk) begin cci_rd_req_enable <= (STATE_WRITE == state) && (cci_rd_req_ctr_next != cmd_data_size) - && !cci_pending_reads_full && !cp2af_sRxPort.c0TxAlmFull; if (cci_rd_req_fire) begin @@ -716,8 +760,8 @@ always @(posedge clk) begin end*/ if (cci_dram_wr_req_fire) begin - cci_dram_wr_req_addr_unqual <= cci_dram_wr_req_addr_unqual + ((CCI_RD_RQ_TAGW'(cci_dram_wr_req_ctr) == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) ? DRAM_ADDR_WIDTH'(CCI_RD_WINDOW_SIZE) : DRAM_ADDR_WIDTH'(0)); - cci_dram_wr_req_ctr <= cci_dram_wr_req_ctr + DRAM_ADDR_WIDTH'(1); + cci_dram_wr_req_addr_unqual <= cci_dram_wr_req_addr_unqual + ((CCI_RD_RQ_TAGW'(cci_dram_wr_req_ctr) == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) ? CCI_ADDR_WIDTH'(CCI_RD_WINDOW_SIZE) : CCI_ADDR_WIDTH'(0)); + cci_dram_wr_req_ctr <= cci_dram_wr_req_ctr + CCI_ADDR_WIDTH'(1); end end end @@ -761,9 +805,9 @@ VX_fifo_queue #( // CCI-P Write Request ////////////////////////////////////////////////////////// -reg [DRAM_ADDR_WIDTH-1:0] cci_dram_rd_req_ctr; -reg [DRAM_ADDR_WIDTH-1:0] cci_wr_req_ctr; -reg [DRAM_ADDR_WIDTH-1:0] cci_dram_rd_req_addr_r; +reg [CCI_ADDR_WIDTH-1:0] cci_dram_rd_req_ctr; +reg [CCI_ADDR_WIDTH-1:0] cci_wr_req_ctr; +reg [CCI_ADDR_WIDTH-1:0] cci_dram_rd_req_addr_r; t_ccip_clAddr cci_wr_req_addr; always @(*) begin @@ -827,7 +871,7 @@ begin if (cci_wr_req_fire) begin assert(cci_wr_req_ctr != 0); cci_wr_req_addr <= cci_wr_req_addr + t_ccip_clAddr'(1); - cci_wr_req_ctr <= cci_wr_req_ctr - DRAM_ADDR_WIDTH'(1); + cci_wr_req_ctr <= cci_wr_req_ctr - CCI_ADDR_WIDTH'(1); `ifdef DBG_PRINT_OPAE $display("%t: CCI Wr Req: addr=%0h, rem=%0d, pending=%0d, data=%0h", $time, cci_wr_req_addr, (cci_wr_req_ctr - 1), cci_pending_writes, af2cp_sTxPort.c1.data); `endif @@ -840,8 +884,8 @@ begin `endif*/ if (cci_dram_rd_req_fire) begin - cci_dram_rd_req_addr_r <= cci_dram_rd_req_addr_r + DRAM_ADDR_WIDTH'(1); - cci_dram_rd_req_ctr <= cci_dram_rd_req_ctr - DRAM_ADDR_WIDTH'(1); + cci_dram_rd_req_addr_r <= cci_dram_rd_req_addr_r + CCI_ADDR_WIDTH'(1); + cci_dram_rd_req_ctr <= cci_dram_rd_req_ctr - CCI_ADDR_WIDTH'(1); end end end diff --git a/hw/rtl/afu/vortex_afu.vh b/hw/rtl/afu/vortex_afu.vh index 691d488c..3eb8cfd2 100644 --- a/hw/rtl/afu/vortex_afu.vh +++ b/hw/rtl/afu/vortex_afu.vh @@ -1,18 +1,19 @@ `ifndef __VORTEX_AFU__ `define __VORTEX_AFU__ -`IGNORE_WARNINGS_BEGIN `include "ccip_if_pkg.sv" -`IGNORE_WARNINGS_END `define PLATFORM_PROVIDES_LOCAL_MEMORY -`define PLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH 26 -`define PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH 512 + +`ifndef PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS +`define PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS 6 +`endif + +`define PLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH (32-`PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS) +`define PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH (8 << `PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS) `define PLATFORM_PARAM_LOCAL_MEMORY_BURST_CNT_WIDTH 4 -`IGNORE_WARNINGS_BEGIN `include "local_mem_cfg_pkg.sv" -`IGNORE_WARNINGS_END `define AFU_ACCEL_NAME "vortex_afu" `define AFU_ACCEL_UUID 128'h35f9452b_25c2_434c_93d5_6f8c60db361c diff --git a/hw/rtl/cache/VX_cache_core_req_bank_sel.v b/hw/rtl/cache/VX_cache_core_req_bank_sel.v index 16fb01df..73f791ee 100644 --- a/hw/rtl/cache/VX_cache_core_req_bank_sel.v +++ b/hw/rtl/cache/VX_cache_core_req_bank_sel.v @@ -45,6 +45,7 @@ module VX_cache_core_req_bank_sel #( output wire [NUM_BANKS-1:0][CORE_TAG_WIDTH-1:0] per_bank_core_req_tag, input wire [`BANK_READY_COUNT-1:0] per_bank_core_req_ready ); + `UNUSED_PARAM (CACHE_ID) `STATIC_ASSERT (NUM_REQS >= NUM_BANKS, ("invalid number of banks")); `UNUSED_VAR (clk) diff --git a/hw/rtl/cache/VX_cache_core_rsp_merge.v b/hw/rtl/cache/VX_cache_core_rsp_merge.v index 5427a7a9..2713943a 100644 --- a/hw/rtl/cache/VX_cache_core_rsp_merge.v +++ b/hw/rtl/cache/VX_cache_core_rsp_merge.v @@ -33,6 +33,8 @@ module VX_cache_core_rsp_merge #( output wire [NUM_REQS-1:0][`WORD_WIDTH-1:0] core_rsp_data, input wire [`CORE_REQ_TAG_COUNT-1:0] core_rsp_ready ); + `UNUSED_PARAM (CACHE_ID) + if (NUM_BANKS > 1) begin reg [NUM_REQS-1:0] core_rsp_valid_unqual; diff --git a/hw/scripts/gen_config.py b/hw/scripts/gen_config.py index 9f33c01f..6753f86e 100755 --- a/hw/scripts/gen_config.py +++ b/hw/scripts/gen_config.py @@ -2,6 +2,7 @@ # coding=utf-8 from __future__ import print_function +import sys import os import os.path as path import re @@ -10,55 +11,19 @@ from datetime import datetime script_dir = path.dirname(path.realpath(__file__)) -defines = {} -for k, v in os.environ.items(): - if k.upper().startswith('V_'): - defines[k[2:]] = v - -print('Custom params:', ', '.join(['='.join(x) for x in defines.items()])) - parser = argparse.ArgumentParser() -parser.add_argument('--outc', default='none', help='Output C header') -parser.add_argument('--outv', default='none', help='Output Verilog header') +parser.add_argument('-i', "--input", default='none', help='Verilog header') +parser.add_argument('-o', "--output", default='none', help='C header') args = parser.parse_args() -if args.outc == 'none' and args.outv == 'none': - print('Warning: not emitting any files. Specify arguments') - -if args.outv != 'none': - with open(args.outv, 'w') as f: - print(''' -// auto-generated by gen_config.py. DO NOT EDIT -// Generated at {date} - -`ifndef VX_USER_CONFIG -`define VX_USER_CONFIG -'''[1:].format(date=datetime.now()), file=f) - - for k, v in defines.items(): - print('`define {} {}'.format(k, v), file=f) - - print('\n`endif', file=f) - -if args.outc != 'none': - with open(args.outc, 'w') as f: - print(''' -// auto-generated by gen_config.py. DO NOT EDIT -// Generated at {date} - -#ifndef VX_USER_CONFIG -#define VX_USER_CONFIG -'''[1:].format(date=datetime.now()), file=f) - - for k, v in defines.items(): - print('#define {} {}'.format(k, v), file=f) - - print('\n#endif', file=f) +if args.input == 'none' or args.output == 'none': + print('Error: invalid arguments') + sys.exit() translation_rules = [ # preprocessor directives - (re.compile(r'^\s*`include .*$'), r''), + (re.compile(r'`include\s+.*$'), r''), (re.compile(r'`ifdef'), r'#ifdef'), (re.compile(r'`ifndef'), r'#ifndef'), (re.compile(r'`elif'), r'#elif'), @@ -75,25 +40,24 @@ translation_rules = [ (re.compile(r"\d+'h([\da-fA-F]+)"), r'0x\1') ] -if args.outc != 'none': - with open(args.outc, 'a') as f: - print(''' +with open(args.output, 'w') as f: + print(''' // auto-generated by gen_config.py. DO NOT EDIT // Generated at {date} // Translated from VX_config.vh: '''[1:].format(date=datetime.now()), file=f) - with open(path.join(script_dir, '../rtl/VX_config.vh'), 'r') as r: - lineno = 0 - for line in r: - for pat, repl in translation_rules: - match = pat.search(line) - if match: - line = re.sub(pat, repl, line) - #print("*** match @" + str(lineno) + ": " + match.group() + " => " + line) - f.write(line) - lineno = lineno + 1 - print(''' + with open(args.input, 'r') as r: + lineno = 0 + for line in r: + for pat, repl in translation_rules: + match = pat.search(line) + if match: + line = re.sub(pat, repl, line) + #print("*** match @" + str(lineno) + ": " + match.group() + " => " + line) + f.write(line) + lineno = lineno + 1 + print(''' '''[1:], file=f) diff --git a/hw/simulate/Makefile b/hw/simulate/Makefile index c30d91b1..7b1d9b9c 100644 --- a/hw/simulate/Makefile +++ b/hw/simulate/Makefile @@ -21,11 +21,11 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE DBG_FLAGS += $(DBG_PRINT_FLAGS) DBG_FLAGS += -DDBG_CACHE_REQ_INFO -SINGLECORE += -DNUM_CLUSTERS=1 -DNUM_CORES=1 -DL2_ENABLE=0 +SINGLECORE = -DNUM_CLUSTERS=1 -DNUM_CORES=1 -DL2_ENABLE=0 -#MULTICORE ?= -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 -#MULTICORE ?= -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 -MULTICORE ?= -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 +#MULTICORE = -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=1 +#MULTICORE = -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=1 +MULTICORE = -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 SINGLECORE += $(CONFIGS) MULTICORE += $(CONFIGS) @@ -42,7 +42,7 @@ SRCS = simulator.cpp testbench.cpp SRCS += $(DPI_DIR)/util_dpi.cpp $(DPI_DIR)/float_dpi.cpp VL_FLAGS += -O2 --language 1800-2009 --assert -Wall -Wpedantic -VL_FLAGS += -Wno-DECLFILENAME +VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += verilator.vlt From cad21a4b920664d2fc5f93cb26488f913ce9ca1a Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 24 Apr 2021 01:17:38 -0400 Subject: [PATCH 09/55] minor update --- driver/opae/vlsim/opae_sim.cpp | 4 +--- driver/opae/vlsim/vortex_afu_shim.sv | 8 +++----- hw/rtl/VX_config.vh | 2 -- hw/rtl/afu/vortex_afu.vh | 4 ++++ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/driver/opae/vlsim/opae_sim.cpp b/driver/opae/vlsim/opae_sim.cpp index 1aaa7e6d..e821fa52 100644 --- a/driver/opae/vlsim/opae_sim.cpp +++ b/driver/opae/vlsim/opae_sim.cpp @@ -312,8 +312,7 @@ void opae_sim::avs_bus() { // process DRAM requests if (!dram_stalled) { assert(!vortex_afu_->avs_read || !vortex_afu_->avs_write); - if (vortex_afu_->avs_write) { - assert(0 == vortex_afu_->mem_bank_select); + if (vortex_afu_->avs_write) { uint64_t byteen = vortex_afu_->avs_byteenable; unsigned base_addr = vortex_afu_->avs_address * DRAM_BLOCK_SIZE; uint8_t* data = (uint8_t*)(vortex_afu_->avs_writedata); @@ -329,7 +328,6 @@ void opae_sim::avs_bus() { printf("\n");*/ } if (vortex_afu_->avs_read) { - assert(0 == vortex_afu_->mem_bank_select); dram_rd_req_t dram_req; dram_req.addr = vortex_afu_->avs_address; ram_.read(vortex_afu_->avs_address * DRAM_BLOCK_SIZE, DRAM_BLOCK_SIZE, dram_req.data.data()); diff --git a/driver/opae/vlsim/vortex_afu_shim.sv b/driver/opae/vlsim/vortex_afu_shim.sv index 8d38fc53..c69dfe09 100644 --- a/driver/opae/vlsim/vortex_afu_shim.sv +++ b/driver/opae/vlsim/vortex_afu_shim.sv @@ -9,9 +9,7 @@ import ccip_if_pkg::*; import local_mem_cfg_pkg::*; /* verilator lint_on IMPORTSTAR */ -module vortex_afu_shim #( - parameter NUM_LOCAL_MEM_BANKS = 2 -) ( +module vortex_afu_shim ( // global signals input clk, input reset, @@ -83,14 +81,14 @@ module vortex_afu_shim #( output t_local_mem_burst_cnt avs_burstcount, input avs_readdatavalid, - output logic [$clog2(NUM_LOCAL_MEM_BANKS)-1:0] mem_bank_select + output logic [$clog2(`PLATFORM_PARAM_LOCAL_MEMORY_BANKS)-1:0] mem_bank_select ); t_if_ccip_Rx cp2af_sRxPort; t_if_ccip_Tx af2cp_sTxPort; vortex_afu #( - .NUM_LOCAL_MEM_BANKS(NUM_LOCAL_MEM_BANKS) + .NUM_LOCAL_MEM_BANKS(`PLATFORM_PARAM_LOCAL_MEMORY_BANKS) ) afu ( .clk(clk), .reset(reset), diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index cf09d93c..40c33428 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -1,8 +1,6 @@ `ifndef VX_CONFIG `define VX_CONFIG -`include "VX_user_config.vh" - `ifndef NUM_CLUSTERS `define NUM_CLUSTERS 1 `endif diff --git a/hw/rtl/afu/vortex_afu.vh b/hw/rtl/afu/vortex_afu.vh index 3eb8cfd2..05a5654e 100644 --- a/hw/rtl/afu/vortex_afu.vh +++ b/hw/rtl/afu/vortex_afu.vh @@ -5,6 +5,10 @@ `define PLATFORM_PROVIDES_LOCAL_MEMORY +`ifndef PLATFORM_PARAM_LOCAL_MEMORY_BANKS +`define PLATFORM_PARAM_LOCAL_MEMORY_BANKS 2 +`endif + `ifndef PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS `define PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS 6 `endif From 0615e7481a51f3590ce8980c35226565d17c4b39 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 24 Apr 2021 03:06:24 -0400 Subject: [PATCH 10/55] minor update --- driver/rtlsim/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/driver/rtlsim/Makefile b/driver/rtlsim/Makefile index 3f2b22ae..5bfe5553 100644 --- a/driver/rtlsim/Makefile +++ b/driver/rtlsim/Makefile @@ -43,10 +43,11 @@ SRCS += $(DPI_DIR)/util_dpi.cpp $(DPI_DIR)/float_dpi.cpp FPU_INCLUDE = -I$(RTL_DIR)/fp_cores -I$(DPI_DIR) -I$(RTL_DIR)/fp_cores/fpnew/src/common_cells/include -I$(RTL_DIR)/fp_cores/fpnew/src/common_cells/src -I$(RTL_DIR)/fp_cores/fpnew/src/fpu_div_sqrt_mvp/hdl -I$(RTL_DIR)/fp_cores/fpnew/src RTL_INCLUDE = -I$(RTL_DIR) -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/cache $(FPU_INCLUDE) -VL_FLAGS += -O2 --language 1800-2009 --assert -Wall -Wpedantic $(CONFIGS) +VL_FLAGS += -O2 --language 1800-2009 --assert -Wall -Wpedantic VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += verilator.vlt +VL_FLAGS += $(CONFIGS) # Enable Verilator multithreaded simulation #THREADS ?= $(shell python3 -c 'import multiprocessing as mp; print(max(1, mp.cpu_count() // 2))') From a60361ac2d0a6d1eaac695ff8e98955e0f91e02f Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 25 Apr 2021 21:10:54 -0700 Subject: [PATCH 11/55] minor update --- hw/rtl/VX_lsu_unit.v | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/rtl/VX_lsu_unit.v b/hw/rtl/VX_lsu_unit.v index 6f393ed3..d3a96ade 100644 --- a/hw/rtl/VX_lsu_unit.v +++ b/hw/rtl/VX_lsu_unit.v @@ -118,12 +118,6 @@ module VX_lsu_unit #( `UNUSED_PIN (empty) ); - always @(posedge clk) begin - if (mbuf_push) begin - pending_tags[mbuf_waddr] <= req_tag; - end - end - assign sent_all_ready = &(dcache_req_if.ready | req_sent_mask); wire [`NUM_THREADS-1:0] req_sent_dup = {{(`NUM_THREADS-1){dcache_req_fire[0] && req_is_dup}}, 1'b0}; @@ -143,8 +137,10 @@ module VX_lsu_unit #( reg [`DCORE_TAG_ID_BITS-1:0] req_tag_hold; wire [`DCORE_TAG_ID_BITS-1:0] req_tag = (0 == req_sent_mask) ? mbuf_waddr : req_tag_hold; always @(posedge clk) begin - if (mbuf_push) + if (mbuf_push) begin + pending_tags[mbuf_waddr] <= req_tag; req_tag_hold <= mbuf_waddr; + end end wire [`NUM_THREADS-1:0] req_tmask_dup = req_tmask & {{(`NUM_THREADS-1){~req_is_dup}}, 1'b1}; From d808aa27350e12cda9261e0f55af854899909e03 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 25 Apr 2021 21:15:24 -0700 Subject: [PATCH 12/55] perf counters generic size --- hw/rtl/VX_csr_data.v | 56 +++++++++++------------ hw/rtl/VX_define.vh | 2 + hw/rtl/VX_issue.v | 28 ++++++------ hw/rtl/VX_mem_unit.v | 24 +++++----- hw/rtl/cache/VX_cache.v | 45 +++++++++--------- hw/rtl/cache/VX_cache_core_req_bank_sel.v | 6 +-- hw/rtl/cache/VX_shared_mem.v | 12 ++--- hw/rtl/interfaces/VX_perf_cache_if.v | 16 +++---- hw/rtl/interfaces/VX_perf_memsys_if.v | 38 +++++++-------- hw/rtl/interfaces/VX_perf_pipeline_if.v | 14 +++--- 10 files changed, 123 insertions(+), 118 deletions(-) diff --git a/hw/rtl/VX_csr_data.v b/hw/rtl/VX_csr_data.v index 64e237e4..502f124f 100644 --- a/hw/rtl/VX_csr_data.v +++ b/hw/rtl/VX_csr_data.v @@ -114,61 +114,61 @@ module VX_csr_data #( `ifdef PERF_ENABLE // PERF: pipeline `CSR_MPM_IBUF_ST : read_data_r = perf_pipeline_if.ibf_stalls[31:0]; - `CSR_MPM_IBUF_ST_H : read_data_r = 32'(perf_pipeline_if.ibf_stalls[43:32]); + `CSR_MPM_IBUF_ST_H : read_data_r = 32'(perf_pipeline_if.ibf_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_SCRB_ST : read_data_r = perf_pipeline_if.scb_stalls[31:0]; - `CSR_MPM_SCRB_ST_H : read_data_r = 32'(perf_pipeline_if.scb_stalls[43:32]); + `CSR_MPM_SCRB_ST_H : read_data_r = 32'(perf_pipeline_if.scb_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_ALU_ST : read_data_r = perf_pipeline_if.alu_stalls[31:0]; - `CSR_MPM_ALU_ST_H : read_data_r = 32'(perf_pipeline_if.alu_stalls[43:32]); + `CSR_MPM_ALU_ST_H : read_data_r = 32'(perf_pipeline_if.alu_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_LSU_ST : read_data_r = perf_pipeline_if.lsu_stalls[31:0]; - `CSR_MPM_LSU_ST_H : read_data_r = 32'(perf_pipeline_if.lsu_stalls[43:32]); + `CSR_MPM_LSU_ST_H : read_data_r = 32'(perf_pipeline_if.lsu_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_CSR_ST : read_data_r = perf_pipeline_if.csr_stalls[31:0]; - `CSR_MPM_CSR_ST_H : read_data_r = 32'(perf_pipeline_if.csr_stalls[43:32]); + `CSR_MPM_CSR_ST_H : read_data_r = 32'(perf_pipeline_if.csr_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_FPU_ST : read_data_r = perf_pipeline_if.fpu_stalls[31:0]; - `CSR_MPM_FPU_ST_H : read_data_r = 32'(perf_pipeline_if.fpu_stalls[43:32]); + `CSR_MPM_FPU_ST_H : read_data_r = 32'(perf_pipeline_if.fpu_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_GPU_ST : read_data_r = perf_pipeline_if.gpu_stalls[31:0]; - `CSR_MPM_GPU_ST_H : read_data_r = 32'(perf_pipeline_if.gpu_stalls[43:32]); + `CSR_MPM_GPU_ST_H : read_data_r = 32'(perf_pipeline_if.gpu_stalls[`PERF_CTR_BITS-1:32]); // PERF: icache `CSR_MPM_ICACHE_READS : read_data_r = perf_memsys_if.icache_reads[31:0]; - `CSR_MPM_ICACHE_READS_H : read_data_r = 32'(perf_memsys_if.icache_reads[43:32]); + `CSR_MPM_ICACHE_READS_H : read_data_r = 32'(perf_memsys_if.icache_reads[`PERF_CTR_BITS-1:32]); `CSR_MPM_ICACHE_MISS_R : read_data_r = perf_memsys_if.icache_read_misses[31:0]; - `CSR_MPM_ICACHE_MISS_R_H : read_data_r = 32'(perf_memsys_if.icache_read_misses[43:32]); + `CSR_MPM_ICACHE_MISS_R_H : read_data_r = 32'(perf_memsys_if.icache_read_misses[`PERF_CTR_BITS-1:32]); `CSR_MPM_ICACHE_PIPE_ST : read_data_r = perf_memsys_if.icache_pipe_stalls[31:0]; - `CSR_MPM_ICACHE_PIPE_ST_H : read_data_r = 32'(perf_memsys_if.icache_pipe_stalls[43:32]); + `CSR_MPM_ICACHE_PIPE_ST_H : read_data_r = 32'(perf_memsys_if.icache_pipe_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_ICACHE_CRSP_ST : read_data_r = perf_memsys_if.icache_crsp_stalls[31:0]; - `CSR_MPM_ICACHE_CRSP_ST_H : read_data_r = 32'(perf_memsys_if.icache_crsp_stalls[43:32]); + `CSR_MPM_ICACHE_CRSP_ST_H : read_data_r = 32'(perf_memsys_if.icache_crsp_stalls[`PERF_CTR_BITS-1:32]); // PERF: dcache `CSR_MPM_DCACHE_READS : read_data_r = perf_memsys_if.dcache_reads[31:0]; - `CSR_MPM_DCACHE_READS_H : read_data_r = 32'(perf_memsys_if.dcache_reads[43:32]); + `CSR_MPM_DCACHE_READS_H : read_data_r = 32'(perf_memsys_if.dcache_reads[`PERF_CTR_BITS-1:32]); `CSR_MPM_DCACHE_WRITES : read_data_r = perf_memsys_if.dcache_writes[31:0]; - `CSR_MPM_DCACHE_WRITES_H : read_data_r = 32'(perf_memsys_if.dcache_writes[43:32]); + `CSR_MPM_DCACHE_WRITES_H : read_data_r = 32'(perf_memsys_if.dcache_writes[`PERF_CTR_BITS-1:32]); `CSR_MPM_DCACHE_MISS_R : read_data_r = perf_memsys_if.dcache_read_misses[31:0]; - `CSR_MPM_DCACHE_MISS_R_H : read_data_r = 32'(perf_memsys_if.dcache_read_misses[43:32]); + `CSR_MPM_DCACHE_MISS_R_H : read_data_r = 32'(perf_memsys_if.dcache_read_misses[`PERF_CTR_BITS-1:32]); `CSR_MPM_DCACHE_MISS_W : read_data_r = perf_memsys_if.dcache_write_misses[31:0]; - `CSR_MPM_DCACHE_MISS_W_H : read_data_r = 32'(perf_memsys_if.dcache_write_misses[43:32]); + `CSR_MPM_DCACHE_MISS_W_H : read_data_r = 32'(perf_memsys_if.dcache_write_misses[`PERF_CTR_BITS-1:32]); `CSR_MPM_DCACHE_BANK_ST : read_data_r = perf_memsys_if.dcache_bank_stalls[31:0]; - `CSR_MPM_DCACHE_BANK_ST_H : read_data_r = 32'(perf_memsys_if.dcache_bank_stalls[43:32]); + `CSR_MPM_DCACHE_BANK_ST_H : read_data_r = 32'(perf_memsys_if.dcache_bank_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_DCACHE_MSHR_ST : read_data_r = perf_memsys_if.dcache_mshr_stalls[31:0]; - `CSR_MPM_DCACHE_MSHR_ST_H : read_data_r = 32'(perf_memsys_if.dcache_mshr_stalls[43:32]); + `CSR_MPM_DCACHE_MSHR_ST_H : read_data_r = 32'(perf_memsys_if.dcache_mshr_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_DCACHE_PIPE_ST : read_data_r = perf_memsys_if.dcache_pipe_stalls[31:0]; - `CSR_MPM_DCACHE_PIPE_ST_H : read_data_r = 32'(perf_memsys_if.dcache_pipe_stalls[43:32]); + `CSR_MPM_DCACHE_PIPE_ST_H : read_data_r = 32'(perf_memsys_if.dcache_pipe_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_DCACHE_CRSP_ST : read_data_r = perf_memsys_if.dcache_crsp_stalls[31:0]; - `CSR_MPM_DCACHE_CRSP_ST_H : read_data_r = 32'(perf_memsys_if.dcache_crsp_stalls[43:32]); + `CSR_MPM_DCACHE_CRSP_ST_H : read_data_r = 32'(perf_memsys_if.dcache_crsp_stalls[`PERF_CTR_BITS-1:32]); // PERF: smem `CSR_MPM_SMEM_READS : read_data_r = perf_memsys_if.smem_reads[31:0]; - `CSR_MPM_SMEM_READS_H : read_data_r = 32'(perf_memsys_if.smem_reads[43:32]); + `CSR_MPM_SMEM_READS_H : read_data_r = 32'(perf_memsys_if.smem_reads[`PERF_CTR_BITS-1:32]); `CSR_MPM_SMEM_WRITES : read_data_r = perf_memsys_if.smem_writes[31:0]; - `CSR_MPM_SMEM_WRITES_H : read_data_r = 32'(perf_memsys_if.smem_writes[43:32]); + `CSR_MPM_SMEM_WRITES_H : read_data_r = 32'(perf_memsys_if.smem_writes[`PERF_CTR_BITS-1:32]); `CSR_MPM_SMEM_BANK_ST : read_data_r = perf_memsys_if.smem_bank_stalls[31:0]; - `CSR_MPM_SMEM_BANK_ST_H : read_data_r = 32'(perf_memsys_if.smem_bank_stalls[43:32]); + `CSR_MPM_SMEM_BANK_ST_H : read_data_r = 32'(perf_memsys_if.smem_bank_stalls[`PERF_CTR_BITS-1:32]); // PERF: DRAM `CSR_MPM_DRAM_READS : read_data_r = perf_memsys_if.dram_reads[31:0]; - `CSR_MPM_DRAM_READS_H : read_data_r = 32'(perf_memsys_if.dram_reads[43:32]); + `CSR_MPM_DRAM_READS_H : read_data_r = 32'(perf_memsys_if.dram_reads[`PERF_CTR_BITS-1:32]); `CSR_MPM_DRAM_WRITES : read_data_r = perf_memsys_if.dram_writes[31:0]; - `CSR_MPM_DRAM_WRITES_H : read_data_r = 32'(perf_memsys_if.dram_writes[43:32]); + `CSR_MPM_DRAM_WRITES_H : read_data_r = 32'(perf_memsys_if.dram_writes[`PERF_CTR_BITS-1:32]); `CSR_MPM_DRAM_ST : read_data_r = perf_memsys_if.dram_stalls[31:0]; - `CSR_MPM_DRAM_ST_H : read_data_r = 32'(perf_memsys_if.dram_stalls[43:32]); + `CSR_MPM_DRAM_ST_H : read_data_r = 32'(perf_memsys_if.dram_stalls[`PERF_CTR_BITS-1:32]); `CSR_MPM_DRAM_LAT : read_data_r = perf_memsys_if.dram_latency[31:0]; - `CSR_MPM_DRAM_LAT_H : read_data_r = 32'(perf_memsys_if.dram_latency[43:32]); + `CSR_MPM_DRAM_LAT_H : read_data_r = 32'(perf_memsys_if.dram_latency[`PERF_CTR_BITS-1:32]); `endif `CSR_SATP : read_data_r = 32'(csr_satp); @@ -186,9 +186,9 @@ module VX_csr_data #( `CSR_PMPADDR0 : read_data_r = 32'(csr_pmpaddr[0]); `CSR_CYCLE : read_data_r = csr_cycle[31:0]; - `CSR_CYCLE_H : read_data_r = 32'(csr_cycle[43:32]); + `CSR_CYCLE_H : read_data_r = 32'(csr_cycle[`PERF_CTR_BITS-1:32]); `CSR_INSTRET : read_data_r = csr_instret[31:0]; - `CSR_INSTRET_H : read_data_r = 32'(csr_instret[43:32]); + `CSR_INSTRET_H : read_data_r = 32'(csr_instret[`PERF_CTR_BITS-1:32]); `CSR_MVENDORID : read_data_r = `VENDOR_ID; `CSR_MARCHID : read_data_r = `ARCHITECTURE_ID; diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index 66afd80e..46d6666c 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -28,6 +28,8 @@ `define CSR_WIDTH 12 +`define PERF_CTR_BITS 44 + /////////////////////////////////////////////////////////////////////////////// `define INST_LUI 7'b0110111 diff --git a/hw/rtl/VX_issue.v b/hw/rtl/VX_issue.v index 269f0956..00b727a4 100644 --- a/hw/rtl/VX_issue.v +++ b/hw/rtl/VX_issue.v @@ -120,14 +120,14 @@ module VX_issue #( `SCOPE_ASSIGN (writeback_eop, writeback_if.eop); `ifdef PERF_ENABLE - reg [43:0] perf_ibf_stalls; - reg [43:0] perf_scb_stalls; - reg [43:0] perf_alu_stalls; - reg [43:0] perf_lsu_stalls; - reg [43:0] perf_csr_stalls; - reg [43:0] perf_gpu_stalls; + reg [`PERF_CTR_BITS-1:0] perf_ibf_stalls; + reg [`PERF_CTR_BITS-1:0] perf_scb_stalls; + reg [`PERF_CTR_BITS-1:0] perf_alu_stalls; + reg [`PERF_CTR_BITS-1:0] perf_lsu_stalls; + reg [`PERF_CTR_BITS-1:0] perf_csr_stalls; + reg [`PERF_CTR_BITS-1:0] perf_gpu_stalls; `ifdef EXT_F_ENABLE - reg [43:0] perf_fpu_stalls; + reg [`PERF_CTR_BITS-1:0] perf_fpu_stalls; `endif always @(posedge clk) begin @@ -143,26 +143,26 @@ module VX_issue #( `endif end else begin if (decode_if.valid & !decode_if.ready) begin - perf_ibf_stalls <= perf_ibf_stalls + 44'd1; + perf_ibf_stalls <= perf_ibf_stalls + `PERF_CTR_BITS'd1; end if (ibuf_deq_if.valid & scoreboard_delay) begin - perf_scb_stalls <= perf_scb_stalls + 44'd1; + perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'd1; end if (alu_req_if.valid & !alu_req_if.ready) begin - perf_alu_stalls <= perf_alu_stalls + 44'd1; + perf_alu_stalls <= perf_alu_stalls + `PERF_CTR_BITS'd1; end if (lsu_req_if.valid & !lsu_req_if.ready) begin - perf_lsu_stalls <= perf_lsu_stalls + 44'd1; + perf_lsu_stalls <= perf_lsu_stalls + `PERF_CTR_BITS'd1; end if (csr_req_if.valid & !csr_req_if.ready) begin - perf_csr_stalls <= perf_csr_stalls + 44'd1; + perf_csr_stalls <= perf_csr_stalls + `PERF_CTR_BITS'd1; end if (gpu_req_if.valid & !gpu_req_if.ready) begin - perf_gpu_stalls <= perf_gpu_stalls + 44'd1; + perf_gpu_stalls <= perf_gpu_stalls + `PERF_CTR_BITS'd1; end `ifdef EXT_F_ENABLE if (fpu_req_if.valid & !fpu_req_if.ready) begin - perf_fpu_stalls <= perf_fpu_stalls + 44'd1; + perf_fpu_stalls <= perf_fpu_stalls + `PERF_CTR_BITS'd1; end `endif end diff --git a/hw/rtl/VX_mem_unit.v b/hw/rtl/VX_mem_unit.v index 9e3b36d1..d3d89a62 100644 --- a/hw/rtl/VX_mem_unit.v +++ b/hw/rtl/VX_mem_unit.v @@ -101,7 +101,8 @@ module VX_mem_unit # ( .WRITE_ENABLE (0), .CORE_TAG_WIDTH (`ICORE_TAG_WIDTH), .CORE_TAG_ID_BITS (`ICORE_TAG_ID_BITS), - .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH) + .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH), + .IN_ORDER_DRAM (!(`L2_ENABLE || `L3_ENABLE)) ) icache ( `SCOPE_BIND_VX_mem_unit_icache @@ -160,7 +161,8 @@ module VX_mem_unit # ( .WRITE_ENABLE (1), .CORE_TAG_WIDTH (`DCORE_TAG_WIDTH), .CORE_TAG_ID_BITS (`DCORE_TAG_ID_BITS), - .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH) + .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH), + .IN_ORDER_DRAM (!(`L2_ENABLE || `L3_ENABLE)) ) dcache ( `SCOPE_BIND_VX_mem_unit_dcache @@ -319,22 +321,22 @@ end else begin assign perf_memsys_if.smem_bank_stalls = 0; end - reg [43:0] perf_dram_lat_per_cycle; + reg [`PERF_CTR_BITS-1:0] perf_dram_lat_per_cycle; always @(posedge clk) begin if (reset) begin perf_dram_lat_per_cycle <= 0; end else begin perf_dram_lat_per_cycle <= perf_dram_lat_per_cycle + - 44'($signed(2'((dram_req_if.valid && !dram_req_if.rw && dram_req_if.ready) && !(dram_rsp_if.valid && dram_rsp_if.ready)) - + `PERF_CTR_BITS'($signed(2'((dram_req_if.valid && !dram_req_if.rw && dram_req_if.ready) && !(dram_rsp_if.valid && dram_rsp_if.ready)) - 2'((dram_rsp_if.valid && dram_rsp_if.ready) && !(dram_req_if.valid && !dram_req_if.rw && dram_req_if.ready)))); end end - reg [43:0] perf_dram_reads; - reg [43:0] perf_dram_writes; - reg [43:0] perf_dram_lat; - reg [43:0] perf_dram_stalls; + reg [`PERF_CTR_BITS-1:0] perf_dram_reads; + reg [`PERF_CTR_BITS-1:0] perf_dram_writes; + reg [`PERF_CTR_BITS-1:0] perf_dram_lat; + reg [`PERF_CTR_BITS-1:0] perf_dram_stalls; always @(posedge clk) begin if (reset) begin @@ -344,13 +346,13 @@ end perf_dram_stalls <= 0; end else begin if (dram_req_if.valid && dram_req_if.ready && !dram_req_if.rw) begin - perf_dram_reads <= perf_dram_reads + 44'd1; + perf_dram_reads <= perf_dram_reads + `PERF_CTR_BITS'd1; end if (dram_req_if.valid && dram_req_if.ready && dram_req_if.rw) begin - perf_dram_writes <= perf_dram_writes + 44'd1; + perf_dram_writes <= perf_dram_writes + `PERF_CTR_BITS'd1; end if (dram_req_if.valid && !dram_req_if.ready) begin - perf_dram_stalls <= perf_dram_stalls + 44'd1; + perf_dram_stalls <= perf_dram_stalls + `PERF_CTR_BITS'd1; end perf_dram_lat <= perf_dram_lat + perf_dram_lat_per_cycle; end diff --git a/hw/rtl/cache/VX_cache.v b/hw/rtl/cache/VX_cache.v index 7a419512..1487477f 100644 --- a/hw/rtl/cache/VX_cache.v +++ b/hw/rtl/cache/VX_cache.v @@ -49,8 +49,6 @@ module VX_cache #( input wire clk, input wire reset, - input wire flush, - // Core request input wire [NUM_REQS-1:0] core_req_valid, input wire [NUM_REQS-1:0] core_req_rw, @@ -66,11 +64,6 @@ module VX_cache #( output wire [`CORE_REQ_TAG_COUNT-1:0][CORE_TAG_WIDTH-1:0] core_rsp_tag, input wire [`CORE_REQ_TAG_COUNT-1:0] core_rsp_ready, - // PERF -`ifdef PERF_ENABLE - VX_perf_cache_if perf_cache_if, -`endif - // DRAM request output wire dram_req_valid, output wire dram_req_rw, @@ -84,7 +77,15 @@ module VX_cache #( input wire dram_rsp_valid, input wire [`CACHE_LINE_WIDTH-1:0] dram_rsp_data, input wire [DRAM_TAG_WIDTH-1:0] dram_rsp_tag, - output wire dram_rsp_ready + output wire dram_rsp_ready, + + // PERF +`ifdef PERF_ENABLE + VX_perf_cache_if perf_cache_if, +`endif + + // device flush + input wire flush ); `STATIC_ASSERT(NUM_BANKS <= NUM_REQS, ("invalid value")) @@ -422,13 +423,13 @@ module VX_cache #( assign perf_mshr_stall_per_cycle = $countones(perf_mshr_stall_per_bank); assign perf_pipe_stall_per_cycle = $countones(perf_pipe_stall_per_bank); - reg [43:0] perf_core_reads; - reg [43:0] perf_core_writes; - reg [43:0] perf_read_misses; - reg [43:0] perf_write_misses; - reg [43:0] perf_mshr_stalls; - reg [43:0] perf_pipe_stalls; - reg [43:0] perf_crsp_stalls; + reg [`PERF_CTR_BITS-1:0] perf_core_reads; + reg [`PERF_CTR_BITS-1:0] perf_core_writes; + reg [`PERF_CTR_BITS-1:0] perf_read_misses; + reg [`PERF_CTR_BITS-1:0] perf_write_misses; + reg [`PERF_CTR_BITS-1:0] perf_mshr_stalls; + reg [`PERF_CTR_BITS-1:0] perf_pipe_stalls; + reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; always @(posedge clk) begin if (reset) begin @@ -440,13 +441,13 @@ module VX_cache #( perf_pipe_stalls <= 0; perf_crsp_stalls <= 0; end else begin - perf_core_reads <= perf_core_reads + 44'(perf_core_reads_per_cycle); - perf_core_writes <= perf_core_writes + 44'(perf_core_writes_per_cycle); - perf_read_misses <= perf_read_misses + 44'(perf_read_miss_per_cycle); - perf_write_misses <= perf_write_misses+ 44'(perf_write_miss_per_cycle); - perf_mshr_stalls <= perf_mshr_stalls + 44'(perf_mshr_stall_per_cycle); - perf_pipe_stalls <= perf_pipe_stalls + 44'(perf_pipe_stall_per_cycle); - perf_crsp_stalls <= perf_crsp_stalls + 44'(perf_crsp_stall_per_cycle); + perf_core_reads <= perf_core_reads + `PERF_CTR_BITS'(perf_core_reads_per_cycle); + perf_core_writes <= perf_core_writes + `PERF_CTR_BITS'(perf_core_writes_per_cycle); + perf_read_misses <= perf_read_misses + `PERF_CTR_BITS'(perf_read_miss_per_cycle); + perf_write_misses <= perf_write_misses+ `PERF_CTR_BITS'(perf_write_miss_per_cycle); + perf_mshr_stalls <= perf_mshr_stalls + `PERF_CTR_BITS'(perf_mshr_stall_per_cycle); + perf_pipe_stalls <= perf_pipe_stalls + `PERF_CTR_BITS'(perf_pipe_stall_per_cycle); + perf_crsp_stalls <= perf_crsp_stalls + `PERF_CTR_BITS'(perf_crsp_stall_per_cycle); end end diff --git a/hw/rtl/cache/VX_cache_core_req_bank_sel.v b/hw/rtl/cache/VX_cache_core_req_bank_sel.v index 73f791ee..554b8583 100644 --- a/hw/rtl/cache/VX_cache_core_req_bank_sel.v +++ b/hw/rtl/cache/VX_cache_core_req_bank_sel.v @@ -24,7 +24,7 @@ module VX_cache_core_req_bank_sel #( input wire reset, `ifdef PERF_ENABLE - output wire [43:0] bank_stalls, + output wire [`PERF_CTR_BITS-1:0] bank_stalls, `endif input wire [NUM_REQS-1:0] core_req_valid, @@ -306,13 +306,13 @@ module VX_cache_core_req_bank_sel #( end end - reg [43:0] bank_stalls_r; + reg [`PERF_CTR_BITS-1:0] bank_stalls_r; always @(posedge clk) begin if (reset) begin bank_stalls_r <= 0; end else begin - bank_stalls_r <= bank_stalls_r + 44'($countones(core_req_sel_r & ~core_req_ready)); + bank_stalls_r <= bank_stalls_r + `PERF_CTR_BITS'($countones(core_req_sel_r & ~core_req_ready)); end end diff --git a/hw/rtl/cache/VX_shared_mem.v b/hw/rtl/cache/VX_shared_mem.v index fc412772..d2d38fad 100644 --- a/hw/rtl/cache/VX_shared_mem.v +++ b/hw/rtl/cache/VX_shared_mem.v @@ -250,9 +250,9 @@ module VX_shared_mem #( assign perf_crsp_stall_per_cycle = $countones(core_rsp_valid & ~core_rsp_ready); end - reg [43:0] perf_core_reads; - reg [43:0] perf_core_writes; - reg [43:0] perf_crsp_stalls; + reg [`PERF_CTR_BITS-1:0] perf_core_reads; + reg [`PERF_CTR_BITS-1:0] perf_core_writes; + reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; always @(posedge clk) begin if (reset) begin @@ -260,9 +260,9 @@ module VX_shared_mem #( perf_core_writes <= 0; perf_crsp_stalls <= 0; end else begin - perf_core_reads <= perf_core_reads + 44'(perf_core_reads_per_cycle); - perf_core_writes <= perf_core_writes + 44'(perf_core_writes_per_cycle); - perf_crsp_stalls <= perf_crsp_stalls + 44'(perf_crsp_stall_per_cycle); + perf_core_reads <= perf_core_reads + `PERF_CTR_BITS'(perf_core_reads_per_cycle); + perf_core_writes <= perf_core_writes + `PERF_CTR_BITS'(perf_core_writes_per_cycle); + perf_crsp_stalls <= perf_crsp_stalls + `PERF_CTR_BITS'(perf_crsp_stall_per_cycle); end end diff --git a/hw/rtl/interfaces/VX_perf_cache_if.v b/hw/rtl/interfaces/VX_perf_cache_if.v index c52352f9..35004368 100644 --- a/hw/rtl/interfaces/VX_perf_cache_if.v +++ b/hw/rtl/interfaces/VX_perf_cache_if.v @@ -5,14 +5,14 @@ interface VX_perf_cache_if (); - wire [43:0] reads; - wire [43:0] writes; - wire [43:0] read_misses; - wire [43:0] write_misses; - wire [43:0] bank_stalls; - wire [43:0] mshr_stalls; - wire [43:0] pipe_stalls; - wire [43:0] crsp_stalls; + wire [`PERF_CTR_BITS-1:0] reads; + wire [`PERF_CTR_BITS-1:0] writes; + wire [`PERF_CTR_BITS-1:0] read_misses; + wire [`PERF_CTR_BITS-1:0] write_misses; + wire [`PERF_CTR_BITS-1:0] bank_stalls; + wire [`PERF_CTR_BITS-1:0] mshr_stalls; + wire [`PERF_CTR_BITS-1:0] pipe_stalls; + wire [`PERF_CTR_BITS-1:0] crsp_stalls; endinterface diff --git a/hw/rtl/interfaces/VX_perf_memsys_if.v b/hw/rtl/interfaces/VX_perf_memsys_if.v index 0cf6b26d..21484151 100644 --- a/hw/rtl/interfaces/VX_perf_memsys_if.v +++ b/hw/rtl/interfaces/VX_perf_memsys_if.v @@ -5,28 +5,28 @@ interface VX_perf_memsys_if (); - wire [43:0] icache_reads; - wire [43:0] icache_read_misses; - wire [43:0] icache_pipe_stalls; - wire [43:0] icache_crsp_stalls; + wire [`PERF_CTR_BITS-1:0] icache_reads; + wire [`PERF_CTR_BITS-1:0] icache_read_misses; + wire [`PERF_CTR_BITS-1:0] icache_pipe_stalls; + wire [`PERF_CTR_BITS-1:0] icache_crsp_stalls; - wire [43:0] dcache_reads; - wire [43:0] dcache_writes; - wire [43:0] dcache_read_misses; - wire [43:0] dcache_write_misses; - wire [43:0] dcache_bank_stalls; - wire [43:0] dcache_mshr_stalls; - wire [43:0] dcache_pipe_stalls; - wire [43:0] dcache_crsp_stalls; + wire [`PERF_CTR_BITS-1:0] dcache_reads; + wire [`PERF_CTR_BITS-1:0] dcache_writes; + wire [`PERF_CTR_BITS-1:0] dcache_read_misses; + wire [`PERF_CTR_BITS-1:0] dcache_write_misses; + wire [`PERF_CTR_BITS-1:0] dcache_bank_stalls; + wire [`PERF_CTR_BITS-1:0] dcache_mshr_stalls; + wire [`PERF_CTR_BITS-1:0] dcache_pipe_stalls; + wire [`PERF_CTR_BITS-1:0] dcache_crsp_stalls; - wire [43:0] smem_reads; - wire [43:0] smem_writes; - wire [43:0] smem_bank_stalls; + wire [`PERF_CTR_BITS-1:0] smem_reads; + wire [`PERF_CTR_BITS-1:0] smem_writes; + wire [`PERF_CTR_BITS-1:0] smem_bank_stalls; - wire [43:0] dram_reads; - wire [43:0] dram_writes; - wire [43:0] dram_stalls; - wire [43:0] dram_latency; + wire [`PERF_CTR_BITS-1:0] dram_reads; + wire [`PERF_CTR_BITS-1:0] dram_writes; + wire [`PERF_CTR_BITS-1:0] dram_stalls; + wire [`PERF_CTR_BITS-1:0] dram_latency; endinterface diff --git a/hw/rtl/interfaces/VX_perf_pipeline_if.v b/hw/rtl/interfaces/VX_perf_pipeline_if.v index 25cae8f1..12d76d9c 100644 --- a/hw/rtl/interfaces/VX_perf_pipeline_if.v +++ b/hw/rtl/interfaces/VX_perf_pipeline_if.v @@ -4,14 +4,14 @@ `include "VX_define.vh" interface VX_perf_pipeline_if (); - wire [43:0] ibf_stalls; - wire [43:0] scb_stalls; - wire [43:0] lsu_stalls; - wire [43:0] csr_stalls; - wire [43:0] alu_stalls; - wire [43:0] gpu_stalls; + wire [`PERF_CTR_BITS-1:0] ibf_stalls; + wire [`PERF_CTR_BITS-1:0] scb_stalls; + wire [`PERF_CTR_BITS-1:0] lsu_stalls; + wire [`PERF_CTR_BITS-1:0] csr_stalls; + wire [`PERF_CTR_BITS-1:0] alu_stalls; + wire [`PERF_CTR_BITS-1:0] gpu_stalls; `ifdef EXT_F_ENABLE - wire [43:0] fpu_stalls; + wire [`PERF_CTR_BITS-1:0] fpu_stalls; `endif endinterface From 8410c49f53831e185b5948e9048c3865cc135de4 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 26 Apr 2021 00:58:48 -0700 Subject: [PATCH 13/55] code refactoring: DRAM => MEM renaming --- ci/regression.sh | 2 +- driver/common/vx_utils.cpp | 48 +-- driver/opae/vlsim/Makefile | 2 +- driver/opae/vlsim/opae_sim.cpp | 96 +++--- driver/opae/vlsim/opae_sim.h | 8 +- driver/rtlsim/Makefile | 2 +- hw/rtl/VX_cluster.v | 208 ++++++------ hw/rtl/VX_config.vh | 64 ++-- hw/rtl/VX_core.v | 72 ++-- hw/rtl/VX_csr_data.v | 18 +- hw/rtl/VX_define.vh | 68 ++-- hw/rtl/VX_mem_unit.v | 198 +++++------ hw/rtl/Vortex.v | 220 ++++++------- hw/rtl/afu/VX_avs_wrapper.v | 62 ++-- hw/rtl/afu/VX_cci_to_mem.v | 106 +++--- hw/rtl/afu/vortex_afu.sv | 402 +++++++++++------------ hw/rtl/cache/VX_bank.v | 146 ++++---- hw/rtl/cache/VX_cache.v | 188 +++++------ hw/rtl/cache/VX_cache_config.vh | 10 +- hw/rtl/interfaces/VX_cache_dram_req_if.v | 22 -- hw/rtl/interfaces/VX_cache_dram_rsp_if.v | 18 - hw/rtl/interfaces/VX_cache_mem_req_if.v | 23 ++ hw/rtl/interfaces/VX_cache_mem_rsp_if.v | 18 + hw/rtl/interfaces/VX_perf_memsys_if.v | 8 +- hw/scripts/scope.json | 34 +- hw/simulate/Makefile | 2 +- hw/simulate/simulator.cpp | 112 +++---- hw/simulate/simulator.h | 10 +- hw/{ => syn}/modelsim/Makefile | 0 hw/{ => syn}/modelsim/cshrc.modelsim | 0 hw/{ => syn}/modelsim/vortex_dpi.cpp | 0 hw/{ => syn}/modelsim/vortex_dpi.h | 0 hw/{ => syn}/modelsim/vortex_tb.v | 0 hw/syn/opae/README | 7 +- hw/unit_tests/cache/Makefile | 2 +- hw/unit_tests/cache/cachesim.cpp | 122 +++---- hw/unit_tests/cache/cachesim.h | 22 +- hw/unit_tests/cache/testbench.cpp | 2 +- 38 files changed, 1161 insertions(+), 1161 deletions(-) delete mode 100644 hw/rtl/interfaces/VX_cache_dram_req_if.v delete mode 100644 hw/rtl/interfaces/VX_cache_dram_rsp_if.v create mode 100644 hw/rtl/interfaces/VX_cache_mem_req_if.v create mode 100644 hw/rtl/interfaces/VX_cache_mem_rsp_if.v rename hw/{ => syn}/modelsim/Makefile (100%) rename hw/{ => syn}/modelsim/cshrc.modelsim (100%) rename hw/{ => syn}/modelsim/vortex_dpi.cpp (100%) rename hw/{ => syn}/modelsim/vortex_dpi.h (100%) rename hw/{ => syn}/modelsim/vortex_tb.v (100%) diff --git a/ci/regression.sh b/ci/regression.sh index 439b28ef..005e20da 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -16,7 +16,7 @@ make -s # Blackbox tests ./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --perf --app=demo --args="-n1" ./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --debug --app=demo --args="-n1" -./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --scope --app=demo --args="-n1" +./ci/travis_run.py ./ci/blackbox.sh --driver=vlsim --cores=1 --scope --app=basic --args="-t0 -n1" ./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=demo --args="-n1" ./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=demo --args="-n1" ./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=demo --args="-n1" diff --git a/driver/common/vx_utils.cpp b/driver/common/vx_utils.cpp index c265002d..4bc2017b 100644 --- a/driver/common/vx_utils.cpp +++ b/driver/common/vx_utils.cpp @@ -115,10 +115,10 @@ extern int vx_dump_perf(vx_device_h device, FILE* stream) { uint64_t smem_writes = 0; uint64_t smem_bank_stalls = 0; // PERF: memory - uint64_t dram_reads = 0; - uint64_t dram_writes = 0; - uint64_t dram_stalls = 0; - uint64_t dram_lat = 0; + uint64_t mem_reads = 0; + uint64_t mem_writes = 0; + uint64_t mem_stalls = 0; + uint64_t mem_lat = 0; #endif for (unsigned core_id = 0; core_id < num_cores; ++core_id) { @@ -255,21 +255,21 @@ extern int vx_dump_perf(vx_device_h device, FILE* stream) { if (num_cores > 1) fprintf(stream, "PERF: core%d: smem bank stalls=%ld (utilization=%d%%)\n", core_id, smem_bank_st_per_core, smem_bank_utilization); smem_bank_stalls += smem_bank_st_per_core; - // PERF: DRAM - uint64_t dram_reads_per_core, dram_writes_per_core, dram_stalls_per_core, dram_lat_per_core; - ret |= vx_csr_get_l(device, core_id, CSR_MPM_DRAM_READS, CSR_MPM_DRAM_READS_H, &dram_reads_per_core); - ret |= vx_csr_get_l(device, core_id, CSR_MPM_DRAM_WRITES, CSR_MPM_DRAM_WRITES_H, &dram_writes_per_core); - ret |= vx_csr_get_l(device, core_id, CSR_MPM_DRAM_ST, CSR_MPM_DRAM_ST_H, &dram_stalls_per_core); - ret |= vx_csr_get_l(device, core_id, CSR_MPM_DRAM_LAT, CSR_MPM_DRAM_LAT_H, &dram_lat_per_core); - int dram_utilization = (int)((double(dram_reads_per_core + dram_writes_per_core) / double(dram_reads_per_core + dram_writes_per_core + dram_stalls_per_core)) * 100); - int dram_avg_lat = (int)(double(dram_lat_per_core) / double(dram_reads_per_core)); - if (num_cores > 1) fprintf(stream, "PERF: core%d: dram requests=%ld (reads=%ld, writes=%ld)\n", core_id, (dram_reads_per_core + dram_writes_per_core), dram_reads_per_core, dram_writes_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: dram stalls=%ld (utilization=%d%%)\n", core_id, dram_stalls_per_core, dram_utilization); - if (num_cores > 1) fprintf(stream, "PERF: core%d: dram average latency=%d cycles\n", core_id, dram_avg_lat); - dram_reads += dram_reads_per_core; - dram_writes += dram_writes_per_core; - dram_stalls += dram_stalls_per_core; - dram_lat += dram_lat_per_core; + // PERF: memory + uint64_t mem_reads_per_core, mem_writes_per_core, mem_stalls_per_core, mem_lat_per_core; + ret |= vx_csr_get_l(device, core_id, CSR_MPM_MEM_READS, CSR_MPM_MEM_READS_H, &mem_reads_per_core); + ret |= vx_csr_get_l(device, core_id, CSR_MPM_MEM_WRITES, CSR_MPM_MEM_WRITES_H, &mem_writes_per_core); + ret |= vx_csr_get_l(device, core_id, CSR_MPM_MEM_ST, CSR_MPM_MEM_ST_H, &mem_stalls_per_core); + ret |= vx_csr_get_l(device, core_id, CSR_MPM_MEM_LAT, CSR_MPM_MEM_LAT_H, &mem_lat_per_core); + int mem_utilization = (int)((double(mem_reads_per_core + mem_writes_per_core) / double(mem_reads_per_core + mem_writes_per_core + mem_stalls_per_core)) * 100); + int mem_avg_lat = (int)(double(mem_lat_per_core) / double(mem_reads_per_core)); + if (num_cores > 1) fprintf(stream, "PERF: core%d: memory requests=%ld (reads=%ld, writes=%ld)\n", core_id, (mem_reads_per_core + mem_writes_per_core), mem_reads_per_core, mem_writes_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: memory stalls=%ld (utilization=%d%%)\n", core_id, mem_stalls_per_core, mem_utilization); + if (num_cores > 1) fprintf(stream, "PERF: core%d: memory average latency=%d cycles\n", core_id, mem_avg_lat); + mem_reads += mem_reads_per_core; + mem_writes += mem_writes_per_core; + mem_stalls += mem_stalls_per_core; + mem_lat += mem_lat_per_core; #endif } @@ -282,8 +282,8 @@ extern int vx_dump_perf(vx_device_h device, FILE* stream) { int dcache_write_hit_ratio = (int)((1.0 - (double(dcache_write_misses) / double(dcache_writes))) * 100); int dcache_bank_utilization = (int)((double(dcache_reads + dcache_writes) / double(dcache_reads + dcache_writes + dcache_bank_stalls)) * 100); int smem_bank_utilization = (int)((double(smem_reads + smem_writes) / double(smem_reads + smem_writes + smem_bank_stalls)) * 100); - int dram_utilization = (int)((double(dram_reads + dram_writes) / double(dram_reads + dram_writes + dram_stalls)) * 100); - int dram_avg_lat = (int)(double(dram_lat) / double(dram_reads)); + int mem_utilization = (int)((double(mem_reads + mem_writes) / double(mem_reads + mem_writes + mem_stalls)) * 100); + int mem_avg_lat = (int)(double(mem_lat) / double(mem_reads)); fprintf(stream, "PERF: ibuffer stalls=%ld\n", ibuffer_stalls); fprintf(stream, "PERF: scoreboard stalls=%ld\n", scoreboard_stalls); fprintf(stream, "PERF: alu unit stalls=%ld\n", alu_stalls); @@ -306,9 +306,9 @@ extern int vx_dump_perf(vx_device_h device, FILE* stream) { fprintf(stream, "PERF: smem reads=%ld\n", smem_reads); fprintf(stream, "PERF: smem writes=%ld\n", smem_writes); fprintf(stream, "PERF: smem bank stalls=%ld (utilization=%d%%)\n", smem_bank_stalls, smem_bank_utilization); - fprintf(stream, "PERF: dram requests=%ld (reads=%ld, writes=%ld)\n", (dram_reads + dram_writes), dram_reads, dram_writes); - fprintf(stream, "PERF: dram stalls=%ld (utilization=%d%%)\n", dram_stalls, dram_utilization); - fprintf(stream, "PERF: dram average latency=%d cycles\n", dram_avg_lat); + fprintf(stream, "PERF: memory requests=%ld (reads=%ld, writes=%ld)\n", (mem_reads + mem_writes), mem_reads, mem_writes); + fprintf(stream, "PERF: memory stalls=%ld (utilization=%d%%)\n", mem_stalls, mem_utilization); + fprintf(stream, "PERF: memory average latency=%d cycles\n", mem_avg_lat); #endif return ret; diff --git a/driver/opae/vlsim/Makefile b/driver/opae/vlsim/Makefile index 64f7691d..dcd58806 100644 --- a/driver/opae/vlsim/Makefile +++ b/driver/opae/vlsim/Makefile @@ -13,7 +13,7 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_BANK DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_MSHR DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_TAG DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_DATA -DBG_PRINT_FLAGS += -DDBG_PRINT_DRAM +DBG_PRINT_FLAGS += -DDBG_PRINT_MEM DBG_PRINT_FLAGS += -DDBG_PRINT_OPAE DBG_PRINT_FLAGS += -DDBG_PRINT_AVS DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE diff --git a/driver/opae/vlsim/opae_sim.cpp b/driver/opae/vlsim/opae_sim.cpp index e821fa52..d62319a5 100644 --- a/driver/opae/vlsim/opae_sim.cpp +++ b/driver/opae/vlsim/opae_sim.cpp @@ -10,10 +10,10 @@ #define RESET_DELAY 4 -#define ENABLE_DRAM_STALLS -#define DRAM_LATENCY 24 -#define DRAM_RQ_SIZE 16 -#define DRAM_STALLS_MODULO 16 +#define ENABLE_MEM_STALLS +#define MEM_LATENCY 24 +#define MEM_RQ_SIZE 16 +#define MEM_STALLS_MODULO 16 uint64_t timestamp = 0; @@ -138,7 +138,7 @@ void opae_sim::flush() { void opae_sim::reset() { host_buffers_.clear(); - dram_reads_.clear(); + mem_reads_.clear(); cci_reads_.clear(); cci_writes_.clear(); vortex_afu_->vcp2af_sRxPort_c0_rspValid = 0; @@ -268,87 +268,87 @@ void opae_sim::sTxPort_bus() { } void opae_sim::avs_bus() { - // update DRAM responses schedule - for (auto& rsp : dram_reads_) { + // update memory responses schedule + for (auto& rsp : mem_reads_) { if (rsp.cycles_left > 0) rsp.cycles_left -= 1; } - // schedule DRAM responses in FIFO order - std::list::iterator dram_rd_it(dram_reads_.end()); - if (!dram_reads_.empty() - && (0 == dram_reads_.begin()->cycles_left)) { - dram_rd_it = dram_reads_.begin(); + // schedule memory responses in FIFO order + std::list::iterator mem_rd_it(mem_reads_.end()); + if (!mem_reads_.empty() + && (0 == mem_reads_.begin()->cycles_left)) { + mem_rd_it = mem_reads_.begin(); } - // send DRAM response + // send memory response vortex_afu_->avs_readdatavalid = 0; - if (dram_rd_it != dram_reads_.end()) { + if (mem_rd_it != mem_reads_.end()) { vortex_afu_->avs_readdatavalid = 1; - memcpy(vortex_afu_->avs_readdata, dram_rd_it->data.data(), DRAM_BLOCK_SIZE); - uint32_t addr = dram_rd_it->addr; - dram_reads_.erase(dram_rd_it); - /*printf("%0ld: [sim] DRAM Rd Rsp: addr=%x, pending={", timestamp, addr * DRAM_BLOCK_SIZE); - for (auto& req : dram_reads_) { + memcpy(vortex_afu_->avs_readdata, mem_rd_it->data.data(), MEM_BLOCK_SIZE); + uint32_t addr = mem_rd_it->addr; + mem_reads_.erase(mem_rd_it); + /*printf("%0ld: [sim] MEM Rd Rsp: addr=%x, pending={", timestamp, addr * MEM_BLOCK_SIZE); + for (auto& req : mem_reads_) { if (req.cycles_left != 0) - printf(" !%0x", req.addr * DRAM_BLOCK_SIZE); + printf(" !%0x", req.addr * MEM_BLOCK_SIZE); else - printf(" %0x", req.addr * DRAM_BLOCK_SIZE); + printf(" %0x", req.addr * MEM_BLOCK_SIZE); } printf("}\n");*/ } - // handle DRAM stalls - bool dram_stalled = false; -#ifdef ENABLE_DRAM_STALLS - if (0 == ((timestamp/2) % DRAM_STALLS_MODULO)) { - dram_stalled = true; + // handle memory stalls + bool mem_stalled = false; +#ifdef ENABLE_MEM_STALLS + if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) { + mem_stalled = true; } else - if (dram_reads_.size() >= DRAM_RQ_SIZE) { - dram_stalled = true; + if (mem_reads_.size() >= MEM_RQ_SIZE) { + mem_stalled = true; } #endif - // process DRAM requests - if (!dram_stalled) { + // process memory requests + if (!mem_stalled) { assert(!vortex_afu_->avs_read || !vortex_afu_->avs_write); if (vortex_afu_->avs_write) { uint64_t byteen = vortex_afu_->avs_byteenable; - unsigned base_addr = vortex_afu_->avs_address * DRAM_BLOCK_SIZE; + unsigned base_addr = vortex_afu_->avs_address * MEM_BLOCK_SIZE; uint8_t* data = (uint8_t*)(vortex_afu_->avs_writedata); - for (int i = 0; i < DRAM_BLOCK_SIZE; i++) { + for (int i = 0; i < MEM_BLOCK_SIZE; i++) { if ((byteen >> i) & 0x1) { ram_[base_addr + i] = data[i]; } } - /*printf("%0ld: [sim] DRAM Wr Req: addr=%x, data=", timestamp, base_addr); - for (int i = 0; i < DRAM_BLOCK_SIZE; i++) { - printf("%0x", data[(DRAM_BLOCK_SIZE-1)-i]); + /*printf("%0ld: [sim] MEM Wr Req: addr=%x, data=", timestamp, base_addr); + for (int i = 0; i < MEM_BLOCK_SIZE; i++) { + printf("%0x", data[(MEM_BLOCK_SIZE-1)-i]); } printf("\n");*/ } if (vortex_afu_->avs_read) { - dram_rd_req_t dram_req; - dram_req.addr = vortex_afu_->avs_address; - ram_.read(vortex_afu_->avs_address * DRAM_BLOCK_SIZE, DRAM_BLOCK_SIZE, dram_req.data.data()); - dram_req.cycles_left = DRAM_LATENCY; - for (auto& rsp : dram_reads_) { - if (dram_req.addr == rsp.addr) { - dram_req.cycles_left = rsp.cycles_left; + mem_rd_req_t mem_req; + mem_req.addr = vortex_afu_->avs_address; + ram_.read(vortex_afu_->avs_address * MEM_BLOCK_SIZE, MEM_BLOCK_SIZE, mem_req.data.data()); + mem_req.cycles_left = MEM_LATENCY; + for (auto& rsp : mem_reads_) { + if (mem_req.addr == rsp.addr) { + mem_req.cycles_left = rsp.cycles_left; break; } } - dram_reads_.emplace_back(dram_req); - /*printf("%0ld: [sim] DRAM Rd Req: addr=%x, pending={", timestamp, dram_req.addr * DRAM_BLOCK_SIZE); - for (auto& req : dram_reads_) { + mem_reads_.emplace_back(mem_req); + /*printf("%0ld: [sim] MEM Rd Req: addr=%x, pending={", timestamp, mem_req.addr * MEM_BLOCK_SIZE); + for (auto& req : mem_reads_) { if (req.cycles_left != 0) - printf(" !%0x", req.addr * DRAM_BLOCK_SIZE); + printf(" !%0x", req.addr * MEM_BLOCK_SIZE); else - printf(" %0x", req.addr * DRAM_BLOCK_SIZE); + printf(" %0x", req.addr * MEM_BLOCK_SIZE); } printf("}\n");*/ } } - vortex_afu_->avs_waitrequest = dram_stalled; + vortex_afu_->avs_waitrequest = mem_stalled; } \ No newline at end of file diff --git a/driver/opae/vlsim/opae_sim.h b/driver/opae/vlsim/opae_sim.h index 15689769..76e5f435 100644 --- a/driver/opae/vlsim/opae_sim.h +++ b/driver/opae/vlsim/opae_sim.h @@ -17,7 +17,7 @@ #include #include -#define DRAM_BLOCK_SIZE (PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH / 8) +#define MEM_BLOCK_SIZE (PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH / 8) #define CACHE_BLOCK_SIZE 64 @@ -43,9 +43,9 @@ private: typedef struct { int cycles_left; - std::array data; + std::array data; uint32_t addr; - } dram_rd_req_t; + } mem_rd_req_t; typedef struct { int cycles_left; @@ -80,7 +80,7 @@ private: std::unordered_map host_buffers_; - std::list dram_reads_; + std::list mem_reads_; std::list cci_reads_; diff --git a/driver/rtlsim/Makefile b/driver/rtlsim/Makefile index 5bfe5553..11ef6760 100644 --- a/driver/rtlsim/Makefile +++ b/driver/rtlsim/Makefile @@ -12,7 +12,7 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_BANK DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_MSHR DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_TAG DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_DATA -DBG_PRINT_FLAGS += -DDBG_PRINT_DRAM +DBG_PRINT_FLAGS += -DDBG_PRINT_MEM DBG_PRINT_FLAGS += -DDBG_PRINT_OPAE DBG_PRINT_FLAGS += -DDBG_PRINT_AVS DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE diff --git a/hw/rtl/VX_cluster.v b/hw/rtl/VX_cluster.v index ea9a766b..d9521b8e 100644 --- a/hw/rtl/VX_cluster.v +++ b/hw/rtl/VX_cluster.v @@ -9,20 +9,20 @@ module VX_cluster #( input wire clk, input wire reset, - // DRAM request - output wire dram_req_valid, - output wire dram_req_rw, - output wire [`L2DRAM_BYTEEN_WIDTH-1:0] dram_req_byteen, - output wire [`L2DRAM_ADDR_WIDTH-1:0] dram_req_addr, - output wire [`L2DRAM_LINE_WIDTH-1:0] dram_req_data, - output wire [`L2DRAM_TAG_WIDTH-1:0] dram_req_tag, - input wire dram_req_ready, + // Memory request + output wire mem_req_valid, + output wire mem_req_rw, + output wire [`L2MEM_BYTEEN_WIDTH-1:0] mem_req_byteen, + output wire [`L2MEM_ADDR_WIDTH-1:0] mem_req_addr, + output wire [`L2MEM_LINE_WIDTH-1:0] mem_req_data, + output wire [`L2MEM_TAG_WIDTH-1:0] mem_req_tag, + input wire mem_req_ready, - // DRAM response - input wire dram_rsp_valid, - input wire [`L2DRAM_LINE_WIDTH-1:0] dram_rsp_data, - input wire [`L2DRAM_TAG_WIDTH-1:0] dram_rsp_tag, - output wire dram_rsp_ready, + // Memory response + input wire mem_rsp_valid, + input wire [`L2MEM_LINE_WIDTH-1:0] mem_rsp_data, + input wire [`L2MEM_TAG_WIDTH-1:0] mem_rsp_tag, + output wire mem_rsp_ready, // CSR Request input wire csr_req_valid, @@ -42,31 +42,31 @@ module VX_cluster #( output wire ebreak ); - wire [`NUM_CORES-1:0] per_core_dram_req_valid; - wire [`NUM_CORES-1:0] per_core_dram_req_rw; - wire [`NUM_CORES-1:0][`DDRAM_BYTEEN_WIDTH-1:0] per_core_dram_req_byteen; - wire [`NUM_CORES-1:0][`DDRAM_ADDR_WIDTH-1:0] per_core_dram_req_addr; - wire [`NUM_CORES-1:0][`DDRAM_LINE_WIDTH-1:0] per_core_dram_req_data; - wire [`NUM_CORES-1:0][`XDRAM_TAG_WIDTH-1:0] per_core_dram_req_tag; - wire [`NUM_CORES-1:0] per_core_dram_req_ready; + wire [`NUM_CORES-1:0] per_core_mem_req_valid; + wire [`NUM_CORES-1:0] per_core_mem_req_rw; + wire [`NUM_CORES-1:0][`DMEM_BYTEEN_WIDTH-1:0] per_core_mem_req_byteen; + wire [`NUM_CORES-1:0][`DMEM_ADDR_WIDTH-1:0] per_core_mem_req_addr; + wire [`NUM_CORES-1:0][`DMEM_LINE_WIDTH-1:0] per_core_mem_req_data; + wire [`NUM_CORES-1:0][`XMEM_TAG_WIDTH-1:0] per_core_mem_req_tag; + wire [`NUM_CORES-1:0] per_core_mem_req_ready; - wire [`NUM_CORES-1:0] per_core_dram_rsp_valid; - wire [`NUM_CORES-1:0][`DDRAM_LINE_WIDTH-1:0] per_core_dram_rsp_data; - wire [`NUM_CORES-1:0][`XDRAM_TAG_WIDTH-1:0] per_core_dram_rsp_tag; - wire [`NUM_CORES-1:0] per_core_dram_rsp_ready; + wire [`NUM_CORES-1:0] per_core_mem_rsp_valid; + wire [`NUM_CORES-1:0][`DMEM_LINE_WIDTH-1:0] per_core_mem_rsp_data; + wire [`NUM_CORES-1:0][`XMEM_TAG_WIDTH-1:0] per_core_mem_rsp_tag; + wire [`NUM_CORES-1:0] per_core_mem_rsp_ready; - wire [`NUM_CORES-1:0] per_core_csr_req_valid; - wire [`NUM_CORES-1:0][11:0] per_core_csr_req_addr; - wire [`NUM_CORES-1:0] per_core_csr_req_rw; - wire [`NUM_CORES-1:0][31:0] per_core_csr_req_data; - wire [`NUM_CORES-1:0] per_core_csr_req_ready; + wire [`NUM_CORES-1:0] per_core_csr_req_valid; + wire [`NUM_CORES-1:0][11:0] per_core_csr_req_addr; + wire [`NUM_CORES-1:0] per_core_csr_req_rw; + wire [`NUM_CORES-1:0][31:0] per_core_csr_req_data; + wire [`NUM_CORES-1:0] per_core_csr_req_ready; - wire [`NUM_CORES-1:0] per_core_csr_rsp_valid; - wire [`NUM_CORES-1:0][31:0] per_core_csr_rsp_data; - wire [`NUM_CORES-1:0] per_core_csr_rsp_ready; + wire [`NUM_CORES-1:0] per_core_csr_rsp_valid; + wire [`NUM_CORES-1:0][31:0] per_core_csr_rsp_data; + wire [`NUM_CORES-1:0] per_core_csr_rsp_ready; - wire [`NUM_CORES-1:0] per_core_busy; - wire [`NUM_CORES-1:0] per_core_ebreak; + wire [`NUM_CORES-1:0] per_core_busy; + wire [`NUM_CORES-1:0] per_core_ebreak; for (genvar i = 0; i < `NUM_CORES; i++) begin @@ -87,18 +87,18 @@ module VX_cluster #( .clk (clk), .reset (core_reset), - .dram_req_valid (per_core_dram_req_valid[i]), - .dram_req_rw (per_core_dram_req_rw [i]), - .dram_req_byteen(per_core_dram_req_byteen[i]), - .dram_req_addr (per_core_dram_req_addr [i]), - .dram_req_data (per_core_dram_req_data [i]), - .dram_req_tag (per_core_dram_req_tag [i]), - .dram_req_ready (per_core_dram_req_ready[i]), + .mem_req_valid (per_core_mem_req_valid[i]), + .mem_req_rw (per_core_mem_req_rw [i]), + .mem_req_byteen (per_core_mem_req_byteen[i]), + .mem_req_addr (per_core_mem_req_addr [i]), + .mem_req_data (per_core_mem_req_data [i]), + .mem_req_tag (per_core_mem_req_tag [i]), + .mem_req_ready (per_core_mem_req_ready[i]), - .dram_rsp_valid (per_core_dram_rsp_valid[i]), - .dram_rsp_data (per_core_dram_rsp_data [i]), - .dram_rsp_tag (per_core_dram_rsp_tag [i]), - .dram_rsp_ready (per_core_dram_rsp_ready[i]), + .mem_rsp_valid (per_core_mem_rsp_valid[i]), + .mem_rsp_data (per_core_mem_rsp_data [i]), + .mem_rsp_tag (per_core_mem_rsp_tag [i]), + .mem_rsp_ready (per_core_mem_rsp_ready[i]), .csr_req_valid (per_core_csr_req_valid [i]), .csr_req_rw (per_core_csr_req_rw [i]), @@ -169,12 +169,12 @@ module VX_cluster #( .NUM_REQS (`NUM_CORES), .CREQ_SIZE (`L2CREQ_SIZE), .MSHR_SIZE (`L2MSHR_SIZE), - .DRSQ_SIZE (`L2DRSQ_SIZE), - .DREQ_SIZE (`L2DREQ_SIZE), + .MRSQ_SIZE (`L2MRSQ_SIZE), + .MREQ_SIZE (`L2MREQ_SIZE), .WRITE_ENABLE (1), - .CORE_TAG_WIDTH (`XDRAM_TAG_WIDTH), + .CORE_TAG_WIDTH (`XMEM_TAG_WIDTH), .CORE_TAG_ID_BITS (0), - .DRAM_TAG_WIDTH (`L2DRAM_TAG_WIDTH) + .MEM_TAG_WIDTH (`L2MEM_TAG_WIDTH) ) l2cache ( `SCOPE_BIND_VX_cluster_l2cache @@ -188,78 +188,78 @@ module VX_cluster #( `endif // Core request - .core_req_valid (per_core_dram_req_valid), - .core_req_rw (per_core_dram_req_rw), - .core_req_byteen (per_core_dram_req_byteen), - .core_req_addr (per_core_dram_req_addr), - .core_req_data (per_core_dram_req_data), - .core_req_tag (per_core_dram_req_tag), - .core_req_ready (per_core_dram_req_ready), + .core_req_valid (per_core_mem_req_valid), + .core_req_rw (per_core_mem_req_rw), + .core_req_byteen (per_core_mem_req_byteen), + .core_req_addr (per_core_mem_req_addr), + .core_req_data (per_core_mem_req_data), + .core_req_tag (per_core_mem_req_tag), + .core_req_ready (per_core_mem_req_ready), // Core response - .core_rsp_valid (per_core_dram_rsp_valid), - .core_rsp_data (per_core_dram_rsp_data), - .core_rsp_tag (per_core_dram_rsp_tag), - .core_rsp_ready (per_core_dram_rsp_ready), + .core_rsp_valid (per_core_mem_rsp_valid), + .core_rsp_data (per_core_mem_rsp_data), + .core_rsp_tag (per_core_mem_rsp_tag), + .core_rsp_ready (per_core_mem_rsp_ready), - // DRAM request - .dram_req_valid (dram_req_valid), - .dram_req_rw (dram_req_rw), - .dram_req_byteen (dram_req_byteen), - .dram_req_addr (dram_req_addr), - .dram_req_data (dram_req_data), - .dram_req_tag (dram_req_tag), - .dram_req_ready (dram_req_ready), + // Memory request + .mem_req_valid (mem_req_valid), + .mem_req_rw (mem_req_rw), + .mem_req_byteen (mem_req_byteen), + .mem_req_addr (mem_req_addr), + .mem_req_data (mem_req_data), + .mem_req_tag (mem_req_tag), + .mem_req_ready (mem_req_ready), - // DRAM response - .dram_rsp_valid (dram_rsp_valid), - .dram_rsp_tag (dram_rsp_tag), - .dram_rsp_data (dram_rsp_data), - .dram_rsp_ready (dram_rsp_ready) + // Memory response + .mem_rsp_valid (mem_rsp_valid), + .mem_rsp_tag (mem_rsp_tag), + .mem_rsp_data (mem_rsp_data), + .mem_rsp_ready (mem_rsp_ready) ); end else begin VX_mem_arb #( - .NUM_REQS (`NUM_CORES), - .DATA_WIDTH (`L2DRAM_LINE_WIDTH), - .TAG_IN_WIDTH (`XDRAM_TAG_WIDTH), - .TAG_OUT_WIDTH (`L2DRAM_TAG_WIDTH), - .BUFFERED_REQ (1), - .BUFFERED_RSP (1) - ) dram_arb ( + .NUM_REQS (`NUM_CORES), + .DATA_WIDTH (`L2MEM_LINE_WIDTH), + .TAG_IN_WIDTH (`XMEM_TAG_WIDTH), + .TAG_OUT_WIDTH (`L2MEM_TAG_WIDTH), + .BUFFERED_REQ (1), + .BUFFERED_RSP (1) + ) mem_arb ( .clk (clk), .reset (reset), // Core request - .req_valid_in (per_core_dram_req_valid), - .req_rw_in (per_core_dram_req_rw), - .req_byteen_in (per_core_dram_req_byteen), - .req_addr_in (per_core_dram_req_addr), - .req_data_in (per_core_dram_req_data), - .req_tag_in (per_core_dram_req_tag), - .req_ready_in (per_core_dram_req_ready), + .req_valid_in (per_core_mem_req_valid), + .req_rw_in (per_core_mem_req_rw), + .req_byteen_in (per_core_mem_req_byteen), + .req_addr_in (per_core_mem_req_addr), + .req_data_in (per_core_mem_req_data), + .req_tag_in (per_core_mem_req_tag), + .req_ready_in (per_core_mem_req_ready), - // DRAM request - .req_valid_out (dram_req_valid), - .req_rw_out (dram_req_rw), - .req_byteen_out (dram_req_byteen), - .req_addr_out (dram_req_addr), - .req_data_out (dram_req_data), - .req_tag_out (dram_req_tag), - .req_ready_out (dram_req_ready), + // Memory request + .req_valid_out (mem_req_valid), + .req_rw_out (mem_req_rw), + .req_byteen_out (mem_req_byteen), + .req_addr_out (mem_req_addr), + .req_data_out (mem_req_data), + .req_tag_out (mem_req_tag), + .req_ready_out (mem_req_ready), // Core response - .rsp_valid_out (per_core_dram_rsp_valid), - .rsp_data_out (per_core_dram_rsp_data), - .rsp_tag_out (per_core_dram_rsp_tag), - .rsp_ready_out (per_core_dram_rsp_ready), + .rsp_valid_out (per_core_mem_rsp_valid), + .rsp_data_out (per_core_mem_rsp_data), + .rsp_tag_out (per_core_mem_rsp_tag), + .rsp_ready_out (per_core_mem_rsp_ready), - // DRAM response - .rsp_valid_in (dram_rsp_valid), - .rsp_tag_in (dram_rsp_tag), - .rsp_data_in (dram_rsp_data), - .rsp_ready_in (dram_rsp_ready) + // Memory response + .rsp_valid_in (mem_rsp_valid), + .rsp_tag_in (mem_rsp_tag), + .rsp_data_in (mem_rsp_data), + .rsp_ready_in (mem_rsp_ready) ); end diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 40c33428..2b2727fc 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -207,14 +207,14 @@ `define CSR_MPM_SMEM_BANK_ST 12'hB18 // bank conflicts stalls `define CSR_MPM_SMEM_BANK_ST_H 12'hB98 // PERF: memory -`define CSR_MPM_DRAM_READS 12'hB19 // dram reads -`define CSR_MPM_DRAM_READS_H 12'hB99 -`define CSR_MPM_DRAM_WRITES 12'hB1A // dram writes -`define CSR_MPM_DRAM_WRITES_H 12'hB9A -`define CSR_MPM_DRAM_ST 12'hB1B // dram request stalls -`define CSR_MPM_DRAM_ST_H 12'hB9B -`define CSR_MPM_DRAM_LAT 12'hB1C // dram latency (total) -`define CSR_MPM_DRAM_LAT_H 12'hB9C +`define CSR_MPM_MEM_READS 12'hB19 // memory reads +`define CSR_MPM_MEM_READS_H 12'hB99 +`define CSR_MPM_MEM_WRITES 12'hB1A // memory writes +`define CSR_MPM_MEM_WRITES_H 12'hB9A +`define CSR_MPM_MEM_ST 12'hB1B // memory request stalls +`define CSR_MPM_MEM_ST_H 12'hB9B +`define CSR_MPM_MEM_LAT 12'hB1C // memory latency (total) +`define CSR_MPM_MEM_LAT_H 12'hB9C // Machine Information Registers `define CSR_MVENDORID 12'hF11 @@ -264,14 +264,14 @@ `define IMSHR_SIZE `NUM_WARPS `endif -// DRAM Request Queue Size -`ifndef IDREQ_SIZE -`define IDREQ_SIZE 4 +// Memory Request Queue Size +`ifndef IMREQ_SIZE +`define IMREQ_SIZE 4 `endif -// DRAM Response Queue Size -`ifndef IDRSQ_SIZE -`define IDRSQ_SIZE 4 +// Memory Response Queue Size +`ifndef IMRSQ_SIZE +`define IMRSQ_SIZE 4 `endif // Dcache Configurable Knobs ////////////////////////////////////////////////// @@ -301,14 +301,14 @@ `define DMSHR_SIZE `LSUQ_SIZE `endif -// DRAM Request Queue Size -`ifndef DDREQ_SIZE -`define DDREQ_SIZE 4 +// Memory Request Queue Size +`ifndef DMREQ_SIZE +`define DMREQ_SIZE 4 `endif -// DRAM Response Queue Size -`ifndef DDRSQ_SIZE -`define DDRSQ_SIZE `MAX(4, (`DNUM_BANKS * 2)) +// Memory Response Queue Size +`ifndef DMRSQ_SIZE +`define DMRSQ_SIZE `MAX(4, (`DNUM_BANKS * 2)) `endif // SM Configurable Knobs ////////////////////////////////////////////////////// @@ -355,14 +355,14 @@ `define L2MSHR_SIZE 16 `endif -// DRAM Request Queue Size -`ifndef L2DREQ_SIZE -`define L2DREQ_SIZE 4 +// L2 Request Queue Size +`ifndef L2MREQ_SIZE +`define L2MREQ_SIZE 4 `endif -// DRAM Response Queue Size -`ifndef L2DRSQ_SIZE -`define L2DRSQ_SIZE `MAX(4, (`L2NUM_BANKS * 2)) +// L2 Response Queue Size +`ifndef L2MRSQ_SIZE +`define L2MRSQ_SIZE `MAX(4, (`L2NUM_BANKS * 2)) `endif // L3cache Configurable Knobs ///////////////////////////////////////////////// @@ -387,14 +387,14 @@ `define L3MSHR_SIZE 16 `endif -// DRAM Request Queue Size -`ifndef L3DREQ_SIZE -`define L3DREQ_SIZE 4 +// L3 Request Queue Size +`ifndef L3MREQ_SIZE +`define L3MREQ_SIZE 4 `endif -// DRAM Response Queue Size -`ifndef L3DRSQ_SIZE -`define L3DRSQ_SIZE `MAX(4, (`L3NUM_BANKS * 2)) +// L3 Response Queue Size +`ifndef L3MRSQ_SIZE +`define L3MRSQ_SIZE `MAX(4, (`L3NUM_BANKS * 2)) `endif `endif diff --git a/hw/rtl/VX_core.v b/hw/rtl/VX_core.v index b34b6788..3a13ac66 100644 --- a/hw/rtl/VX_core.v +++ b/hw/rtl/VX_core.v @@ -9,20 +9,20 @@ module VX_core #( input wire clk, input wire reset, - // DRAM request - output wire dram_req_valid, - output wire dram_req_rw, - output wire [`DDRAM_BYTEEN_WIDTH-1:0] dram_req_byteen, - output wire [`DDRAM_ADDR_WIDTH-1:0] dram_req_addr, - output wire [`DDRAM_LINE_WIDTH-1:0] dram_req_data, - output wire [`XDRAM_TAG_WIDTH-1:0] dram_req_tag, - input wire dram_req_ready, + // Memory request + output wire mem_req_valid, + output wire mem_req_rw, + output wire [`DMEM_BYTEEN_WIDTH-1:0] mem_req_byteen, + output wire [`DMEM_ADDR_WIDTH-1:0] mem_req_addr, + output wire [`DMEM_LINE_WIDTH-1:0] mem_req_data, + output wire [`XMEM_TAG_WIDTH-1:0] mem_req_tag, + input wire mem_req_ready, - // DRAM reponse - input wire dram_rsp_valid, - input wire [`DDRAM_LINE_WIDTH-1:0] dram_rsp_data, - input wire [`XDRAM_TAG_WIDTH-1:0] dram_rsp_tag, - output wire dram_rsp_ready, + // Memory reponse + input wire mem_rsp_valid, + input wire [`DMEM_LINE_WIDTH-1:0] mem_rsp_data, + input wire [`XMEM_TAG_WIDTH-1:0] mem_rsp_tag, + output wire mem_rsp_ready, // CSR request input wire csr_req_valid, @@ -44,29 +44,29 @@ module VX_core #( VX_perf_memsys_if perf_memsys_if(); `endif - VX_cache_dram_req_if #( - .DRAM_LINE_WIDTH(`DDRAM_LINE_WIDTH), - .DRAM_ADDR_WIDTH(`DDRAM_ADDR_WIDTH), - .DRAM_TAG_WIDTH(`XDRAM_TAG_WIDTH) - ) dram_req_if(); + VX_cache_mem_req_if #( + .MEM_LINE_WIDTH(`DMEM_LINE_WIDTH), + .MEM_ADDR_WIDTH(`DMEM_ADDR_WIDTH), + .MEM_TAG_WIDTH(`XMEM_TAG_WIDTH) + ) mem_req_if(); - VX_cache_dram_rsp_if #( - .DRAM_LINE_WIDTH(`DDRAM_LINE_WIDTH), - .DRAM_TAG_WIDTH(`XDRAM_TAG_WIDTH) - ) dram_rsp_if(); + VX_cache_mem_rsp_if #( + .MEM_LINE_WIDTH(`DMEM_LINE_WIDTH), + .MEM_TAG_WIDTH(`XMEM_TAG_WIDTH) + ) mem_rsp_if(); - assign dram_req_valid = dram_req_if.valid; - assign dram_req_rw = dram_req_if.rw; - assign dram_req_byteen= dram_req_if.byteen; - assign dram_req_addr = dram_req_if.addr; - assign dram_req_data = dram_req_if.data; - assign dram_req_tag = dram_req_if.tag; - assign dram_req_if.ready = dram_req_ready; + assign mem_req_valid = mem_req_if.valid; + assign mem_req_rw = mem_req_if.rw; + assign mem_req_byteen= mem_req_if.byteen; + assign mem_req_addr = mem_req_if.addr; + assign mem_req_data = mem_req_if.data; + assign mem_req_tag = mem_req_if.tag; + assign mem_req_if.ready = mem_req_ready; - assign dram_rsp_if.valid = dram_rsp_valid; - assign dram_rsp_if.data = dram_rsp_data; - assign dram_rsp_if.tag = dram_rsp_tag; - assign dram_rsp_ready = dram_rsp_if.ready; + assign mem_rsp_if.valid = mem_rsp_valid; + assign mem_rsp_if.data = mem_rsp_data; + assign mem_rsp_if.tag = mem_rsp_tag; + assign mem_rsp_ready = mem_rsp_if.ready; //-- @@ -168,9 +168,9 @@ module VX_core #( .icache_core_req_if (icache_core_req_if), .icache_core_rsp_if (icache_core_rsp_if), - // DRAM - .dram_req_if (dram_req_if), - .dram_rsp_if (dram_rsp_if) + // Memory + .mem_req_if (mem_req_if), + .mem_rsp_if (mem_rsp_if) ); endmodule diff --git a/hw/rtl/VX_csr_data.v b/hw/rtl/VX_csr_data.v index 502f124f..0bd5a5fc 100644 --- a/hw/rtl/VX_csr_data.v +++ b/hw/rtl/VX_csr_data.v @@ -160,15 +160,15 @@ module VX_csr_data #( `CSR_MPM_SMEM_WRITES_H : read_data_r = 32'(perf_memsys_if.smem_writes[`PERF_CTR_BITS-1:32]); `CSR_MPM_SMEM_BANK_ST : read_data_r = perf_memsys_if.smem_bank_stalls[31:0]; `CSR_MPM_SMEM_BANK_ST_H : read_data_r = 32'(perf_memsys_if.smem_bank_stalls[`PERF_CTR_BITS-1:32]); - // PERF: DRAM - `CSR_MPM_DRAM_READS : read_data_r = perf_memsys_if.dram_reads[31:0]; - `CSR_MPM_DRAM_READS_H : read_data_r = 32'(perf_memsys_if.dram_reads[`PERF_CTR_BITS-1:32]); - `CSR_MPM_DRAM_WRITES : read_data_r = perf_memsys_if.dram_writes[31:0]; - `CSR_MPM_DRAM_WRITES_H : read_data_r = 32'(perf_memsys_if.dram_writes[`PERF_CTR_BITS-1:32]); - `CSR_MPM_DRAM_ST : read_data_r = perf_memsys_if.dram_stalls[31:0]; - `CSR_MPM_DRAM_ST_H : read_data_r = 32'(perf_memsys_if.dram_stalls[`PERF_CTR_BITS-1:32]); - `CSR_MPM_DRAM_LAT : read_data_r = perf_memsys_if.dram_latency[31:0]; - `CSR_MPM_DRAM_LAT_H : read_data_r = 32'(perf_memsys_if.dram_latency[`PERF_CTR_BITS-1:32]); + // PERF: MEM + `CSR_MPM_MEM_READS : read_data_r = perf_memsys_if.mem_reads[31:0]; + `CSR_MPM_MEM_READS_H : read_data_r = 32'(perf_memsys_if.mem_reads[`PERF_CTR_BITS-1:32]); + `CSR_MPM_MEM_WRITES : read_data_r = perf_memsys_if.mem_writes[31:0]; + `CSR_MPM_MEM_WRITES_H : read_data_r = 32'(perf_memsys_if.mem_writes[`PERF_CTR_BITS-1:32]); + `CSR_MPM_MEM_ST : read_data_r = perf_memsys_if.mem_stalls[31:0]; + `CSR_MPM_MEM_ST_H : read_data_r = 32'(perf_memsys_if.mem_stalls[`PERF_CTR_BITS-1:32]); + `CSR_MPM_MEM_LAT : read_data_r = perf_memsys_if.mem_latency[31:0]; + `CSR_MPM_MEM_LAT_H : read_data_r = 32'(perf_memsys_if.mem_latency[`PERF_CTR_BITS-1:32]); `endif `CSR_SATP : read_data_r = 32'(csr_satp); diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index 46d6666c..79de9b8f 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -263,11 +263,11 @@ // Core request tag bits `define ICORE_TAG_WIDTH (`DBG_CACHE_REQ_MDATAW + `ICORE_TAG_ID_BITS) -// DRAM request data bits -`define IDRAM_LINE_WIDTH (`ICACHE_LINE_SIZE * 8) +// Memory request data bits +`define IMEM_LINE_WIDTH (`ICACHE_LINE_SIZE * 8) -// DRAM byte enable bits -`define IDRAM_BYTEEN_WIDTH `ICACHE_LINE_SIZE +// Memory byte enable bits +`define IMEM_BYTEEN_WIDTH `ICACHE_LINE_SIZE ////////////////////////// Dcache Configurable Knobs ////////////////////////// @@ -275,7 +275,7 @@ `define DCACHE_ID (32'(`L3_ENABLE) + 32'(`L2_ENABLE) * `NUM_CLUSTERS + CORE_ID * 3 + 1) // Block size in bytes -`define DCACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `GLOBAL_BLOCK_SIZE) +`define DCACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `GLOBAL_BLOCK_SIZE) // Word size in bytes `define DWORD_SIZE 4 @@ -286,17 +286,17 @@ // Core request tag bits `define DCORE_TAG_WIDTH (`DBG_CACHE_REQ_MDATAW + `DCORE_TAG_ID_BITS) -// DRAM request data bits -`define DDRAM_LINE_WIDTH (`DCACHE_LINE_SIZE * 8) +// Memory request data bits +`define DMEM_LINE_WIDTH (`DCACHE_LINE_SIZE * 8) -// DRAM request address bits -`define DDRAM_ADDR_WIDTH (32 - `CLOG2(`DCACHE_LINE_SIZE)) +// Memory request address bits +`define DMEM_ADDR_WIDTH (32 - `CLOG2(`DCACHE_LINE_SIZE)) -// DRAM byte enable bits -`define DDRAM_BYTEEN_WIDTH `DCACHE_LINE_SIZE +// Memory byte enable bits +`define DMEM_BYTEEN_WIDTH `DCACHE_LINE_SIZE -// DRAM request tag bits -`define DDRAM_TAG_WIDTH `DDRAM_ADDR_WIDTH +// Memory request tag bits +`define DMEM_TAG_WIDTH `DMEM_ADDR_WIDTH // Core request size `define DNUM_REQUESTS `NUM_THREADS @@ -332,17 +332,17 @@ // Core request tag bits `define L2CORE_TAG_WIDTH (`DCORE_TAG_WIDTH + `CLOG2(`NUM_CORES)) -// DRAM request data bits -`define L2DRAM_LINE_WIDTH (`L2CACHE_LINE_SIZE * 8) +// Memory request data bits +`define L2MEM_LINE_WIDTH (`L2CACHE_LINE_SIZE * 8) -// DRAM request address bits -`define L2DRAM_ADDR_WIDTH (32 - `CLOG2(`L2CACHE_LINE_SIZE)) +// Memory request address bits +`define L2MEM_ADDR_WIDTH (32 - `CLOG2(`L2CACHE_LINE_SIZE)) -// DRAM byte enable bits -`define L2DRAM_BYTEEN_WIDTH `L2CACHE_LINE_SIZE +// Memory byte enable bits +`define L2MEM_BYTEEN_WIDTH `L2CACHE_LINE_SIZE -// DRAM request tag bits -`define L2DRAM_TAG_WIDTH (`L2_ENABLE ? `L2DRAM_ADDR_WIDTH : (`XDRAM_TAG_WIDTH+`CLOG2(`NUM_CORES))) +// Memory request tag bits +`define L2MEM_TAG_WIDTH (`L2_ENABLE ? `L2MEM_ADDR_WIDTH : (`XMEM_TAG_WIDTH+`CLOG2(`NUM_CORES))) ////////////////////////// L3cache Configurable Knobs ///////////////////////// @@ -358,30 +358,30 @@ // Core request tag bits `define L3CORE_TAG_WIDTH (`L2CORE_TAG_WIDTH + `CLOG2(`NUM_CLUSTERS)) -// DRAM request data bits -`define L3DRAM_LINE_WIDTH (`L3CACHE_LINE_SIZE * 8) +// Memory request data bits +`define L3MEM_LINE_WIDTH (`L3CACHE_LINE_SIZE * 8) -// DRAM request address bits -`define L3DRAM_ADDR_WIDTH (32 - `CLOG2(`L3CACHE_LINE_SIZE)) +// Memory request address bits +`define L3MEM_ADDR_WIDTH (32 - `CLOG2(`L3CACHE_LINE_SIZE)) -// DRAM byte enable bits -`define L3DRAM_BYTEEN_WIDTH `L3CACHE_LINE_SIZE +// Memory byte enable bits +`define L3MEM_BYTEEN_WIDTH `L3CACHE_LINE_SIZE -// DRAM request tag bits -`define L3DRAM_TAG_WIDTH (`L3_ENABLE ? `L3DRAM_ADDR_WIDTH : (`L2DRAM_TAG_WIDTH+`CLOG2(`NUM_CLUSTERS))) +// Memory request tag bits +`define L3MEM_TAG_WIDTH (`L3_ENABLE ? `L3MEM_ADDR_WIDTH : (`L2MEM_TAG_WIDTH+`CLOG2(`NUM_CLUSTERS))) /////////////////////////////////////////////////////////////////////////////// -`define VX_DRAM_BYTEEN_WIDTH `L3DRAM_BYTEEN_WIDTH -`define VX_DRAM_ADDR_WIDTH `L3DRAM_ADDR_WIDTH -`define VX_DRAM_LINE_WIDTH `L3DRAM_LINE_WIDTH -`define VX_DRAM_TAG_WIDTH `L3DRAM_TAG_WIDTH +`define VX_MEM_BYTEEN_WIDTH `L3MEM_BYTEEN_WIDTH +`define VX_MEM_ADDR_WIDTH `L3MEM_ADDR_WIDTH +`define VX_MEM_LINE_WIDTH `L3MEM_LINE_WIDTH +`define VX_MEM_TAG_WIDTH `L3MEM_TAG_WIDTH `define VX_CORE_TAG_WIDTH `L3CORE_TAG_WIDTH `define VX_CSR_ID_WIDTH `LOG2UP(`NUM_CLUSTERS * `NUM_CORES) `define TO_FULL_ADDR(x) {x, (32-$bits(x))'(0)} -`define XDRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH+`CLOG2(2)) +`define XMEM_TAG_WIDTH (`DMEM_TAG_WIDTH+`CLOG2(2)) `include "VX_types.vh" diff --git a/hw/rtl/VX_mem_unit.v b/hw/rtl/VX_mem_unit.v index d3d89a62..6b09af6d 100644 --- a/hw/rtl/VX_mem_unit.v +++ b/hw/rtl/VX_mem_unit.v @@ -20,25 +20,25 @@ module VX_mem_unit # ( VX_icache_core_req_if icache_core_req_if, VX_icache_core_rsp_if icache_core_rsp_if, - // DRAM - VX_cache_dram_req_if dram_req_if, - VX_cache_dram_rsp_if dram_rsp_if + // Memory + VX_cache_mem_req_if mem_req_if, + VX_cache_mem_rsp_if mem_rsp_if ); `ifdef PERF_ENABLE VX_perf_cache_if perf_icache_if(), perf_dcache_if(), perf_smem_if(); `endif - VX_cache_dram_req_if #( - .DRAM_LINE_WIDTH (`DDRAM_LINE_WIDTH), - .DRAM_ADDR_WIDTH (`DDRAM_ADDR_WIDTH), - .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH) - ) dcache_dram_req_if(), icache_dram_req_if(); + VX_cache_mem_req_if #( + .MEM_LINE_WIDTH (`DMEM_LINE_WIDTH), + .MEM_ADDR_WIDTH (`DMEM_ADDR_WIDTH), + .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH) + ) dcache_mem_req_if(), icache_mem_req_if(); - VX_cache_dram_rsp_if #( - .DRAM_LINE_WIDTH (`DDRAM_LINE_WIDTH), - .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH) - ) dcache_dram_rsp_if(), icache_dram_rsp_if(); + VX_cache_mem_rsp_if #( + .MEM_LINE_WIDTH (`DMEM_LINE_WIDTH), + .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH) + ) dcache_mem_rsp_if(), icache_mem_rsp_if(); VX_dcache_core_req_if #( .NUM_REQS (`DNUM_REQUESTS), @@ -96,13 +96,13 @@ module VX_mem_unit # ( .NUM_REQS (1), .CREQ_SIZE (`ICREQ_SIZE), .MSHR_SIZE (`IMSHR_SIZE), - .DRSQ_SIZE (`IDRSQ_SIZE), - .DREQ_SIZE (`IDREQ_SIZE), + .MRSQ_SIZE (`IMRSQ_SIZE), + .MREQ_SIZE (`IMREQ_SIZE), .WRITE_ENABLE (0), .CORE_TAG_WIDTH (`ICORE_TAG_WIDTH), .CORE_TAG_ID_BITS (`ICORE_TAG_ID_BITS), - .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH), - .IN_ORDER_DRAM (!(`L2_ENABLE || `L3_ENABLE)) + .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH), + .IN_ORDER_MEM (!(`L2_ENABLE || `L3_ENABLE)) ) icache ( `SCOPE_BIND_VX_mem_unit_icache @@ -130,20 +130,20 @@ module VX_mem_unit # ( .perf_cache_if (perf_icache_if), `endif - // DRAM Req - .dram_req_valid (icache_dram_req_if.valid), - .dram_req_rw (icache_dram_req_if.rw), - .dram_req_byteen (icache_dram_req_if.byteen), - .dram_req_addr (icache_dram_req_if.addr), - .dram_req_data (icache_dram_req_if.data), - .dram_req_tag (icache_dram_req_if.tag), - .dram_req_ready (icache_dram_req_if.ready), + // Memory Request + .mem_req_valid (icache_mem_req_if.valid), + .mem_req_rw (icache_mem_req_if.rw), + .mem_req_byteen (icache_mem_req_if.byteen), + .mem_req_addr (icache_mem_req_if.addr), + .mem_req_data (icache_mem_req_if.data), + .mem_req_tag (icache_mem_req_if.tag), + .mem_req_ready (icache_mem_req_if.ready), - // DRAM response - .dram_rsp_valid (icache_dram_rsp_if.valid), - .dram_rsp_data (icache_dram_rsp_if.data), - .dram_rsp_tag (icache_dram_rsp_if.tag), - .dram_rsp_ready (icache_dram_rsp_if.ready) + // Memory response + .mem_rsp_valid (icache_mem_rsp_if.valid), + .mem_rsp_data (icache_mem_rsp_if.data), + .mem_rsp_tag (icache_mem_rsp_if.tag), + .mem_rsp_ready (icache_mem_rsp_if.ready) ); VX_cache #( @@ -156,13 +156,13 @@ module VX_mem_unit # ( .NUM_REQS (`DNUM_REQUESTS), .CREQ_SIZE (`DCREQ_SIZE), .MSHR_SIZE (`DMSHR_SIZE), - .DRSQ_SIZE (`DDRSQ_SIZE), - .DREQ_SIZE (`DDREQ_SIZE), + .MRSQ_SIZE (`DMRSQ_SIZE), + .MREQ_SIZE (`DMREQ_SIZE), .WRITE_ENABLE (1), .CORE_TAG_WIDTH (`DCORE_TAG_WIDTH), .CORE_TAG_ID_BITS (`DCORE_TAG_ID_BITS), - .DRAM_TAG_WIDTH (`DDRAM_TAG_WIDTH), - .IN_ORDER_DRAM (!(`L2_ENABLE || `L3_ENABLE)) + .MEM_TAG_WIDTH (`DMEM_TAG_WIDTH), + .IN_ORDER_MEM (!(`L2_ENABLE || `L3_ENABLE)) ) dcache ( `SCOPE_BIND_VX_mem_unit_dcache @@ -190,20 +190,20 @@ module VX_mem_unit # ( .perf_cache_if (perf_dcache_if), `endif - // DRAM request - .dram_req_valid (dcache_dram_req_if.valid), - .dram_req_rw (dcache_dram_req_if.rw), - .dram_req_byteen (dcache_dram_req_if.byteen), - .dram_req_addr (dcache_dram_req_if.addr), - .dram_req_data (dcache_dram_req_if.data), - .dram_req_tag (dcache_dram_req_if.tag), - .dram_req_ready (dcache_dram_req_if.ready), + // Memory request + .mem_req_valid (dcache_mem_req_if.valid), + .mem_req_rw (dcache_mem_req_if.rw), + .mem_req_byteen (dcache_mem_req_if.byteen), + .mem_req_addr (dcache_mem_req_if.addr), + .mem_req_data (dcache_mem_req_if.data), + .mem_req_tag (dcache_mem_req_if.tag), + .mem_req_ready (dcache_mem_req_if.ready), - // DRAM response - .dram_rsp_valid (dcache_dram_rsp_if.valid), - .dram_rsp_data (dcache_dram_rsp_if.data), - .dram_rsp_tag (dcache_dram_rsp_if.tag), - .dram_rsp_ready (dcache_dram_rsp_if.ready) + // Memory response + .mem_rsp_valid (dcache_mem_rsp_if.valid), + .mem_rsp_data (dcache_mem_rsp_if.data), + .mem_rsp_tag (dcache_mem_rsp_if.tag), + .mem_rsp_ready (dcache_mem_rsp_if.ready) ); if (`SM_ENABLE) begin @@ -254,45 +254,45 @@ module VX_mem_unit # ( VX_mem_arb #( .NUM_REQS (2), - .DATA_WIDTH (`DDRAM_LINE_WIDTH), - .ADDR_WIDTH (`DDRAM_ADDR_WIDTH), - .TAG_IN_WIDTH (`DDRAM_TAG_WIDTH), - .TAG_OUT_WIDTH (`XDRAM_TAG_WIDTH), + .DATA_WIDTH (`DMEM_LINE_WIDTH), + .ADDR_WIDTH (`DMEM_ADDR_WIDTH), + .TAG_IN_WIDTH (`DMEM_TAG_WIDTH), + .TAG_OUT_WIDTH (`XMEM_TAG_WIDTH), .BUFFERED_REQ (1), .BUFFERED_RSP (0) - ) dram_arb ( + ) mem_arb ( .clk (clk), .reset (reset), // Source request - .req_valid_in ({dcache_dram_req_if.valid, icache_dram_req_if.valid}), - .req_rw_in ({dcache_dram_req_if.rw, icache_dram_req_if.rw}), - .req_byteen_in ({dcache_dram_req_if.byteen, icache_dram_req_if.byteen}), - .req_addr_in ({dcache_dram_req_if.addr, icache_dram_req_if.addr}), - .req_data_in ({dcache_dram_req_if.data, icache_dram_req_if.data}), - .req_tag_in ({dcache_dram_req_if.tag, icache_dram_req_if.tag}), - .req_ready_in ({dcache_dram_req_if.ready, icache_dram_req_if.ready}), + .req_valid_in ({dcache_mem_req_if.valid, icache_mem_req_if.valid}), + .req_rw_in ({dcache_mem_req_if.rw, icache_mem_req_if.rw}), + .req_byteen_in ({dcache_mem_req_if.byteen, icache_mem_req_if.byteen}), + .req_addr_in ({dcache_mem_req_if.addr, icache_mem_req_if.addr}), + .req_data_in ({dcache_mem_req_if.data, icache_mem_req_if.data}), + .req_tag_in ({dcache_mem_req_if.tag, icache_mem_req_if.tag}), + .req_ready_in ({dcache_mem_req_if.ready, icache_mem_req_if.ready}), - // DRAM request - .req_valid_out (dram_req_if.valid), - .req_rw_out (dram_req_if.rw), - .req_byteen_out (dram_req_if.byteen), - .req_addr_out (dram_req_if.addr), - .req_data_out (dram_req_if.data), - .req_tag_out (dram_req_if.tag), - .req_ready_out (dram_req_if.ready), + // Memory request + .req_valid_out (mem_req_if.valid), + .req_rw_out (mem_req_if.rw), + .req_byteen_out (mem_req_if.byteen), + .req_addr_out (mem_req_if.addr), + .req_data_out (mem_req_if.data), + .req_tag_out (mem_req_if.tag), + .req_ready_out (mem_req_if.ready), // Source response - .rsp_valid_out ({dcache_dram_rsp_if.valid, icache_dram_rsp_if.valid}), - .rsp_data_out ({dcache_dram_rsp_if.data, icache_dram_rsp_if.data}), - .rsp_tag_out ({dcache_dram_rsp_if.tag, icache_dram_rsp_if.tag}), - .rsp_ready_out ({dcache_dram_rsp_if.ready, icache_dram_rsp_if.ready}), + .rsp_valid_out ({dcache_mem_rsp_if.valid, icache_mem_rsp_if.valid}), + .rsp_data_out ({dcache_mem_rsp_if.data, icache_mem_rsp_if.data}), + .rsp_tag_out ({dcache_mem_rsp_if.tag, icache_mem_rsp_if.tag}), + .rsp_ready_out ({dcache_mem_rsp_if.ready, icache_mem_rsp_if.ready}), - // DRAM response - .rsp_valid_in (dram_rsp_if.valid), - .rsp_tag_in (dram_rsp_if.tag), - .rsp_data_in (dram_rsp_if.data), - .rsp_ready_in (dram_rsp_if.ready) + // Memory response + .rsp_valid_in (mem_rsp_if.valid), + .rsp_tag_in (mem_rsp_if.tag), + .rsp_data_in (mem_rsp_if.data), + .rsp_ready_in (mem_rsp_if.ready) ); `ifdef PERF_ENABLE @@ -321,47 +321,47 @@ end else begin assign perf_memsys_if.smem_bank_stalls = 0; end - reg [`PERF_CTR_BITS-1:0] perf_dram_lat_per_cycle; + reg [`PERF_CTR_BITS-1:0] perf_mem_lat_per_cycle; always @(posedge clk) begin if (reset) begin - perf_dram_lat_per_cycle <= 0; + perf_mem_lat_per_cycle <= 0; end else begin - perf_dram_lat_per_cycle <= perf_dram_lat_per_cycle + - `PERF_CTR_BITS'($signed(2'((dram_req_if.valid && !dram_req_if.rw && dram_req_if.ready) && !(dram_rsp_if.valid && dram_rsp_if.ready)) - - 2'((dram_rsp_if.valid && dram_rsp_if.ready) && !(dram_req_if.valid && !dram_req_if.rw && dram_req_if.ready)))); + perf_mem_lat_per_cycle <= perf_mem_lat_per_cycle + + `PERF_CTR_BITS'($signed(2'((mem_req_if.valid && !mem_req_if.rw && mem_req_if.ready) && !(mem_rsp_if.valid && mem_rsp_if.ready)) - + 2'((mem_rsp_if.valid && mem_rsp_if.ready) && !(mem_req_if.valid && !mem_req_if.rw && mem_req_if.ready)))); end end - reg [`PERF_CTR_BITS-1:0] perf_dram_reads; - reg [`PERF_CTR_BITS-1:0] perf_dram_writes; - reg [`PERF_CTR_BITS-1:0] perf_dram_lat; - reg [`PERF_CTR_BITS-1:0] perf_dram_stalls; + reg [`PERF_CTR_BITS-1:0] perf_mem_reads; + reg [`PERF_CTR_BITS-1:0] perf_mem_writes; + reg [`PERF_CTR_BITS-1:0] perf_mem_lat; + reg [`PERF_CTR_BITS-1:0] perf_mem_stalls; always @(posedge clk) begin if (reset) begin - perf_dram_reads <= 0; - perf_dram_writes <= 0; - perf_dram_lat <= 0; - perf_dram_stalls <= 0; + perf_mem_reads <= 0; + perf_mem_writes <= 0; + perf_mem_lat <= 0; + perf_mem_stalls <= 0; end else begin - if (dram_req_if.valid && dram_req_if.ready && !dram_req_if.rw) begin - perf_dram_reads <= perf_dram_reads + `PERF_CTR_BITS'd1; + if (mem_req_if.valid && mem_req_if.ready && !mem_req_if.rw) begin + perf_mem_reads <= perf_mem_reads + `PERF_CTR_BITS'd1; end - if (dram_req_if.valid && dram_req_if.ready && dram_req_if.rw) begin - perf_dram_writes <= perf_dram_writes + `PERF_CTR_BITS'd1; + if (mem_req_if.valid && mem_req_if.ready && mem_req_if.rw) begin + perf_mem_writes <= perf_mem_writes + `PERF_CTR_BITS'd1; end - if (dram_req_if.valid && !dram_req_if.ready) begin - perf_dram_stalls <= perf_dram_stalls + `PERF_CTR_BITS'd1; + if (mem_req_if.valid && !mem_req_if.ready) begin + perf_mem_stalls <= perf_mem_stalls + `PERF_CTR_BITS'd1; end - perf_dram_lat <= perf_dram_lat + perf_dram_lat_per_cycle; + perf_mem_lat <= perf_mem_lat + perf_mem_lat_per_cycle; end end - assign perf_memsys_if.dram_reads = perf_dram_reads; - assign perf_memsys_if.dram_writes = perf_dram_writes; - assign perf_memsys_if.dram_latency = perf_dram_lat; - assign perf_memsys_if.dram_stalls = perf_dram_stalls; + assign perf_memsys_if.mem_reads = perf_mem_reads; + assign perf_memsys_if.mem_writes = perf_mem_writes; + assign perf_memsys_if.mem_latency = perf_mem_lat; + assign perf_memsys_if.mem_stalls = perf_mem_stalls; `endif endmodule diff --git a/hw/rtl/Vortex.v b/hw/rtl/Vortex.v index 2f2d34e9..15a1def4 100644 --- a/hw/rtl/Vortex.v +++ b/hw/rtl/Vortex.v @@ -7,20 +7,20 @@ module Vortex ( input wire clk, input wire reset, - // DRAM request - output wire dram_req_valid, - output wire dram_req_rw, - output wire [`VX_DRAM_BYTEEN_WIDTH-1:0] dram_req_byteen, - output wire [`VX_DRAM_ADDR_WIDTH-1:0] dram_req_addr, - output wire [`VX_DRAM_LINE_WIDTH-1:0] dram_req_data, - output wire [`VX_DRAM_TAG_WIDTH-1:0] dram_req_tag, - input wire dram_req_ready, + // Memory request + output wire mem_req_valid, + output wire mem_req_rw, + output wire [`VX_MEM_BYTEEN_WIDTH-1:0] mem_req_byteen, + output wire [`VX_MEM_ADDR_WIDTH-1:0] mem_req_addr, + output wire [`VX_MEM_LINE_WIDTH-1:0] mem_req_data, + output wire [`VX_MEM_TAG_WIDTH-1:0] mem_req_tag, + input wire mem_req_ready, - // DRAM response - input wire dram_rsp_valid, - input wire [`VX_DRAM_LINE_WIDTH-1:0] dram_rsp_data, - input wire [`VX_DRAM_TAG_WIDTH-1:0] dram_rsp_tag, - output wire dram_rsp_ready, + // Memory response + input wire mem_rsp_valid, + input wire [`VX_MEM_LINE_WIDTH-1:0] mem_rsp_data, + input wire [`VX_MEM_TAG_WIDTH-1:0] mem_rsp_tag, + output wire mem_rsp_ready, // CSR Request input wire csr_req_valid, @@ -40,18 +40,18 @@ module Vortex ( output wire ebreak ); - wire [`NUM_CLUSTERS-1:0] per_cluster_dram_req_valid; - wire [`NUM_CLUSTERS-1:0] per_cluster_dram_req_rw; - wire [`NUM_CLUSTERS-1:0][`L2DRAM_BYTEEN_WIDTH-1:0] per_cluster_dram_req_byteen; - wire [`NUM_CLUSTERS-1:0][`L2DRAM_ADDR_WIDTH-1:0] per_cluster_dram_req_addr; - wire [`NUM_CLUSTERS-1:0][`L2DRAM_LINE_WIDTH-1:0] per_cluster_dram_req_data; - wire [`NUM_CLUSTERS-1:0][`L2DRAM_TAG_WIDTH-1:0] per_cluster_dram_req_tag; - wire [`NUM_CLUSTERS-1:0] per_cluster_dram_req_ready; + wire [`NUM_CLUSTERS-1:0] per_cluster_mem_req_valid; + wire [`NUM_CLUSTERS-1:0] per_cluster_mem_req_rw; + wire [`NUM_CLUSTERS-1:0][`L2MEM_BYTEEN_WIDTH-1:0] per_cluster_mem_req_byteen; + wire [`NUM_CLUSTERS-1:0][`L2MEM_ADDR_WIDTH-1:0] per_cluster_mem_req_addr; + wire [`NUM_CLUSTERS-1:0][`L2MEM_LINE_WIDTH-1:0] per_cluster_mem_req_data; + wire [`NUM_CLUSTERS-1:0][`L2MEM_TAG_WIDTH-1:0] per_cluster_mem_req_tag; + wire [`NUM_CLUSTERS-1:0] per_cluster_mem_req_ready; - wire [`NUM_CLUSTERS-1:0] per_cluster_dram_rsp_valid; - wire [`NUM_CLUSTERS-1:0][`L2DRAM_LINE_WIDTH-1:0] per_cluster_dram_rsp_data; - wire [`NUM_CLUSTERS-1:0][`L2DRAM_TAG_WIDTH-1:0] per_cluster_dram_rsp_tag; - wire [`NUM_CLUSTERS-1:0] per_cluster_dram_rsp_ready; + wire [`NUM_CLUSTERS-1:0] per_cluster_mem_rsp_valid; + wire [`NUM_CLUSTERS-1:0][`L2MEM_LINE_WIDTH-1:0] per_cluster_mem_rsp_data; + wire [`NUM_CLUSTERS-1:0][`L2MEM_TAG_WIDTH-1:0] per_cluster_mem_rsp_tag; + wire [`NUM_CLUSTERS-1:0] per_cluster_mem_rsp_ready; wire [`NUM_CLUSTERS-1:0] per_cluster_csr_req_valid; wire [`NUM_CLUSTERS-1:0][11:0] per_cluster_csr_req_addr; @@ -88,18 +88,18 @@ module Vortex ( .clk (clk), .reset (cluster_reset), - .dram_req_valid (per_cluster_dram_req_valid [i]), - .dram_req_rw (per_cluster_dram_req_rw [i]), - .dram_req_byteen(per_cluster_dram_req_byteen[i]), - .dram_req_addr (per_cluster_dram_req_addr [i]), - .dram_req_data (per_cluster_dram_req_data [i]), - .dram_req_tag (per_cluster_dram_req_tag [i]), - .dram_req_ready (per_cluster_dram_req_ready [i]), + .mem_req_valid (per_cluster_mem_req_valid [i]), + .mem_req_rw (per_cluster_mem_req_rw [i]), + .mem_req_byteen (per_cluster_mem_req_byteen[i]), + .mem_req_addr (per_cluster_mem_req_addr [i]), + .mem_req_data (per_cluster_mem_req_data [i]), + .mem_req_tag (per_cluster_mem_req_tag [i]), + .mem_req_ready (per_cluster_mem_req_ready [i]), - .dram_rsp_valid (per_cluster_dram_rsp_valid [i]), - .dram_rsp_data (per_cluster_dram_rsp_data [i]), - .dram_rsp_tag (per_cluster_dram_rsp_tag [i]), - .dram_rsp_ready (per_cluster_dram_rsp_ready [i]), + .mem_rsp_valid (per_cluster_mem_rsp_valid [i]), + .mem_rsp_data (per_cluster_mem_rsp_data [i]), + .mem_rsp_tag (per_cluster_mem_rsp_tag [i]), + .mem_rsp_ready (per_cluster_mem_rsp_ready [i]), .csr_req_valid (per_cluster_csr_req_valid [i]), .csr_req_coreid (csr_core_id), @@ -171,12 +171,12 @@ module Vortex ( .NUM_REQS (`NUM_CLUSTERS), .CREQ_SIZE (`L3CREQ_SIZE), .MSHR_SIZE (`L3MSHR_SIZE), - .DRSQ_SIZE (`L3DRSQ_SIZE), - .DREQ_SIZE (`L3DREQ_SIZE), + .MRSQ_SIZE (`L3MRSQ_SIZE), + .MREQ_SIZE (`L3MREQ_SIZE), .WRITE_ENABLE (1), - .CORE_TAG_WIDTH (`L2DRAM_TAG_WIDTH), + .CORE_TAG_WIDTH (`L2MEM_TAG_WIDTH), .CORE_TAG_ID_BITS (0), - .DRAM_TAG_WIDTH (`L3DRAM_TAG_WIDTH) + .MEM_TAG_WIDTH (`L3MEM_TAG_WIDTH) ) l3cache ( `SCOPE_BIND_Vortex_l3cache @@ -190,105 +190,105 @@ module Vortex ( `endif // Core request - .core_req_valid (per_cluster_dram_req_valid), - .core_req_rw (per_cluster_dram_req_rw), - .core_req_byteen (per_cluster_dram_req_byteen), - .core_req_addr (per_cluster_dram_req_addr), - .core_req_data (per_cluster_dram_req_data), - .core_req_tag (per_cluster_dram_req_tag), - .core_req_ready (per_cluster_dram_req_ready), + .core_req_valid (per_cluster_mem_req_valid), + .core_req_rw (per_cluster_mem_req_rw), + .core_req_byteen (per_cluster_mem_req_byteen), + .core_req_addr (per_cluster_mem_req_addr), + .core_req_data (per_cluster_mem_req_data), + .core_req_tag (per_cluster_mem_req_tag), + .core_req_ready (per_cluster_mem_req_ready), // Core response - .core_rsp_valid (per_cluster_dram_rsp_valid), - .core_rsp_data (per_cluster_dram_rsp_data), - .core_rsp_tag (per_cluster_dram_rsp_tag), - .core_rsp_ready (per_cluster_dram_rsp_ready), + .core_rsp_valid (per_cluster_mem_rsp_valid), + .core_rsp_data (per_cluster_mem_rsp_data), + .core_rsp_tag (per_cluster_mem_rsp_tag), + .core_rsp_ready (per_cluster_mem_rsp_ready), - // DRAM request - .dram_req_valid (dram_req_valid), - .dram_req_rw (dram_req_rw), - .dram_req_byteen (dram_req_byteen), - .dram_req_addr (dram_req_addr), - .dram_req_data (dram_req_data), - .dram_req_tag (dram_req_tag), - .dram_req_ready (dram_req_ready), + // Memory request + .mem_req_valid (mem_req_valid), + .mem_req_rw (mem_req_rw), + .mem_req_byteen (mem_req_byteen), + .mem_req_addr (mem_req_addr), + .mem_req_data (mem_req_data), + .mem_req_tag (mem_req_tag), + .mem_req_ready (mem_req_ready), - // DRAM response - .dram_rsp_valid (dram_rsp_valid), - .dram_rsp_data (dram_rsp_data), - .dram_rsp_tag (dram_rsp_tag), - .dram_rsp_ready (dram_rsp_ready) + // Memory response + .mem_rsp_valid (mem_rsp_valid), + .mem_rsp_data (mem_rsp_data), + .mem_rsp_tag (mem_rsp_tag), + .mem_rsp_ready (mem_rsp_ready) ); end else begin VX_mem_arb #( - .NUM_REQS (`NUM_CLUSTERS), - .DATA_WIDTH (`L3DRAM_LINE_WIDTH), - .TAG_IN_WIDTH (`L2DRAM_TAG_WIDTH), - .TAG_OUT_WIDTH (`L3DRAM_TAG_WIDTH), - .BUFFERED_REQ (1), - .BUFFERED_RSP (1) - ) dram_arb ( + .NUM_REQS (`NUM_CLUSTERS), + .DATA_WIDTH (`L3MEM_LINE_WIDTH), + .TAG_IN_WIDTH (`L2MEM_TAG_WIDTH), + .TAG_OUT_WIDTH (`L3MEM_TAG_WIDTH), + .BUFFERED_REQ (1), + .BUFFERED_RSP (1) + ) mem_arb ( .clk (clk), .reset (reset), // Core request - .req_valid_in (per_cluster_dram_req_valid), - .req_rw_in (per_cluster_dram_req_rw), - .req_byteen_in (per_cluster_dram_req_byteen), - .req_addr_in (per_cluster_dram_req_addr), - .req_data_in (per_cluster_dram_req_data), - .req_tag_in (per_cluster_dram_req_tag), - .req_ready_in (per_cluster_dram_req_ready), + .req_valid_in (per_cluster_mem_req_valid), + .req_rw_in (per_cluster_mem_req_rw), + .req_byteen_in (per_cluster_mem_req_byteen), + .req_addr_in (per_cluster_mem_req_addr), + .req_data_in (per_cluster_mem_req_data), + .req_tag_in (per_cluster_mem_req_tag), + .req_ready_in (per_cluster_mem_req_ready), - // DRAM request - .req_valid_out (dram_req_valid), - .req_rw_out (dram_req_rw), - .req_byteen_out (dram_req_byteen), - .req_addr_out (dram_req_addr), - .req_data_out (dram_req_data), - .req_tag_out (dram_req_tag), - .req_ready_out (dram_req_ready), + // Memory request + .req_valid_out (mem_req_valid), + .req_rw_out (mem_req_rw), + .req_byteen_out (mem_req_byteen), + .req_addr_out (mem_req_addr), + .req_data_out (mem_req_data), + .req_tag_out (mem_req_tag), + .req_ready_out (mem_req_ready), // Core response - .rsp_valid_out (per_cluster_dram_rsp_valid), - .rsp_data_out (per_cluster_dram_rsp_data), - .rsp_tag_out (per_cluster_dram_rsp_tag), - .rsp_ready_out (per_cluster_dram_rsp_ready), + .rsp_valid_out (per_cluster_mem_rsp_valid), + .rsp_data_out (per_cluster_mem_rsp_data), + .rsp_tag_out (per_cluster_mem_rsp_tag), + .rsp_ready_out (per_cluster_mem_rsp_ready), - // DRAM response - .rsp_valid_in (dram_rsp_valid), - .rsp_tag_in (dram_rsp_tag), - .rsp_data_in (dram_rsp_data), - .rsp_ready_in (dram_rsp_ready) + // Memory response + .rsp_valid_in (mem_rsp_valid), + .rsp_tag_in (mem_rsp_tag), + .rsp_data_in (mem_rsp_data), + .rsp_ready_in (mem_rsp_ready) ); end `SCOPE_ASSIGN (reset, reset); - `SCOPE_ASSIGN (dram_req_fire, dram_req_valid && dram_req_ready); - `SCOPE_ASSIGN (dram_req_addr, `TO_FULL_ADDR(dram_req_addr)); - `SCOPE_ASSIGN (dram_req_rw, dram_req_rw); - `SCOPE_ASSIGN (dram_req_byteen, dram_req_byteen); - `SCOPE_ASSIGN (dram_req_data, dram_req_data); - `SCOPE_ASSIGN (dram_req_tag, dram_req_tag); - `SCOPE_ASSIGN (dram_rsp_fire, dram_rsp_valid && dram_rsp_ready); - `SCOPE_ASSIGN (dram_rsp_data, dram_rsp_data); - `SCOPE_ASSIGN (dram_rsp_tag, dram_rsp_tag); + `SCOPE_ASSIGN (mem_req_fire, mem_req_valid && mem_req_ready); + `SCOPE_ASSIGN (mem_req_addr, `TO_FULL_ADDR(mem_req_addr)); + `SCOPE_ASSIGN (mem_req_rw, mem_req_rw); + `SCOPE_ASSIGN (mem_req_byteen, mem_req_byteen); + `SCOPE_ASSIGN (mem_req_data, mem_req_data); + `SCOPE_ASSIGN (mem_req_tag, mem_req_tag); + `SCOPE_ASSIGN (mem_rsp_fire, mem_rsp_valid && mem_rsp_ready); + `SCOPE_ASSIGN (mem_rsp_data, mem_rsp_data); + `SCOPE_ASSIGN (mem_rsp_tag, mem_rsp_tag); `SCOPE_ASSIGN (busy, busy); -`ifdef DBG_PRINT_DRAM +`ifdef DBG_PRINT_MEM always @(posedge clk) begin - if (dram_req_valid && dram_req_ready) begin - if (dram_req_rw) - $display("%t: DRAM Wr Req: addr=%0h, tag=%0h, byteen=%0h data=%0h", $time, `TO_FULL_ADDR(dram_req_addr), dram_req_tag, dram_req_byteen, dram_req_data); + if (mem_req_valid && mem_req_ready) begin + if (mem_req_rw) + $display("%t: MEM Wr Req: addr=%0h, tag=%0h, byteen=%0h data=%0h", $time, `TO_FULL_ADDR(mem_req_addr), mem_req_tag, mem_req_byteen, mem_req_data); else - $display("%t: DRAM Rd Req: addr=%0h, tag=%0h, byteen=%0h", $time, `TO_FULL_ADDR(dram_req_addr), dram_req_tag, dram_req_byteen); + $display("%t: MEM Rd Req: addr=%0h, tag=%0h, byteen=%0h", $time, `TO_FULL_ADDR(mem_req_addr), mem_req_tag, mem_req_byteen); end - if (dram_rsp_valid && dram_rsp_ready) begin - $display("%t: DRAM Rsp: tag=%0h, data=%0h", $time, dram_rsp_tag, dram_rsp_data); + if (mem_rsp_valid && mem_rsp_ready) begin + $display("%t: MEM Rsp: tag=%0h, data=%0h", $time, mem_rsp_tag, mem_rsp_data); end end `endif diff --git a/hw/rtl/afu/VX_avs_wrapper.v b/hw/rtl/afu/VX_avs_wrapper.v index 36f0a986..361bd2fa 100644 --- a/hw/rtl/afu/VX_avs_wrapper.v +++ b/hw/rtl/afu/VX_avs_wrapper.v @@ -15,20 +15,20 @@ module VX_avs_wrapper #( input wire clk, input wire reset, - // DRAM request - input wire dram_req_valid, - input wire dram_req_rw, - input wire [AVS_BYTEENW-1:0] dram_req_byteen, - input wire [AVS_ADDRW-1:0] dram_req_addr, - input wire [AVS_DATAW-1:0] dram_req_data, - input wire [REQ_TAGW-1:0] dram_req_tag, - output wire dram_req_ready, + // Memory request + input wire mem_req_valid, + input wire mem_req_rw, + input wire [AVS_BYTEENW-1:0] mem_req_byteen, + input wire [AVS_ADDRW-1:0] mem_req_addr, + input wire [AVS_DATAW-1:0] mem_req_data, + input wire [REQ_TAGW-1:0] mem_req_tag, + output wire mem_req_ready, - // DRAM response - output wire dram_rsp_valid, - output wire [AVS_DATAW-1:0] dram_rsp_data, - output wire [REQ_TAGW-1:0] dram_rsp_tag, - input wire dram_rsp_ready, + // Memory response + output wire mem_rsp_valid, + output wire [AVS_DATAW-1:0] mem_rsp_data, + output wire [REQ_TAGW-1:0] mem_rsp_tag, + input wire mem_rsp_ready, // AVS bus output wire [AVS_DATAW-1:0] avs_writedata, @@ -45,8 +45,8 @@ module VX_avs_wrapper #( reg [AVS_BANKS_BITS-1:0] avs_bankselect_r; reg [AVS_BURSTW-1:0] avs_burstcount_r; - wire avs_reqq_push = dram_req_valid && dram_req_ready && !dram_req_rw; - wire avs_reqq_pop = dram_rsp_valid && dram_rsp_ready; + wire avs_reqq_push = mem_req_valid && mem_req_ready && !mem_req_rw; + wire avs_reqq_pop = mem_rsp_valid && mem_rsp_ready; wire avs_rspq_push = avs_readdatavalid; wire avs_rspq_pop = avs_reqq_pop; @@ -80,8 +80,8 @@ module VX_avs_wrapper #( .reset (reset), .push (avs_reqq_push), .pop (avs_reqq_pop), - .data_in (dram_req_tag), - .data_out (dram_rsp_tag), + .data_in (mem_req_tag), + .data_out (mem_rsp_tag), `UNUSED_PIN (empty), `UNUSED_PIN (full), `UNUSED_PIN (alm_empty), @@ -98,7 +98,7 @@ module VX_avs_wrapper #( .push (avs_rspq_push), .pop (avs_rspq_pop), .data_in (avs_readdata), - .data_out (dram_rsp_data), + .data_out (mem_rsp_data), .empty (avs_rspq_empty), `UNUSED_PIN (full), `UNUSED_PIN (alm_empty), @@ -106,28 +106,28 @@ module VX_avs_wrapper #( `UNUSED_PIN (size) ); - assign avs_read = dram_req_valid && !dram_req_rw && !rsp_queue_going_full; - assign avs_write = dram_req_valid && dram_req_rw && !rsp_queue_going_full; - assign avs_address = dram_req_addr; - assign avs_byteenable = dram_req_byteen; - assign avs_writedata = dram_req_data; + assign avs_read = mem_req_valid && !mem_req_rw && !rsp_queue_going_full; + assign avs_write = mem_req_valid && mem_req_rw && !rsp_queue_going_full; + assign avs_address = mem_req_addr; + assign avs_byteenable = mem_req_byteen; + assign avs_writedata = mem_req_data; assign avs_burstcount = avs_burstcount_r; assign avs_bankselect = avs_bankselect_r; - assign dram_req_ready = !avs_waitrequest && !rsp_queue_going_full; + assign mem_req_ready = !avs_waitrequest && !rsp_queue_going_full; - assign dram_rsp_valid = !avs_rspq_empty; + assign mem_rsp_valid = !avs_rspq_empty; `ifdef DBG_PRINT_AVS always @(posedge clk) begin - if (dram_req_valid && dram_req_ready) begin - if (dram_req_rw) - $display("%t: AVS Wr Req: addr=%0h, byteen=%0h, tag=%0h, data=%0h", $time, `TO_FULL_ADDR(dram_req_addr), dram_req_byteen, dram_req_tag, dram_req_data); + if (mem_req_valid && mem_req_ready) begin + if (mem_req_rw) + $display("%t: AVS Wr Req: addr=%0h, byteen=%0h, tag=%0h, data=%0h", $time, `TO_FULL_ADDR(mem_req_addr), mem_req_byteen, mem_req_tag, mem_req_data); else - $display("%t: AVS Rd Req: addr=%0h, byteen=%0h, tag=%0h, pending=%0d", $time, `TO_FULL_ADDR(dram_req_addr), dram_req_byteen, dram_req_tag, rsp_queue_size); + $display("%t: AVS Rd Req: addr=%0h, byteen=%0h, tag=%0h, pending=%0d", $time, `TO_FULL_ADDR(mem_req_addr), mem_req_byteen, mem_req_tag, rsp_queue_size); end - if (dram_rsp_valid && dram_rsp_ready) begin - $display("%t: AVS Rd Rsp: tag=%0h, data=%0h, pending=%0d", $time, dram_rsp_tag, dram_rsp_data, rsp_queue_size); + if (mem_rsp_valid && mem_rsp_ready) begin + $display("%t: AVS Rd Rsp: tag=%0h, data=%0h, pending=%0d", $time, mem_rsp_tag, mem_rsp_data, rsp_queue_size); end end `endif diff --git a/hw/rtl/afu/VX_cci_to_mem.v b/hw/rtl/afu/VX_cci_to_mem.v index 71eb19a7..fe003b47 100644 --- a/hw/rtl/afu/VX_cci_to_mem.v +++ b/hw/rtl/afu/VX_cci_to_mem.v @@ -11,30 +11,30 @@ module VX_cci_to_mem #( input wire clk, input wire reset, - input wire dram_req_valid_in, - input wire [CCI_ADDRW-1:0] dram_req_addr_in, - input wire dram_req_rw_in, - input wire [CCI_DATAW-1:0] dram_req_data_in, - input wire [TAG_WIDTH-1:0] dram_req_tag_in, - output wire dram_req_ready_in, + input wire mem_req_valid_in, + input wire [CCI_ADDRW-1:0] mem_req_addr_in, + input wire mem_req_rw_in, + input wire [CCI_DATAW-1:0] mem_req_data_in, + input wire [TAG_WIDTH-1:0] mem_req_tag_in, + output wire mem_req_ready_in, - output wire dram_req_valid_out, - output wire [AVS_ADDRW-1:0] dram_req_addr_out, - output wire dram_req_rw_out, - output wire [AVS_BYTEENW-1:0] dram_req_byteen_out, - output wire [AVS_DATAW-1:0] dram_req_data_out, - output wire [TAG_WIDTH-1:0] dram_req_tag_out, - input wire dram_req_ready_out, + output wire mem_req_valid_out, + output wire [AVS_ADDRW-1:0] mem_req_addr_out, + output wire mem_req_rw_out, + output wire [AVS_BYTEENW-1:0] mem_req_byteen_out, + output wire [AVS_DATAW-1:0] mem_req_data_out, + output wire [TAG_WIDTH-1:0] mem_req_tag_out, + input wire mem_req_ready_out, - input wire dram_rsp_valid_in, - input wire [AVS_DATAW-1:0] dram_rsp_data_in, - input wire [TAG_WIDTH-1:0] dram_rsp_tag_in, - output wire dram_rsp_ready_in, + input wire mem_rsp_valid_in, + input wire [AVS_DATAW-1:0] mem_rsp_data_in, + input wire [TAG_WIDTH-1:0] mem_rsp_tag_in, + output wire mem_rsp_ready_in, - output wire dram_rsp_valid_out, - output wire [CCI_DATAW-1:0] dram_rsp_data_out, - output wire [TAG_WIDTH-1:0] dram_rsp_tag_out, - input wire dram_rsp_ready_out + output wire mem_rsp_valid_out, + output wire [CCI_DATAW-1:0] mem_rsp_data_out, + output wire [TAG_WIDTH-1:0] mem_rsp_tag_out, + input wire mem_rsp_ready_out ); localparam N = AVS_ADDRW - CCI_ADDRW; @@ -44,35 +44,35 @@ module VX_cci_to_mem #( `UNUSED_VAR (clk) `UNUSED_VAR (reset) - assign dram_req_valid_out = dram_req_valid_in; - assign dram_req_addr_out = dram_req_addr_in; - assign dram_req_rw_out = dram_req_rw_in; - assign dram_req_byteen_out = {AVS_BYTEENW{1'b1}}; - assign dram_req_data_out = dram_req_data_in; - assign dram_req_tag_out = dram_req_tag_in; - assign dram_req_ready_in = dram_req_ready_out; + assign mem_req_valid_out = mem_req_valid_in; + assign mem_req_addr_out = mem_req_addr_in; + assign mem_req_rw_out = mem_req_rw_in; + assign mem_req_byteen_out = {AVS_BYTEENW{1'b1}}; + assign mem_req_data_out = mem_req_data_in; + assign mem_req_tag_out = mem_req_tag_in; + assign mem_req_ready_in = mem_req_ready_out; - assign dram_rsp_valid_out = dram_rsp_valid_in; - assign dram_rsp_data_out = dram_rsp_data_in; - assign dram_rsp_tag_out = dram_rsp_tag_in; - assign dram_rsp_ready_in = dram_rsp_ready_out; + assign mem_rsp_valid_out = mem_rsp_valid_in; + assign mem_rsp_data_out = mem_rsp_data_in; + assign mem_rsp_tag_out = mem_rsp_tag_in; + assign mem_rsp_ready_in = mem_rsp_ready_out; end else begin reg [N-1:0] req_ctr, rsp_ctr; - wire [(2**N)-1:0][AVS_DATAW-1:0] dram_req_data_w_in; + wire [(2**N)-1:0][AVS_DATAW-1:0] mem_req_data_w_in; - reg [(2**N)-1:0][AVS_DATAW-1:0] dram_rsp_data_r_out, dram_rsp_data_n_out; + reg [(2**N)-1:0][AVS_DATAW-1:0] mem_rsp_data_r_out, mem_rsp_data_n_out; - wire dram_req_fire_out = dram_req_valid_out && dram_req_ready_out; - wire dram_rsp_fire_in = dram_rsp_valid_in && dram_rsp_ready_in; + wire mem_req_fire_out = mem_req_valid_out && mem_req_ready_out; + wire mem_rsp_fire_in = mem_rsp_valid_in && mem_rsp_ready_in; - assign dram_req_data_w_in = dram_req_data_in; + assign mem_req_data_w_in = mem_req_data_in; always @(*) begin - dram_rsp_data_n_out = dram_rsp_data_r_out; - dram_rsp_data_n_out[rsp_ctr] = dram_rsp_data_in; + mem_rsp_data_n_out = mem_rsp_data_r_out; + mem_rsp_data_n_out[rsp_ctr] = mem_rsp_data_in; end always @(posedge clk) begin @@ -80,28 +80,28 @@ module VX_cci_to_mem #( req_ctr <= 0; rsp_ctr <= 0; end else begin - if (dram_req_fire_out) begin + if (mem_req_fire_out) begin req_ctr <= req_ctr + 1; end - if (dram_rsp_fire_in) begin + if (mem_rsp_fire_in) begin rsp_ctr <= rsp_ctr + 1; - dram_rsp_data_r_out <= dram_rsp_data_n_out; + mem_rsp_data_r_out <= mem_rsp_data_n_out; end end end - assign dram_req_valid_out = dram_req_valid_in; - assign dram_req_addr_out = {dram_req_addr_in, req_ctr}; - assign dram_req_rw_out = dram_req_rw_in; - assign dram_req_byteen_out = {AVS_BYTEENW{1'b1}}; - assign dram_req_data_out = dram_req_data_w_in[req_ctr]; - assign dram_req_tag_out = dram_req_tag_in; - assign dram_req_ready_in = dram_req_ready_out && (req_ctr == (2**N-1)); + assign mem_req_valid_out = mem_req_valid_in; + assign mem_req_addr_out = {mem_req_addr_in, req_ctr}; + assign mem_req_rw_out = mem_req_rw_in; + assign mem_req_byteen_out = {AVS_BYTEENW{1'b1}}; + assign mem_req_data_out = mem_req_data_w_in[req_ctr]; + assign mem_req_tag_out = mem_req_tag_in; + assign mem_req_ready_in = mem_req_ready_out && (req_ctr == (2**N-1)); - assign dram_rsp_valid_out = dram_rsp_valid_in && (rsp_ctr == (2**N-1)); - assign dram_rsp_data_out = dram_rsp_data_n_out; - assign dram_rsp_tag_out = dram_rsp_tag_in; - assign dram_rsp_ready_in = dram_rsp_ready_out; + assign mem_rsp_valid_out = mem_rsp_valid_in && (rsp_ctr == (2**N-1)); + assign mem_rsp_data_out = mem_rsp_data_n_out; + assign mem_rsp_tag_out = mem_rsp_tag_in; + assign mem_rsp_ready_in = mem_rsp_ready_out; end endmodule \ No newline at end of file diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 0f99530b..61c4cc8d 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -40,19 +40,19 @@ module vortex_afu #( localparam RESET_DELAY = 3; -localparam DRAM_LINE_WIDTH = $bits(t_local_mem_data); -localparam DRAM_ADDR_WIDTH = $bits(t_local_mem_addr); -localparam DRAM_BURST_CTRW = $bits(t_local_mem_burst_cnt); -localparam DRAM_LINE_LW = $clog2(DRAM_LINE_WIDTH); +localparam MEM_LINE_WIDTH = $bits(t_local_mem_data); +localparam MEM_ADDR_WIDTH = $bits(t_local_mem_addr); +localparam MEM_BURST_CTRW = $bits(t_local_mem_burst_cnt); +localparam MEM_LINE_LW = $clog2(MEM_LINE_WIDTH); localparam CCI_LINE_WIDTH = $bits(t_ccip_clData); localparam CCI_ADDR_WIDTH = 32 - $clog2(CCI_LINE_WIDTH / 8); -localparam VX_DRAM_LINE_LW = $clog2(`VX_DRAM_LINE_WIDTH); -localparam VX_DRAM_LINE_IDX = (DRAM_LINE_LW - VX_DRAM_LINE_LW); +localparam VX_MEM_LINE_LW = $clog2(`VX_MEM_LINE_WIDTH); +localparam VX_MEM_LINE_IDX = (MEM_LINE_LW - VX_MEM_LINE_LW); localparam AVS_RD_QUEUE_SIZE = 16; -localparam AVS_REQ_TAGW = `VX_DRAM_TAG_WIDTH + VX_DRAM_LINE_IDX; +localparam AVS_REQ_TAGW = `VX_MEM_TAG_WIDTH + VX_MEM_LINE_IDX; localparam CCI_RD_WINDOW_SIZE = 8; localparam CCI_RD_QUEUE_SIZE = 2 * CCI_RD_WINDOW_SIZE; @@ -104,18 +104,18 @@ reg [STATE_WIDTH-1:0] state; // Vortex ports /////////////////////////////////////////////////////////////// -wire vx_dram_req_valid; -wire vx_dram_req_rw; -wire [`VX_DRAM_BYTEEN_WIDTH-1:0] vx_dram_req_byteen; -wire [`VX_DRAM_ADDR_WIDTH-1:0] vx_dram_req_addr; -wire [`VX_DRAM_LINE_WIDTH-1:0] vx_dram_req_data; -wire [`VX_DRAM_TAG_WIDTH-1:0] vx_dram_req_tag; -wire vx_dram_req_ready; +wire vx_mem_req_valid; +wire vx_mem_req_rw; +wire [`VX_MEM_BYTEEN_WIDTH-1:0] vx_mem_req_byteen; +wire [`VX_MEM_ADDR_WIDTH-1:0] vx_mem_req_addr; +wire [`VX_MEM_LINE_WIDTH-1:0] vx_mem_req_data; +wire [`VX_MEM_TAG_WIDTH-1:0] vx_mem_req_tag; +wire vx_mem_req_ready; -wire vx_dram_rsp_valid; -wire [`VX_DRAM_LINE_WIDTH-1:0] vx_dram_rsp_data; -wire [`VX_DRAM_TAG_WIDTH-1:0] vx_dram_rsp_tag; -wire vx_dram_rsp_ready; +wire vx_mem_rsp_valid; +wire [`VX_MEM_LINE_WIDTH-1:0] vx_mem_rsp_data; +wire [`VX_MEM_TAG_WIDTH-1:0] vx_mem_rsp_tag; +wire vx_mem_rsp_ready; wire vx_csr_io_req_valid; wire [`VX_CSR_ID_WIDTH-1:0] vx_csr_io_req_coreid; @@ -131,7 +131,7 @@ wire vx_csr_io_rsp_ready; wire vx_busy; reg vx_reset; -reg vx_dram_en; +reg vx_mem_en; // CMD variables ////////////////////////////////////////////////////////////// @@ -343,7 +343,7 @@ always @(posedge clk) begin if (reset) begin state <= STATE_IDLE; vx_reset <= 0; - vx_dram_en <= 0; + vx_mem_en <= 0; end else begin case (state) STATE_IDLE: begin @@ -407,14 +407,14 @@ always @(posedge clk) begin // vortex reset cycles if (vx_reset_ctr == $bits(vx_reset_ctr)'(RESET_DELAY)) begin vx_reset <= 0; - vx_dram_en <= 1; + vx_mem_en <= 1; state <= STATE_RUN; end end STATE_RUN: begin if (cmd_run_done) begin - vx_dram_en <= 0; + vx_mem_en <= 0; state <= STATE_IDLE; `ifdef DBG_PRINT_OPAE $display("%t: STATE IDLE", $time); @@ -450,164 +450,164 @@ end // AVS Controller ///////////////////////////////////////////////////////////// -wire dram_req_valid; -wire dram_req_rw; -t_local_mem_byte_mask dram_req_byteen; -t_local_mem_addr dram_req_addr; -t_local_mem_data dram_req_data; -wire [AVS_REQ_TAGW:0] dram_req_tag; -wire dram_req_ready; +wire mem_req_valid; +wire mem_req_rw; +t_local_mem_byte_mask mem_req_byteen; +t_local_mem_addr mem_req_addr; +t_local_mem_data mem_req_data; +wire [AVS_REQ_TAGW:0] mem_req_tag; +wire mem_req_ready; -wire dram_rsp_valid; -t_local_mem_data dram_rsp_data; -wire [AVS_REQ_TAGW:0] dram_rsp_tag; -wire dram_rsp_ready; +wire mem_rsp_valid; +t_local_mem_data mem_rsp_data; +wire [AVS_REQ_TAGW:0] mem_rsp_tag; +wire mem_rsp_ready; -wire cci_dram_req_tmp_valid; -wire cci_dram_req_tmp_rw; -t_local_mem_byte_mask cci_dram_req_tmp_byteen; -t_local_mem_addr cci_dram_req_tmp_addr; -t_local_mem_data cci_dram_req_tmp_data; -wire [AVS_REQ_TAGW-1:0] cci_dram_req_tmp_tag; -wire cci_dram_req_tmp_ready; +wire cci_mem_req_tmp_valid; +wire cci_mem_req_tmp_rw; +t_local_mem_byte_mask cci_mem_req_tmp_byteen; +t_local_mem_addr cci_mem_req_tmp_addr; +t_local_mem_data cci_mem_req_tmp_data; +wire [AVS_REQ_TAGW-1:0] cci_mem_req_tmp_tag; +wire cci_mem_req_tmp_ready; -wire cci_dram_rsp_tmp_valid; -t_local_mem_data cci_dram_rsp_tmp_data; -wire [AVS_REQ_TAGW-1:0] cci_dram_rsp_tmp_tag; -wire cci_dram_rsp_tmp_ready; +wire cci_mem_rsp_tmp_valid; +t_local_mem_data cci_mem_rsp_tmp_data; +wire [AVS_REQ_TAGW-1:0] cci_mem_rsp_tmp_tag; +wire cci_mem_rsp_tmp_ready; -wire vx_dram_req_valid_qual; -t_local_mem_addr vx_dram_req_addr_qual; -t_local_mem_byte_mask vx_dram_req_byteen_qual; -t_local_mem_data vx_dram_req_data_qual; -wire [AVS_REQ_TAGW-1:0] vx_dram_req_tag_qual; +wire vx_mem_req_valid_qual; +t_local_mem_addr vx_mem_req_addr_qual; +t_local_mem_byte_mask vx_mem_req_byteen_qual; +t_local_mem_data vx_mem_req_data_qual; +wire [AVS_REQ_TAGW-1:0] vx_mem_req_tag_qual; -wire [(1 << VX_DRAM_LINE_IDX)-1:0][`VX_DRAM_LINE_WIDTH-1:0] vx_dram_rsp_data_unqual; -wire [AVS_REQ_TAGW-1:0] vx_dram_rsp_tag_unqual; +wire [(1 << VX_MEM_LINE_IDX)-1:0][`VX_MEM_LINE_WIDTH-1:0] vx_mem_rsp_data_unqual; +wire [AVS_REQ_TAGW-1:0] vx_mem_rsp_tag_unqual; -wire cci_dram_rd_req_valid; -wire cci_dram_wr_req_valid; -wire [CCI_ADDR_WIDTH-1:0] cci_dram_rd_req_addr; -wire [CCI_ADDR_WIDTH-1:0] cci_dram_wr_req_addr; +wire cci_mem_rd_req_valid; +wire cci_mem_wr_req_valid; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_addr; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr; wire [CCI_RD_RQ_DATAW-1:0] cci_rdq_dout; -wire cci_dram_req_ready; +wire cci_mem_req_ready; -wire cci_dram_rsp_valid; -wire [CCI_LINE_WIDTH-1:0] cci_dram_rsp_data; -wire [AVS_REQ_TAGW-1:0] cci_dram_rsp_tag; -wire cci_dram_rsp_ready; +wire cci_mem_rsp_valid; +wire [CCI_LINE_WIDTH-1:0] cci_mem_rsp_data; +wire [AVS_REQ_TAGW-1:0] cci_mem_rsp_tag; +wire cci_mem_rsp_ready; //-- VX_cci_to_mem #( .CCI_DATAW (CCI_LINE_WIDTH), .CCI_ADDRW (CCI_ADDR_WIDTH), - .AVS_DATAW (DRAM_LINE_WIDTH), - .AVS_ADDRW (DRAM_ADDR_WIDTH), + .AVS_DATAW (MEM_LINE_WIDTH), + .AVS_ADDRW (MEM_ADDR_WIDTH), .TAG_WIDTH (AVS_REQ_TAGW) ) cci_to_mem( .clk (clk), .reset (reset), - .dram_req_valid_in ((CMD_MEM_WRITE == state) ? cci_dram_wr_req_valid : cci_dram_rd_req_valid), - .dram_req_addr_in ((CMD_MEM_WRITE == state) ? cci_dram_wr_req_addr : cci_dram_rd_req_addr), - .dram_req_rw_in ((CMD_MEM_WRITE == state)), - .dram_req_data_in (cci_rdq_dout[CCI_RD_RQ_DATAW-1:CCI_RD_RQ_TAGW]), - .dram_req_tag_in (AVS_REQ_TAGW'(0)), - .dram_req_ready_in (cci_dram_req_ready), + .mem_req_valid_in ((CMD_MEM_WRITE == state) ? cci_mem_wr_req_valid : cci_mem_rd_req_valid), + .mem_req_addr_in ((CMD_MEM_WRITE == state) ? cci_mem_wr_req_addr : cci_mem_rd_req_addr), + .mem_req_rw_in ((CMD_MEM_WRITE == state)), + .mem_req_data_in (cci_rdq_dout[CCI_RD_RQ_DATAW-1:CCI_RD_RQ_TAGW]), + .mem_req_tag_in (AVS_REQ_TAGW'(0)), + .mem_req_ready_in (cci_mem_req_ready), - .dram_req_valid_out (cci_dram_req_tmp_valid), - .dram_req_addr_out (cci_dram_req_tmp_addr), - .dram_req_rw_out (cci_dram_req_tmp_rw), - .dram_req_byteen_out(cci_dram_req_tmp_byteen), - .dram_req_data_out (cci_dram_req_tmp_data), - .dram_req_tag_out (cci_dram_req_tmp_tag), - .dram_req_ready_out (cci_dram_req_tmp_ready), + .mem_req_valid_out (cci_mem_req_tmp_valid), + .mem_req_addr_out (cci_mem_req_tmp_addr), + .mem_req_rw_out (cci_mem_req_tmp_rw), + .mem_req_byteen_out(cci_mem_req_tmp_byteen), + .mem_req_data_out (cci_mem_req_tmp_data), + .mem_req_tag_out (cci_mem_req_tmp_tag), + .mem_req_ready_out (cci_mem_req_tmp_ready), - .dram_rsp_valid_in (cci_dram_rsp_tmp_valid), - .dram_rsp_data_in (cci_dram_rsp_tmp_data), - .dram_rsp_tag_in (cci_dram_rsp_tmp_tag), - .dram_rsp_ready_in (cci_dram_rsp_tmp_ready), + .mem_rsp_valid_in (cci_mem_rsp_tmp_valid), + .mem_rsp_data_in (cci_mem_rsp_tmp_data), + .mem_rsp_tag_in (cci_mem_rsp_tmp_tag), + .mem_rsp_ready_in (cci_mem_rsp_tmp_ready), - .dram_rsp_valid_out (cci_dram_rsp_valid), - .dram_rsp_data_out (cci_dram_rsp_data), - .dram_rsp_tag_out (cci_dram_rsp_tag), - .dram_rsp_ready_out (cci_dram_rsp_ready) + .mem_rsp_valid_out (cci_mem_rsp_valid), + .mem_rsp_data_out (cci_mem_rsp_data), + .mem_rsp_tag_out (cci_mem_rsp_tag), + .mem_rsp_ready_out (cci_mem_rsp_ready) ); -`UNUSED_VAR (cci_dram_rsp_tag) +`UNUSED_VAR (cci_mem_rsp_tag) //-- -assign vx_dram_req_valid_qual = vx_dram_req_valid && vx_dram_en; +assign vx_mem_req_valid_qual = vx_mem_req_valid && vx_mem_en; -assign vx_dram_req_addr_qual = vx_dram_req_addr[`VX_DRAM_ADDR_WIDTH-1:`VX_DRAM_ADDR_WIDTH-DRAM_ADDR_WIDTH]; +assign vx_mem_req_addr_qual = vx_mem_req_addr[`VX_MEM_ADDR_WIDTH-1:`VX_MEM_ADDR_WIDTH-MEM_ADDR_WIDTH]; -if (`VX_DRAM_LINE_WIDTH != DRAM_LINE_WIDTH) begin - wire [VX_DRAM_LINE_IDX-1:0] vx_dram_req_idx = vx_dram_req_addr[VX_DRAM_LINE_IDX-1:0]; - wire [VX_DRAM_LINE_IDX-1:0] vx_dram_rsp_idx = vx_dram_rsp_tag_unqual[VX_DRAM_LINE_IDX-1:0]; - assign vx_dram_req_byteen_qual = 64'(vx_dram_req_byteen) << (6'(vx_dram_req_addr[VX_DRAM_LINE_IDX-1:0]) << (VX_DRAM_LINE_LW-3)); - assign vx_dram_req_data_qual = DRAM_LINE_WIDTH'(vx_dram_req_data) << ((DRAM_LINE_LW'(vx_dram_req_idx)) << VX_DRAM_LINE_LW); - assign vx_dram_req_tag_qual = {vx_dram_req_tag, vx_dram_req_idx}; - assign vx_dram_rsp_data = vx_dram_rsp_data_unqual[vx_dram_rsp_idx]; +if (`VX_MEM_LINE_WIDTH != MEM_LINE_WIDTH) begin + wire [VX_MEM_LINE_IDX-1:0] vx_mem_req_idx = vx_mem_req_addr[VX_MEM_LINE_IDX-1:0]; + wire [VX_MEM_LINE_IDX-1:0] vx_mem_rsp_idx = vx_mem_rsp_tag_unqual[VX_MEM_LINE_IDX-1:0]; + assign vx_mem_req_byteen_qual = 64'(vx_mem_req_byteen) << (6'(vx_mem_req_addr[VX_MEM_LINE_IDX-1:0]) << (VX_MEM_LINE_LW-3)); + assign vx_mem_req_data_qual = MEM_LINE_WIDTH'(vx_mem_req_data) << ((MEM_LINE_LW'(vx_mem_req_idx)) << VX_MEM_LINE_LW); + assign vx_mem_req_tag_qual = {vx_mem_req_tag, vx_mem_req_idx}; + assign vx_mem_rsp_data = vx_mem_rsp_data_unqual[vx_mem_rsp_idx]; end else begin - assign vx_dram_req_byteen_qual = vx_dram_req_byteen; - assign vx_dram_req_tag_qual = vx_dram_req_tag; - assign vx_dram_req_data_qual = vx_dram_req_data; - assign vx_dram_rsp_data = vx_dram_rsp_data_unqual; + assign vx_mem_req_byteen_qual = vx_mem_req_byteen; + assign vx_mem_req_tag_qual = vx_mem_req_tag; + assign vx_mem_req_data_qual = vx_mem_req_data; + assign vx_mem_rsp_data = vx_mem_rsp_data_unqual; end -assign vx_dram_rsp_tag = vx_dram_rsp_tag_unqual[`VX_DRAM_TAG_WIDTH+VX_DRAM_LINE_IDX-1:VX_DRAM_LINE_IDX]; +assign vx_mem_rsp_tag = vx_mem_rsp_tag_unqual[`VX_MEM_TAG_WIDTH+VX_MEM_LINE_IDX-1:VX_MEM_LINE_IDX]; //-- VX_mem_arb #( .NUM_REQS (2), - .DATA_WIDTH (DRAM_LINE_WIDTH), - .ADDR_WIDTH (DRAM_ADDR_WIDTH), + .DATA_WIDTH (MEM_LINE_WIDTH), + .ADDR_WIDTH (MEM_ADDR_WIDTH), .TAG_IN_WIDTH (AVS_REQ_TAGW), .TAG_OUT_WIDTH (AVS_REQ_TAGW+1) -) dram_arb ( +) mem_arb ( .clk (clk), .reset (reset), // Source request - .req_valid_in ({cci_dram_req_tmp_valid, vx_dram_req_valid_qual}), - .req_rw_in ({cci_dram_req_tmp_rw, vx_dram_req_rw}), - .req_byteen_in ({cci_dram_req_tmp_byteen, vx_dram_req_byteen_qual}), - .req_addr_in ({cci_dram_req_tmp_addr, vx_dram_req_addr_qual}), - .req_data_in ({cci_dram_req_tmp_data, vx_dram_req_data_qual}), - .req_tag_in ({cci_dram_req_tmp_tag, vx_dram_req_tag_qual}), - .req_ready_in ({cci_dram_req_tmp_ready, vx_dram_req_ready}), + .req_valid_in ({cci_mem_req_tmp_valid, vx_mem_req_valid_qual}), + .req_rw_in ({cci_mem_req_tmp_rw, vx_mem_req_rw}), + .req_byteen_in ({cci_mem_req_tmp_byteen, vx_mem_req_byteen_qual}), + .req_addr_in ({cci_mem_req_tmp_addr, vx_mem_req_addr_qual}), + .req_data_in ({cci_mem_req_tmp_data, vx_mem_req_data_qual}), + .req_tag_in ({cci_mem_req_tmp_tag, vx_mem_req_tag_qual}), + .req_ready_in ({cci_mem_req_tmp_ready, vx_mem_req_ready}), - // DRAM request - .req_valid_out (dram_req_valid), - .req_rw_out (dram_req_rw), - .req_byteen_out (dram_req_byteen), - .req_addr_out (dram_req_addr), - .req_data_out (dram_req_data), - .req_tag_out (dram_req_tag), - .req_ready_out (dram_req_ready), + // Memory request + .req_valid_out (mem_req_valid), + .req_rw_out (mem_req_rw), + .req_byteen_out (mem_req_byteen), + .req_addr_out (mem_req_addr), + .req_data_out (mem_req_data), + .req_tag_out (mem_req_tag), + .req_ready_out (mem_req_ready), // Source response - .rsp_valid_out ({cci_dram_rsp_tmp_valid, vx_dram_rsp_valid}), - .rsp_data_out ({cci_dram_rsp_tmp_data, vx_dram_rsp_data_unqual}), - .rsp_tag_out ({cci_dram_rsp_tmp_tag, vx_dram_rsp_tag_unqual}), - .rsp_ready_out ({cci_dram_rsp_tmp_ready, vx_dram_rsp_ready}), + .rsp_valid_out ({cci_mem_rsp_tmp_valid, vx_mem_rsp_valid}), + .rsp_data_out ({cci_mem_rsp_tmp_data, vx_mem_rsp_data_unqual}), + .rsp_tag_out ({cci_mem_rsp_tmp_tag, vx_mem_rsp_tag_unqual}), + .rsp_ready_out ({cci_mem_rsp_tmp_ready, vx_mem_rsp_ready}), - // DRAM response - .rsp_valid_in (dram_rsp_valid), - .rsp_tag_in (dram_rsp_tag), - .rsp_data_in (dram_rsp_data), - .rsp_ready_in (dram_rsp_ready) + // Memory response + .rsp_valid_in (mem_rsp_valid), + .rsp_tag_in (mem_rsp_tag), + .rsp_data_in (mem_rsp_data), + .rsp_ready_in (mem_rsp_ready) ); //-- VX_avs_wrapper #( - .AVS_DATAW (DRAM_LINE_WIDTH), - .AVS_ADDRW (DRAM_ADDR_WIDTH), - .AVS_BURSTW (DRAM_BURST_CTRW), + .AVS_DATAW (MEM_LINE_WIDTH), + .AVS_ADDRW (MEM_ADDR_WIDTH), + .AVS_BURSTW (MEM_BURST_CTRW), .AVS_BANKS (NUM_LOCAL_MEM_BANKS), .REQ_TAGW (AVS_REQ_TAGW+1), .RD_QUEUE_SIZE (AVS_RD_QUEUE_SIZE) @@ -615,20 +615,20 @@ VX_avs_wrapper #( .clk (clk), .reset (reset), - // DRAM request - .dram_req_valid (dram_req_valid), - .dram_req_rw (dram_req_rw), - .dram_req_byteen (dram_req_byteen), - .dram_req_addr (dram_req_addr), - .dram_req_data (dram_req_data), - .dram_req_tag (dram_req_tag), - .dram_req_ready (dram_req_ready), + // Memory request + .mem_req_valid (mem_req_valid), + .mem_req_rw (mem_req_rw), + .mem_req_byteen (mem_req_byteen), + .mem_req_addr (mem_req_addr), + .mem_req_data (mem_req_data), + .mem_req_tag (mem_req_tag), + .mem_req_ready (mem_req_ready), - // DRAM response - .dram_rsp_valid (dram_rsp_valid), - .dram_rsp_data (dram_rsp_data), - .dram_rsp_tag (dram_rsp_tag), - .dram_rsp_ready (dram_rsp_ready), + // Memory response + .mem_rsp_valid (mem_rsp_valid), + .mem_rsp_data (mem_rsp_data), + .mem_rsp_tag (mem_rsp_tag), + .mem_rsp_ready (mem_rsp_ready), // AVS bus .avs_writedata (avs_writedata), @@ -645,10 +645,10 @@ VX_avs_wrapper #( // CCI-P Read Request /////////////////////////////////////////////////////////// -reg [CCI_ADDR_WIDTH-1:0] cci_dram_wr_req_ctr; +reg [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_ctr; reg [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr; wire [CCI_ADDR_WIDTH-1:0] cci_rd_req_ctr_next; -reg [CCI_ADDR_WIDTH-1:0] cci_dram_wr_req_addr_unqual; +reg [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr_unqual; wire [CCI_RD_RQ_TAGW-1:0] cci_rd_req_tag, cci_rd_rsp_tag; reg [CCI_RD_RQ_TAGW-1:0] cci_rd_rsp_ctr; t_ccip_clAddr cci_rd_req_addr; @@ -665,7 +665,7 @@ always @(*) begin af2cp_sTxPort.c0.hdr.mdata = t_ccip_mdata'(cci_rd_req_tag); end -wire cci_dram_wr_req_fire = cci_dram_wr_req_valid && cci_dram_req_ready; +wire cci_mem_wr_req_fire = cci_mem_wr_req_valid && cci_mem_req_ready; wire cci_rd_req_fire = af2cp_sTxPort.c0.valid; @@ -678,7 +678,7 @@ assign cci_rd_rsp_tag = CCI_RD_RQ_TAGW'(cp2af_sRxPort.c0.hdr.mdata); assign cci_rd_req_ctr_next = cci_rd_req_ctr + CCI_ADDR_WIDTH'(cci_rd_req_fire ? 1 : 0); -assign cci_rdq_pop = cci_dram_wr_req_fire; +assign cci_rdq_pop = cci_mem_wr_req_fire; assign cci_rdq_push = cci_rd_rsp_fire; assign cci_rdq_din = {cp2af_sRxPort.c0.data, cci_rd_rsp_tag}; @@ -697,13 +697,13 @@ VX_pending_size #( ); `UNUSED_VAR (cci_pending_reads) -assign cci_dram_wr_req_valid = !cci_rdq_empty; +assign cci_mem_wr_req_valid = !cci_rdq_empty; -assign cci_dram_wr_req_addr = cci_dram_wr_req_addr_unqual + (CCI_ADDR_WIDTH'(CCI_RD_RQ_TAGW'(cci_rdq_dout))); +assign cci_mem_wr_req_addr = cci_mem_wr_req_addr_unqual + (CCI_ADDR_WIDTH'(CCI_RD_RQ_TAGW'(cci_rdq_dout))); assign af2cp_sTxPort.c0.valid = cci_rd_req_enable && !(cci_rd_req_wait || cci_pending_reads_full); -assign cmd_write_done = (cci_dram_wr_req_ctr == cmd_data_size); +assign cmd_write_done = (cci_mem_wr_req_ctr == cmd_data_size); // Send read requests to CCI always @(posedge clk) begin @@ -713,19 +713,19 @@ always @(posedge clk) begin cci_rd_rsp_ctr <= 0; cci_rd_req_enable <= 0; cci_rd_req_wait <= 0; - cci_dram_wr_req_ctr <= 0; - cci_dram_wr_req_addr_unqual <= 0; + cci_mem_wr_req_ctr <= 0; + cci_mem_wr_req_addr_unqual <= 0; end else begin if ((STATE_IDLE == state) && (CMD_MEM_WRITE == cmd_type)) begin - cci_rd_req_addr <= cmd_io_addr; - cci_rd_req_ctr <= 0; - cci_rd_rsp_ctr <= 0; - cci_rd_req_enable <= (cmd_data_size != 0); - cci_rd_req_wait <= 0; - cci_dram_wr_req_ctr <= 0; - cci_dram_wr_req_addr_unqual <= cmd_mem_addr; + cci_rd_req_addr <= cmd_io_addr; + cci_rd_req_ctr <= 0; + cci_rd_rsp_ctr <= 0; + cci_rd_req_enable <= (cmd_data_size != 0); + cci_rd_req_wait <= 0; + cci_mem_wr_req_ctr <= 0; + cci_mem_wr_req_addr_unqual <= cmd_mem_addr; end cci_rd_req_enable <= (STATE_WRITE == state) @@ -759,9 +759,9 @@ always @(posedge clk) begin `endif end*/ - if (cci_dram_wr_req_fire) begin - cci_dram_wr_req_addr_unqual <= cci_dram_wr_req_addr_unqual + ((CCI_RD_RQ_TAGW'(cci_dram_wr_req_ctr) == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) ? CCI_ADDR_WIDTH'(CCI_RD_WINDOW_SIZE) : CCI_ADDR_WIDTH'(0)); - cci_dram_wr_req_ctr <= cci_dram_wr_req_ctr + CCI_ADDR_WIDTH'(1); + if (cci_mem_wr_req_fire) begin + cci_mem_wr_req_addr_unqual <= cci_mem_wr_req_addr_unqual + ((CCI_RD_RQ_TAGW'(cci_mem_wr_req_ctr) == CCI_RD_RQ_TAGW'(CCI_RD_WINDOW_SIZE-1)) ? CCI_ADDR_WIDTH'(CCI_RD_WINDOW_SIZE) : CCI_ADDR_WIDTH'(0)); + cci_mem_wr_req_ctr <= cci_mem_wr_req_ctr + CCI_ADDR_WIDTH'(1); end end end @@ -805,22 +805,22 @@ VX_fifo_queue #( // CCI-P Write Request ////////////////////////////////////////////////////////// -reg [CCI_ADDR_WIDTH-1:0] cci_dram_rd_req_ctr; +reg [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_ctr; reg [CCI_ADDR_WIDTH-1:0] cci_wr_req_ctr; -reg [CCI_ADDR_WIDTH-1:0] cci_dram_rd_req_addr_r; +reg [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_addr_r; t_ccip_clAddr cci_wr_req_addr; always @(*) begin af2cp_sTxPort.c1.hdr = t_ccip_c1_ReqMemHdr'(0); af2cp_sTxPort.c1.hdr.address = cci_wr_req_addr; af2cp_sTxPort.c1.hdr.sop = 1; // single line write mode - af2cp_sTxPort.c1.data = t_ccip_clData'(cci_dram_rsp_data); + af2cp_sTxPort.c1.data = t_ccip_clData'(cci_mem_rsp_data); end -wire cci_dram_rd_req_fire = cci_dram_rd_req_valid && cci_dram_req_ready; -wire cci_dram_rd_rsp_fire = cci_dram_rsp_valid && cci_dram_rsp_ready; +wire cci_mem_rd_req_fire = cci_mem_rd_req_valid && cci_mem_req_ready; +wire cci_mem_rd_rsp_fire = cci_mem_rsp_valid && cci_mem_rsp_ready; -wire cci_wr_req_fire = cci_dram_rd_rsp_fire; +wire cci_wr_req_fire = cci_mem_rd_rsp_fire; wire cci_wr_rsp_fire = (STATE_READ == state) && cp2af_sRxPort.c1.rspValid @@ -842,11 +842,11 @@ VX_pending_size #( ); `UNUSED_VAR (cci_pending_writes) -assign cci_dram_rd_req_valid = (cci_dram_rd_req_ctr != 0); -assign cci_dram_rd_req_addr = cci_dram_rd_req_addr_r; +assign cci_mem_rd_req_valid = (cci_mem_rd_req_ctr != 0); +assign cci_mem_rd_req_addr = cci_mem_rd_req_addr_r; -assign af2cp_sTxPort.c1.valid = cci_dram_rd_rsp_fire; -assign cci_dram_rsp_ready = !cp2af_sRxPort.c1TxAlmFull && !cci_pending_writes_full; +assign af2cp_sTxPort.c1.valid = cci_mem_rd_rsp_fire; +assign cci_mem_rsp_ready = !cp2af_sRxPort.c1TxAlmFull && !cci_pending_writes_full; assign cmd_read_done = (0 == cci_wr_req_ctr) && cci_pending_writes_empty; @@ -854,18 +854,18 @@ assign cmd_read_done = (0 == cci_wr_req_ctr) && cci_pending_writes_empty; always @(posedge clk) begin if (reset) begin - cci_wr_req_addr <= 0; - cci_wr_req_ctr <= 0; - cci_dram_rd_req_ctr <= 0; - cci_dram_rd_req_addr_r <= 0; + cci_wr_req_addr <= 0; + cci_wr_req_ctr <= 0; + cci_mem_rd_req_ctr <= 0; + cci_mem_rd_req_addr_r <= 0; end else begin if ((STATE_IDLE == state) && (CMD_MEM_READ == cmd_type)) begin - cci_wr_req_addr <= cmd_io_addr; - cci_wr_req_ctr <= cmd_data_size; - cci_dram_rd_req_ctr <= cmd_data_size; - cci_dram_rd_req_addr_r <= cmd_mem_addr; + cci_wr_req_addr <= cmd_io_addr; + cci_wr_req_ctr <= cmd_data_size; + cci_mem_rd_req_ctr <= cmd_data_size; + cci_mem_rd_req_addr_r <= cmd_mem_addr; end if (cci_wr_req_fire) begin @@ -883,9 +883,9 @@ begin end `endif*/ - if (cci_dram_rd_req_fire) begin - cci_dram_rd_req_addr_r <= cci_dram_rd_req_addr_r + CCI_ADDR_WIDTH'(1); - cci_dram_rd_req_ctr <= cci_dram_rd_req_ctr - CCI_ADDR_WIDTH'(1); + if (cci_mem_rd_req_fire) begin + cci_mem_rd_req_addr_r <= cci_mem_rd_req_addr_r + CCI_ADDR_WIDTH'(1); + cci_mem_rd_req_ctr <= cci_mem_rd_req_ctr - CCI_ADDR_WIDTH'(1); end end end @@ -934,20 +934,20 @@ Vortex #() vortex ( .clk (clk), .reset (reset | vx_reset), - // DRAM request - .dram_req_valid (vx_dram_req_valid), - .dram_req_rw (vx_dram_req_rw), - .dram_req_byteen(vx_dram_req_byteen), - .dram_req_addr (vx_dram_req_addr), - .dram_req_data (vx_dram_req_data), - .dram_req_tag (vx_dram_req_tag), - .dram_req_ready (vx_dram_req_ready), + // Memory request + .mem_req_valid (vx_mem_req_valid), + .mem_req_rw (vx_mem_req_rw), + .mem_req_byteen (vx_mem_req_byteen), + .mem_req_addr (vx_mem_req_addr), + .mem_req_data (vx_mem_req_data), + .mem_req_tag (vx_mem_req_tag), + .mem_req_ready (vx_mem_req_ready), - // DRAM response - .dram_rsp_valid (vx_dram_rsp_valid), - .dram_rsp_data (vx_dram_rsp_data), - .dram_rsp_tag (vx_dram_rsp_tag), - .dram_rsp_ready (vx_dram_rsp_ready), + // Memory response + .mem_rsp_valid (vx_mem_rsp_valid), + .mem_rsp_data (vx_mem_rsp_data), + .mem_rsp_tag (vx_mem_rsp_tag), + .mem_rsp_ready (vx_mem_rsp_ready), // CSR Request .csr_req_valid (vx_csr_io_req_valid), @@ -996,8 +996,8 @@ Vortex #() vortex ( `SCOPE_ASSIGN (avs_burstcount, avs_burstcount); `SCOPE_ASSIGN (avs_readdatavalid, avs_readdatavalid); `SCOPE_ASSIGN (mem_bank_select, mem_bank_select); -`SCOPE_ASSIGN (cci_dram_rd_req_ctr, cci_dram_rd_req_ctr); -`SCOPE_ASSIGN (cci_dram_wr_req_ctr, cci_dram_wr_req_ctr); +`SCOPE_ASSIGN (cci_mem_rd_req_ctr, cci_mem_rd_req_ctr); +`SCOPE_ASSIGN (cci_mem_wr_req_ctr, cci_mem_wr_req_ctr); `SCOPE_ASSIGN (cci_rd_req_ctr, cci_rd_req_ctr); `SCOPE_ASSIGN (cci_rd_rsp_ctr, cci_rd_rsp_ctr); `SCOPE_ASSIGN (cci_wr_req_ctr, cci_wr_req_ctr); @@ -1008,11 +1008,11 @@ Vortex #() vortex ( `SCOPE_ASSIGN (cci_pending_reads_full, cci_pending_reads_full); `SCOPE_ASSIGN (cci_pending_writes_empty, cci_pending_writes_empty); `SCOPE_ASSIGN (cci_pending_writes_full, cci_pending_writes_full); -`SCOPE_ASSIGN (afu_dram_req_fire, (dram_req_valid && dram_req_ready)); -`SCOPE_ASSIGN (afu_dram_req_addr, dram_req_addr); -`SCOPE_ASSIGN (afu_dram_req_tag, dram_req_tag); -`SCOPE_ASSIGN (afu_dram_rsp_fire, (dram_rsp_valid && dram_rsp_ready)); -`SCOPE_ASSIGN (afu_dram_rsp_tag, dram_rsp_tag); +`SCOPE_ASSIGN (afu_mem_req_fire, (mem_req_valid && mem_req_ready)); +`SCOPE_ASSIGN (afu_mem_req_addr, mem_req_addr); +`SCOPE_ASSIGN (afu_mem_req_tag, mem_req_tag); +`SCOPE_ASSIGN (afu_mem_rsp_fire, (mem_rsp_valid && mem_rsp_ready)); +`SCOPE_ASSIGN (afu_mem_rsp_tag, mem_rsp_tag); wire scope_changed = `SCOPE_TRIGGER; diff --git a/hw/rtl/cache/VX_bank.v b/hw/rtl/cache/VX_bank.v index 81df57ad..34c6308c 100644 --- a/hw/rtl/cache/VX_bank.v +++ b/hw/rtl/cache/VX_bank.v @@ -22,8 +22,8 @@ module VX_bank #( parameter CREQ_SIZE = 1, // Miss Reserv Queue Knob parameter MSHR_SIZE = 1, - // DRAM Request Queue Size - parameter DREQ_SIZE = 1, + // Memory Request Queue Size + parameter MREQ_SIZE = 1, // Enable cache writeable parameter WRITE_ENABLE = 1, @@ -38,7 +38,7 @@ module VX_bank #( parameter BANK_ADDR_OFFSET = 0, // in-order DRAN - parameter IN_ORDER_DRAM = 0 + parameter IN_ORDER_MEM = 0 ) ( `SCOPE_IO_VX_bank @@ -71,19 +71,19 @@ module VX_bank #( output wire [CORE_TAG_WIDTH-1:0] core_rsp_tag, input wire core_rsp_ready, - // DRAM request - output wire dram_req_valid, - output wire dram_req_rw, - output wire [CACHE_LINE_SIZE-1:0] dram_req_byteen, - output wire [`LINE_ADDR_WIDTH-1:0] dram_req_addr, - output wire [`CACHE_LINE_WIDTH-1:0] dram_req_data, - input wire dram_req_ready, + // Memory request + output wire mem_req_valid, + output wire mem_req_rw, + output wire [CACHE_LINE_SIZE-1:0] mem_req_byteen, + output wire [`LINE_ADDR_WIDTH-1:0] mem_req_addr, + output wire [`CACHE_LINE_WIDTH-1:0] mem_req_data, + input wire mem_req_ready, - // DRAM response - input wire dram_rsp_valid, - input wire [`LINE_ADDR_WIDTH-1:0] dram_rsp_addr, - input wire [`CACHE_LINE_WIDTH-1:0] dram_rsp_data, - output wire dram_rsp_ready, + // Memory response + input wire mem_rsp_valid, + input wire [`LINE_ADDR_WIDTH-1:0] mem_rsp_addr, + input wire [`CACHE_LINE_WIDTH-1:0] mem_rsp_data, + output wire mem_rsp_ready, // flush input wire flush_enable, @@ -167,8 +167,8 @@ module VX_bank #( wire is_flush_st0; wire crsq_in_valid, crsq_in_ready, crsq_in_stall; - wire dreq_alm_full; - wire drsq_pop; + wire mreq_alm_full; + wire mrsq_pop; wire crsq_in_fire = crsq_in_valid && crsq_in_ready; @@ -186,24 +186,24 @@ module VX_bank #( // determine which queue to pop next in priority order wire mshr_pop_unqual = mshr_valid - && !dreq_alm_full; // ensure DRAM request queue not full (deadlock prevention) - wire drsq_pop_unqual = !mshr_pop_unqual && dram_rsp_valid; - wire creq_pop_unqual = !mshr_pop_unqual && !drsq_pop_unqual && !creq_empty && !flush_enable; + && !mreq_alm_full; // ensure memory request queue not full (deadlock prevention) + wire mrsq_pop_unqual = !mshr_pop_unqual && mem_rsp_valid; + wire creq_pop_unqual = !mshr_pop_unqual && !mrsq_pop_unqual && !creq_empty && !flush_enable; wire is_miss_st1 = valid_st1 && (miss_st1 || force_miss_st1); assign mshr_pop = mshr_pop_unqual - && !(!IN_ORDER_DRAM && is_miss_st1 && is_mshr_st1) // do not schedule another mshr request if the previous one missed + && !(!IN_ORDER_MEM && is_miss_st1 && is_mshr_st1) // do not schedule another mshr request if the previous one missed && !crsq_in_stall; // ensure core response ready - assign drsq_pop = drsq_pop_unqual + assign mrsq_pop = mrsq_pop_unqual && !crsq_in_stall; // ensure core response ready assign creq_pop = creq_pop_unqual - && !dreq_alm_full // ensure dram request ready + && !mreq_alm_full // ensure memory request ready && !mshr_alm_full // ensure mshr enqueue ready && !crsq_in_stall; // ensure core response ready - assign dram_rsp_ready = drsq_pop; + assign mem_rsp_ready = mrsq_pop; // we have a miss in mshr or entering it for the current address wire mshr_pending_sel = mshr_pending @@ -238,12 +238,12 @@ module VX_bank #( assign creq_line_data = creq_data; end - wire [`LINE_ADDR_WIDTH-1:0] dram_rsp_addr_qual; - if (IN_ORDER_DRAM) begin - `UNUSED_VAR (dram_rsp_addr) - assign dram_rsp_addr_qual = mshr_addr; + wire [`LINE_ADDR_WIDTH-1:0] mem_rsp_addr_qual; + if (IN_ORDER_MEM) begin + `UNUSED_VAR (mem_rsp_addr) + assign mem_rsp_addr_qual = mshr_addr; end else begin - assign dram_rsp_addr_qual = dram_rsp_addr; + assign mem_rsp_addr_qual = mem_rsp_addr; end VX_pipe_register #( @@ -254,13 +254,13 @@ module VX_bank #( .reset (reset), .enable (!crsq_in_stall), .data_in ({ - flush_enable || mshr_pop || drsq_pop || creq_pop, + flush_enable || mshr_pop || mrsq_pop || creq_pop, flush_enable, mshr_pop_unqual, - drsq_pop_unqual || flush_enable, + mrsq_pop_unqual || flush_enable, mshr_pop_unqual ? 1'b0 : creq_rw, - mshr_pop_unqual ? mshr_addr : (dram_rsp_valid ? dram_rsp_addr_qual : (flush_enable ? `LINE_ADDR_WIDTH'(flush_addr) : creq_addr)), - dram_rsp_valid ? dram_rsp_data : creq_line_data, + mshr_pop_unqual ? mshr_addr : (mem_rsp_valid ? mem_rsp_addr_qual : (flush_enable ? `LINE_ADDR_WIDTH'(flush_addr) : creq_addr)), + mem_rsp_valid ? mem_rsp_data : creq_line_data, mshr_pop_unqual ? mshr_wsel : creq_wsel, mshr_pop_unqual ? mshr_byteen : creq_byteen, mshr_pop_unqual ? mshr_tid : creq_tid, @@ -307,7 +307,7 @@ module VX_bank #( ); // redundant fills - wire is_redundant_fill_st0 = !IN_ORDER_DRAM && is_fill_st0 && tag_match_st0; + wire is_redundant_fill_st0 = !IN_ORDER_MEM && is_fill_st0 && tag_match_st0; // we had a miss with prior request for the current address assign prev_miss_dep_st0 = is_miss_st1 && (addr_st0 == addr_st1); @@ -322,9 +322,9 @@ module VX_bank #( assign writeen_unqual_st0 = (WRITE_ENABLE && !is_fill_st0 && tag_match_st0 && mem_rw_st0) || (is_fill_st0 && !is_redundant_fill_st0); - assign incoming_fill_st0 = dram_rsp_valid && (addr_st0 == dram_rsp_addr_qual); + assign incoming_fill_st0 = mem_rsp_valid && (addr_st0 == mem_rsp_addr_qual); - assign fill_req_unqual_st0 = !mem_rw_st0 && (!force_miss_st0 || (!IN_ORDER_DRAM && is_mshr_st0 && !prev_miss_dep_st0)); + assign fill_req_unqual_st0 = !mem_rw_st0 && (!force_miss_st0 || (!IN_ORDER_MEM && is_mshr_st0 && !prev_miss_dep_st0)); VX_pipe_register #( .DATAW (1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + `LINE_ADDR_WIDTH + `CACHE_LINE_WIDTH + (`UP(`WORD_SELECT_BITS) + WORD_SIZE + `REQS_BITS + 1) * NUM_PORTS + CORE_TAG_WIDTH), @@ -351,12 +351,12 @@ module VX_bank #( wire mshr_push_st1 = !is_fill_st1 && !mem_rw_st1 && (miss_st1 || force_miss_st1); - wire incoming_fill_qual_st1 = (dram_rsp_valid && (addr_st1 == dram_rsp_addr_qual)) + wire incoming_fill_qual_st1 = (mem_rsp_valid && (addr_st1 == mem_rsp_addr_qual)) || incoming_fill_st1; wire do_writeback_st1 = !is_fill_st1 && mem_rw_st1; - wire dreq_push_st1 = (miss_st1 && fill_req_unqual_st1 && !incoming_fill_qual_st1) + wire mreq_push_st1 = (miss_st1 && fill_req_unqual_st1 && !incoming_fill_qual_st1) || do_writeback_st1; wire [`WORDS_PER_LINE-1:0][WORD_SIZE-1:0] line_byteen_st1; @@ -408,15 +408,15 @@ module VX_bank #( assign mshr_push = valid_st1 && mshr_push_st1; wire mshr_dequeue = valid_st1 && is_mshr_st1 && !mshr_push_st1 && crsq_in_ready; - wire mshr_restore = !IN_ORDER_DRAM && is_mshr_st1; - `RUNTIME_ASSERT(!IN_ORDER_DRAM || !(mshr_push && mshr_restore), ("Oops!")) + wire mshr_restore = !IN_ORDER_MEM && is_mshr_st1; + `RUNTIME_ASSERT(!IN_ORDER_MEM || !(mshr_push && mshr_restore), ("Oops!")) // push a missed request as 'ready' if it was a forced miss that actually had a hit // or the fill request for this block is comming wire mshr_init_ready_state = !miss_st1 || incoming_fill_qual_st1; - // use dram rsp or core req address to lookup the mshr - wire [`LINE_ADDR_WIDTH-1:0] lookup_addr = dram_rsp_valid ? dram_rsp_addr_qual : creq_addr; + // use memory rsp or core req address to lookup the mshr + wire [`LINE_ADDR_WIDTH-1:0] lookup_addr = mem_rsp_valid ? mem_rsp_addr_qual : creq_addr; VX_miss_resrv #( .BANK_ID (BANK_ID), @@ -450,7 +450,7 @@ module VX_bank #( `UNUSED_PIN (enqueue_full), // lookup - .lookup_ready (drsq_pop), + .lookup_ready (mrsq_pop), .lookup_addr (lookup_addr), .lookup_match (mshr_pending), @@ -500,41 +500,41 @@ module VX_bank #( .ready_out (core_rsp_ready) ); - // Enqueue DRAM request + // Enqueue memory request - wire [CACHE_LINE_SIZE-1:0] dreq_byteen; - wire [`LINE_ADDR_WIDTH-1:0] dreq_addr; - wire [`CACHE_LINE_WIDTH-1:0] dreq_data; - wire dreq_push, dreq_pop, dreq_empty, dreq_rw; + wire [CACHE_LINE_SIZE-1:0] mreq_byteen; + wire [`LINE_ADDR_WIDTH-1:0] mreq_addr; + wire [`CACHE_LINE_WIDTH-1:0] mreq_data; + wire mreq_push, mreq_pop, mreq_empty, mreq_rw; - assign dreq_push = valid_st1 && dreq_push_st1; + assign mreq_push = valid_st1 && mreq_push_st1; - assign dreq_pop = dram_req_valid && dram_req_ready; + assign mreq_pop = mem_req_valid && mem_req_ready; - assign dreq_rw = WRITE_ENABLE && do_writeback_st1; - assign dreq_byteen = dreq_rw ? line_byteen_st1 : {CACHE_LINE_SIZE{1'b1}}; - assign dreq_addr = addr_st1; - assign dreq_data = wdata_st1; + assign mreq_rw = WRITE_ENABLE && do_writeback_st1; + assign mreq_byteen = mreq_rw ? line_byteen_st1 : {CACHE_LINE_SIZE{1'b1}}; + assign mreq_addr = addr_st1; + assign mreq_data = wdata_st1; VX_fifo_queue #( .DATAW (1 + CACHE_LINE_SIZE + `LINE_ADDR_WIDTH + `CACHE_LINE_WIDTH), - .SIZE (DREQ_SIZE), - .ALM_FULL (DREQ_SIZE-2) - ) dram_req_queue ( + .SIZE (MREQ_SIZE), + .ALM_FULL (MREQ_SIZE-2) + ) mem_req_queue ( .clk (clk), .reset (reset), - .push (dreq_push), - .pop (dreq_pop), - .data_in ({dreq_rw, dreq_byteen, dreq_addr, dreq_data}), - .data_out ({dram_req_rw, dram_req_byteen, dram_req_addr, dram_req_data}), - .empty (dreq_empty), - .alm_full (dreq_alm_full), + .push (mreq_push), + .pop (mreq_pop), + .data_in ({mreq_rw, mreq_byteen, mreq_addr, mreq_data}), + .data_out ({mem_req_rw, mem_req_byteen, mem_req_addr, mem_req_data}), + .empty (mreq_empty), + .alm_full (mreq_alm_full), `UNUSED_PIN (full), `UNUSED_PIN (alm_empty), `UNUSED_PIN (size) ); - assign dram_req_valid = !dreq_empty; + assign mem_req_valid = !mreq_empty; `SCOPE_ASSIGN (valid_st0, valid_st0); `SCOPE_ASSIGN (valid_st1, valid_st1); @@ -544,7 +544,7 @@ module VX_bank #( `SCOPE_ASSIGN (force_miss_st0, force_miss_st0); `SCOPE_ASSIGN (mshr_push, mshr_push); `SCOPE_ASSIGN (crsq_in_stall, crsq_in_stall); - `SCOPE_ASSIGN (dreq_alm_full, dreq_alm_full); + `SCOPE_ASSIGN (mreq_alm_full, mreq_alm_full); `SCOPE_ASSIGN (mshr_alm_full, mshr_alm_full); `SCOPE_ASSIGN (addr_st0, `LINE_TO_BYTE_ADDR(addr_st0, BANK_ID)); `SCOPE_ASSIGN (addr_st1, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID)); @@ -552,7 +552,7 @@ module VX_bank #( `ifdef PERF_ENABLE assign perf_read_misses = valid_st1 && !is_fill_st1 && !is_mshr_st1 && miss_st1 && !mem_rw_st1; assign perf_write_misses = valid_st1 && !is_fill_st1 && !is_mshr_st1 && miss_st1 && mem_rw_st1; - assign perf_pipe_stalls = crsq_in_stall || dreq_alm_full || mshr_alm_full; + assign perf_pipe_stalls = crsq_in_stall || mreq_alm_full || mshr_alm_full; assign perf_mshr_stalls = mshr_alm_full; `endif @@ -565,14 +565,14 @@ module VX_bank #( $display("%t: *** cache%0d:%0d miss with incoming fill - addr=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID)); assert(!is_mshr_st1); end - if (crsq_in_stall || dreq_alm_full || mshr_alm_full) begin - $display("%t: cache%0d:%0d pipeline-stall: cwbq=%b, dwbq=%b, mshr=%b", $time, CACHE_ID, BANK_ID, crsq_in_stall, dreq_alm_full, mshr_alm_full); + if (crsq_in_stall || mreq_alm_full || mshr_alm_full) begin + $display("%t: cache%0d:%0d pipeline-stall: cwbq=%b, dwbq=%b, mshr=%b", $time, CACHE_ID, BANK_ID, crsq_in_stall, mreq_alm_full, mshr_alm_full); end if (flush_enable) begin $display("%t: cache%0d:%0d flush: addr=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(flush_addr, BANK_ID)); end - if (drsq_pop) begin - $display("%t: cache%0d:%0d fill-rsp: addr=%0h, data=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(dram_rsp_addr_qual, BANK_ID), dram_rsp_data); + if (mrsq_pop) begin + $display("%t: cache%0d:%0d fill-rsp: addr=%0h, data=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mem_rsp_addr_qual, BANK_ID), mem_rsp_data); end if (mshr_pop) begin $display("%t: cache%0d:%0d mshr-rd-req: addr=%0h, tag=%0h, pmask=%0b, tid=%0d, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mshr_addr, BANK_ID), mshr_tag, mshr_pmask, mshr_tid, mshr_byteen, debug_wid_sel, debug_pc_sel); @@ -586,11 +586,11 @@ module VX_bank #( if (crsq_in_fire) begin $display("%t: cache%0d:%0d core-rsp: addr=%0h, tag=%0h, pmask=%0b, tid=%0d, data=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(addr_st1, BANK_ID), crsq_tag, crsq_pmask, crsq_tid, crsq_data, debug_wid_st1, debug_pc_st1); end - if (dreq_push) begin + if (mreq_push) begin if (do_writeback_st1) - $display("%t: cache%0d:%0d writeback: addr=%0h, data=%0h, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(dreq_addr, BANK_ID), dreq_data, dreq_byteen, debug_wid_st1, debug_pc_st1); + $display("%t: cache%0d:%0d writeback: addr=%0h, data=%0h, byteen=%b, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mreq_addr, BANK_ID), mreq_data, mreq_byteen, debug_wid_st1, debug_pc_st1); else - $display("%t: cache%0d:%0d fill-req: addr=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(dreq_addr, BANK_ID), debug_wid_st1, debug_pc_st1); + $display("%t: cache%0d:%0d fill-req: addr=%0h, wid=%0d, PC=%0h", $time, CACHE_ID, BANK_ID, `LINE_TO_BYTE_ADDR(mreq_addr, BANK_ID), debug_wid_st1, debug_pc_st1); end end `endif diff --git a/hw/rtl/cache/VX_cache.v b/hw/rtl/cache/VX_cache.v index 1487477f..20bbc0ab 100644 --- a/hw/rtl/cache/VX_cache.v +++ b/hw/rtl/cache/VX_cache.v @@ -21,10 +21,10 @@ module VX_cache #( parameter CREQ_SIZE = 4, // Miss Reserv Queue Knob parameter MSHR_SIZE = 8, - // DRAM Response Queue Size - parameter DRSQ_SIZE = 4, - // DRAM Request Queue Size - parameter DREQ_SIZE = 4, + // Memory Response Queue Size + parameter MRSQ_SIZE = 4, + // Memory Request Queue Size + parameter MREQ_SIZE = 4, // Enable cache writeable parameter WRITE_ENABLE = 1, @@ -35,14 +35,14 @@ module VX_cache #( // size of tag id in core request tag parameter CORE_TAG_ID_BITS = CORE_TAG_WIDTH, - // dram request tag size - parameter DRAM_TAG_WIDTH = (32 - $clog2(CACHE_LINE_SIZE)), + // Memory request tag size + parameter MEM_TAG_WIDTH = (32 - $clog2(CACHE_LINE_SIZE)), // bank offset from beginning of index range parameter BANK_ADDR_OFFSET = 0, // in-order DRAN - parameter IN_ORDER_DRAM = 0 + parameter IN_ORDER_MEM = 0 ) ( `SCOPE_IO_VX_cache @@ -64,20 +64,20 @@ module VX_cache #( output wire [`CORE_REQ_TAG_COUNT-1:0][CORE_TAG_WIDTH-1:0] core_rsp_tag, input wire [`CORE_REQ_TAG_COUNT-1:0] core_rsp_ready, - // DRAM request - output wire dram_req_valid, - output wire dram_req_rw, - output wire [CACHE_LINE_SIZE-1:0] dram_req_byteen, - output wire [`DRAM_ADDR_WIDTH-1:0] dram_req_addr, - output wire [`CACHE_LINE_WIDTH-1:0] dram_req_data, - output wire [DRAM_TAG_WIDTH-1:0] dram_req_tag, - input wire dram_req_ready, + // Memory request + output wire mem_req_valid, + output wire mem_req_rw, + output wire [CACHE_LINE_SIZE-1:0] mem_req_byteen, + output wire [`MEM_ADDR_WIDTH-1:0] mem_req_addr, + output wire [`CACHE_LINE_WIDTH-1:0] mem_req_data, + output wire [MEM_TAG_WIDTH-1:0] mem_req_tag, + input wire mem_req_ready, - // DRAM response - input wire dram_rsp_valid, - input wire [`CACHE_LINE_WIDTH-1:0] dram_rsp_data, - input wire [DRAM_TAG_WIDTH-1:0] dram_rsp_tag, - output wire dram_rsp_ready, + // Memory response + input wire mem_rsp_valid, + input wire [`CACHE_LINE_WIDTH-1:0] mem_rsp_data, + input wire [MEM_TAG_WIDTH-1:0] mem_rsp_tag, + output wire mem_rsp_ready, // PERF `ifdef PERF_ENABLE @@ -107,17 +107,17 @@ module VX_cache #( wire [NUM_BANKS-1:0][CORE_TAG_WIDTH-1:0] per_bank_core_rsp_tag; wire [NUM_BANKS-1:0] per_bank_core_rsp_ready; - wire [NUM_BANKS-1:0] per_bank_dram_req_valid; - wire [NUM_BANKS-1:0] per_bank_dram_req_rw; - wire [NUM_BANKS-1:0][CACHE_LINE_SIZE-1:0] per_bank_dram_req_byteen; - wire [NUM_BANKS-1:0][`DRAM_ADDR_WIDTH-1:0] per_bank_dram_req_addr; - wire [NUM_BANKS-1:0][`CACHE_LINE_WIDTH-1:0] per_bank_dram_req_data; - wire [NUM_BANKS-1:0] per_bank_dram_req_ready; + wire [NUM_BANKS-1:0] per_bank_mem_req_valid; + wire [NUM_BANKS-1:0] per_bank_mem_req_rw; + wire [NUM_BANKS-1:0][CACHE_LINE_SIZE-1:0] per_bank_mem_req_byteen; + wire [NUM_BANKS-1:0][`MEM_ADDR_WIDTH-1:0] per_bank_mem_req_addr; + wire [NUM_BANKS-1:0][`CACHE_LINE_WIDTH-1:0] per_bank_mem_req_data; + wire [NUM_BANKS-1:0] per_bank_mem_req_ready; - wire [NUM_BANKS-1:0] per_bank_dram_rsp_ready; + wire [NUM_BANKS-1:0] per_bank_mem_rsp_ready; - wire [`CACHE_LINE_WIDTH-1:0] dram_rsp_data_qual; - wire [DRAM_TAG_WIDTH-1:0] dram_rsp_tag_qual; + wire [`CACHE_LINE_WIDTH-1:0] mem_rsp_data_qual; + wire [MEM_TAG_WIDTH-1:0] mem_rsp_tag_qual; wire [`LINE_SELECT_BITS-1:0] flush_addr; wire flush_enable; @@ -130,35 +130,35 @@ module VX_cache #( /////////////////////////////////////////////////////////////////////////// - wire drsq_full, drsq_empty; - wire drsq_push, drsq_pop; + wire mrsq_full, mrsq_empty; + wire mrsq_push, mrsq_pop; - assign drsq_push = dram_rsp_valid && dram_rsp_ready; - assign dram_rsp_ready = !drsq_full; + assign mrsq_push = mem_rsp_valid && mem_rsp_ready; + assign mem_rsp_ready = !mrsq_full; VX_fifo_queue #( - .DATAW (DRAM_TAG_WIDTH + `CACHE_LINE_WIDTH), - .SIZE (DRSQ_SIZE), + .DATAW (MEM_TAG_WIDTH + `CACHE_LINE_WIDTH), + .SIZE (MRSQ_SIZE), .BUFFERED (1) - ) dram_rsp_queue ( + ) mem_rsp_queue ( .clk (clk), .reset (reset), - .push (drsq_push), - .pop (drsq_pop), - .data_in ({dram_rsp_tag, dram_rsp_data}), - .data_out ({dram_rsp_tag_qual, dram_rsp_data_qual}), - .empty (drsq_empty), - .full (drsq_full), + .push (mrsq_push), + .pop (mrsq_pop), + .data_in ({mem_rsp_tag, mem_rsp_data}), + .data_out ({mem_rsp_tag_qual, mem_rsp_data_qual}), + .empty (mrsq_empty), + .full (mrsq_full), `UNUSED_PIN (alm_full), `UNUSED_PIN (alm_empty), `UNUSED_PIN (size) ); if (NUM_BANKS == 1) begin - `UNUSED_VAR (dram_rsp_tag_qual) - assign drsq_pop = !drsq_empty && per_bank_dram_rsp_ready; + `UNUSED_VAR (mem_rsp_tag_qual) + assign mrsq_pop = !mrsq_empty && per_bank_mem_rsp_ready; end else begin - assign drsq_pop = !drsq_empty && per_bank_dram_rsp_ready[`DRAM_ADDR_BANK(dram_rsp_tag_qual)]; + assign mrsq_pop = !mrsq_empty && per_bank_mem_rsp_ready[`MEM_ADDR_BANK(mem_rsp_tag_qual)]; end /////////////////////////////////////////////////////////////////////////// @@ -229,17 +229,17 @@ module VX_cache #( wire [CORE_TAG_WIDTH-1:0] curr_bank_core_rsp_tag; wire curr_bank_core_rsp_ready; - wire curr_bank_dram_req_valid; - wire curr_bank_dram_req_rw; - wire [CACHE_LINE_SIZE-1:0] curr_bank_dram_req_byteen; - wire [`LINE_ADDR_WIDTH-1:0] curr_bank_dram_req_addr; - wire[`CACHE_LINE_WIDTH-1:0] curr_bank_dram_req_data; - wire curr_bank_dram_req_ready; + wire curr_bank_mem_req_valid; + wire curr_bank_mem_req_rw; + wire [CACHE_LINE_SIZE-1:0] curr_bank_mem_req_byteen; + wire [`LINE_ADDR_WIDTH-1:0] curr_bank_mem_req_addr; + wire[`CACHE_LINE_WIDTH-1:0] curr_bank_mem_req_data; + wire curr_bank_mem_req_ready; - wire curr_bank_dram_rsp_valid; - wire [`LINE_ADDR_WIDTH-1:0] curr_bank_dram_rsp_addr; - wire [`CACHE_LINE_WIDTH-1:0] curr_bank_dram_rsp_data; - wire curr_bank_dram_rsp_ready; + wire curr_bank_mem_rsp_valid; + wire [`LINE_ADDR_WIDTH-1:0] curr_bank_mem_rsp_addr; + wire [`CACHE_LINE_WIDTH-1:0] curr_bank_mem_rsp_data; + wire curr_bank_mem_rsp_ready; // Core Req assign curr_bank_core_req_valid = per_bank_core_req_valid[i]; @@ -260,28 +260,28 @@ module VX_cache #( assign per_bank_core_rsp_tag [i] = curr_bank_core_rsp_tag; assign per_bank_core_rsp_data [i] = curr_bank_core_rsp_data; - // DRAM request - assign per_bank_dram_req_valid[i] = curr_bank_dram_req_valid; - assign per_bank_dram_req_rw[i] = curr_bank_dram_req_rw; - assign per_bank_dram_req_byteen[i] = curr_bank_dram_req_byteen; + // Memory request + assign per_bank_mem_req_valid[i] = curr_bank_mem_req_valid; + assign per_bank_mem_req_rw[i] = curr_bank_mem_req_rw; + assign per_bank_mem_req_byteen[i] = curr_bank_mem_req_byteen; if (NUM_BANKS == 1) begin - assign per_bank_dram_req_addr[i] = curr_bank_dram_req_addr; + assign per_bank_mem_req_addr[i] = curr_bank_mem_req_addr; end else begin - assign per_bank_dram_req_addr[i] = `LINE_TO_DRAM_ADDR(curr_bank_dram_req_addr, i); + assign per_bank_mem_req_addr[i] = `LINE_TO_MEM_ADDR(curr_bank_mem_req_addr, i); end - assign per_bank_dram_req_data[i] = curr_bank_dram_req_data; - assign curr_bank_dram_req_ready = per_bank_dram_req_ready[i]; + assign per_bank_mem_req_data[i] = curr_bank_mem_req_data; + assign curr_bank_mem_req_ready = per_bank_mem_req_ready[i]; - // DRAM response + // Memory response if (NUM_BANKS == 1) begin - assign curr_bank_dram_rsp_valid = !drsq_empty; - assign curr_bank_dram_rsp_addr = dram_rsp_tag_qual; + assign curr_bank_mem_rsp_valid = !mrsq_empty; + assign curr_bank_mem_rsp_addr = mem_rsp_tag_qual; end else begin - assign curr_bank_dram_rsp_valid = !drsq_empty && (`DRAM_ADDR_BANK(dram_rsp_tag_qual) == i); - assign curr_bank_dram_rsp_addr = `DRAM_TO_LINE_ADDR(dram_rsp_tag_qual); + assign curr_bank_mem_rsp_valid = !mrsq_empty && (`MEM_ADDR_BANK(mem_rsp_tag_qual) == i); + assign curr_bank_mem_rsp_addr = `MEM_TO_LINE_ADDR(mem_rsp_tag_qual); end - assign curr_bank_dram_rsp_data = dram_rsp_data_qual; - assign per_bank_dram_rsp_ready[i] = curr_bank_dram_rsp_ready; + assign curr_bank_mem_rsp_data = mem_rsp_data_qual; + assign per_bank_mem_rsp_ready[i] = curr_bank_mem_rsp_ready; VX_bank #( .BANK_ID (i), @@ -294,12 +294,12 @@ module VX_cache #( .NUM_REQS (NUM_REQS), .CREQ_SIZE (CREQ_SIZE), .MSHR_SIZE (MSHR_SIZE), - .DREQ_SIZE (DREQ_SIZE), + .MREQ_SIZE (MREQ_SIZE), .WRITE_ENABLE (WRITE_ENABLE), .CORE_TAG_WIDTH (CORE_TAG_WIDTH), .CORE_TAG_ID_BITS (CORE_TAG_ID_BITS), .BANK_ADDR_OFFSET (BANK_ADDR_OFFSET), - .IN_ORDER_DRAM (IN_ORDER_DRAM) + .IN_ORDER_MEM (IN_ORDER_MEM) ) bank ( `SCOPE_BIND_VX_cache_bank(i) @@ -332,19 +332,19 @@ module VX_cache #( .core_rsp_tag (curr_bank_core_rsp_tag), .core_rsp_ready (curr_bank_core_rsp_ready), - // DRAM request - .dram_req_valid (curr_bank_dram_req_valid), - .dram_req_rw (curr_bank_dram_req_rw), - .dram_req_byteen (curr_bank_dram_req_byteen), - .dram_req_addr (curr_bank_dram_req_addr), - .dram_req_data (curr_bank_dram_req_data), - .dram_req_ready (curr_bank_dram_req_ready), + // Memory request + .mem_req_valid (curr_bank_mem_req_valid), + .mem_req_rw (curr_bank_mem_req_rw), + .mem_req_byteen (curr_bank_mem_req_byteen), + .mem_req_addr (curr_bank_mem_req_addr), + .mem_req_data (curr_bank_mem_req_data), + .mem_req_ready (curr_bank_mem_req_ready), - // DRAM response - .dram_rsp_valid (curr_bank_dram_rsp_valid), - .dram_rsp_addr (curr_bank_dram_rsp_addr), - .dram_rsp_data (curr_bank_dram_rsp_data), - .dram_rsp_ready (curr_bank_dram_rsp_ready), + // Memory response + .mem_rsp_valid (curr_bank_mem_rsp_valid), + .mem_rsp_addr (curr_bank_mem_rsp_addr), + .mem_rsp_data (curr_bank_mem_rsp_data), + .mem_rsp_ready (curr_bank_mem_rsp_ready), // flush .flush_enable (flush_enable), @@ -375,27 +375,27 @@ module VX_cache #( .core_rsp_ready (core_rsp_ready) ); - wire [NUM_BANKS-1:0][(`DRAM_ADDR_WIDTH + 1 + CACHE_LINE_SIZE + `CACHE_LINE_WIDTH)-1:0] data_in; + wire [NUM_BANKS-1:0][(`MEM_ADDR_WIDTH + 1 + CACHE_LINE_SIZE + `CACHE_LINE_WIDTH)-1:0] data_in; for (genvar i = 0; i < NUM_BANKS; i++) begin - assign data_in[i] = {per_bank_dram_req_addr[i], per_bank_dram_req_rw[i], per_bank_dram_req_byteen[i], per_bank_dram_req_data[i]}; + assign data_in[i] = {per_bank_mem_req_addr[i], per_bank_mem_req_rw[i], per_bank_mem_req_byteen[i], per_bank_mem_req_data[i]}; end VX_stream_arbiter #( .NUM_REQS (NUM_BANKS), - .DATAW (`DRAM_ADDR_WIDTH + 1 + CACHE_LINE_SIZE + `CACHE_LINE_WIDTH), + .DATAW (`MEM_ADDR_WIDTH + 1 + CACHE_LINE_SIZE + `CACHE_LINE_WIDTH), .BUFFERED (1) - ) dram_req_arb ( + ) mem_req_arb ( .clk (clk), .reset (reset), - .valid_in (per_bank_dram_req_valid), + .valid_in (per_bank_mem_req_valid), .data_in (data_in), - .ready_in (per_bank_dram_req_ready), - .valid_out (dram_req_valid), - .data_out ({dram_req_addr, dram_req_rw, dram_req_byteen, dram_req_data}), - .ready_out (dram_req_ready) + .ready_in (per_bank_mem_req_ready), + .valid_out (mem_req_valid), + .data_out ({mem_req_addr, mem_req_rw, mem_req_byteen, mem_req_data}), + .ready_out (mem_req_ready) ); - assign dram_req_tag = dram_req_addr; + assign mem_req_tag = mem_req_addr; `ifdef PERF_ENABLE // per cycle: core_reads, core_writes diff --git a/hw/rtl/cache/VX_cache_config.vh b/hw/rtl/cache/VX_cache_config.vh index bfe8b96c..4b896521 100644 --- a/hw/rtl/cache/VX_cache_config.vh +++ b/hw/rtl/cache/VX_cache_config.vh @@ -21,8 +21,8 @@ `define WORDS_PER_LINE (CACHE_LINE_SIZE / WORD_SIZE) `define WORD_ADDR_WIDTH (32-`CLOG2(WORD_SIZE)) -`define DRAM_ADDR_WIDTH (32-`CLOG2(CACHE_LINE_SIZE)) -`define LINE_ADDR_WIDTH (`DRAM_ADDR_WIDTH-`BANK_SELECT_BITS) +`define MEM_ADDR_WIDTH (32-`CLOG2(CACHE_LINE_SIZE)) +`define LINE_ADDR_WIDTH (`MEM_ADDR_WIDTH-`BANK_SELECT_BITS) // Word select `define WORD_SELECT_BITS `CLOG2(`WORDS_PER_LINE) @@ -57,11 +57,11 @@ `define BANK_READY_COUNT ((SHARED_BANK_READY != 0) ? 1 : NUM_BANKS) -`define DRAM_ADDR_BANK(x) x[`BANK_SELECT_BITS+BANK_ADDR_OFFSET-1 : BANK_ADDR_OFFSET] +`define MEM_ADDR_BANK(x) x[`BANK_SELECT_BITS+BANK_ADDR_OFFSET-1 : BANK_ADDR_OFFSET] -`define DRAM_TO_LINE_ADDR(x) x[`DRAM_ADDR_WIDTH-1 : `BANK_SELECT_BITS] +`define MEM_TO_LINE_ADDR(x) x[`MEM_ADDR_WIDTH-1 : `BANK_SELECT_BITS] -`define LINE_TO_DRAM_ADDR(x, i) {x, `BANK_SELECT_BITS'(i)} +`define LINE_TO_MEM_ADDR(x, i) {x, `BANK_SELECT_BITS'(i)} `define LINE_TO_BYTE_ADDR(x, i) {x, (32-$bits(x))'(i << (32-$bits(x)-`BANK_SELECT_BITS))} diff --git a/hw/rtl/interfaces/VX_cache_dram_req_if.v b/hw/rtl/interfaces/VX_cache_dram_req_if.v deleted file mode 100644 index 5591bf9f..00000000 --- a/hw/rtl/interfaces/VX_cache_dram_req_if.v +++ /dev/null @@ -1,22 +0,0 @@ -`ifndef VX_CACHE_DRAM_REQ_IF -`define VX_CACHE_DRAM_REQ_IF - -`include "../cache/VX_cache_config.vh" - -interface VX_cache_dram_req_if #( - parameter DRAM_LINE_WIDTH = 1, - parameter DRAM_ADDR_WIDTH = 1, - parameter DRAM_TAG_WIDTH = 1 -) (); - - wire valid; - wire rw; - wire [(DRAM_LINE_WIDTH/8)-1:0] byteen; - wire [DRAM_ADDR_WIDTH-1:0] addr; - wire [DRAM_LINE_WIDTH-1:0] data; - wire [DRAM_TAG_WIDTH-1:0] tag; - wire ready; - -endinterface - -`endif \ No newline at end of file diff --git a/hw/rtl/interfaces/VX_cache_dram_rsp_if.v b/hw/rtl/interfaces/VX_cache_dram_rsp_if.v deleted file mode 100644 index 2a3d15e0..00000000 --- a/hw/rtl/interfaces/VX_cache_dram_rsp_if.v +++ /dev/null @@ -1,18 +0,0 @@ -`ifndef VX_CACHE_DRAM_RSP_IF -`define VX_CACHE_DRAM_RSP_IF - -`include "../cache/VX_cache_config.vh" - -interface VX_cache_dram_rsp_if #( - parameter DRAM_LINE_WIDTH = 1, - parameter DRAM_TAG_WIDTH = 1 -) (); - - wire valid; - wire [DRAM_LINE_WIDTH-1:0] data; - wire [DRAM_TAG_WIDTH-1:0] tag; - wire ready; - -endinterface - -`endif \ No newline at end of file diff --git a/hw/rtl/interfaces/VX_cache_mem_req_if.v b/hw/rtl/interfaces/VX_cache_mem_req_if.v new file mode 100644 index 00000000..b761b61f --- /dev/null +++ b/hw/rtl/interfaces/VX_cache_mem_req_if.v @@ -0,0 +1,23 @@ +`ifndef VX_CACHE_MEM_REQ_IF +`define VX_CACHE_MEM_REQ_IF + +`include "../cache/VX_cache_config.vh" + +interface VX_cache_mem_req_if #( + parameter MEM_LINE_WIDTH = 1, + parameter MEM_ADDR_WIDTH = 1, + parameter MEM_TAG_WIDTH = 1, + parameter MEM_LINE_SIZE = MEM_LINE_WIDTH / 8 +) (); + + wire valid; + wire rw; + wire [MEM_LINE_SIZE-1:0] byteen; + wire [MEM_ADDR_WIDTH-1:0] addr; + wire [MEM_LINE_WIDTH-1:0] data; + wire [MEM_TAG_WIDTH-1:0] tag; + wire ready; + +endinterface + +`endif \ No newline at end of file diff --git a/hw/rtl/interfaces/VX_cache_mem_rsp_if.v b/hw/rtl/interfaces/VX_cache_mem_rsp_if.v new file mode 100644 index 00000000..eb4abf26 --- /dev/null +++ b/hw/rtl/interfaces/VX_cache_mem_rsp_if.v @@ -0,0 +1,18 @@ +`ifndef VX_CACHE_MEM_RSP_IF +`define VX_CACHE_MEM_RSP_IF + +`include "../cache/VX_cache_config.vh" + +interface VX_cache_mem_rsp_if #( + parameter MEM_LINE_WIDTH = 1, + parameter MEM_TAG_WIDTH = 1 +) (); + + wire valid; + wire [MEM_LINE_WIDTH-1:0] data; + wire [MEM_TAG_WIDTH-1:0] tag; + wire ready; + +endinterface + +`endif \ No newline at end of file diff --git a/hw/rtl/interfaces/VX_perf_memsys_if.v b/hw/rtl/interfaces/VX_perf_memsys_if.v index 21484151..a2ef4835 100644 --- a/hw/rtl/interfaces/VX_perf_memsys_if.v +++ b/hw/rtl/interfaces/VX_perf_memsys_if.v @@ -23,10 +23,10 @@ interface VX_perf_memsys_if (); wire [`PERF_CTR_BITS-1:0] smem_writes; wire [`PERF_CTR_BITS-1:0] smem_bank_stalls; - wire [`PERF_CTR_BITS-1:0] dram_reads; - wire [`PERF_CTR_BITS-1:0] dram_writes; - wire [`PERF_CTR_BITS-1:0] dram_stalls; - wire [`PERF_CTR_BITS-1:0] dram_latency; + wire [`PERF_CTR_BITS-1:0] mem_reads; + wire [`PERF_CTR_BITS-1:0] mem_writes; + wire [`PERF_CTR_BITS-1:0] mem_stalls; + wire [`PERF_CTR_BITS-1:0] mem_latency; endinterface diff --git a/hw/scripts/scope.json b/hw/scripts/scope.json index d4d8033f..6290a622 100644 --- a/hw/scripts/scope.json +++ b/hw/scripts/scope.json @@ -98,8 +98,8 @@ "avs_burstcount":4, "avs_readdatavalid":1, "mem_bank_select":1, - "cci_dram_rd_req_ctr":26, - "cci_dram_wr_req_ctr":26, + "cci_mem_rd_req_ctr":26, + "cci_mem_wr_req_ctr":26, "cci_rd_req_ctr":26, "cci_rd_rsp_ctr":3, "cci_wr_req_ctr":26, @@ -110,23 +110,23 @@ "!cci_pending_reads_full":1, "!cci_pending_writes_empty":1, "!cci_pending_writes_full": 1, - "?afu_dram_req_fire": 1, - "afu_dram_req_addr": 26, - "afu_dram_req_tag": 28, - "?afu_dram_rsp_fire": 1, - "afu_dram_rsp_tag": 28 + "?afu_mem_req_fire": 1, + "afu_mem_req_addr": 26, + "afu_mem_req_tag": 28, + "?afu_mem_rsp_fire": 1, + "afu_mem_rsp_tag": 28 }, "afu/vortex": { "!reset": 1, - "?dram_req_fire": 1, - "dram_req_addr": 32, - "dram_req_rw": 1, - "dram_req_byteen":"`VX_DRAM_BYTEEN_WIDTH", - "dram_req_data":"`VX_DRAM_LINE_WIDTH", - "dram_req_tag":"`VX_DRAM_TAG_WIDTH", - "?dram_rsp_fire": 1, - "dram_rsp_data":"`VX_DRAM_LINE_WIDTH", - "dram_rsp_tag":"`VX_DRAM_TAG_WIDTH", + "?mem_req_fire": 1, + "mem_req_addr": 32, + "mem_req_rw": 1, + "mem_req_byteen":"`VX_MEM_BYTEEN_WIDTH", + "mem_req_data":"`VX_MEM_LINE_WIDTH", + "mem_req_tag":"`VX_MEM_TAG_WIDTH", + "?mem_rsp_fire": 1, + "mem_rsp_data":"`VX_MEM_LINE_WIDTH", + "mem_rsp_tag":"`VX_MEM_TAG_WIDTH", "busy": 1 }, "afu/vortex/cluster/core/pipeline/fetch/icache_stage": { @@ -213,7 +213,7 @@ "force_miss_st0": 1, "mshr_push": 1, "?crsq_in_stall": 1, - "?dreq_alm_full": 1, + "?mreq_alm_full": 1, "?mshr_alm_full": 1 } } diff --git a/hw/simulate/Makefile b/hw/simulate/Makefile index 7b1d9b9c..dbbae208 100644 --- a/hw/simulate/Makefile +++ b/hw/simulate/Makefile @@ -13,7 +13,7 @@ DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_BANK DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_MSHR DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_TAG DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_DATA -DBG_PRINT_FLAGS += -DDBG_PRINT_DRAM +DBG_PRINT_FLAGS += -DDBG_PRINT_MEM DBG_PRINT_FLAGS += -DDBG_PRINT_OPAE DBG_PRINT_FLAGS += -DDBG_PRINT_AVS DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE diff --git a/hw/simulate/simulator.cpp b/hw/simulate/simulator.cpp index 2a4d8a1a..e19aaacd 100644 --- a/hw/simulate/simulator.cpp +++ b/hw/simulate/simulator.cpp @@ -5,10 +5,10 @@ #define RESET_DELAY 4 -#define ENABLE_DRAM_STALLS -#define DRAM_LATENCY 24 -#define DRAM_RQ_SIZE 16 -#define DRAM_STALLS_MODULO 16 +#define ENABLE_MEM_STALLS +#define MEM_LATENCY 24 +#define MEM_RQ_SIZE 16 +#define MEM_STALLS_MODULO 16 #define VL_WDATA_GETW(lwp, i, n, w) \ VL_SEL_IWII(0, n * w, 0, 0, lwp, i * w, w) @@ -56,19 +56,19 @@ Simulator::~Simulator() { void Simulator::attach_ram(RAM* ram) { ram_ = ram; - dram_rsp_vec_.clear(); + mem_rsp_vec_.clear(); } void Simulator::reset() { print_bufs_.clear(); - dram_rsp_vec_.clear(); + mem_rsp_vec_.clear(); - dram_rsp_active_ = false; + mem_rsp_active_ = false; csr_req_active_ = false; csr_rsp_value_ = nullptr; - vortex_->dram_rsp_valid = 0; - vortex_->dram_req_ready = 0; + vortex_->mem_rsp_valid = 0; + vortex_->mem_req_ready = 0; //vortex_->io_req_ready = 0; //vortex_->io_rsp_valid = 0; vortex_->csr_req_valid = 0; @@ -94,13 +94,13 @@ void Simulator::step() { vortex_->clk = 0; this->eval(); - dram_rsp_ready_ = vortex_->dram_rsp_ready; + mem_rsp_ready_ = vortex_->mem_rsp_ready; csr_req_ready_ = vortex_->csr_req_ready; vortex_->clk = 1; this->eval(); - this->eval_dram_bus(); + this->eval_mem_bus(); this->eval_io_bus(); this->eval_csr_bus(); @@ -117,83 +117,83 @@ void Simulator::eval() { ++timestamp; } -void Simulator::eval_dram_bus() { +void Simulator::eval_mem_bus() { if (ram_ == nullptr) { - vortex_->dram_req_ready = 0; + vortex_->mem_req_ready = 0; return; } - // update DRAM responses schedule - for (auto& rsp : dram_rsp_vec_) { + // update memory responses schedule + for (auto& rsp : mem_rsp_vec_) { if (rsp.cycles_left > 0) rsp.cycles_left -= 1; } - // schedule DRAM responses in FIFO order - std::list::iterator dram_rsp_it(dram_rsp_vec_.end()); - if (!dram_rsp_vec_.empty() - && (0 == dram_rsp_vec_.begin()->cycles_left)) { - dram_rsp_it = dram_rsp_vec_.begin(); + // schedule memory responses in FIFO order + std::list::iterator mem_rsp_it(mem_rsp_vec_.end()); + if (!mem_rsp_vec_.empty() + && (0 == mem_rsp_vec_.begin()->cycles_left)) { + mem_rsp_it = mem_rsp_vec_.begin(); } - // send DRAM response - if (dram_rsp_active_ - && vortex_->dram_rsp_valid && dram_rsp_ready_) { - dram_rsp_active_ = false; + // send memory response + if (mem_rsp_active_ + && vortex_->mem_rsp_valid && mem_rsp_ready_) { + mem_rsp_active_ = false; } - if (!dram_rsp_active_) { - if (dram_rsp_it != dram_rsp_vec_.end()) { - vortex_->dram_rsp_valid = 1; - memcpy((uint8_t*)vortex_->dram_rsp_data, dram_rsp_it->block.data(), GLOBAL_BLOCK_SIZE); - vortex_->dram_rsp_tag = dram_rsp_it->tag; - dram_rsp_vec_.erase(dram_rsp_it); - dram_rsp_active_ = true; + if (!mem_rsp_active_) { + if (mem_rsp_it != mem_rsp_vec_.end()) { + vortex_->mem_rsp_valid = 1; + memcpy((uint8_t*)vortex_->mem_rsp_data, mem_rsp_it->block.data(), GLOBAL_BLOCK_SIZE); + vortex_->mem_rsp_tag = mem_rsp_it->tag; + mem_rsp_vec_.erase(mem_rsp_it); + mem_rsp_active_ = true; } else { - vortex_->dram_rsp_valid = 0; + vortex_->mem_rsp_valid = 0; } } - // handle DRAM stalls - bool dram_stalled = false; -#ifdef ENABLE_DRAM_STALLS - if (0 == ((timestamp/2) % DRAM_STALLS_MODULO)) { - dram_stalled = true; + // handle memory stalls + bool mem_stalled = false; +#ifdef ENABLE_MEM_STALLS + if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) { + mem_stalled = true; } else - if (dram_rsp_vec_.size() >= DRAM_RQ_SIZE) { - dram_stalled = true; + if (mem_rsp_vec_.size() >= MEM_RQ_SIZE) { + mem_stalled = true; } #endif - // process DRAM requests - if (!dram_stalled) { - if (vortex_->dram_req_valid) { - if (vortex_->dram_req_rw) { - uint64_t byteen = vortex_->dram_req_byteen; - unsigned base_addr = (vortex_->dram_req_addr * GLOBAL_BLOCK_SIZE); - uint8_t* data = (uint8_t*)(vortex_->dram_req_data); + // process memory requests + if (!mem_stalled) { + if (vortex_->mem_req_valid) { + if (vortex_->mem_req_rw) { + uint64_t byteen = vortex_->mem_req_byteen; + unsigned base_addr = (vortex_->mem_req_addr * GLOBAL_BLOCK_SIZE); + uint8_t* data = (uint8_t*)(vortex_->mem_req_data); for (int i = 0; i < GLOBAL_BLOCK_SIZE; i++) { if ((byteen >> i) & 0x1) { (*ram_)[base_addr + i] = data[i]; } } } else { - dram_req_t dram_req; - dram_req.tag = vortex_->dram_req_tag; - dram_req.addr = vortex_->dram_req_addr; - ram_->read(vortex_->dram_req_addr * GLOBAL_BLOCK_SIZE, GLOBAL_BLOCK_SIZE, dram_req.block.data()); - dram_req.cycles_left = DRAM_LATENCY; - for (auto& rsp : dram_rsp_vec_) { - if (dram_req.addr == rsp.addr) { - dram_req.cycles_left = rsp.cycles_left; + mem_req_t mem_req; + mem_req.tag = vortex_->mem_req_tag; + mem_req.addr = vortex_->mem_req_addr; + ram_->read(vortex_->mem_req_addr * GLOBAL_BLOCK_SIZE, GLOBAL_BLOCK_SIZE, mem_req.block.data()); + mem_req.cycles_left = MEM_LATENCY; + for (auto& rsp : mem_rsp_vec_) { + if (mem_req.addr == rsp.addr) { + mem_req.cycles_left = rsp.cycles_left; break; } } - dram_rsp_vec_.emplace_back(dram_req); + mem_rsp_vec_.emplace_back(mem_req); } } } - vortex_->dram_req_ready = !dram_stalled; + vortex_->mem_req_ready = !mem_stalled; } void Simulator::eval_io_bus() { diff --git a/hw/simulate/simulator.h b/hw/simulate/simulator.h index 626474bd..f800e643 100644 --- a/hw/simulate/simulator.h +++ b/hw/simulate/simulator.h @@ -51,20 +51,20 @@ private: std::array block; uint32_t addr; uint32_t tag; - } dram_req_t; + } mem_req_t; std::unordered_map print_bufs_; void eval(); - void eval_dram_bus(); + void eval_mem_bus(); void eval_io_bus(); void eval_csr_bus(); - std::list dram_rsp_vec_; - bool dram_rsp_active_; + std::list mem_rsp_vec_; + bool mem_rsp_active_; - bool dram_rsp_ready_; + bool mem_rsp_ready_; bool csr_req_ready_; bool csr_req_active_; uint32_t* csr_rsp_value_; diff --git a/hw/modelsim/Makefile b/hw/syn/modelsim/Makefile similarity index 100% rename from hw/modelsim/Makefile rename to hw/syn/modelsim/Makefile diff --git a/hw/modelsim/cshrc.modelsim b/hw/syn/modelsim/cshrc.modelsim similarity index 100% rename from hw/modelsim/cshrc.modelsim rename to hw/syn/modelsim/cshrc.modelsim diff --git a/hw/modelsim/vortex_dpi.cpp b/hw/syn/modelsim/vortex_dpi.cpp similarity index 100% rename from hw/modelsim/vortex_dpi.cpp rename to hw/syn/modelsim/vortex_dpi.cpp diff --git a/hw/modelsim/vortex_dpi.h b/hw/syn/modelsim/vortex_dpi.h similarity index 100% rename from hw/modelsim/vortex_dpi.h rename to hw/syn/modelsim/vortex_dpi.h diff --git a/hw/modelsim/vortex_tb.v b/hw/syn/modelsim/vortex_tb.v similarity index 100% rename from hw/modelsim/vortex_tb.v rename to hw/syn/modelsim/vortex_tb.v diff --git a/hw/syn/opae/README b/hw/syn/opae/README index 03233d0b..35a2a9a6 100644 --- a/hw/syn/opae/README +++ b/hw/syn/opae/README @@ -63,6 +63,7 @@ qsub-sim make ase # tests +./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n128 -t0 ./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n16 ./run_ase.sh build_ase_1c ../../../driver/tests/demo/demo -n16 ./run_ase.sh build_ase_1c ../../../driver/tests/dogfood/dogfood -n16 @@ -78,17 +79,15 @@ run -all tar -zcvf output_files_1c.tar.gz `find ./build_fpga_1c -type f \( -iname \*.rpt -o -iname \*.txt -o -iname \*summary -o -iname \*.log \)` # compress VCD trace -tar -zcvf vortex.vcd.tar.gz ./build_ase_1c/work/vortex.vcd +tar -zcvf trace.vcd.tar.gz ./build_ase_1c/work/trace.vcd tar -zcvf trace.vcd.tar.gz obj_dir/trace.vcd tar -zcvf trace.fst.tar.gz trace.fst run.log tar -zcvf run.log.tar.gz run.log -tar -cvjf vortex.vcd.tar.bz2 build_ase_1c/work/vortex.vcd -tar -zcvf vortex.vcd.tar.gz build_ase_1c/work/vortex.vcd -tar -zcvf run.log.tar.gz build_ase_1c/work/run.log tar -zcvf vx_scope.vcd.tar.gz vx_scope.vcd tar -cvjf vx_scope.vcd.tar.bz2 vx_scope.vcd tar -cvjf trace.fst.tar.bz2 trace.fst run.log tar -cvjf trace.vcd.tar.bz2 trace.vcd run.log +tar -cvjf trace.vcd.tar.bz2 build_ase_1c/work/run.log build_ase_1c/work/trace.vcd # decompress VCD trace tar -zxvf vortex.vcd.tar.gz diff --git a/hw/unit_tests/cache/Makefile b/hw/unit_tests/cache/Makefile index bf22bcbc..b6552316 100644 --- a/hw/unit_tests/cache/Makefile +++ b/hw/unit_tests/cache/Makefile @@ -10,7 +10,7 @@ DBG_PRINT_FLAGS = -DDBG_PRINT_CORE_ICACHE \ -DDBG_PRINT_CACHE_MSHR \ -DDBG_PRINT_CACHE_TAG \ -DDBG_PRINT_CACHE_DATA \ - -DDBG_PRINT_DRAM \ + -DDBG_PRINT_MEM \ -DDBG_PRINT_OPAE \ -DDBG_PRINT_AVS diff --git a/hw/unit_tests/cache/cachesim.cpp b/hw/unit_tests/cache/cachesim.cpp index 93bef54b..528a5dfe 100644 --- a/hw/unit_tests/cache/cachesim.cpp +++ b/hw/unit_tests/cache/cachesim.cpp @@ -18,7 +18,7 @@ CacheSim::CacheSim() { ram_ = nullptr; cache_ = new VVX_cache(); - dram_rsp_active_ = false; + mem_rsp_active_ = false; snp_req_active_ = false; //#ifdef VCD_OUTPUT @@ -39,7 +39,7 @@ CacheSim::~CacheSim() { void CacheSim::attach_ram(RAM* ram) { ram_ = ram; - dram_rsp_vec_.clear(); + mem_rsp_vec_.clear(); } void CacheSim::reset() { @@ -52,7 +52,7 @@ void CacheSim::reset() { cache_->reset = 0; this->step(); - dram_rsp_vec_.clear(); + mem_rsp_vec_.clear(); //clear req and rsp vecs } @@ -66,10 +66,10 @@ void CacheSim::step() { cache_->clk = 1; this->eval(); - //handle core and dram reqs and rsps + //handle core and memory reqs and rsps this->eval_reqs(); this->eval_rsps(); - this->eval_dram_bus(); + this->eval_mem_bus(); timestamp++; } @@ -104,7 +104,7 @@ void CacheSim::run(){ } stalls--; if (stalls == 20){ - //stall_dram(); + //stall_mem(); //send_snoop_req(); stalls--; } @@ -168,8 +168,8 @@ void CacheSim::eval_rsps(){ } } -void CacheSim::stall_dram(){ - cache_->dram_req_ready = 0; +void CacheSim::stall_mem(){ + cache_->mem_req_ready = 0; } void CacheSim::send_snoop_req(){ @@ -179,81 +179,81 @@ void CacheSim::send_snoop_req(){ cache_->snp_req_tag = 0xff; } -void CacheSim::eval_dram_bus() { +void CacheSim::eval_mem_bus() { if (ram_ == nullptr) { - cache_->dram_req_ready = 0; + cache_->mem_req_ready = 0; return; } - // schedule DRAM responses + // schedule memory responses int dequeue_index = -1; - for (int i = 0; i < dram_rsp_vec_.size(); i++) { - if (dram_rsp_vec_[i].cycles_left > 0) { - dram_rsp_vec_[i].cycles_left -= 1; + for (int i = 0; i < mem_rsp_vec_.size(); i++) { + if (mem_rsp_vec_[i].cycles_left > 0) { + mem_rsp_vec_[i].cycles_left -= 1; } if ((dequeue_index == -1) - && (dram_rsp_vec_[i].cycles_left == 0)) { + && (mem_rsp_vec_[i].cycles_left == 0)) { dequeue_index = i; } } - // send DRAM response - if (dram_rsp_active_ - && cache_->dram_rsp_valid - && cache_->dram_rsp_ready) { - dram_rsp_active_ = false; + // send memory response + if (mem_rsp_active_ + && cache_->mem_rsp_valid + && cache_->mem_rsp_ready) { + mem_rsp_active_ = false; } - if (!dram_rsp_active_) { + if (!mem_rsp_active_) { if (dequeue_index != -1) { //time to respond to the request - cache_->dram_rsp_valid = 1; + cache_->mem_rsp_valid = 1; //copy data from the rsp queue to the cache module - memcpy((uint8_t*)cache_->dram_rsp_data, dram_rsp_vec_[dequeue_index].data, GLOBAL_BLOCK_SIZE); + memcpy((uint8_t*)cache_->mem_rsp_data, mem_rsp_vec_[dequeue_index].data, GLOBAL_BLOCK_SIZE); - cache_->dram_rsp_tag = dram_rsp_vec_[dequeue_index].tag; - free(dram_rsp_vec_[dequeue_index].data); //take data out of the queue - dram_rsp_vec_.erase(dram_rsp_vec_.begin() + dequeue_index); - dram_rsp_active_ = true; + cache_->mem_rsp_tag = mem_rsp_vec_[dequeue_index].tag; + free(mem_rsp_vec_[dequeue_index].data); //take data out of the queue + mem_rsp_vec_.erase(mem_rsp_vec_.begin() + dequeue_index); + mem_rsp_active_ = true; } else { - cache_->dram_rsp_valid = 0; + cache_->mem_rsp_valid = 0; } } - // handle DRAM stalls - bool dram_stalled = false; -#ifdef ENABLE_DRAM_STALLS - if (0 == ((timestamp/2) % DRAM_STALLS_MODULO)) { - dram_stalled = true; + // handle memory stalls + bool mem_stalled = false; +#ifdef ENABLE_MEM_STALLS + if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) { + mem_stalled = true; } else - if (dram_rsp_vec_.size() >= DRAM_RQ_SIZE) { - dram_stalled = true; + if (mem_rsp_vec_.size() >= MEM_RQ_SIZE) { + mem_stalled = true; } #endif - // process DRAM requests - if (!dram_stalled) { - if (cache_->dram_req_valid) { - if (cache_->dram_req_rw) { //write = 1 - uint64_t byteen = cache_->dram_req_byteen; - unsigned base_addr = (cache_->dram_req_addr * GLOBAL_BLOCK_SIZE); - uint8_t* data = (uint8_t*)(cache_->dram_req_data); + // process memory requests + if (!mem_stalled) { + if (cache_->mem_req_valid) { + if (cache_->mem_req_rw) { //write = 1 + uint64_t byteen = cache_->mem_req_byteen; + unsigned base_addr = (cache_->mem_req_addr * GLOBAL_BLOCK_SIZE); + uint8_t* data = (uint8_t*)(cache_->mem_req_data); for (int i = 0; i < GLOBAL_BLOCK_SIZE; i++) { if ((byteen >> i) & 0x1) { (*ram_)[base_addr + i] = data[i]; } } } else { - dram_req_t dram_req; - dram_req.cycles_left = DRAM_LATENCY; - dram_req.data = (uint8_t*)malloc(GLOBAL_BLOCK_SIZE); - dram_req.tag = cache_->dram_req_tag; - ram_->read(cache_->dram_req_addr * GLOBAL_BLOCK_SIZE, GLOBAL_BLOCK_SIZE, dram_req.data); - dram_rsp_vec_.push_back(dram_req); + mem_req_t mem_req; + mem_req.cycles_left = MEM_LATENCY; + mem_req.data = (uint8_t*)malloc(GLOBAL_BLOCK_SIZE); + mem_req.tag = cache_->mem_req_tag; + ram_->read(cache_->mem_req_addr * GLOBAL_BLOCK_SIZE, GLOBAL_BLOCK_SIZE, mem_req.data); + mem_rsp_vec_.push_back(mem_req); } } } - cache_->dram_req_ready = ~dram_stalled; + cache_->mem_req_ready = ~mem_stalled; } bool CacheSim::assert_equal(unsigned int* data, unsigned int tag){ @@ -302,19 +302,19 @@ void CacheSim::get_core_rsp(){ std::cout << std::hex << "core_rsp_tag: " << cache_->core_rsp_tag << std::endl; } -void CacheSim::get_dram_req(){ - std::cout << std::hex << "dram_req_valid: " << cache_->dram_req_valid << std::endl; - std::cout << std::hex << "dram_req_rw: " << cache_->dram_req_rw << std::endl; - std::cout << std::hex << "dram_req_byteen: " << cache_->dram_req_byteen << std::endl; - std::cout << std::hex << "dram_req_addr: " << cache_->dram_req_addr << std::endl; - std::cout << std::hex << "dram_req_data: " << cache_->dram_req_data << std::endl; - std::cout << std::hex << "dram_req_tag: " << cache_->dram_req_tag << std::endl; +void CacheSim::get_mem_req(){ + std::cout << std::hex << "mem_req_valid: " << cache_->mem_req_valid << std::endl; + std::cout << std::hex << "mem_req_rw: " << cache_->mem_req_rw << std::endl; + std::cout << std::hex << "mem_req_byteen: " << cache_->mem_req_byteen << std::endl; + std::cout << std::hex << "mem_req_addr: " << cache_->mem_req_addr << std::endl; + std::cout << std::hex << "mem_req_data: " << cache_->mem_req_data << std::endl; + std::cout << std::hex << "mem_req_tag: " << cache_->mem_req_tag << std::endl; } -void CacheSim::get_dram_rsp(){ - std::cout << std::hex << "dram_rsp_valid: " << cache_->dram_rsp_valid << std::endl; - std::cout << std::hex << "dram_rsp_data: " << cache_->dram_rsp_data << std::endl; - std::cout << std::hex << "dram_rsp_tag: " << cache_->dram_rsp_tag << std::endl; - std::cout << std::hex << "dram_rsp_ready: " << cache_->dram_rsp_ready << std::endl; +void CacheSim::get_mem_rsp(){ + std::cout << std::hex << "mem_rsp_valid: " << cache_->mem_rsp_valid << std::endl; + std::cout << std::hex << "mem_rsp_data: " << cache_->mem_rsp_data << std::endl; + std::cout << std::hex << "mem_rsp_tag: " << cache_->mem_rsp_tag << std::endl; + std::cout << std::hex << "mem_rsp_ready: " << cache_->mem_rsp_ready << std::endl; } diff --git a/hw/unit_tests/cache/cachesim.h b/hw/unit_tests/cache/cachesim.h index e6324bf6..2a4be624 100644 --- a/hw/unit_tests/cache/cachesim.h +++ b/hw/unit_tests/cache/cachesim.h @@ -14,17 +14,17 @@ #include #include -#define ENABLE_DRAM_STALLS -#define DRAM_LATENCY 100 -#define DRAM_RQ_SIZE 16 -#define DRAM_STALLS_MODULO 16 +#define ENABLE_MEM_STALLS +#define MEM_LATENCY 100 +#define MEM_RQ_SIZE 16 +#define MEM_STALLS_MODULO 16 #define GLOBAL_BLOCK_SIZE 16 typedef struct { int cycles_left; uint8_t *data; unsigned tag; -} dram_req_t; +} mem_req_t; typedef struct { char valid; @@ -52,7 +52,7 @@ public: //req/rsp void send_req(core_req_t *req); void clear_req(); - void stall_dram(); + void stall_mem(); void send_snoop_req(); void send_snp_fwd_in(); @@ -60,12 +60,12 @@ public: bool assert_equal(unsigned int* data, unsigned int tag); //debug funcs - void get_dram_req(); + void get_mem_req(); void get_core_req(unsigned int (&rsp)[4]); void get_core_rsp(); bool get_core_req_ready(); bool get_core_rsp_ready(); - void get_dram_rsp(); + void get_mem_rsp(); void display_miss(); private: @@ -73,12 +73,12 @@ private: void eval(); void eval_reqs(); void eval_rsps(); - void eval_dram_bus(); + void eval_mem_bus(); std::queue core_req_vec_; - std::vector dram_rsp_vec_; + std::vector mem_rsp_vec_; std::map core_rsp_vec_; - int dram_rsp_active_; + int mem_rsp_active_; uint32_t snp_req_active_; uint32_t snp_req_size_; diff --git a/hw/unit_tests/cache/testbench.cpp b/hw/unit_tests/cache/testbench.cpp index c668f26a..4a38bb7c 100644 --- a/hw/unit_tests/cache/testbench.cpp +++ b/hw/unit_tests/cache/testbench.cpp @@ -175,7 +175,7 @@ int FLUSH(CacheSim *sim){ int BACK_PRESSURE(CacheSim *sim){ - //happens whenever the core is stalled or DRAM is stalled + //happens whenever the core is stalled or memory is stalled unsigned int addr[4] = {0x12222222, 0xabbbbbbb, 0xcddddddd, 0xe4444444}; unsigned int data[4] = {0xffffffff, 0x11111111, 0x22222222, 0x33333333}; unsigned int rsp[4] = {0,0,0,0}; From 8543e3a8bfe1b63efd286256861bc655f18a5bee Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 26 Apr 2021 02:34:21 -0700 Subject: [PATCH 14/55] code refactoring --- driver/opae/vlsim/opae_sim.h | 2 -- hw/rtl/VX_config.vh | 8 ++++---- hw/rtl/VX_define.vh | 8 ++++---- hw/simulate/simulator.cpp | 8 ++++---- hw/simulate/simulator.h | 2 +- hw/unit_tests/cache/cachesim.cpp | 10 +++++----- hw/unit_tests/cache/cachesim.h | 2 +- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/driver/opae/vlsim/opae_sim.h b/driver/opae/vlsim/opae_sim.h index 76e5f435..ee4f022a 100644 --- a/driver/opae/vlsim/opae_sim.h +++ b/driver/opae/vlsim/opae_sim.h @@ -17,8 +17,6 @@ #include #include -#define MEM_BLOCK_SIZE (PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH / 8) - #define CACHE_BLOCK_SIZE 64 class opae_sim { diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 2b2727fc..2f7bfe07 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -33,11 +33,11 @@ `define SM_ENABLE 1 `endif -`ifndef GLOBAL_BLOCK_SIZE -`ifdef PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH - `define GLOBAL_BLOCK_SIZE (`PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH / 8) +`ifndef MEM_BLOCK_SIZE +`ifdef LOCAL_MEM_DATA_N_BYTES + `define MEM_BLOCK_SIZE `LOCAL_MEM_DATA_N_BYTES `else - `define GLOBAL_BLOCK_SIZE 64 + `define MEM_BLOCK_SIZE 64 `endif `endif diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index 79de9b8f..b9ef4014 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -243,7 +243,7 @@ `define ICACHE_ID (32'(`L3_ENABLE) + 32'(`L2_ENABLE) * `NUM_CLUSTERS + CORE_ID * 3 + 0) // Block size in bytes -`define ICACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `GLOBAL_BLOCK_SIZE) +`define ICACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `MEM_BLOCK_SIZE) // Word size in bytes `define IWORD_SIZE 4 @@ -275,7 +275,7 @@ `define DCACHE_ID (32'(`L3_ENABLE) + 32'(`L2_ENABLE) * `NUM_CLUSTERS + CORE_ID * 3 + 1) // Block size in bytes -`define DCACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `GLOBAL_BLOCK_SIZE) +`define DCACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `MEM_BLOCK_SIZE) // Word size in bytes `define DWORD_SIZE 4 @@ -324,7 +324,7 @@ `define L2CACHE_ID (32'(`L3_ENABLE) + CLUSTER_ID) // Block size in bytes -`define L2CACHE_LINE_SIZE `GLOBAL_BLOCK_SIZE +`define L2CACHE_LINE_SIZE `MEM_BLOCK_SIZE // Word size in bytes `define L2WORD_SIZE `DCACHE_LINE_SIZE @@ -350,7 +350,7 @@ `define L3CACHE_ID 0 // Block size in bytes -`define L3CACHE_LINE_SIZE `GLOBAL_BLOCK_SIZE +`define L3CACHE_LINE_SIZE `MEM_BLOCK_SIZE // Word size in bytes `define L3WORD_SIZE `L2CACHE_LINE_SIZE diff --git a/hw/simulate/simulator.cpp b/hw/simulate/simulator.cpp index e19aaacd..86156b94 100644 --- a/hw/simulate/simulator.cpp +++ b/hw/simulate/simulator.cpp @@ -144,7 +144,7 @@ void Simulator::eval_mem_bus() { if (!mem_rsp_active_) { if (mem_rsp_it != mem_rsp_vec_.end()) { vortex_->mem_rsp_valid = 1; - memcpy((uint8_t*)vortex_->mem_rsp_data, mem_rsp_it->block.data(), GLOBAL_BLOCK_SIZE); + memcpy((uint8_t*)vortex_->mem_rsp_data, mem_rsp_it->block.data(), MEM_BLOCK_SIZE); vortex_->mem_rsp_tag = mem_rsp_it->tag; mem_rsp_vec_.erase(mem_rsp_it); mem_rsp_active_ = true; @@ -169,9 +169,9 @@ void Simulator::eval_mem_bus() { if (vortex_->mem_req_valid) { if (vortex_->mem_req_rw) { uint64_t byteen = vortex_->mem_req_byteen; - unsigned base_addr = (vortex_->mem_req_addr * GLOBAL_BLOCK_SIZE); + unsigned base_addr = (vortex_->mem_req_addr * MEM_BLOCK_SIZE); uint8_t* data = (uint8_t*)(vortex_->mem_req_data); - for (int i = 0; i < GLOBAL_BLOCK_SIZE; i++) { + for (int i = 0; i < MEM_BLOCK_SIZE; i++) { if ((byteen >> i) & 0x1) { (*ram_)[base_addr + i] = data[i]; } @@ -180,7 +180,7 @@ void Simulator::eval_mem_bus() { mem_req_t mem_req; mem_req.tag = vortex_->mem_req_tag; mem_req.addr = vortex_->mem_req_addr; - ram_->read(vortex_->mem_req_addr * GLOBAL_BLOCK_SIZE, GLOBAL_BLOCK_SIZE, mem_req.block.data()); + ram_->read(vortex_->mem_req_addr * MEM_BLOCK_SIZE, MEM_BLOCK_SIZE, mem_req.block.data()); mem_req.cycles_left = MEM_LATENCY; for (auto& rsp : mem_rsp_vec_) { if (mem_req.addr == rsp.addr) { diff --git a/hw/simulate/simulator.h b/hw/simulate/simulator.h index f800e643..80e2fa42 100644 --- a/hw/simulate/simulator.h +++ b/hw/simulate/simulator.h @@ -48,7 +48,7 @@ private: typedef struct { int cycles_left; - std::array block; + std::array block; uint32_t addr; uint32_t tag; } mem_req_t; diff --git a/hw/unit_tests/cache/cachesim.cpp b/hw/unit_tests/cache/cachesim.cpp index 528a5dfe..951740d8 100644 --- a/hw/unit_tests/cache/cachesim.cpp +++ b/hw/unit_tests/cache/cachesim.cpp @@ -208,7 +208,7 @@ void CacheSim::eval_mem_bus() { cache_->mem_rsp_valid = 1; //copy data from the rsp queue to the cache module - memcpy((uint8_t*)cache_->mem_rsp_data, mem_rsp_vec_[dequeue_index].data, GLOBAL_BLOCK_SIZE); + memcpy((uint8_t*)cache_->mem_rsp_data, mem_rsp_vec_[dequeue_index].data, MEM_BLOCK_SIZE); cache_->mem_rsp_tag = mem_rsp_vec_[dequeue_index].tag; free(mem_rsp_vec_[dequeue_index].data); //take data out of the queue @@ -235,9 +235,9 @@ void CacheSim::eval_mem_bus() { if (cache_->mem_req_valid) { if (cache_->mem_req_rw) { //write = 1 uint64_t byteen = cache_->mem_req_byteen; - unsigned base_addr = (cache_->mem_req_addr * GLOBAL_BLOCK_SIZE); + unsigned base_addr = (cache_->mem_req_addr * MEM_BLOCK_SIZE); uint8_t* data = (uint8_t*)(cache_->mem_req_data); - for (int i = 0; i < GLOBAL_BLOCK_SIZE; i++) { + for (int i = 0; i < MEM_BLOCK_SIZE; i++) { if ((byteen >> i) & 0x1) { (*ram_)[base_addr + i] = data[i]; } @@ -245,9 +245,9 @@ void CacheSim::eval_mem_bus() { } else { mem_req_t mem_req; mem_req.cycles_left = MEM_LATENCY; - mem_req.data = (uint8_t*)malloc(GLOBAL_BLOCK_SIZE); + mem_req.data = (uint8_t*)malloc(MEM_BLOCK_SIZE); mem_req.tag = cache_->mem_req_tag; - ram_->read(cache_->mem_req_addr * GLOBAL_BLOCK_SIZE, GLOBAL_BLOCK_SIZE, mem_req.data); + ram_->read(cache_->mem_req_addr * MEM_BLOCK_SIZE, MEM_BLOCK_SIZE, mem_req.data); mem_rsp_vec_.push_back(mem_req); } } diff --git a/hw/unit_tests/cache/cachesim.h b/hw/unit_tests/cache/cachesim.h index 2a4be624..72cc44f9 100644 --- a/hw/unit_tests/cache/cachesim.h +++ b/hw/unit_tests/cache/cachesim.h @@ -18,7 +18,7 @@ #define MEM_LATENCY 100 #define MEM_RQ_SIZE 16 #define MEM_STALLS_MODULO 16 -#define GLOBAL_BLOCK_SIZE 16 +#define MEM_BLOCK_SIZE 16 typedef struct { int cycles_left; From 0910f9561652008baa02b6a05888996858bbf598 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 26 Apr 2021 02:35:50 -0700 Subject: [PATCH 15/55] code refactoring --- hw/syn/opae/Makefile | 43 ++++++++++++++++++++----------------- hw/syn/opae/gen_sources.sh | 3 ++- hw/syn/opae/sources_32c.txt | 2 -- hw/syn/opae/sources_64c.txt | 2 -- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/hw/syn/opae/Makefile b/hw/syn/opae/Makefile index 5a871248..b0b48661 100644 --- a/hw/syn/opae/Makefile +++ b/hw/syn/opae/Makefile @@ -1,8 +1,14 @@ -ASE_BUILD_DIR=build_ase -FPGA_BUILD_DIR=build_fpga +ASE_BUILD_DIR ?= build_ase +FPGA_BUILD_DIR ?= build_fpga RTL_DIR=../../rtl -ifeq (, $(shell which qsub-synth)) +ifdef $(shell [[ '$(FPGA_CLASS)' =~ 'fpga-pac-s10' ]] && echo matched) + DEVICE_FAMILY ?= stratix10 +else + DEVICE_FAMILY ?= arria10 +endif + +ifeq ($(shell which qsub-synth),) RUN_SYNTH=$(OPAE_PLATFORM_ROOT)/bin/run.sh > build.log 2>&1 & else RUN_SYNTH=qsub-synth @@ -10,21 +16,18 @@ endif all: ase-1c -gen_sources_a10: - ./gen_sources.sh arria10 > sources.txt +gen-sources: + ./gen_sources.sh $(DEVICE_FAMILY) > sources.txt -gen_sources_s10: - ./gen_sources.sh stratix10 > sources.txt - -ase-1c: gen_sources_a10 setup-ase-1c +ase-1c: gen-sources setup-ase-1c make -C $(ASE_BUILD_DIR)_1c - cp $(RTL_DIR)/fp_cores/altera/arria10/*.hex $(ASE_BUILD_DIR)_1c/work + cp $(RTL_DIR)/fp_cores/altera/$(DEVICE_FAMILY)/*.hex $(ASE_BUILD_DIR)_1c/work -ase-2c: gen_sources_a10 setup-ase-2c +ase-2c: gen-sources setup-ase-2c make -C $(ASE_BUILD_DIR)_2c - cp $(RTL_DIR)/fp_cores/altera/arria10/*.hex $(ASE_BUILD_DIR)_2c/work + cp $(RTL_DIR)/fp_cores/altera/arria$(DEVICE_FAMILY)10/*.hex $(ASE_BUILD_DIR)_2c/work -ase-4c: gen_sources_a10 setup-ase-4c +ase-4c: gen-sources setup-ase-4c make -C $(ASE_BUILD_DIR)_4c cp $(RTL_DIR)/fp_cores/altera/arria10/*.hex $(ASE_BUILD_DIR)_4c/work @@ -43,25 +46,25 @@ $(ASE_BUILD_DIR)_2c/Makefile: $(ASE_BUILD_DIR)_4c/Makefile: afu_sim_setup -s sources_4c.txt $(ASE_BUILD_DIR)_4c -fpga-1c: gen_sources_a10 setup-fpga-1c +fpga-1c: gen-sources setup-fpga-1c cd $(FPGA_BUILD_DIR)_1c && $(RUN_SYNTH) -fpga-2c: gen_sources_a10 setup-fpga-2c +fpga-2c: gen-sources setup-fpga-2c cd $(FPGA_BUILD_DIR)_2c && $(RUN_SYNTH) -fpga-4c: gen_sources_a10 setup-fpga-4c +fpga-4c: gen-sources setup-fpga-4c cd $(FPGA_BUILD_DIR)_4c && $(RUN_SYNTH) -fpga-8c: gen_sources_a10 setup-fpga-8c +fpga-8c: gen-sources setup-fpga-8c cd $(FPGA_BUILD_DIR)_8c && $(RUN_SYNTH) -fpga-16c: gen_sources_a10 setup-fpga-16c +fpga-16c: gen-sources setup-fpga-16c cd $(FPGA_BUILD_DIR)_16c && $(RUN_SYNTH) -fpga-32c: gen_sources_s10 setup-fpga-32c +fpga-32c: gen-sources setup-fpga-32c cd $(FPGA_BUILD_DIR)_32c && $(RUN_SYNTH) -fpga-64c: gen_sources_s10 setup-fpga-64c +fpga-64c: gen-sources setup-fpga-64c cd $(FPGA_BUILD_DIR)_64c && $(RUN_SYNTH) setup-fpga-1c: $(FPGA_BUILD_DIR)_1c/build/dcp.qpf diff --git a/hw/syn/opae/gen_sources.sh b/hw/syn/opae/gen_sources.sh index 02c1a06b..350735e7 100755 --- a/hw/syn/opae/gen_sources.sh +++ b/hw/syn/opae/gen_sources.sh @@ -3,6 +3,7 @@ rtl_dir="../../rtl" exclude_list="VX_fpu_fpnew.v" file_list="" +device_family=$1 add_dirs() { @@ -29,7 +30,7 @@ add_files() done } -add_dirs $rtl_dir/fp_cores/altera/$1 +add_dirs $rtl_dir/fp_cores/altera/$device_family add_dirs $rtl_dir/libs $rtl_dir/interfaces $rtl_dir/fp_cores $rtl_dir/cache $rtl_dir $rtl_dir/afu diff --git a/hw/syn/opae/sources_32c.txt b/hw/syn/opae/sources_32c.txt index 1fc88ecd..e1bf6649 100644 --- a/hw/syn/opae/sources_32c.txt +++ b/hw/syn/opae/sources_32c.txt @@ -2,8 +2,6 @@ +define+NUM_CLUSTERS=4 #+define+L3_ENABLE=1 -+define+GLOBAL_BLOCK_SIZE=16 - +define+SYNTHESIS +define+QUARTUS #+define+PERF_ENABLE diff --git a/hw/syn/opae/sources_64c.txt b/hw/syn/opae/sources_64c.txt index bf267717..8cc42e1b 100644 --- a/hw/syn/opae/sources_64c.txt +++ b/hw/syn/opae/sources_64c.txt @@ -2,8 +2,6 @@ +define+NUM_CLUSTERS=8 #+define+L3_ENABLE=1 -+define+GLOBAL_BLOCK_SIZE=16 - +define+SYNTHESIS +define+QUARTUS #+define+PERF_ENABLE From 64848788a162664ce2eab16ba8ad941afa2abe50 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 26 Apr 2021 20:34:28 -0700 Subject: [PATCH 16/55] minor update --- driver/opae/vlsim/vortex_afu_shim.sv | 5 +++- hw/rtl/VX_config.vh | 6 +---- hw/rtl/afu/vortex_afu.sv | 35 +++++++++++++++------------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/driver/opae/vlsim/vortex_afu_shim.sv b/driver/opae/vlsim/vortex_afu_shim.sv index c69dfe09..f299aa79 100644 --- a/driver/opae/vlsim/vortex_afu_shim.sv +++ b/driver/opae/vlsim/vortex_afu_shim.sv @@ -2,13 +2,16 @@ `IGNORE_WARNINGS_BEGIN `include "vortex_afu.vh" `IGNORE_WARNINGS_END -`include "VX_define.vh" /* verilator lint_off IMPORTSTAR */ import ccip_if_pkg::*; import local_mem_cfg_pkg::*; /* verilator lint_on IMPORTSTAR */ +`define MEM_BLOCK_SIZE LOCAL_MEM_DATA_N_BYTES + +`include "VX_define.vh" + module vortex_afu_shim ( // global signals input clk, diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 2f7bfe07..6368eaa7 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -34,11 +34,7 @@ `endif `ifndef MEM_BLOCK_SIZE -`ifdef LOCAL_MEM_DATA_N_BYTES - `define MEM_BLOCK_SIZE `LOCAL_MEM_DATA_N_BYTES -`else - `define MEM_BLOCK_SIZE 64 -`endif +`define MEM_BLOCK_SIZE 64 `endif `ifndef L1_BLOCK_SIZE diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 61c4cc8d..97a1b4f1 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -6,13 +6,16 @@ `else `include "afu_json_info.vh" `endif -`include "VX_define.vh" /* verilator lint_off IMPORTSTAR */ import ccip_if_pkg::*; import local_mem_cfg_pkg::*; /* verilator lint_on IMPORTSTAR */ +`define MEM_BLOCK_SIZE LOCAL_MEM_DATA_N_BYTES + +`include "VX_define.vh" + module vortex_afu #( parameter NUM_LOCAL_MEM_BANKS = 2 ) ( @@ -40,16 +43,16 @@ module vortex_afu #( localparam RESET_DELAY = 3; -localparam MEM_LINE_WIDTH = $bits(t_local_mem_data); -localparam MEM_ADDR_WIDTH = $bits(t_local_mem_addr); -localparam MEM_BURST_CTRW = $bits(t_local_mem_burst_cnt); -localparam MEM_LINE_LW = $clog2(MEM_LINE_WIDTH); +localparam LMEM_LINE_WIDTH = $bits(t_local_mem_data); +localparam LMEM_ADDR_WIDTH = $bits(t_local_mem_addr); +localparam LMEM_BURST_CTRW = $bits(t_local_mem_burst_cnt); +localparam LMEM_LINE_LW = $clog2(LMEM_LINE_WIDTH); localparam CCI_LINE_WIDTH = $bits(t_ccip_clData); localparam CCI_ADDR_WIDTH = 32 - $clog2(CCI_LINE_WIDTH / 8); localparam VX_MEM_LINE_LW = $clog2(`VX_MEM_LINE_WIDTH); -localparam VX_MEM_LINE_IDX = (MEM_LINE_LW - VX_MEM_LINE_LW); +localparam VX_MEM_LINE_IDX = (LMEM_LINE_LW - VX_MEM_LINE_LW); localparam AVS_RD_QUEUE_SIZE = 16; localparam AVS_REQ_TAGW = `VX_MEM_TAG_WIDTH + VX_MEM_LINE_IDX; @@ -502,8 +505,8 @@ wire cci_mem_rsp_ready; VX_cci_to_mem #( .CCI_DATAW (CCI_LINE_WIDTH), .CCI_ADDRW (CCI_ADDR_WIDTH), - .AVS_DATAW (MEM_LINE_WIDTH), - .AVS_ADDRW (MEM_ADDR_WIDTH), + .AVS_DATAW (LMEM_LINE_WIDTH), + .AVS_ADDRW (LMEM_ADDR_WIDTH), .TAG_WIDTH (AVS_REQ_TAGW) ) cci_to_mem( .clk (clk), @@ -541,13 +544,13 @@ VX_cci_to_mem #( assign vx_mem_req_valid_qual = vx_mem_req_valid && vx_mem_en; -assign vx_mem_req_addr_qual = vx_mem_req_addr[`VX_MEM_ADDR_WIDTH-1:`VX_MEM_ADDR_WIDTH-MEM_ADDR_WIDTH]; +assign vx_mem_req_addr_qual = vx_mem_req_addr[`VX_MEM_ADDR_WIDTH-1:`VX_MEM_ADDR_WIDTH-LMEM_ADDR_WIDTH]; -if (`VX_MEM_LINE_WIDTH != MEM_LINE_WIDTH) begin +if (`VX_MEM_LINE_WIDTH != LMEM_LINE_WIDTH) begin wire [VX_MEM_LINE_IDX-1:0] vx_mem_req_idx = vx_mem_req_addr[VX_MEM_LINE_IDX-1:0]; wire [VX_MEM_LINE_IDX-1:0] vx_mem_rsp_idx = vx_mem_rsp_tag_unqual[VX_MEM_LINE_IDX-1:0]; assign vx_mem_req_byteen_qual = 64'(vx_mem_req_byteen) << (6'(vx_mem_req_addr[VX_MEM_LINE_IDX-1:0]) << (VX_MEM_LINE_LW-3)); - assign vx_mem_req_data_qual = MEM_LINE_WIDTH'(vx_mem_req_data) << ((MEM_LINE_LW'(vx_mem_req_idx)) << VX_MEM_LINE_LW); + assign vx_mem_req_data_qual = LMEM_LINE_WIDTH'(vx_mem_req_data) << ((LMEM_LINE_LW'(vx_mem_req_idx)) << VX_MEM_LINE_LW); assign vx_mem_req_tag_qual = {vx_mem_req_tag, vx_mem_req_idx}; assign vx_mem_rsp_data = vx_mem_rsp_data_unqual[vx_mem_rsp_idx]; end else begin @@ -563,8 +566,8 @@ assign vx_mem_rsp_tag = vx_mem_rsp_tag_unqual[`VX_MEM_TAG_WIDTH+VX_MEM_LINE_IDX- VX_mem_arb #( .NUM_REQS (2), - .DATA_WIDTH (MEM_LINE_WIDTH), - .ADDR_WIDTH (MEM_ADDR_WIDTH), + .DATA_WIDTH (LMEM_LINE_WIDTH), + .ADDR_WIDTH (LMEM_ADDR_WIDTH), .TAG_IN_WIDTH (AVS_REQ_TAGW), .TAG_OUT_WIDTH (AVS_REQ_TAGW+1) ) mem_arb ( @@ -605,9 +608,9 @@ VX_mem_arb #( //-- VX_avs_wrapper #( - .AVS_DATAW (MEM_LINE_WIDTH), - .AVS_ADDRW (MEM_ADDR_WIDTH), - .AVS_BURSTW (MEM_BURST_CTRW), + .AVS_DATAW (LMEM_LINE_WIDTH), + .AVS_ADDRW (LMEM_ADDR_WIDTH), + .AVS_BURSTW (LMEM_BURST_CTRW), .AVS_BANKS (NUM_LOCAL_MEM_BANKS), .REQ_TAGW (AVS_REQ_TAGW+1), .RD_QUEUE_SIZE (AVS_RD_QUEUE_SIZE) From 2216a3059dc8002b7717a4d14f39bcd9902561cb Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 27 Apr 2021 05:52:01 -0400 Subject: [PATCH 17/55] minor update --- driver/common/vx_utils.cpp | 7 ++ driver/opae/vlsim/opae_sim.h | 9 ++- driver/opae/vlsim/verilated_stub.h | 126 +++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 driver/opae/vlsim/verilated_stub.h diff --git a/driver/common/vx_utils.cpp b/driver/common/vx_utils.cpp index 4bc2017b..754cea4b 100644 --- a/driver/common/vx_utils.cpp +++ b/driver/common/vx_utils.cpp @@ -33,6 +33,13 @@ extern int vx_upload_kernel_bytes(vx_device_h device, const void* content, size_ while (offset < size) { auto chunk_size = std::min(buffer_transfer_size, size - offset); std::memcpy(buf_ptr, (uint8_t*)content + offset, chunk_size); + + /*printf("** Upload Kernel to 0x%0x: data=", kernel_base_addr + offset); + for (int i = 0, n = ((chunk_size+7)/8); i < n; ++i) { + printf("%08x", ((uint64_t*)((uint8_t*)content + offset))[n-1-i]); + } + printf("\n");*/ + err = vx_copy_to_dev(buffer, kernel_base_addr + offset, chunk_size, 0); if (err != 0) { vx_buf_release(buffer); diff --git a/driver/opae/vlsim/opae_sim.h b/driver/opae/vlsim/opae_sim.h index ee4f022a..1d9bef54 100644 --- a/driver/opae/vlsim/opae_sim.h +++ b/driver/opae/vlsim/opae_sim.h @@ -1,8 +1,10 @@ #pragma once +#include "verilated.h" +#include "verilated_stub.h" + #include "Vvortex_afu_shim.h" #include "Vvortex_afu_shim__Syms.h" -#include "verilated.h" #ifdef VCD_OUTPUT #include @@ -17,7 +19,10 @@ #include #include -#define CACHE_BLOCK_SIZE 64 +#undef MEM_BLOCK_SIZE +#define MEM_BLOCK_SIZE (Vvortex_afu_shim::VL_BITS_avs_writedata / 8) + +#define CACHE_BLOCK_SIZE 64 class opae_sim { public: diff --git a/driver/opae/vlsim/verilated_stub.h b/driver/opae/vlsim/verilated_stub.h new file mode 100644 index 00000000..ad79adac --- /dev/null +++ b/driver/opae/vlsim/verilated_stub.h @@ -0,0 +1,126 @@ +#pragma once + +#undef VL_ST_SIG8 +#define VL_ST_SIG8(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + CData name + +#undef VL_ST_SIG16 +#define VL_ST_SIG16(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + SData name + +#undef VL_ST_SIG64 +#define VL_ST_SIG64(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + QData name + +#undef VL_ST_SIG +#define VL_ST_SIG(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + IData name + +#undef VL_ST_SIGW +#define VL_ST_SIGW(name, msb, lsb, words) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + WData name[words] + +#undef VL_SIG8 +#define VL_SIG8(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + CData name + +#undef VL_SIG16 +#define VL_SIG16(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + SData name + +#undef VL_SIG64 +#define VL_SIG64(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + QData name + +#undef VL_SIG +#define VL_SIG(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + IData name + +#undef VL_SIGW +#define VL_SIGW(name, msb, lsb, words) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + WData name[words] + +#undef VL_IN8 +#define VL_IN8(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + CData name + +#undef VL_IN16 +#define VL_IN16(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + SData name + +#undef VL_IN64 +#define VL_IN64(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + QData name + +#undef VL_IN +#define VL_IN(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + IData name + +#undef VL_INW +#define VL_INW(name, msb, lsb, words) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + WData name[words] + +#undef VL_INOUT8 +#define VL_INOUT8(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + CData name + +#undef VL_INOUT16 +#define VL_INOUT16(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + SData name + +#undef VL_INOUT64 +#define VL_INOUT64(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + QData name + +#undef VL_INOUT +#define VL_INOUT(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + IData name + +#undef VL_INOUTW +#define VL_INOUTW(name, msb, lsb, words) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + WData name[words] + +#undef VL_OUT8 +#define VL_OUT8(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + CData name + +#undef VL_OUT16 +#define VL_OUT16(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + SData name + +#undef VL_OUT64 +#define VL_OUT64(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + QData name + +#undef VL_OUT +#define VL_OUT(name, msb, lsb) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + IData name + +#undef VL_OUTW +#define VL_OUTW(name, msb, lsb, words) \ + enum { VL_MSB_##name = msb, VL_LSB_##name = lsb, VL_BITS_##name = (msb - lsb + 1) }; \ + WData name[words] From 35308dbe2d8df36dc41a6571fe6ae7112570af84 Mon Sep 17 00:00:00 2001 From: Malik Aki Burton Date: Wed, 28 Apr 2021 14:50:25 -0400 Subject: [PATCH 18/55] Created Images directory and updated Vortex.md with Codebase and Microarchitecture hyperlinks --- doc/{ => Images}/vortex_microarchitecture_v2.png | Bin doc/Microarchitecture.md | 2 +- doc/Vortex.md | 5 +++-- 3 files changed, 4 insertions(+), 3 deletions(-) rename doc/{ => Images}/vortex_microarchitecture_v2.png (100%) diff --git a/doc/vortex_microarchitecture_v2.png b/doc/Images/vortex_microarchitecture_v2.png similarity index 100% rename from doc/vortex_microarchitecture_v2.png rename to doc/Images/vortex_microarchitecture_v2.png diff --git a/doc/Microarchitecture.md b/doc/Microarchitecture.md index d8892e62..1b410066 100644 --- a/doc/Microarchitecture.md +++ b/doc/Microarchitecture.md @@ -32,7 +32,7 @@ Vortex uses the SIMT (Single Instruction, Multiple Threads) execution model with ### Vortex Pipeline/Datapath -![Image of Vortex Microarchitecture](vortex_microarchitecture_v2.png) +![Image of Vortex Microarchitecture](./Images/vortex_microarchitecture_v2.png) Vortex has a 5-stage pipeline: FI | ID | Issue | EX | WB. diff --git a/doc/Vortex.md b/doc/Vortex.md index 16dad807..f1d410a6 100644 --- a/doc/Vortex.md +++ b/doc/Vortex.md @@ -2,10 +2,11 @@ ### Table of Contents -- Vortex Microarchitecture +- [Vortex Codebase Layout](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Codebase.md) +- [Vortex Microarchitecture and Extended RISC-V ISA](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Microarchitecture.md) - Vortex Software - [Vortex Simulation](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Simulation.md) -- [FPGA](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Flubber_FPGA_Startup_Guide.md) +- [FPGA Configuration, Program and Test](https://github.com/vortexgpgpu/vortex-dev/blob/master/doc/Flubber_FPGA_Startup_Guide.md) - Debugging - Useful Links From 95f057bc2e3a4001839de1951b471ebc23ec2712 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 29 Apr 2021 06:17:28 -0700 Subject: [PATCH 19/55] fpga build refactoring --- ci/regression.sh | 10 +- driver/opae/vlsim/Makefile | 5 +- driver/rtlsim/Makefile | 5 +- hw/rtl/VX_define.vh | 2 +- hw/rtl/afu/vortex_afu.sv | 4 +- hw/simulate/Makefile | 5 +- hw/syn/opae/Makefile | 194 ++++++++++++++-------- hw/syn/opae/README | 13 +- hw/syn/opae/gen_sources.sh | 70 ++++---- hw/syn/opae/{sources_4c.txt => setup.cfg} | 3 - hw/syn/opae/sources_16c.txt | 12 -- hw/syn/opae/sources_1c.txt | 24 --- hw/syn/opae/sources_2c.txt | 10 -- hw/syn/opae/sources_32c.txt | 12 -- hw/syn/opae/sources_64c.txt | 12 -- hw/syn/opae/sources_8c.txt | 12 -- 16 files changed, 185 insertions(+), 208 deletions(-) rename hw/syn/opae/{sources_4c.txt => setup.cfg} (66%) delete mode 100644 hw/syn/opae/sources_16c.txt delete mode 100644 hw/syn/opae/sources_1c.txt delete mode 100644 hw/syn/opae/sources_2c.txt delete mode 100644 hw/syn/opae/sources_32c.txt delete mode 100644 hw/syn/opae/sources_64c.txt delete mode 100644 hw/syn/opae/sources_8c.txt diff --git a/ci/regression.sh b/ci/regression.sh index 005e20da..cc5c8faa 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -21,15 +21,17 @@ make -s ./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=demo --args="-n1" ./ci/travis_run.py ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=demo --args="-n1" -# Build tests disabling extensions +# disabling M extension CONFIGS=-DEXT_M_DISABLE make -C hw/simulate + +# disabling F extension CONFIGS=-DEXT_F_DISABLE make -C hw/simulate # disable shared memory CONFIGS=-DSM_ENABLE=0 make -C hw/simulate -# test 128-bit DRAM bus -CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS=4 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo +# using FPNEW core +FPU_CORE=FPU_FPNEW ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=demo -# test 256-bit DRAM bus +# test 128-bit DRAM bus CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS=4 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo \ No newline at end of file diff --git a/driver/opae/vlsim/Makefile b/driver/opae/vlsim/Makefile index dcd58806..b84c24f4 100644 --- a/driver/opae/vlsim/Makefile +++ b/driver/opae/vlsim/Makefile @@ -82,8 +82,9 @@ endif VL_FLAGS += -DNOPAE CFLAGS += -DNOPAE -# use DPI FPU -VL_FLAGS += -DFPU_DPI +# FPU backend +FPU_CORE ?= FPU_DPI +VL_FLAGS += -D$(FPU_CORE) PROJECT = libopae-c-vlsim.so diff --git a/driver/rtlsim/Makefile b/driver/rtlsim/Makefile index 11ef6760..b3d466f7 100644 --- a/driver/rtlsim/Makefile +++ b/driver/rtlsim/Makefile @@ -68,8 +68,9 @@ ifdef PERF CFLAGS += -DPERF_ENABLE endif -# use DPI FPU -VL_FLAGS += -DFPU_DPI +# FPU backend +FPU_CORE ?= FPU_DPI +VL_FLAGS += -D$(FPU_CORE) PROJECT = libvortex.so # PROJECT = libvortex.dylib diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index b9ef4014..ece01117 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -243,7 +243,7 @@ `define ICACHE_ID (32'(`L3_ENABLE) + 32'(`L2_ENABLE) * `NUM_CLUSTERS + CORE_ID * 3 + 0) // Block size in bytes -`define ICACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `MEM_BLOCK_SIZE) +`define ICACHE_LINE_SIZE (`L2_ENABLE ? `L1_BLOCK_SIZE : `MEM_BLOCK_SIZE) // Word size in bytes `define IWORD_SIZE 4 diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 97a1b4f1..78269ee7 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -10,9 +10,7 @@ /* verilator lint_off IMPORTSTAR */ import ccip_if_pkg::*; import local_mem_cfg_pkg::*; -/* verilator lint_on IMPORTSTAR */ - -`define MEM_BLOCK_SIZE LOCAL_MEM_DATA_N_BYTES +/* verilator lint_on IMPORTSTAR */ `include "VX_define.vh" diff --git a/hw/simulate/Makefile b/hw/simulate/Makefile index dbbae208..e8ddfe9b 100644 --- a/hw/simulate/Makefile +++ b/hw/simulate/Makefile @@ -49,8 +49,9 @@ VL_FLAGS += verilator.vlt VL_FLAGS += --exe $(SRCS) $(RTL_INCLUDE) VL_FLAGS += --cc Vortex.v --top-module $(TOP) -# Use FPNEW PFU core -VL_FLAGS += -DFPU_FPNEW +# FPU backend +FPU_CORE ?= FPU_DPI +VL_FLAGS += -D$(FPU_CORE) DBG_FLAGS += -DVCD_OUTPUT diff --git a/hw/syn/opae/Makefile b/hw/syn/opae/Makefile index b0b48661..9e4ea121 100644 --- a/hw/syn/opae/Makefile +++ b/hw/syn/opae/Makefile @@ -1,11 +1,14 @@ ASE_BUILD_DIR ?= build_ase FPGA_BUILD_DIR ?= build_fpga +DEVICE_FAMILY ?= arria10 RTL_DIR=../../rtl -ifdef $(shell [[ '$(FPGA_CLASS)' =~ 'fpga-pac-s10' ]] && echo matched) - DEVICE_FAMILY ?= stratix10 -else - DEVICE_FAMILY ?= arria10 +ifeq ($(DEVICE_FAMILY),arria10) + CFLAGS += -DMEM_BLOCK_SIZE=64 +endif + +ifeq ($(DEVICE_FAMILY),stratix10) + CFLAGS += -DMEM_BLOCK_SIZE=16 endif ifeq ($(shell which qsub-synth),) @@ -14,22 +17,106 @@ else RUN_SYNTH=qsub-synth endif +# control RTL debug print states +DBG_PRINT_FLAGS += -DDBG_PRINT_PIPELINE +DBG_PRINT_FLAGS += -DDBG_PRINT_CORE_ICACHE +DBG_PRINT_FLAGS += -DDBG_PRINT_CORE_DCACHE +DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_BANK +DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_MSHR +DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_TAG +DBG_PRINT_FLAGS += -DDBG_PRINT_CACHE_DATA +DBG_PRINT_FLAGS += -DDBG_PRINT_MEM +DBG_PRINT_FLAGS += -DDBG_PRINT_OPAE +DBG_PRINT_FLAGS += -DDBG_PRINT_AVS +DBG_PRINT_FLAGS += -DDBG_PRINT_SCOPE + +DBG_FLAGS += $(DBG_PRINT_FLAGS) +DBG_FLAGS += -DDBG_CACHE_REQ_INFO + +CONFIG1 := -DNUM_CLUSTERS=1 -DNUM_CORES=1 -DL2_ENABLE=0 -DL3_ENABLE=0 $(CONFIGS) +CONFIG2 := -DNUM_CLUSTERS=1 -DNUM_CORES=2 -DL2_ENABLE=0 -DL3_ENABLE=0 $(CONFIGS) +CONFIG4 := -DNUM_CLUSTERS=1 -DNUM_CORES=4 -DL2_ENABLE=0 -DL3_ENABLE=0 $(CONFIGS) +CONFIG8 := -DNUM_CLUSTERS=2 -DNUM_CORES=4 -DL2_ENABLE=0 -DL3_ENABLE=0 $(CONFIGS) +CONFIG16 := -DNUM_CLUSTERS=4 -DNUM_CORES=4 -DL2_ENABLE=0 -DL3_ENABLE=0 $(CONFIGS) +CONFIG32 := -DNUM_CLUSTERS=4 -DNUM_CORES=8 -DL2_ENABLE=0 -DL3_ENABLE=0 $(CONFIGS) +CONFIG64 := -DNUM_CLUSTERS=8 -DNUM_CORES=8 -DL2_ENABLE=0 -DL3_ENABLE=0 $(CONFIGS) + +FPU_INCLUDE = -I$(RTL_DIR)/fp_cores -I$(RTL_DIR)/fp_cores/altera/$(DEVICE_FAMILY) +RTL_INCLUDE = -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/cache $(FPU_INCLUDE) -I$(RTL_DIR) -I$(RTL_DIR)/afu + +CFLAGS += $(RTL_INCLUDE) + +# Debugigng +ifdef DEBUG + CFLAGS += $(DBG_FLAGS) +else + CFLAGS += -DNDEBUG +endif + +# Enable scope analyzer +ifdef SCOPE + CFLAGS += -DSCOPE +endif + +# Enable perf counters +ifdef PERF + CFLAGS += -DPERF_ENABLE +endif + all: ase-1c -gen-sources: - ./gen_sources.sh $(DEVICE_FAMILY) > sources.txt +$(ASE_BUILD_DIR)_1c/Makefile: + afu_sim_setup -s setup.cfg $(ASE_BUILD_DIR)_1c -ase-1c: gen-sources setup-ase-1c - make -C $(ASE_BUILD_DIR)_1c - cp $(RTL_DIR)/fp_cores/altera/$(DEVICE_FAMILY)/*.hex $(ASE_BUILD_DIR)_1c/work +$(ASE_BUILD_DIR)_2c/Makefile: + afu_sim_setup -s setup.cfg $(ASE_BUILD_DIR)_2c -ase-2c: gen-sources setup-ase-2c - make -C $(ASE_BUILD_DIR)_2c - cp $(RTL_DIR)/fp_cores/altera/arria$(DEVICE_FAMILY)10/*.hex $(ASE_BUILD_DIR)_2c/work +$(ASE_BUILD_DIR)_4c/Makefile: + afu_sim_setup -s setup.cfg $(ASE_BUILD_DIR)_4c -ase-4c: gen-sources setup-ase-4c - make -C $(ASE_BUILD_DIR)_4c - cp $(RTL_DIR)/fp_cores/altera/arria10/*.hex $(ASE_BUILD_DIR)_4c/work +$(FPGA_BUILD_DIR)_1c/build/dcp.qpf: + afu_synth_setup -s setup.cfg $(FPGA_BUILD_DIR)_1c + +$(FPGA_BUILD_DIR)_2c/build/dcp.qpf: + afu_synth_setup -s setup.cfg $(FPGA_BUILD_DIR)_2c + +$(FPGA_BUILD_DIR)_4c/build/dcp.qpf: + afu_synth_setup -s setup.cfg $(FPGA_BUILD_DIR)_4c + +$(FPGA_BUILD_DIR)_8c/build/dcp.qpf: + afu_synth_setup -s setup.cfg $(FPGA_BUILD_DIR)_8c + +$(FPGA_BUILD_DIR)_16c/build/dcp.qpf: + afu_synth_setup -s setup.cfg $(FPGA_BUILD_DIR)_16c + +$(FPGA_BUILD_DIR)_32c/build/dcp.qpf: + afu_synth_setup -s setup.cfg $(FPGA_BUILD_DIR)_32c + +$(FPGA_BUILD_DIR)_64c/build/dcp.qpf: + afu_synth_setup -s setup.cfg $(FPGA_BUILD_DIR)_64c + +gen-sources-1c: + ./gen_sources.sh $(CFLAGS) $(CONFIG1) > sources.txt + +gen-sources-2c: + ./gen_sources.sh $(CFLAGS) $(CONFIG2) > sources.txt + +gen-sources-4c: + ./gen_sources.sh $(CFLAGS) $(CONFIG4) > sources.txt + +gen-sources-8c: + ./gen_sources.sh $(CFLAGS) $(CONFIG8) > sources.txt + +gen-sources-16c: + ./gen_sources.sh $(CFLAGS) $(CONFIG16) > sources.txt + +gen-sources-32c: + ./gen_sources.sh $(CFLAGS) $(CONFIG32) > sources.txt + +gen-sources-64c: + ./gen_sources.sh $(CFLAGS) $(CONFIG64) > sources.txt + +# setup setup-ase-1c: $(ASE_BUILD_DIR)_1c/Makefile @@ -37,36 +124,6 @@ setup-ase-2c: $(ASE_BUILD_DIR)_2c/Makefile setup-ase-4c: $(ASE_BUILD_DIR)_4c/Makefile -$(ASE_BUILD_DIR)_1c/Makefile: - afu_sim_setup -s sources_1c.txt $(ASE_BUILD_DIR)_1c - -$(ASE_BUILD_DIR)_2c/Makefile: - afu_sim_setup -s sources_2c.txt $(ASE_BUILD_DIR)_2c - -$(ASE_BUILD_DIR)_4c/Makefile: - afu_sim_setup -s sources_4c.txt $(ASE_BUILD_DIR)_4c - -fpga-1c: gen-sources setup-fpga-1c - cd $(FPGA_BUILD_DIR)_1c && $(RUN_SYNTH) - -fpga-2c: gen-sources setup-fpga-2c - cd $(FPGA_BUILD_DIR)_2c && $(RUN_SYNTH) - -fpga-4c: gen-sources setup-fpga-4c - cd $(FPGA_BUILD_DIR)_4c && $(RUN_SYNTH) - -fpga-8c: gen-sources setup-fpga-8c - cd $(FPGA_BUILD_DIR)_8c && $(RUN_SYNTH) - -fpga-16c: gen-sources setup-fpga-16c - cd $(FPGA_BUILD_DIR)_16c && $(RUN_SYNTH) - -fpga-32c: gen-sources setup-fpga-32c - cd $(FPGA_BUILD_DIR)_32c && $(RUN_SYNTH) - -fpga-64c: gen-sources setup-fpga-64c - cd $(FPGA_BUILD_DIR)_64c && $(RUN_SYNTH) - setup-fpga-1c: $(FPGA_BUILD_DIR)_1c/build/dcp.qpf setup-fpga-2c: $(FPGA_BUILD_DIR)_2c/build/dcp.qpf @@ -81,35 +138,42 @@ setup-fpga-32c: $(FPGA_BUILD_DIR)_32c/build/dcp.qpf setup-fpga-64c: $(FPGA_BUILD_DIR)_64c/build/dcp.qpf -$(FPGA_BUILD_DIR)_1c/build/dcp.qpf: - afu_synth_setup -s sources_1c.txt $(FPGA_BUILD_DIR)_1c +# build -$(FPGA_BUILD_DIR)_2c/build/dcp.qpf: - afu_synth_setup -s sources_2c.txt $(FPGA_BUILD_DIR)_2c +ase-1c: gen-sources-1c setup-ase-1c + make -C $(ASE_BUILD_DIR)_1c + cp $(RTL_DIR)/fp_cores/altera/$(DEVICE_FAMILY)/*.hex $(ASE_BUILD_DIR)_1c/work -$(FPGA_BUILD_DIR)_4c/build/dcp.qpf: - afu_synth_setup -s sources_4c.txt $(FPGA_BUILD_DIR)_4c +ase-2c: gen-sources-2c setup-ase-2c + make -C $(ASE_BUILD_DIR)_2c + cp $(RTL_DIR)/fp_cores/altera/$(DEVICE_FAMILY)/*.hex $(ASE_BUILD_DIR)_2c/work -$(FPGA_BUILD_DIR)_8c/build/dcp.qpf: - afu_synth_setup -s sources_8c.txt $(FPGA_BUILD_DIR)_8c +ase-4c: gen-sources-4c setup-ase-4c + make -C $(ASE_BUILD_DIR)_4c + cp $(RTL_DIR)/fp_cores/altera/$(DEVICE_FAMILY)/*.hex $(ASE_BUILD_DIR)_4c/work -$(FPGA_BUILD_DIR)_16c/build/dcp.qpf: - afu_synth_setup -s sources_16c.txt $(FPGA_BUILD_DIR)_16c +fpga-1c: gen-sources-1c setup-fpga-1c + cd $(FPGA_BUILD_DIR)_1c && $(RUN_SYNTH) -$(FPGA_BUILD_DIR)_32c/build/dcp.qpf: - afu_synth_setup -s sources_32c.txt $(FPGA_BUILD_DIR)_32c +fpga-2c: gen-sources-2c setup-fpga-2c + cd $(FPGA_BUILD_DIR)_2c && $(RUN_SYNTH) -$(FPGA_BUILD_DIR)_64c/build/dcp.qpf: - afu_synth_setup -s sources_64c.txt $(FPGA_BUILD_DIR)_64c +fpga-4c: gen-sources-4c setup-fpga-4c + cd $(FPGA_BUILD_DIR)_4c && $(RUN_SYNTH) -run-ase-1c: - cd $(ASE_BUILD_DIR)_1c && make sim +fpga-8c: gen-sources-8c setup-fpga-8c + cd $(FPGA_BUILD_DIR)_8c && $(RUN_SYNTH) -run-ase-2c: - cd $(ASE_BUILD_DIR)_2c && make sim +fpga-16c: gen-sources-16c setup-fpga-16c + cd $(FPGA_BUILD_DIR)_16c && $(RUN_SYNTH) -run-ase-4c: - cd $(ASE_BUILD_DIR)_4c && make sim +fpga-32c: gen-sources-32c setup-fpga-32c + cd $(FPGA_BUILD_DIR)_32c && $(RUN_SYNTH) + +fpga-64c: gen-sources-64c setup-fpga-64c + cd $(FPGA_BUILD_DIR)_64c && $(RUN_SYNTH) + +# cleanup clean-ase-1c: rm -rf $(ASE_BUILD_DIR)_1c sources.txt diff --git a/hw/syn/opae/README b/hw/syn/opae/README index 35a2a9a6..5e9f9537 100644 --- a/hw/syn/opae/README +++ b/hw/syn/opae/README @@ -97,15 +97,4 @@ tar -xvf vortex.vcd.tar.bz2 lsof +D build_ase_1c # quick off synthesis -make -C unittest clean && make -C unittest > unittest/build.log 2>&1 & -make -C pipeline clean && make -C pipeline > pipeline/build.log 2>&1 & -make -C cache clean && make -C cache > cache/build.log 2>&1 & -make -C core clean && make -C core > core/build.log 2>&1 & -make -C vortex clean && make -C vortex > vortex/build.log 2>&1 & -make -C top1 clean && make -C top1 > top1/build.log 2>&1 & -make -C top2 clean && make -C top2 > top2/build.log 2>&1 & -make -C top4 clean && make -C top4 > top4/build.log 2>&1 & -make -C top8 clean && make -C top8 > top8/build.log 2>&1 & -make -C top16 clean && make -C top16 > top16/build.log 2>&1 & -make -C top32 clean && make -C top32 > top32/build.log 2>&1 & -make -C top64 clean && make -C top64 > top64/build.log 2>&1 & \ No newline at end of file +make core \ No newline at end of file diff --git a/hw/syn/opae/gen_sources.sh b/hw/syn/opae/gen_sources.sh index 350735e7..b330efc1 100755 --- a/hw/syn/opae/gen_sources.sh +++ b/hw/syn/opae/gen_sources.sh @@ -1,40 +1,46 @@ #!/bin/bash -rtl_dir="../../rtl" exclude_list="VX_fpu_fpnew.v" -file_list="" -device_family=$1 +macros=() +includes=() -add_dirs() -{ - for dir in $*; do - echo "+incdir+$dir" - for file in $(find $dir -maxdepth 1 -name '*.v' -o -name '*.sv' -type f); do - exclude=0 - for fe in $exclude_list; do - if [[ $file =~ $fe ]]; then - exclude=1 - fi - done - if [[ $exclude == 0 ]]; then - file_list="$file_list $file" +# parse command arguments +while getopts D:I:h flag +do + case "${flag}" in + D) macros+=( ${OPTARG} );; + I) includes+=( ${OPTARG} );; + h) echo "Usage: [-D macro] [-I include] [-h help]" + exit 0 + ;; + \?) + echo "Invalid option: -$OPTARG" 1>&2 + exit 1 + ;; + esac +done + +# dump macros +for value in ${macros[@]}; do + echo "+define+$value" +done + +# dump include directories +for dir in ${includes[@]}; do + echo "+incdir+$dir" +done + +# dump source files +for dir in ${includes[@]}; do + for file in $(find $dir -maxdepth 1 -name '*.v' -o -name '*.sv' -type f); do + exclude=0 + for fe in $exclude_list; do + if [[ $file =~ $fe ]]; then + exclude=1 fi done + if [[ $exclude == 0 ]]; then + echo $file + fi done -} - -add_files() -{ - for file in $*; do - file_list="$file_list $file" - done -} - -add_dirs $rtl_dir/fp_cores/altera/$device_family - -add_dirs $rtl_dir/libs $rtl_dir/interfaces $rtl_dir/fp_cores $rtl_dir/cache $rtl_dir $rtl_dir/afu - -# dump file list -for file in $file_list; do - echo $file done \ No newline at end of file diff --git a/hw/syn/opae/sources_4c.txt b/hw/syn/opae/setup.cfg similarity index 66% rename from hw/syn/opae/sources_4c.txt rename to hw/syn/opae/setup.cfg index 9ac95cdd..9bb0b72d 100644 --- a/hw/syn/opae/sources_4c.txt +++ b/hw/syn/opae/setup.cfg @@ -1,8 +1,5 @@ -+define+NUM_CORES=4 - +define+SYNTHESIS +define+QUARTUS -#+define+PERF_ENABLE vortex_afu.json QI:vortex_afu.qsf diff --git a/hw/syn/opae/sources_16c.txt b/hw/syn/opae/sources_16c.txt deleted file mode 100644 index cbee87e0..00000000 --- a/hw/syn/opae/sources_16c.txt +++ /dev/null @@ -1,12 +0,0 @@ -+define+NUM_CORES=4 -+define+NUM_CLUSTERS=4 -#+define+L3_ENABLE=1 - -+define+SYNTHESIS -+define+QUARTUS -#+define+PERF_ENABLE - -vortex_afu16.json -QI:vortex_afu.qsf - -C:sources.txt \ No newline at end of file diff --git a/hw/syn/opae/sources_1c.txt b/hw/syn/opae/sources_1c.txt deleted file mode 100644 index a429a492..00000000 --- a/hw/syn/opae/sources_1c.txt +++ /dev/null @@ -1,24 +0,0 @@ -+define+NUM_CORES=1 - -+define+SYNTHESIS -+define+QUARTUS -#+define+SCOPE -#+define+PERF_ENABLE - -#+define+DBG_PRINT_CORE_ICACHE -#+define+DBG_PRINT_CORE_DCACHE -#+define+DBG_PRINT_CACHE_BANK -#+define+DBG_PRINT_CACHE_MSHR -#+define+DBG_PRINT_CACHE_TAG -#+define+DBG_PRINT_CACHE_DATA -#+define+DBG_PRINT_DRAM -#+define+DBG_PRINT_PIPELINE -#+define+DBG_PRINT_OPAE -#+define+DBG_PRINT_AVS -#+define+DBG_PRINT_SCOPE -#+define+DBG_CACHE_REQ_INFO - -vortex_afu.json -QI:vortex_afu.qsf - -C:sources.txt \ No newline at end of file diff --git a/hw/syn/opae/sources_2c.txt b/hw/syn/opae/sources_2c.txt deleted file mode 100644 index a70589f5..00000000 --- a/hw/syn/opae/sources_2c.txt +++ /dev/null @@ -1,10 +0,0 @@ -+define+NUM_CORES=2 - -+define+SYNTHESIS -+define+QUARTUS -#+define+PERF_ENABLE - -vortex_afu.json -QI:vortex_afu.qsf - -C:sources.txt \ No newline at end of file diff --git a/hw/syn/opae/sources_32c.txt b/hw/syn/opae/sources_32c.txt deleted file mode 100644 index e1bf6649..00000000 --- a/hw/syn/opae/sources_32c.txt +++ /dev/null @@ -1,12 +0,0 @@ -+define+NUM_CORES=8 -+define+NUM_CLUSTERS=4 -#+define+L3_ENABLE=1 - -+define+SYNTHESIS -+define+QUARTUS -#+define+PERF_ENABLE - -vortex_afu.json -QI:vortex_afu.qsf - -C:sources.txt \ No newline at end of file diff --git a/hw/syn/opae/sources_64c.txt b/hw/syn/opae/sources_64c.txt deleted file mode 100644 index 8cc42e1b..00000000 --- a/hw/syn/opae/sources_64c.txt +++ /dev/null @@ -1,12 +0,0 @@ -+define+NUM_CORES=8 -+define+NUM_CLUSTERS=8 -#+define+L3_ENABLE=1 - -+define+SYNTHESIS -+define+QUARTUS -#+define+PERF_ENABLE - -vortex_afu.json -QI:vortex_afu.qsf - -C:sources.txt \ No newline at end of file diff --git a/hw/syn/opae/sources_8c.txt b/hw/syn/opae/sources_8c.txt deleted file mode 100644 index baafe36a..00000000 --- a/hw/syn/opae/sources_8c.txt +++ /dev/null @@ -1,12 +0,0 @@ -+define+NUM_CORES=4 -+define+NUM_CLUSTERS=2 -#+define+L3_ENABLE=1 - -+define+SYNTHESIS -+define+QUARTUS -#+define+PERF_ENABLE - -vortex_afu8.json -QI:vortex_afu.qsf - -C:sources.txt \ No newline at end of file From d19270cc31ba811198ab27f71b0b43ac0e31b795 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 29 Apr 2021 06:24:53 -0700 Subject: [PATCH 20/55] minor update --- evaluation/scripts/build.sh | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/evaluation/scripts/build.sh b/evaluation/scripts/build.sh index 21b9f345..94a6a736 100755 --- a/evaluation/scripts/build.sh +++ b/evaluation/scripts/build.sh @@ -28,26 +28,15 @@ fi cd ${BUILD_DIR} -sources_file="./sources_${cores}c.txt" - -if [ ${perf} = 1 ]; then - if grep -Fxq '#+define+PERF_ENABLE' ${sources_file}; then - sed -i 's/+define+PERF_ENABLE/#+define+PERF_ENABLE/' ${sources_file} - elif ! grep -Fxq '+define+PERF_ENABLE' ${sources_file}; then - sed -i '1s/^/+define+PERF_ENABLE\n/' ${sources_file} - fi -else - if grep -v '^ *#' ${sources_file} | grep -Fxq '+define+SYNTHESIS'; then - sed -i 's/+define+PERF_ENABLE/#+define+PERF_ENABLE/' ${sources_file} - elif ! grep -Fxq '#+define+PERF_ENABLE' ${sources_file}; then - sed -i '1s/^/#+define+PERF_ENABLE\n/' ${sources_file} - fi -fi - if [ -d "./build_fpga_{$cores}c" ]; then make "clean-fpga-${cores}c" fi -make "fpga-${cores}c" + +if [ ${perf} = 1 ]; then + PERF=1 make "fpga-${cores}c" +else + make "fpga-${cores}c" +fi if [ ${wait} = 1 ]; then sleep 30 From 269c06f7ea1dd0126fc47b68651f1bb31c6d3b4b Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 29 Apr 2021 23:58:45 -0700 Subject: [PATCH 21/55] minor update --- hw/simulate/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/simulate/Makefile b/hw/simulate/Makefile index e8ddfe9b..192be90d 100644 --- a/hw/simulate/Makefile +++ b/hw/simulate/Makefile @@ -50,7 +50,7 @@ VL_FLAGS += --exe $(SRCS) $(RTL_INCLUDE) VL_FLAGS += --cc Vortex.v --top-module $(TOP) # FPU backend -FPU_CORE ?= FPU_DPI +FPU_CORE ?= FPU_FPNEW VL_FLAGS += -D$(FPU_CORE) DBG_FLAGS += -DVCD_OUTPUT From d504adb236ba4651263c59b0300d2862cb9cb09c Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 1 May 2021 08:39:52 -0700 Subject: [PATCH 22/55] afu mem controller refactoring --- ci/regression.sh | 13 +- driver/opae/vlsim/vortex_afu_shim.sv | 4 +- hw/rtl/VX_platform.vh | 2 + hw/rtl/afu/VX_avs_wrapper.v | 72 ++--- hw/rtl/afu/{VX_cci_to_mem.v => VX_to_mem.v} | 0 hw/rtl/afu/vortex_afu.sv | 318 +++++++++++--------- hw/rtl/afu/vortex_afu.vh | 12 +- hw/syn/opae/Makefile | 8 - hw/syn/opae/README | 5 +- 9 files changed, 235 insertions(+), 199 deletions(-) rename hw/rtl/afu/{VX_cci_to_mem.v => VX_to_mem.v} (100%) diff --git a/ci/regression.sh b/ci/regression.sh index cc5c8faa..8adb5427 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -33,5 +33,14 @@ CONFIGS=-DSM_ENABLE=0 make -C hw/simulate # using FPNEW core FPU_CORE=FPU_FPNEW ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=demo -# test 128-bit DRAM bus -CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS=4 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo \ No newline at end of file +# test 128-bit MEM block +CONFIGS=-DMEM_BLOCK_SIZE=16 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo + +# test 128-bit DRAM block +CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo + +# test 128-bit MEM and DRAM block +CONFIGS="-DMEM_BLOCK_SIZE=16 -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=128 -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=28" ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo + +# test 27-bit DRAM address +CONFIGS=-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27 ./ci/blackbox.sh --driver=vlsim --cores=1 --app=demo \ No newline at end of file diff --git a/driver/opae/vlsim/vortex_afu_shim.sv b/driver/opae/vlsim/vortex_afu_shim.sv index f299aa79..ed7537c5 100644 --- a/driver/opae/vlsim/vortex_afu_shim.sv +++ b/driver/opae/vlsim/vortex_afu_shim.sv @@ -6,9 +6,7 @@ /* verilator lint_off IMPORTSTAR */ import ccip_if_pkg::*; import local_mem_cfg_pkg::*; -/* verilator lint_on IMPORTSTAR */ - -`define MEM_BLOCK_SIZE LOCAL_MEM_DATA_N_BYTES +/* verilator lint_on IMPORTSTAR */ `include "VX_define.vh" diff --git a/hw/rtl/VX_platform.vh b/hw/rtl/VX_platform.vh index 312d3d58..83eb0891 100644 --- a/hw/rtl/VX_platform.vh +++ b/hw/rtl/VX_platform.vh @@ -70,6 +70,8 @@ `define LOG2UP(x) (((x) > 1) ? $clog2(x) : 1) `define ISPOW2(x) (((x) != 0) && (0 == ((x) & ((x) - 1)))) +`define ABS(x) (($signed(x) < 0) ? (-$signed(x)) : x); + `define MIN(x, y) ((x < y) ? (x) : (y)) `define MAX(x, y) ((x > y) ? (x) : (y)) diff --git a/hw/rtl/afu/VX_avs_wrapper.v b/hw/rtl/afu/VX_avs_wrapper.v index 361bd2fa..ff7d1dd1 100644 --- a/hw/rtl/afu/VX_avs_wrapper.v +++ b/hw/rtl/afu/VX_avs_wrapper.v @@ -1,49 +1,49 @@ `include "VX_define.vh" module VX_avs_wrapper #( - parameter AVS_DATAW = 1, - parameter AVS_ADDRW = 1, - parameter AVS_BURSTW = 1, - parameter AVS_BANKS = 1, - parameter REQ_TAGW = 1, - parameter RD_QUEUE_SIZE = 1, + parameter AVS_DATA_WIDTH = 1, + parameter AVS_ADDR_WIDTH = 1, + parameter AVS_BURST_WIDTH = 1, + parameter AVS_BANKS = 1, + parameter REQ_TAG_WIDTH = 1, + parameter RD_QUEUE_SIZE = 1, - parameter AVS_BYTEENW = (AVS_DATAW / 8), - parameter RD_QUEUE_ADDRW= $clog2(RD_QUEUE_SIZE+1), - parameter AVS_BANKS_BITS= $clog2(AVS_BANKS) + parameter AVS_BYTEENW = (AVS_DATA_WIDTH / 8), + parameter RD_QUEUE_ADDR_WIDTH = $clog2(RD_QUEUE_SIZE+1), + parameter AVS_BANKS_BITS = $clog2(AVS_BANKS) ) ( - input wire clk, - input wire reset, + input wire clk, + input wire reset, // Memory request - input wire mem_req_valid, - input wire mem_req_rw, - input wire [AVS_BYTEENW-1:0] mem_req_byteen, - input wire [AVS_ADDRW-1:0] mem_req_addr, - input wire [AVS_DATAW-1:0] mem_req_data, - input wire [REQ_TAGW-1:0] mem_req_tag, - output wire mem_req_ready, + input wire mem_req_valid, + input wire mem_req_rw, + input wire [AVS_BYTEENW-1:0] mem_req_byteen, + input wire [AVS_ADDR_WIDTH-1:0] mem_req_addr, + input wire [AVS_DATA_WIDTH-1:0] mem_req_data, + input wire [REQ_TAG_WIDTH-1:0] mem_req_tag, + output wire mem_req_ready, // Memory response - output wire mem_rsp_valid, - output wire [AVS_DATAW-1:0] mem_rsp_data, - output wire [REQ_TAGW-1:0] mem_rsp_tag, - input wire mem_rsp_ready, + output wire mem_rsp_valid, + output wire [AVS_DATA_WIDTH-1:0] mem_rsp_data, + output wire [REQ_TAG_WIDTH-1:0] mem_rsp_tag, + input wire mem_rsp_ready, // AVS bus - output wire [AVS_DATAW-1:0] avs_writedata, - input wire [AVS_DATAW-1:0] avs_readdata, - output wire [AVS_ADDRW-1:0] avs_address, - input wire avs_waitrequest, - output wire avs_write, - output wire avs_read, - output wire [AVS_BYTEENW-1:0] avs_byteenable, - output wire [AVS_BURSTW-1:0] avs_burstcount, - input avs_readdatavalid, - output wire [AVS_BANKS_BITS-1:0] avs_bankselect + output wire [AVS_DATA_WIDTH-1:0] avs_writedata, + input wire [AVS_DATA_WIDTH-1:0] avs_readdata, + output wire [AVS_ADDR_WIDTH-1:0] avs_address, + input wire avs_waitrequest, + output wire avs_write, + output wire avs_read, + output wire [AVS_BYTEENW-1:0] avs_byteenable, + output wire [AVS_BURST_WIDTH-1:0] avs_burstcount, + input avs_readdatavalid, + output wire [AVS_BANKS_BITS-1:0] avs_bankselect ); reg [AVS_BANKS_BITS-1:0] avs_bankselect_r; - reg [AVS_BURSTW-1:0] avs_burstcount_r; + reg [AVS_BURST_WIDTH-1:0] avs_burstcount_r; wire avs_reqq_push = mem_req_valid && mem_req_ready && !mem_req_rw; wire avs_reqq_pop = mem_rsp_valid && mem_rsp_ready; @@ -53,7 +53,7 @@ module VX_avs_wrapper #( wire avs_rspq_empty; wire rsp_queue_going_full; - wire [RD_QUEUE_ADDRW-1:0] rsp_queue_size; + wire [RD_QUEUE_ADDR_WIDTH-1:0] rsp_queue_size; VX_pending_size #( .SIZE (RD_QUEUE_SIZE) ) pending_size ( @@ -73,7 +73,7 @@ module VX_avs_wrapper #( end VX_fifo_queue #( - .DATAW (REQ_TAGW), + .DATAW (REQ_TAG_WIDTH), .SIZE (RD_QUEUE_SIZE) ) rd_req_queue ( .clk (clk), @@ -90,7 +90,7 @@ module VX_avs_wrapper #( ); VX_fifo_queue #( - .DATAW (AVS_DATAW), + .DATAW (AVS_DATA_WIDTH), .SIZE (RD_QUEUE_SIZE) ) rd_rsp_queue ( .clk (clk), diff --git a/hw/rtl/afu/VX_cci_to_mem.v b/hw/rtl/afu/VX_to_mem.v similarity index 100% rename from hw/rtl/afu/VX_cci_to_mem.v rename to hw/rtl/afu/VX_to_mem.v diff --git a/hw/rtl/afu/vortex_afu.sv b/hw/rtl/afu/vortex_afu.sv index 78269ee7..392c775d 100644 --- a/hw/rtl/afu/vortex_afu.sv +++ b/hw/rtl/afu/vortex_afu.sv @@ -44,16 +44,13 @@ localparam RESET_DELAY = 3; localparam LMEM_LINE_WIDTH = $bits(t_local_mem_data); localparam LMEM_ADDR_WIDTH = $bits(t_local_mem_addr); localparam LMEM_BURST_CTRW = $bits(t_local_mem_burst_cnt); -localparam LMEM_LINE_LW = $clog2(LMEM_LINE_WIDTH); localparam CCI_LINE_WIDTH = $bits(t_ccip_clData); +localparam CCI_LINE_SIZE = CCI_LINE_WIDTH / 8; localparam CCI_ADDR_WIDTH = 32 - $clog2(CCI_LINE_WIDTH / 8); -localparam VX_MEM_LINE_LW = $clog2(`VX_MEM_LINE_WIDTH); -localparam VX_MEM_LINE_IDX = (LMEM_LINE_LW - VX_MEM_LINE_LW); - localparam AVS_RD_QUEUE_SIZE = 16; -localparam AVS_REQ_TAGW = `VX_MEM_TAG_WIDTH + VX_MEM_LINE_IDX; +localparam AVS_REQ_TAGW = `MAX(`VX_MEM_TAG_WIDTH, `VX_MEM_TAG_WIDTH + ($clog2(LMEM_LINE_WIDTH) - $clog2(`VX_MEM_LINE_WIDTH))); localparam CCI_RD_WINDOW_SIZE = 8; localparam CCI_RD_QUEUE_SIZE = 2 * CCI_RD_WINDOW_SIZE; @@ -451,6 +448,137 @@ end // AVS Controller ///////////////////////////////////////////////////////////// +wire cci_mem_rd_req_valid; +wire cci_mem_wr_req_valid; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_addr; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr; +wire [CCI_RD_RQ_DATAW-1:0] cci_rdq_dout; +wire cci_mem_req_ready; + +wire cci_mem_req_valid; +wire cci_mem_req_rw; +wire [CCI_ADDR_WIDTH-1:0] cci_mem_req_addr; +wire cci_mem_req_tag = 1'b0; + +wire cci_mem_rsp_valid; +wire [CCI_LINE_WIDTH-1:0] cci_mem_rsp_data; +wire cci_mem_rsp_tag; +wire cci_mem_rsp_ready; + +`UNUSED_VAR (cci_mem_rsp_tag) + +assign cci_mem_req_rw = (CMD_MEM_WRITE == state); +assign cci_mem_req_valid = cci_mem_req_rw ? cci_mem_wr_req_valid : cci_mem_rd_req_valid; +assign cci_mem_req_addr = cci_mem_req_rw ? cci_mem_wr_req_addr : cci_mem_rd_req_addr; + +//-- + +wire cci_mem_req_arb_valid; +wire cci_mem_req_arb_rw; +t_local_mem_byte_mask cci_mem_req_arb_byteen; +t_local_mem_addr cci_mem_req_arb_addr; +t_local_mem_data cci_mem_req_arb_data; +wire [AVS_REQ_TAGW-1:0] cci_mem_req_arb_tag; +wire cci_mem_req_arb_ready; + +wire cci_mem_rsp_arb_valid; +t_local_mem_data cci_mem_rsp_arb_data; +wire [AVS_REQ_TAGW-1:0] cci_mem_rsp_arb_tag; +wire cci_mem_rsp_arb_ready; + +VX_to_mem #( + .SRC_DATA_WIDTH (CCI_LINE_WIDTH), + .DST_DATA_WIDTH (LMEM_LINE_WIDTH), + .SRC_ADDR_WIDTH (CCI_ADDR_WIDTH), + .DST_ADDR_WIDTH (LMEM_ADDR_WIDTH), + .SRC_TAG_WIDTH (1), + .DST_TAG_WIDTH (AVS_REQ_TAGW) +) cci_to_mem ( + .clk (clk), + .reset (reset), + + .mem_req_valid_in (cci_mem_req_valid), + .mem_req_addr_in (cci_mem_req_addr), + .mem_req_rw_in (cci_mem_req_rw), + .mem_req_byteen_in ({CCI_LINE_SIZE{1'b1}}), + .mem_req_data_in (cci_rdq_dout[CCI_RD_RQ_DATAW-1:CCI_RD_RQ_TAGW]), + .mem_req_tag_in (cci_mem_req_tag), + .mem_req_ready_in (cci_mem_req_ready), + + .mem_req_valid_out (cci_mem_req_arb_valid), + .mem_req_addr_out (cci_mem_req_arb_addr), + .mem_req_rw_out (cci_mem_req_arb_rw), + .mem_req_byteen_out (cci_mem_req_arb_byteen), + .mem_req_data_out (cci_mem_req_arb_data), + .mem_req_tag_out (cci_mem_req_arb_tag), + .mem_req_ready_out (cci_mem_req_arb_ready), + + .mem_rsp_valid_in (cci_mem_rsp_arb_valid), + .mem_rsp_data_in (cci_mem_rsp_arb_data), + .mem_rsp_tag_in (cci_mem_rsp_arb_tag), + .mem_rsp_ready_in (cci_mem_rsp_arb_ready), + + .mem_rsp_valid_out (cci_mem_rsp_valid), + .mem_rsp_data_out (cci_mem_rsp_data), + .mem_rsp_tag_out (cci_mem_rsp_tag), + .mem_rsp_ready_out (cci_mem_rsp_ready) +); + +//-- + +wire vx_mem_req_arb_valid; +wire vx_mem_req_arb_rw; +t_local_mem_byte_mask vx_mem_req_arb_byteen; +t_local_mem_addr vx_mem_req_arb_addr; +t_local_mem_data vx_mem_req_arb_data; +wire [AVS_REQ_TAGW-1:0] vx_mem_req_arb_tag; +wire vx_mem_req_arb_ready; + +wire vx_mem_rsp_arb_valid; +t_local_mem_data vx_mem_rsp_arb_data; +wire [AVS_REQ_TAGW-1:0] vx_mem_rsp_arb_tag; +wire vx_mem_rsp_arb_ready; + +VX_to_mem #( + .SRC_DATA_WIDTH (`VX_MEM_LINE_WIDTH), + .DST_DATA_WIDTH (LMEM_LINE_WIDTH), + .SRC_ADDR_WIDTH (`VX_MEM_ADDR_WIDTH), + .DST_ADDR_WIDTH (LMEM_ADDR_WIDTH), + .SRC_TAG_WIDTH (`VX_MEM_TAG_WIDTH), + .DST_TAG_WIDTH (AVS_REQ_TAGW) +) vx_to_mem ( + .clk (clk), + .reset (reset), + + .mem_req_valid_in (vx_mem_req_valid && vx_mem_en), + .mem_req_addr_in (vx_mem_req_addr), + .mem_req_rw_in (vx_mem_req_rw), + .mem_req_byteen_in (vx_mem_req_byteen), + .mem_req_data_in (vx_mem_req_data), + .mem_req_tag_in (vx_mem_req_tag), + .mem_req_ready_in (vx_mem_req_ready), + + .mem_req_valid_out (vx_mem_req_arb_valid), + .mem_req_addr_out (vx_mem_req_arb_addr), + .mem_req_rw_out (vx_mem_req_arb_rw), + .mem_req_byteen_out (vx_mem_req_arb_byteen), + .mem_req_data_out (vx_mem_req_arb_data), + .mem_req_tag_out (vx_mem_req_arb_tag), + .mem_req_ready_out (vx_mem_req_arb_ready), + + .mem_rsp_valid_in (vx_mem_rsp_arb_valid), + .mem_rsp_data_in (vx_mem_rsp_arb_data), + .mem_rsp_tag_in (vx_mem_rsp_arb_tag), + .mem_rsp_ready_in (vx_mem_rsp_arb_ready), + + .mem_rsp_valid_out (vx_mem_rsp_valid), + .mem_rsp_data_out (vx_mem_rsp_data), + .mem_rsp_tag_out (vx_mem_rsp_tag), + .mem_rsp_ready_out (vx_mem_rsp_ready) +); + +//-- + wire mem_req_valid; wire mem_req_rw; t_local_mem_byte_mask mem_req_byteen; @@ -464,104 +592,6 @@ t_local_mem_data mem_rsp_data; wire [AVS_REQ_TAGW:0] mem_rsp_tag; wire mem_rsp_ready; -wire cci_mem_req_tmp_valid; -wire cci_mem_req_tmp_rw; -t_local_mem_byte_mask cci_mem_req_tmp_byteen; -t_local_mem_addr cci_mem_req_tmp_addr; -t_local_mem_data cci_mem_req_tmp_data; -wire [AVS_REQ_TAGW-1:0] cci_mem_req_tmp_tag; -wire cci_mem_req_tmp_ready; - -wire cci_mem_rsp_tmp_valid; -t_local_mem_data cci_mem_rsp_tmp_data; -wire [AVS_REQ_TAGW-1:0] cci_mem_rsp_tmp_tag; -wire cci_mem_rsp_tmp_ready; - -wire vx_mem_req_valid_qual; -t_local_mem_addr vx_mem_req_addr_qual; -t_local_mem_byte_mask vx_mem_req_byteen_qual; -t_local_mem_data vx_mem_req_data_qual; -wire [AVS_REQ_TAGW-1:0] vx_mem_req_tag_qual; - -wire [(1 << VX_MEM_LINE_IDX)-1:0][`VX_MEM_LINE_WIDTH-1:0] vx_mem_rsp_data_unqual; -wire [AVS_REQ_TAGW-1:0] vx_mem_rsp_tag_unqual; - -wire cci_mem_rd_req_valid; -wire cci_mem_wr_req_valid; -wire [CCI_ADDR_WIDTH-1:0] cci_mem_rd_req_addr; -wire [CCI_ADDR_WIDTH-1:0] cci_mem_wr_req_addr; -wire [CCI_RD_RQ_DATAW-1:0] cci_rdq_dout; -wire cci_mem_req_ready; - -wire cci_mem_rsp_valid; -wire [CCI_LINE_WIDTH-1:0] cci_mem_rsp_data; -wire [AVS_REQ_TAGW-1:0] cci_mem_rsp_tag; -wire cci_mem_rsp_ready; - -//-- - -VX_cci_to_mem #( - .CCI_DATAW (CCI_LINE_WIDTH), - .CCI_ADDRW (CCI_ADDR_WIDTH), - .AVS_DATAW (LMEM_LINE_WIDTH), - .AVS_ADDRW (LMEM_ADDR_WIDTH), - .TAG_WIDTH (AVS_REQ_TAGW) -) cci_to_mem( - .clk (clk), - .reset (reset), - - .mem_req_valid_in ((CMD_MEM_WRITE == state) ? cci_mem_wr_req_valid : cci_mem_rd_req_valid), - .mem_req_addr_in ((CMD_MEM_WRITE == state) ? cci_mem_wr_req_addr : cci_mem_rd_req_addr), - .mem_req_rw_in ((CMD_MEM_WRITE == state)), - .mem_req_data_in (cci_rdq_dout[CCI_RD_RQ_DATAW-1:CCI_RD_RQ_TAGW]), - .mem_req_tag_in (AVS_REQ_TAGW'(0)), - .mem_req_ready_in (cci_mem_req_ready), - - .mem_req_valid_out (cci_mem_req_tmp_valid), - .mem_req_addr_out (cci_mem_req_tmp_addr), - .mem_req_rw_out (cci_mem_req_tmp_rw), - .mem_req_byteen_out(cci_mem_req_tmp_byteen), - .mem_req_data_out (cci_mem_req_tmp_data), - .mem_req_tag_out (cci_mem_req_tmp_tag), - .mem_req_ready_out (cci_mem_req_tmp_ready), - - .mem_rsp_valid_in (cci_mem_rsp_tmp_valid), - .mem_rsp_data_in (cci_mem_rsp_tmp_data), - .mem_rsp_tag_in (cci_mem_rsp_tmp_tag), - .mem_rsp_ready_in (cci_mem_rsp_tmp_ready), - - .mem_rsp_valid_out (cci_mem_rsp_valid), - .mem_rsp_data_out (cci_mem_rsp_data), - .mem_rsp_tag_out (cci_mem_rsp_tag), - .mem_rsp_ready_out (cci_mem_rsp_ready) -); - -`UNUSED_VAR (cci_mem_rsp_tag) - -//-- - -assign vx_mem_req_valid_qual = vx_mem_req_valid && vx_mem_en; - -assign vx_mem_req_addr_qual = vx_mem_req_addr[`VX_MEM_ADDR_WIDTH-1:`VX_MEM_ADDR_WIDTH-LMEM_ADDR_WIDTH]; - -if (`VX_MEM_LINE_WIDTH != LMEM_LINE_WIDTH) begin - wire [VX_MEM_LINE_IDX-1:0] vx_mem_req_idx = vx_mem_req_addr[VX_MEM_LINE_IDX-1:0]; - wire [VX_MEM_LINE_IDX-1:0] vx_mem_rsp_idx = vx_mem_rsp_tag_unqual[VX_MEM_LINE_IDX-1:0]; - assign vx_mem_req_byteen_qual = 64'(vx_mem_req_byteen) << (6'(vx_mem_req_addr[VX_MEM_LINE_IDX-1:0]) << (VX_MEM_LINE_LW-3)); - assign vx_mem_req_data_qual = LMEM_LINE_WIDTH'(vx_mem_req_data) << ((LMEM_LINE_LW'(vx_mem_req_idx)) << VX_MEM_LINE_LW); - assign vx_mem_req_tag_qual = {vx_mem_req_tag, vx_mem_req_idx}; - assign vx_mem_rsp_data = vx_mem_rsp_data_unqual[vx_mem_rsp_idx]; -end else begin - assign vx_mem_req_byteen_qual = vx_mem_req_byteen; - assign vx_mem_req_tag_qual = vx_mem_req_tag; - assign vx_mem_req_data_qual = vx_mem_req_data; - assign vx_mem_rsp_data = vx_mem_rsp_data_unqual; -end - -assign vx_mem_rsp_tag = vx_mem_rsp_tag_unqual[`VX_MEM_TAG_WIDTH+VX_MEM_LINE_IDX-1:VX_MEM_LINE_IDX]; - -//-- - VX_mem_arb #( .NUM_REQS (2), .DATA_WIDTH (LMEM_LINE_WIDTH), @@ -573,13 +603,13 @@ VX_mem_arb #( .reset (reset), // Source request - .req_valid_in ({cci_mem_req_tmp_valid, vx_mem_req_valid_qual}), - .req_rw_in ({cci_mem_req_tmp_rw, vx_mem_req_rw}), - .req_byteen_in ({cci_mem_req_tmp_byteen, vx_mem_req_byteen_qual}), - .req_addr_in ({cci_mem_req_tmp_addr, vx_mem_req_addr_qual}), - .req_data_in ({cci_mem_req_tmp_data, vx_mem_req_data_qual}), - .req_tag_in ({cci_mem_req_tmp_tag, vx_mem_req_tag_qual}), - .req_ready_in ({cci_mem_req_tmp_ready, vx_mem_req_ready}), + .req_valid_in ({cci_mem_req_arb_valid, vx_mem_req_arb_valid}), + .req_rw_in ({cci_mem_req_arb_rw, vx_mem_req_arb_rw}), + .req_byteen_in ({cci_mem_req_arb_byteen, vx_mem_req_arb_byteen}), + .req_addr_in ({cci_mem_req_arb_addr, vx_mem_req_arb_addr}), + .req_data_in ({cci_mem_req_arb_data, vx_mem_req_arb_data}), + .req_tag_in ({cci_mem_req_arb_tag, vx_mem_req_arb_tag}), + .req_ready_in ({cci_mem_req_arb_ready, vx_mem_req_arb_ready}), // Memory request .req_valid_out (mem_req_valid), @@ -591,10 +621,10 @@ VX_mem_arb #( .req_ready_out (mem_req_ready), // Source response - .rsp_valid_out ({cci_mem_rsp_tmp_valid, vx_mem_rsp_valid}), - .rsp_data_out ({cci_mem_rsp_tmp_data, vx_mem_rsp_data_unqual}), - .rsp_tag_out ({cci_mem_rsp_tmp_tag, vx_mem_rsp_tag_unqual}), - .rsp_ready_out ({cci_mem_rsp_tmp_ready, vx_mem_rsp_ready}), + .rsp_valid_out ({cci_mem_rsp_arb_valid, vx_mem_rsp_arb_valid}), + .rsp_data_out ({cci_mem_rsp_arb_data, vx_mem_rsp_arb_data}), + .rsp_tag_out ({cci_mem_rsp_arb_tag, vx_mem_rsp_arb_tag}), + .rsp_ready_out ({cci_mem_rsp_arb_ready, vx_mem_rsp_arb_ready}), // Memory response .rsp_valid_in (mem_rsp_valid), @@ -606,42 +636,42 @@ VX_mem_arb #( //-- VX_avs_wrapper #( - .AVS_DATAW (LMEM_LINE_WIDTH), - .AVS_ADDRW (LMEM_ADDR_WIDTH), - .AVS_BURSTW (LMEM_BURST_CTRW), - .AVS_BANKS (NUM_LOCAL_MEM_BANKS), - .REQ_TAGW (AVS_REQ_TAGW+1), - .RD_QUEUE_SIZE (AVS_RD_QUEUE_SIZE) + .AVS_DATA_WIDTH (LMEM_LINE_WIDTH), + .AVS_ADDR_WIDTH (LMEM_ADDR_WIDTH), + .AVS_BURST_WIDTH (LMEM_BURST_CTRW), + .AVS_BANKS (NUM_LOCAL_MEM_BANKS), + .REQ_TAG_WIDTH (AVS_REQ_TAGW+1), + .RD_QUEUE_SIZE (AVS_RD_QUEUE_SIZE) ) avs_wrapper ( - .clk (clk), - .reset (reset), + .clk (clk), + .reset (reset), // Memory request - .mem_req_valid (mem_req_valid), - .mem_req_rw (mem_req_rw), - .mem_req_byteen (mem_req_byteen), - .mem_req_addr (mem_req_addr), - .mem_req_data (mem_req_data), - .mem_req_tag (mem_req_tag), - .mem_req_ready (mem_req_ready), + .mem_req_valid (mem_req_valid), + .mem_req_rw (mem_req_rw), + .mem_req_byteen (mem_req_byteen), + .mem_req_addr (mem_req_addr), + .mem_req_data (mem_req_data), + .mem_req_tag (mem_req_tag), + .mem_req_ready (mem_req_ready), // Memory response - .mem_rsp_valid (mem_rsp_valid), - .mem_rsp_data (mem_rsp_data), - .mem_rsp_tag (mem_rsp_tag), - .mem_rsp_ready (mem_rsp_ready), + .mem_rsp_valid (mem_rsp_valid), + .mem_rsp_data (mem_rsp_data), + .mem_rsp_tag (mem_rsp_tag), + .mem_rsp_ready (mem_rsp_ready), // AVS bus - .avs_writedata (avs_writedata), - .avs_readdata (avs_readdata), - .avs_address (avs_address), - .avs_waitrequest (avs_waitrequest), - .avs_write (avs_write), - .avs_read (avs_read), - .avs_byteenable (avs_byteenable), - .avs_burstcount (avs_burstcount), - .avs_readdatavalid (avs_readdatavalid), - .avs_bankselect (mem_bank_select) + .avs_writedata (avs_writedata), + .avs_readdata (avs_readdata), + .avs_address (avs_address), + .avs_waitrequest (avs_waitrequest), + .avs_write (avs_write), + .avs_read (avs_read), + .avs_byteenable (avs_byteenable), + .avs_burstcount (avs_burstcount), + .avs_readdatavalid(avs_readdatavalid), + .avs_bankselect (mem_bank_select) ); // CCI-P Read Request /////////////////////////////////////////////////////////// @@ -714,7 +744,7 @@ always @(posedge clk) begin cci_rd_rsp_ctr <= 0; cci_rd_req_enable <= 0; cci_rd_req_wait <= 0; - cci_mem_wr_req_ctr <= 0; + cci_mem_wr_req_ctr <= 0; cci_mem_wr_req_addr_unqual <= 0; end else begin diff --git a/hw/rtl/afu/vortex_afu.vh b/hw/rtl/afu/vortex_afu.vh index 05a5654e..c92a3a32 100644 --- a/hw/rtl/afu/vortex_afu.vh +++ b/hw/rtl/afu/vortex_afu.vh @@ -9,13 +9,17 @@ `define PLATFORM_PARAM_LOCAL_MEMORY_BANKS 2 `endif -`ifndef PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS -`define PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS 6 +`ifndef PLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH +`define PLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH 26 `endif -`define PLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH (32-`PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS) -`define PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH (8 << `PLATFORM_PARAM_LOCAL_MEMORY_DATA_SIZE_BITS) +`ifndef PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH +`define PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH 512 +`endif + +`ifndef PLATFORM_PARAM_LOCAL_MEMORY_BURST_CNT_WIDTH `define PLATFORM_PARAM_LOCAL_MEMORY_BURST_CNT_WIDTH 4 +`endif `include "local_mem_cfg_pkg.sv" diff --git a/hw/syn/opae/Makefile b/hw/syn/opae/Makefile index 9e4ea121..38f21fba 100644 --- a/hw/syn/opae/Makefile +++ b/hw/syn/opae/Makefile @@ -3,14 +3,6 @@ FPGA_BUILD_DIR ?= build_fpga DEVICE_FAMILY ?= arria10 RTL_DIR=../../rtl -ifeq ($(DEVICE_FAMILY),arria10) - CFLAGS += -DMEM_BLOCK_SIZE=64 -endif - -ifeq ($(DEVICE_FAMILY),stratix10) - CFLAGS += -DMEM_BLOCK_SIZE=16 -endif - ifeq ($(shell which qsub-synth),) RUN_SYNTH=$(OPAE_PLATFORM_ROOT)/bin/run.sh > build.log 2>&1 & else diff --git a/hw/syn/opae/README b/hw/syn/opae/README index 5e9f9537..c85981c7 100644 --- a/hw/syn/opae/README +++ b/hw/syn/opae/README @@ -63,7 +63,8 @@ qsub-sim make ase # tests -./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n128 -t0 +./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n1 -t0 +./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n1 -t1 ./run_ase.sh build_ase_1c ../../../driver/tests/basic/basic -n16 ./run_ase.sh build_ase_1c ../../../driver/tests/demo/demo -n16 ./run_ase.sh build_ase_1c ../../../driver/tests/dogfood/dogfood -n16 @@ -86,7 +87,7 @@ tar -zcvf run.log.tar.gz run.log tar -zcvf vx_scope.vcd.tar.gz vx_scope.vcd tar -cvjf vx_scope.vcd.tar.bz2 vx_scope.vcd tar -cvjf trace.fst.tar.bz2 trace.fst run.log -tar -cvjf trace.vcd.tar.bz2 trace.vcd run.log +tar -cvjf trace.vcd.tar.bz2 driver/tests/basic/trace.vcd run.log tar -cvjf trace.vcd.tar.bz2 build_ase_1c/work/run.log build_ase_1c/work/trace.vcd # decompress VCD trace From e40a3feefa3d69de6e610bc3b76078e1d00816c0 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 1 May 2021 10:33:24 -0700 Subject: [PATCH 23/55] minor update --- hw/rtl/afu/VX_to_mem.v | 191 ++++++++++++++++++++++++++++------------- 1 file changed, 131 insertions(+), 60 deletions(-) diff --git a/hw/rtl/afu/VX_to_mem.v b/hw/rtl/afu/VX_to_mem.v index fe003b47..7e786e50 100644 --- a/hw/rtl/afu/VX_to_mem.v +++ b/hw/rtl/afu/VX_to_mem.v @@ -1,78 +1,101 @@ `include "VX_define.vh" -module VX_cci_to_mem #( - parameter CCI_DATAW = 1, - parameter CCI_ADDRW = 1, - parameter AVS_DATAW = 1, - parameter AVS_ADDRW = 1, - parameter AVS_BYTEENW = (AVS_DATAW / 8), - parameter TAG_WIDTH = 1 +module VX_to_mem #( + parameter SRC_DATA_WIDTH = 1, + parameter SRC_ADDR_WIDTH = 1, + parameter DST_DATA_WIDTH = 1, + parameter DST_ADDR_WIDTH = 1, + parameter SRC_TAG_WIDTH = 1, + parameter DST_TAG_WIDTH = 1, + parameter SRC_DATA_SIZE = (SRC_DATA_WIDTH / 8), + parameter DST_DATA_SIZE = (DST_DATA_WIDTH / 8) ) ( - input wire clk, - input wire reset, + input wire clk, + input wire reset, - input wire mem_req_valid_in, - input wire [CCI_ADDRW-1:0] mem_req_addr_in, - input wire mem_req_rw_in, - input wire [CCI_DATAW-1:0] mem_req_data_in, - input wire [TAG_WIDTH-1:0] mem_req_tag_in, - output wire mem_req_ready_in, + input wire mem_req_valid_in, + input wire [SRC_ADDR_WIDTH-1:0] mem_req_addr_in, + input wire mem_req_rw_in, + input wire [SRC_DATA_SIZE-1:0] mem_req_byteen_in, + input wire [SRC_DATA_WIDTH-1:0] mem_req_data_in, + input wire [SRC_TAG_WIDTH-1:0] mem_req_tag_in, + output wire mem_req_ready_in, - output wire mem_req_valid_out, - output wire [AVS_ADDRW-1:0] mem_req_addr_out, - output wire mem_req_rw_out, - output wire [AVS_BYTEENW-1:0] mem_req_byteen_out, - output wire [AVS_DATAW-1:0] mem_req_data_out, - output wire [TAG_WIDTH-1:0] mem_req_tag_out, - input wire mem_req_ready_out, + output wire mem_req_valid_out, + output wire [DST_ADDR_WIDTH-1:0] mem_req_addr_out, + output wire mem_req_rw_out, + output wire [DST_DATA_SIZE-1:0] mem_req_byteen_out, + output wire [DST_DATA_WIDTH-1:0] mem_req_data_out, + output wire [DST_TAG_WIDTH-1:0] mem_req_tag_out, + input wire mem_req_ready_out, - input wire mem_rsp_valid_in, - input wire [AVS_DATAW-1:0] mem_rsp_data_in, - input wire [TAG_WIDTH-1:0] mem_rsp_tag_in, - output wire mem_rsp_ready_in, + input wire mem_rsp_valid_in, + input wire [DST_DATA_WIDTH-1:0] mem_rsp_data_in, + input wire [DST_TAG_WIDTH-1:0] mem_rsp_tag_in, + output wire mem_rsp_ready_in, - output wire mem_rsp_valid_out, - output wire [CCI_DATAW-1:0] mem_rsp_data_out, - output wire [TAG_WIDTH-1:0] mem_rsp_tag_out, - input wire mem_rsp_ready_out -); - localparam N = AVS_ADDRW - CCI_ADDRW; - - `STATIC_ASSERT(N >= 0, ("oops!")) + output wire mem_rsp_valid_out, + output wire [SRC_DATA_WIDTH-1:0] mem_rsp_data_out, + output wire [SRC_TAG_WIDTH-1:0] mem_rsp_tag_out, + input wire mem_rsp_ready_out +); + `STATIC_ASSERT ((DST_TAG_WIDTH >= SRC_TAG_WIDTH), ("oops!")) - if (N == 0) begin + localparam DST_LDATAW = $clog2(DST_DATA_WIDTH); + localparam SRC_LDATAW = $clog2(SRC_DATA_WIDTH); + localparam D = `ABS(DST_LDATAW - SRC_LDATAW); + localparam P = 2**D; + + `UNUSED_VAR (mem_rsp_tag_in) + + if (DST_LDATAW > SRC_LDATAW) begin + `UNUSED_VAR (clk) `UNUSED_VAR (reset) + + wire [D-1:0] req_idx = mem_req_addr_in[D-1:0]; + wire [D-1:0] rsp_idx = mem_rsp_tag_in[D-1:0]; + + wire [SRC_ADDR_WIDTH-D-1:0] mem_req_addr_in_qual = mem_req_addr_in[SRC_ADDR_WIDTH-1:D]; + + wire [P-1:0][SRC_DATA_WIDTH-1:0] mem_rsp_data_in_w = mem_rsp_data_in; + + if (DST_ADDR_WIDTH < (SRC_ADDR_WIDTH - D)) begin + `UNUSED_VAR (mem_req_addr_in_qual) + assign mem_req_addr_out = mem_req_addr_in_qual[DST_ADDR_WIDTH-1:0]; + end else if (DST_ADDR_WIDTH > (SRC_ADDR_WIDTH - D)) begin + assign mem_req_addr_out = DST_ADDR_WIDTH'(mem_req_addr_in_qual); + end else begin + assign mem_req_addr_out = mem_req_addr_in_qual; + end assign mem_req_valid_out = mem_req_valid_in; - assign mem_req_addr_out = mem_req_addr_in; assign mem_req_rw_out = mem_req_rw_in; - assign mem_req_byteen_out = {AVS_BYTEENW{1'b1}}; - assign mem_req_data_out = mem_req_data_in; - assign mem_req_tag_out = mem_req_tag_in; + assign mem_req_byteen_out = DST_DATA_SIZE'(mem_req_byteen_in) << ((DST_LDATAW-3)'(req_idx) << (SRC_LDATAW-3)); + assign mem_req_data_out = DST_DATA_WIDTH'(mem_req_data_in) << ((DST_LDATAW'(req_idx)) << DST_LDATAW); + assign mem_req_tag_out = DST_TAG_WIDTH'({mem_req_tag_in, req_idx}); assign mem_req_ready_in = mem_req_ready_out; assign mem_rsp_valid_out = mem_rsp_valid_in; - assign mem_rsp_data_out = mem_rsp_data_in; - assign mem_rsp_tag_out = mem_rsp_tag_in; + assign mem_rsp_data_out = mem_rsp_data_in_w[rsp_idx]; + assign mem_rsp_tag_out = SRC_TAG_WIDTH'(mem_rsp_tag_in[SRC_TAG_WIDTH+D-1:D]); assign mem_rsp_ready_in = mem_rsp_ready_out; - end else begin + end else if (DST_LDATAW < SRC_LDATAW) begin - reg [N-1:0] req_ctr, rsp_ctr; + reg [D-1:0] req_ctr, rsp_ctr; - wire [(2**N)-1:0][AVS_DATAW-1:0] mem_req_data_w_in; - - reg [(2**N)-1:0][AVS_DATAW-1:0] mem_rsp_data_r_out, mem_rsp_data_n_out; + reg [P-1:0][DST_DATA_WIDTH-1:0] mem_rsp_data_out_r, mem_rsp_data_out_n; wire mem_req_fire_out = mem_req_valid_out && mem_req_ready_out; wire mem_rsp_fire_in = mem_rsp_valid_in && mem_rsp_ready_in; - assign mem_req_data_w_in = mem_req_data_in; + wire [P-1:0][DST_DATA_WIDTH-1:0] mem_req_data_in_w = mem_req_data_in; + wire [P-1:0][DST_DATA_SIZE-1:0] mem_req_byteen_in_w = mem_req_byteen_in; always @(*) begin - mem_rsp_data_n_out = mem_rsp_data_r_out; - mem_rsp_data_n_out[rsp_ctr] = mem_rsp_data_in; + mem_rsp_data_out_n = mem_rsp_data_out_r; + mem_rsp_data_out_n[rsp_ctr] = mem_rsp_data_in; end always @(posedge clk) begin @@ -85,23 +108,71 @@ module VX_cci_to_mem #( end if (mem_rsp_fire_in) begin rsp_ctr <= rsp_ctr + 1; - mem_rsp_data_r_out <= mem_rsp_data_n_out; + mem_rsp_data_out_r <= mem_rsp_data_out_n; end end end - assign mem_req_valid_out = mem_req_valid_in; - assign mem_req_addr_out = {mem_req_addr_in, req_ctr}; - assign mem_req_rw_out = mem_req_rw_in; - assign mem_req_byteen_out = {AVS_BYTEENW{1'b1}}; - assign mem_req_data_out = mem_req_data_w_in[req_ctr]; - assign mem_req_tag_out = mem_req_tag_in; - assign mem_req_ready_in = mem_req_ready_out && (req_ctr == (2**N-1)); + reg [DST_TAG_WIDTH-1:0] mem_rsp_tag_in_r; + wire [DST_TAG_WIDTH-1:0] mem_rsp_tag_in_w; + + always @(posedge clk) begin + if (mem_rsp_fire_in) begin + mem_rsp_tag_in_r <= mem_rsp_tag_in; + end + end + assign mem_rsp_tag_in_w = (rsp_ctr != 0) ? mem_rsp_tag_in_r : mem_rsp_tag_in; + `RUNTIME_ASSERT((mem_rsp_tag_in_w == mem_rsp_tag_in), ("oops!")) - assign mem_rsp_valid_out = mem_rsp_valid_in && (rsp_ctr == (2**N-1)); - assign mem_rsp_data_out = mem_rsp_data_n_out; - assign mem_rsp_tag_out = mem_rsp_tag_in; + wire [SRC_ADDR_WIDTH+D-1:0] mem_req_addr_in_qual = {mem_req_addr_in, req_ctr}; + + if (DST_ADDR_WIDTH < (SRC_ADDR_WIDTH + D)) begin + `UNUSED_VAR (mem_req_addr_in_qual) + assign mem_req_addr_out = mem_req_addr_in_qual[DST_ADDR_WIDTH-1:0]; + end else if (DST_ADDR_WIDTH > (SRC_ADDR_WIDTH + D)) begin + assign mem_req_addr_out = DST_ADDR_WIDTH'(mem_req_addr_in_qual); + end else begin + assign mem_req_addr_out = mem_req_addr_in_qual; + end + + assign mem_req_valid_out = mem_req_valid_in; + assign mem_req_rw_out = mem_req_rw_in; + assign mem_req_byteen_out = mem_req_byteen_in_w[req_ctr]; + assign mem_req_data_out = mem_req_data_in_w[req_ctr]; + assign mem_req_tag_out = DST_TAG_WIDTH'(mem_req_tag_in); + assign mem_req_ready_in = mem_req_ready_out && (req_ctr == (P-1)); + + assign mem_rsp_valid_out = mem_rsp_valid_in && (rsp_ctr == (P-1)); + assign mem_rsp_data_out = mem_rsp_data_out_n; + assign mem_rsp_tag_out = SRC_TAG_WIDTH'(mem_rsp_tag_in); assign mem_rsp_ready_in = mem_rsp_ready_out; + + end else begin + + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + + if (DST_ADDR_WIDTH < SRC_ADDR_WIDTH) begin + `UNUSED_VAR (mem_req_addr_in) + assign mem_req_addr_out = mem_req_addr_in[DST_ADDR_WIDTH-1:0]; + end else if (DST_ADDR_WIDTH > SRC_ADDR_WIDTH) begin + assign mem_req_addr_out = DST_ADDR_WIDTH'(mem_req_addr_in); + end else begin + assign mem_req_addr_out = mem_req_addr_in; + end + + assign mem_req_valid_out = mem_req_valid_in; + assign mem_req_rw_out = mem_req_rw_in; + assign mem_req_byteen_out = mem_req_byteen_in; + assign mem_req_data_out = mem_req_data_in; + assign mem_req_tag_out = DST_TAG_WIDTH'(mem_req_tag_in); + assign mem_req_ready_in = mem_req_ready_out; + + assign mem_rsp_valid_out = mem_rsp_valid_in; + assign mem_rsp_data_out = mem_rsp_data_in; + assign mem_rsp_tag_out = SRC_TAG_WIDTH'(mem_rsp_tag_in); + assign mem_rsp_ready_in = mem_rsp_ready_out; + end endmodule \ No newline at end of file From eee0637a29a3927ac3fead1c81bc806fe1e08ecb Mon Sep 17 00:00:00 2001 From: MalikBurton <42877662+MalikBurton@users.noreply.github.com> Date: Sat, 1 May 2021 15:07:12 -0400 Subject: [PATCH 24/55] Added images for Cache_Subsystem.md --- doc/Images/cache_hierarchy.png | Bin 0 -> 60885 bytes doc/Images/vortex_bank.png | Bin 0 -> 79299 bytes doc/Images/vortex_cache_top_module.png | Bin 0 -> 68415 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/Images/cache_hierarchy.png create mode 100644 doc/Images/vortex_bank.png create mode 100644 doc/Images/vortex_cache_top_module.png diff --git a/doc/Images/cache_hierarchy.png b/doc/Images/cache_hierarchy.png new file mode 100644 index 0000000000000000000000000000000000000000..876f5fe28fc6e6a4bf327c275798eaf28ecb587a GIT binary patch literal 60885 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