Rewrote the top level verilog for a 30x30 array; moved the original 30x50 array to "user_project_wrapper_30x50.v" for safekeeping.
diff --git a/verilog/dv/chaos_test2/chaos_test2.c b/verilog/dv/chaos_test2/chaos_test2.c index add7e5c..b48f9aa 100644 --- a/verilog/dv/chaos_test2/chaos_test2.c +++ b/verilog/dv/chaos_test2/chaos_test2.c
@@ -35,7 +35,6 @@ #define reg_user_data1 (*(volatile uint32_t*)0x3000001c) #define reg_user_data2 (*(volatile uint32_t*)0x30000020) #define reg_user_data3 (*(volatile uint32_t*)0x30000024) -#define reg_user_data4 (*(volatile uint32_t*)0x30000028) /* Configuration further refined to each LUT (16 bits per LUT) */ #define reg_user_config_N (*(volatile uint16_t*)0x30000000)
diff --git a/verilog/dv/chaos_test3/chaos_test3.c b/verilog/dv/chaos_test3/chaos_test3.c index f4445c3..de9ffa0 100644 --- a/verilog/dv/chaos_test3/chaos_test3.c +++ b/verilog/dv/chaos_test3/chaos_test3.c
@@ -37,7 +37,6 @@ #define reg_user_data1 (*(volatile uint32_t*)0x3000001c) #define reg_user_data2 (*(volatile uint32_t*)0x30000020) #define reg_user_data3 (*(volatile uint32_t*)0x30000024) -#define reg_user_data4 (*(volatile uint32_t*)0x30000028) /* Configuration further refined to each LUT (16 bits per LUT) */ #define reg_user_config_N (*(volatile uint16_t*)0x30000000) @@ -123,7 +122,6 @@ reg_user_data1 = 0; reg_user_data2 = 0; reg_user_data3 = 0; - reg_user_data4 = 0; // Apply address 0 (meaning shift by 1 address position each time) reg_user_address = 0; @@ -137,7 +135,8 @@ reg_user_config_W = 0xff00; reg_user_config_E = 0xff00; - for (i = 0; i < 1500; i++) + // Note: 900 = 30 x 30, or the total number of cells. + for (i = 0; i < 900; i++) { // Cycle register to load position reg_user_transfer = 1; @@ -164,21 +163,18 @@ reg_mprj_datal = reg_user_data1; reg_mprj_datal = reg_user_data2; reg_mprj_datal = reg_user_data3; - reg_mprj_datal = reg_user_data4; // Apply one bits to all inputs (with logic analyzer) reg_user_data0 = -1; reg_user_data1 = -1; reg_user_data2 = -1; reg_user_data3 = -1; - reg_user_data4 = -1; // Read bits from all outputs (should be one)---apply to GPIO out reg_mprj_datal = reg_user_data0; reg_mprj_datal = reg_user_data1; reg_mprj_datal = reg_user_data2; reg_mprj_datal = reg_user_data3; - reg_mprj_datal = reg_user_data4; // Flag end of test reg_mprj_datal = 0xAB510000;
diff --git a/verilog/rtl/user_project_wrapper.v b/verilog/rtl/user_project_wrapper.v index 09691b6..3098be5 100644 --- a/verilog/rtl/user_project_wrapper.v +++ b/verilog/rtl/user_project_wrapper.v
@@ -99,9 +99,15 @@ * the cell address, (2) Apply the shift cycle, (3) Read the configuration * data, (4) Apply the finish cycle. * - * * This version uses the chaos_subarray, which is intended to be * prehardened as a macro and tiled in the top level. + * + * The user project wrapper is currently hard-coded to a specific + * array size due to the complexity of aligning the array inputs and + * outputs to the GPIO pins. The original version of this wrapper + * was hard-coded to a 30x50 array, and has been copied back to + * user_project_wrapper_30x50.v. The current version is hard-coded + * to a 30x30 array. *------------------------------------------------------------- */ @@ -117,7 +123,7 @@ module user_project_wrapper #( parameter XSIZE = 30, // Total number of cells left to right - parameter YSIZE = 50, // Total number of cells top to bottom + parameter YSIZE = 30, // Total number of cells top to bottom parameter XTOP = 3, // Number of sub-arrays left to right parameter YTOP = 5, // Number of sub-arrays top to bottom parameter ASIZE = 11, // Enough bits to count XSIZE * YSIZE @@ -208,8 +214,8 @@ wire source_sel; // NOTE: This should be parameterized. - // For the 50x30 array, there are 50+50+30+30 = 160 periphery bits = - // 5 words of 32 bits. This is hard-coded for convenience. If the + // For the 30x30 array, there are 30+30+30+30 = 120 periphery bits = + // 4 words of 32 bits. This is hard-coded for convenience. If the // array size changes, this needs to be changed as well. Needs to be // converted to a "generate" block. wire [4:0] data_sel; @@ -292,12 +298,11 @@ assign direct_sel = (wbs_adr_i[7:2] == `DIRECT); assign source_sel = (wbs_adr_i[7:2] == `SOURCE); - // Hard-coded to 5 words; see note above + // Hard-coded to 4 words; see note above assign data_sel[0] = (wbs_adr_i[7:2] == (`DATATOP + 0)); assign data_sel[1] = (wbs_adr_i[7:2] == (`DATATOP + 1)); assign data_sel[2] = (wbs_adr_i[7:2] == (`DATATOP + 2)); assign data_sel[3] = (wbs_adr_i[7:2] == (`DATATOP + 3)); - assign data_sel[4] = (wbs_adr_i[7:2] == (`DATATOP + 4)); assign valid = wbs_cyc_i && wbs_stb_i; assign wbs_ack_o = ready; @@ -389,235 +394,230 @@ // Define I/O input slices // NOTE: This is hard-coded. There are 38 GPIOs. Assigning 32 of them // (GPIO 37 to 6) to array inputs and outputs. These are arranged as - // 10 on the sides and 6 on the top and bottom. These are further sub- - // divided into 5 inputs and 5 outputs on the sides, and 3 inputs and - // 3 outputs on top and bottom. Depending on the selection, these - // can be injected into various places around the array. + // 8 on the sides and 8 on the top and bottom. Depending on the selection, + // these can be injected into various places around the array. // Another note: It probably makes more sense to define vectors for // io_in_east, io_in_north, etc., and align them in the direction of // the arrays (high to low index is top to bottom, or right to left). - assign gpio_east = // I/O 15 to 6 - (gpio_input_slice == 0) ? 50'b0 : // No pad input + assign gpio_east = // I/O 13 to 6 + (gpio_input_slice == 0) ? 22'b0 : // No pad input (gpio_input_slice == 1) ? // Distributed - {2'b0, io_in[15], 4'b0, io_in[14], 4'b0, io_in[13], - 4'b0, io_in[12], 4'b0, io_in[11], 4'b0, io_in[10], - 4'b0, io_in[9], 4'b0, io_in[8], 4'b0, io_in[7], - 4'b0, io_in[6], 2'b0} : - (gpio_input_slice == 2) ? {40'b0, io_in[15:6]} : // Bottom shifted - (gpio_input_slice == 3) ? {20'b0, io_in[15:6], 20'b0} : // Centered - {io_in[15:6], 40'b0}; // Top shifted + {io_in[13], 3'b0, io_in[12], 3'b0, io_in[11], 3'b0, + io_in[10], 3'b0, io_in[9], 3'b0, io_in[8], 3'b0, + io_in[7], 3'b0, io_in[6], 1'b0} : + (gpio_input_slice == 2) ? {22'b0, io_in[15:6]} : // Bottom shifted + (gpio_input_slice == 3) ? {11'b0, io_in[15:6], 11'b0} : // Centered + {io_in[15:6], 22'b0}; // Top shifted - assign gpio_north = // I/O 21 to 16 - (gpio_input_slice == 0) ? 30'b0 : // No pad input + assign gpio_north = // I/O 21 to 14 + (gpio_input_slice == 0) ? 22'b0 : // No pad input (gpio_input_slice == 1) ? // Distributed - {2'b0, io_in[16], 4'b0, io_in[17], 4'b0, io_in[18], - 4'b0, io_in[19], 4'b0, io_in[20], 4'b0, io_in[21], 2'b0} : - (gpio_input_slice == 2) ? // Right shifted - {14'b0, io_in[16], io_in[17], io_in[18], io_in[19], - io_in[20], io_in[21]} : - (gpio_input_slice == 3) ? // Centered - {7'b0, io_in[16], io_in[17], io_in[18], io_in[19], - io_in[20], io_in[21], 7'b0} : - {io_in[16], io_in[17], io_in[18], io_in[19], io_in[20], - io_in[21], 4'b0}; // Left shifted + {io_in[14], 3'b0, io_in[15], 3'b0, io_in[16], 3'b0, + io_in[17], 3'b0, io_in[18], 3'b0, io_in[19], 3'b0, + io_in[20], 3'b0, io_in[21], 1'b0} : + (gpio_input_slice == 2) ? // Right shifted + {22'b0, io_in[14], io_in[15], io_in[16], io_in[17], + io_in[18], io_in[19], io_in[20], io_in[21]} : + (gpio_input_slice == 3) ? // Centered + {11'b0, io_in[14], io_in[15], io_in[16], io_in[17], + io_in[18], io_in[19], io_in[20], io_in[21], 11'b0} : + {io_in[14], io_in[15], io_in[16], io_in[17], io_in[18], + io_in[19], io_in[20], io_in[21], 22'b0}; // Left shifted - assign gpio_west = // I/O 22 to 31 - (gpio_input_slice == 0) ? 50'b0 : // No pad input + assign gpio_west = // I/O 22 to 29 + (gpio_input_slice == 0) ? 22'b0 : // No pad input (gpio_input_slice == 1) ? // Distributed - {2'b0, io_in[22], 4'b0, io_in[23], 4'b0, io_in[24], - 4'b0, io_in[25], 4'b0, io_in[26], 4'b0, io_in[27], - 4'b0, io_in[28], 4'b0, io_in[29], 4'b0, io_in[30], - 4'b0, io_in[31], 2'b0} : - (gpio_input_slice == 2) ? // Bottom shifted - {40'b0, io_in[22], io_in[23], io_in[24], io_in[25], - io_in[26], io_in[27], io_in[28], io_in[29], io_in[31], - io_in[31]} : - (gpio_input_slice == 3) ? // Centered - {20'b0, io_in[22], io_in[23], io_in[24], io_in[25], - io_in[26], io_in[27], io_in[28], io_in[29], io_in[31], - io_in[31], 20'b0} : + {io_in[22], 3'b0, io_in[23], 3'b0, io_in[24], 3'b0, + io_in[25], 3'b0, io_in[26], 3'b0, io_in[27], 3'b0, + io_in[28], 3'b0, io_in[29], 1'b0} : + (gpio_input_slice == 2) ? // Bottom shifted + {22'b0, io_in[22], io_in[23], io_in[24], io_in[25], + io_in[26], io_in[27], io_in[28], io_in[29]} : + (gpio_input_slice == 3) ? // Centered + {11'b0, io_in[22], io_in[23], io_in[24], io_in[25], + io_in[26], io_in[27], io_in[28], io_in[29], 11'b0} : {io_in[22], io_in[23], io_in[24], io_in[25], io_in[26], - io_in[27], io_in[28], io_in[29], io_in[31], io_in[31], - 40'b0}; // Top shifted + io_in[27], io_in[28], io_in[29], 22'b0}; // Top shifted - assign gpio_south = // I/O 32 to 37 - (gpio_input_slice == 0) ? 30'b0 : // No pad input + assign gpio_south = // I/O 30 to 37 + (gpio_input_slice == 0) ? 22'b0 : // No pad input (gpio_input_slice == 1) ? // Distributed - {2'b0, io_in[37], 4'b0, io_in[36], 4'b0, io_in[35], - 4'b0, io_in[34], 4'b0, io_in[33], 4'b0, io_in[32], 2'b0} : - (gpio_input_slice == 2) ? {14'b0, io_in[37:32]} : // Right shifted - (gpio_input_slice == 3) ? {7'b0, io_in[37:32], 7'b0} : // Centered - {io_in[37:32], 14'b0}; // Left shifted + {io_in[37], 3'b0, io_in[36], 3'b0, io_in[35], 3'b0, + io_in[34], 3'b0, io_in[33], 3'b0, io_in[32], 3'b0, + io_in[31], 3'b0, io_in[30], 1'b0} : + (gpio_input_slice == 2) ? {22'b0, io_in[37:30]} : // Right shifted + (gpio_input_slice == 3) ? {11'b0, io_in[37:30], 11'b0} : // Centered + {io_in[37:30], 22'b0}; // Left shifted // East side assign io_out[6] = - (gpio_output_slice == 0) ? data_out_east[2] : // Distributed - (gpio_output_slice == 1) ? data_out_east[20] : // Center - (gpio_output_slice == 2) ? data_out_east[40] : // Top + (gpio_output_slice == 0) ? data_out_east[0] : // Distributed + (gpio_output_slice == 1) ? data_out_east[11] : // Center + (gpio_output_slice == 2) ? data_out_east[22] : // Top data_out_east[0]; // Bottom assign io_out[7] = - (gpio_output_slice == 0) ? data_out_east[7] : // Distributed - (gpio_output_slice == 1) ? data_out_east[21] : // Center - (gpio_output_slice == 2) ? data_out_east[41] : // Top + (gpio_output_slice == 0) ? data_out_east[4] : // Distributed + (gpio_output_slice == 1) ? data_out_east[12] : // Center + (gpio_output_slice == 2) ? data_out_east[23] : // Top data_out_east[1]; // Bottom assign io_out[8] = - (gpio_output_slice == 0) ? data_out_east[12] : // Distributed - (gpio_output_slice == 1) ? data_out_east[22] : // Center - (gpio_output_slice == 2) ? data_out_east[42] : // Top + (gpio_output_slice == 0) ? data_out_east[8] : // Distributed + (gpio_output_slice == 1) ? data_out_east[13] : // Center + (gpio_output_slice == 2) ? data_out_east[24] : // Top data_out_east[2]; // Bottom assign io_out[9] = - (gpio_output_slice == 0) ? data_out_east[17] : // Distributed - (gpio_output_slice == 1) ? data_out_east[23] : // Center - (gpio_output_slice == 2) ? data_out_east[43] : // Top + (gpio_output_slice == 0) ? data_out_east[12] : // Distributed + (gpio_output_slice == 1) ? data_out_east[14] : // Center + (gpio_output_slice == 2) ? data_out_east[25] : // Top data_out_east[3]; // Bottom assign io_out[10] = - (gpio_output_slice == 0) ? data_out_east[22] : // Distributed - (gpio_output_slice == 1) ? data_out_east[24] : // Center - (gpio_output_slice == 2) ? data_out_east[44] : // Top + (gpio_output_slice == 0) ? data_out_east[16] : // Distributed + (gpio_output_slice == 1) ? data_out_east[15] : // Center + (gpio_output_slice == 2) ? data_out_east[26] : // Top data_out_east[4]; // Bottom assign io_out[11] = - (gpio_output_slice == 0) ? data_out_east[27] : // Distributed - (gpio_output_slice == 1) ? data_out_east[25] : // Center - (gpio_output_slice == 2) ? data_out_east[45] : // Top + (gpio_output_slice == 0) ? data_out_east[20] : // Distributed + (gpio_output_slice == 1) ? data_out_east[16] : // Center + (gpio_output_slice == 2) ? data_out_east[27] : // Top data_out_east[5]; // Bottom assign io_out[12] = - (gpio_output_slice == 0) ? data_out_east[32] : // Distributed - (gpio_output_slice == 1) ? data_out_east[26] : // Center - (gpio_output_slice == 2) ? data_out_east[46] : // Top + (gpio_output_slice == 0) ? data_out_east[24] : // Distributed + (gpio_output_slice == 1) ? data_out_east[17] : // Center + (gpio_output_slice == 2) ? data_out_east[28] : // Top data_out_east[6]; // Bottom assign io_out[13] = - (gpio_output_slice == 0) ? data_out_east[37] : // Distributed - (gpio_output_slice == 1) ? data_out_east[27] : // Center - (gpio_output_slice == 2) ? data_out_east[47] : // Top + (gpio_output_slice == 0) ? data_out_east[28] : // Distributed + (gpio_output_slice == 1) ? data_out_east[18] : // Center + (gpio_output_slice == 2) ? data_out_east[29] : // Top data_out_east[7]; // Bottom - assign io_out[14] = - (gpio_output_slice == 0) ? data_out_east[42] : // Distributed - (gpio_output_slice == 1) ? data_out_east[28] : // Center - (gpio_output_slice == 2) ? data_out_east[48] : // Top - data_out_east[8]; // Bottom - assign io_out[15] = - (gpio_output_slice == 0) ? data_out_east[47] : // Distributed - (gpio_output_slice == 1) ? data_out_east[29] : // Center - (gpio_output_slice == 2) ? data_out_east[49] : // Top - data_out_east[9]; // Bottom // North side + assign io_out[14] = + (gpio_output_slice == 0) ? data_out_north[28] : // Distributed + (gpio_output_slice == 1) ? data_out_north[18] : // Center + (gpio_output_slice == 2) ? data_out_north[29] : // Top + data_out_north[7]; // Bottom + assign io_out[15] = + (gpio_output_slice == 0) ? data_out_north[24] : // Distributed + (gpio_output_slice == 1) ? data_out_north[17] : // Center + (gpio_output_slice == 2) ? data_out_north[28] : // Top + data_out_north[6]; // Bottom assign io_out[16] = - (gpio_output_slice == 0) ? data_out_north[27] : // Distributed + (gpio_output_slice == 0) ? data_out_north[20] : // Distributed (gpio_output_slice == 1) ? data_out_north[16] : // Center - (gpio_output_slice == 2) ? data_out_north[29] : // Right + (gpio_output_slice == 2) ? data_out_north[27] : // Right data_out_north[5]; // Left assign io_out[17] = - (gpio_output_slice == 0) ? data_out_north[22] : // Distributed + (gpio_output_slice == 0) ? data_out_north[16] : // Distributed (gpio_output_slice == 1) ? data_out_north[15] : // Center - (gpio_output_slice == 2) ? data_out_north[28] : // Right + (gpio_output_slice == 2) ? data_out_north[26] : // Right data_out_north[4]; // Left assign io_out[18] = - (gpio_output_slice == 0) ? data_out_north[17] : // Distributed + (gpio_output_slice == 0) ? data_out_north[12] : // Distributed (gpio_output_slice == 1) ? data_out_north[14] : // Center - (gpio_output_slice == 2) ? data_out_north[27] : // Right + (gpio_output_slice == 2) ? data_out_north[25] : // Right data_out_north[3]; // Left assign io_out[19] = - (gpio_output_slice == 0) ? data_out_north[12] : // Distributed + (gpio_output_slice == 0) ? data_out_north[8] : // Distributed (gpio_output_slice == 1) ? data_out_north[13] : // Center - (gpio_output_slice == 2) ? data_out_north[26] : // Right + (gpio_output_slice == 2) ? data_out_north[24] : // Right data_out_north[2]; // Left assign io_out[20] = - (gpio_output_slice == 0) ? data_out_north[7] : // Distributed + (gpio_output_slice == 0) ? data_out_north[4] : // Distributed (gpio_output_slice == 1) ? data_out_north[12] : // Center - (gpio_output_slice == 2) ? data_out_north[25] : // Right + (gpio_output_slice == 2) ? data_out_north[23] : // Right data_out_north[1]; // Left assign io_out[21] = - (gpio_output_slice == 0) ? data_out_north[2] : // Distributed + (gpio_output_slice == 0) ? data_out_north[0] : // Distributed (gpio_output_slice == 1) ? data_out_north[11] : // Center - (gpio_output_slice == 2) ? data_out_north[24] : // Right + (gpio_output_slice == 2) ? data_out_north[22] : // Right data_out_north[0]; // Left // West side assign io_out[22] = - (gpio_output_slice == 0) ? data_out_west[47] : // Distributed - (gpio_output_slice == 1) ? data_out_west[29] : // Center - (gpio_output_slice == 2) ? data_out_west[49] : // Top - data_out_east[9]; // Bottom + (gpio_output_slice == 0) ? data_out_west[28] : // Distributed + (gpio_output_slice == 1) ? data_out_west[18] : // Center + (gpio_output_slice == 2) ? data_out_west[29] : // Top + data_out_west[7]; // Bottom assign io_out[23] = - (gpio_output_slice == 0) ? data_out_west[42] : // Distributed - (gpio_output_slice == 1) ? data_out_west[28] : // Center - (gpio_output_slice == 2) ? data_out_west[48] : // Top - data_out_east[8]; // Bottom + (gpio_output_slice == 0) ? data_out_west[24] : // Distributed + (gpio_output_slice == 1) ? data_out_west[17] : // Center + (gpio_output_slice == 2) ? data_out_west[28] : // Top + data_out_west[6]; // Bottom assign io_out[24] = - (gpio_output_slice == 0) ? data_out_west[37] : // Distributed - (gpio_output_slice == 1) ? data_out_west[27] : // Center - (gpio_output_slice == 2) ? data_out_west[47] : // Top - data_out_east[7]; // Bottom + (gpio_output_slice == 0) ? data_out_west[20] : // Distributed + (gpio_output_slice == 1) ? data_out_west[16] : // Center + (gpio_output_slice == 2) ? data_out_west[27] : // Top + data_out_west[5]; // Bottom assign io_out[25] = - (gpio_output_slice == 0) ? data_out_west[32] : // Distributed - (gpio_output_slice == 1) ? data_out_west[26] : // Center - (gpio_output_slice == 2) ? data_out_west[46] : // Top - data_out_east[6]; // Bottom + (gpio_output_slice == 0) ? data_out_west[16] : // Distributed + (gpio_output_slice == 1) ? data_out_west[15] : // Center + (gpio_output_slice == 2) ? data_out_west[26] : // Top + data_out_west[4]; // Bottom assign io_out[26] = - (gpio_output_slice == 0) ? data_out_west[27] : // Distributed - (gpio_output_slice == 1) ? data_out_west[25] : // Center - (gpio_output_slice == 2) ? data_out_west[45] : // Top - data_out_east[5]; // Bottom - assign io_out[27] = - (gpio_output_slice == 0) ? data_out_west[22] : // Distributed - (gpio_output_slice == 1) ? data_out_west[24] : // Center - (gpio_output_slice == 2) ? data_out_west[44] : // Top - data_out_east[4]; // Bottom - assign io_out[28] = - (gpio_output_slice == 0) ? data_out_west[17] : // Distributed - (gpio_output_slice == 1) ? data_out_west[23] : // Center - (gpio_output_slice == 2) ? data_out_west[43] : // Top - data_out_east[3]; // Bottom - assign io_out[29] = (gpio_output_slice == 0) ? data_out_west[12] : // Distributed - (gpio_output_slice == 1) ? data_out_west[22] : // Center - (gpio_output_slice == 2) ? data_out_west[42] : // Top - data_out_east[2]; // Bottom - assign io_out[30] = - (gpio_output_slice == 0) ? data_out_west[7] : // Distributed - (gpio_output_slice == 1) ? data_out_west[21] : // Center - (gpio_output_slice == 2) ? data_out_west[41] : // Top - data_out_east[1]; // Bottom - assign io_out[31] = - (gpio_output_slice == 0) ? data_out_west[2] : // Distributed - (gpio_output_slice == 1) ? data_out_west[20] : // Center - (gpio_output_slice == 2) ? data_out_west[40] : // Top - data_out_east[0]; // Bottom + (gpio_output_slice == 1) ? data_out_west[14] : // Center + (gpio_output_slice == 2) ? data_out_west[25] : // Top + data_out_west[3]; // Bottom + assign io_out[27] = + (gpio_output_slice == 0) ? data_out_west[8] : // Distributed + (gpio_output_slice == 1) ? data_out_west[13] : // Center + (gpio_output_slice == 2) ? data_out_west[24] : // Top + data_out_west[2]; // Bottom + assign io_out[28] = + (gpio_output_slice == 0) ? data_out_west[4] : // Distributed + (gpio_output_slice == 1) ? data_out_west[12] : // Center + (gpio_output_slice == 2) ? data_out_west[23] : // Top + data_out_west[1]; // Bottom + assign io_out[29] = + (gpio_output_slice == 0) ? data_out_west[0] : // Distributed + (gpio_output_slice == 1) ? data_out_west[11] : // Center + (gpio_output_slice == 2) ? data_out_west[22] : // Top + data_out_west[0]; // Bottom // South side - assign io_out[32] = - (gpio_output_slice == 0) ? data_out_south[2] : // Distributed + assign io_out[30] = + (gpio_output_slice == 0) ? data_out_south[0] : // Distributed (gpio_output_slice == 1) ? data_out_south[11] : // Center - (gpio_output_slice == 2) ? data_out_south[24] : // Right - data_out_north[0]; // Left - assign io_out[33] = - (gpio_output_slice == 0) ? data_out_south[7] : // Distributed + (gpio_output_slice == 2) ? data_out_south[22] : // Top + data_out_south[0]; // Bottom + assign io_out[31] = + (gpio_output_slice == 0) ? data_out_south[4] : // Distributed (gpio_output_slice == 1) ? data_out_south[12] : // Center - (gpio_output_slice == 2) ? data_out_south[25] : // Right - data_out_north[1]; // Left - assign io_out[34] = - (gpio_output_slice == 0) ? data_out_south[12] : // Distributed + (gpio_output_slice == 2) ? data_out_south[23] : // Top + data_out_south[1]; // Bottom + assign io_out[32] = + (gpio_output_slice == 0) ? data_out_south[8] : // Distributed (gpio_output_slice == 1) ? data_out_south[13] : // Center - (gpio_output_slice == 2) ? data_out_south[26] : // Right - data_out_north[2]; // Left - assign io_out[35] = - (gpio_output_slice == 0) ? data_out_south[17] : // Distributed + (gpio_output_slice == 2) ? data_out_south[24] : // Right + data_out_south[2]; // Left + assign io_out[33] = + (gpio_output_slice == 0) ? data_out_south[12] : // Distributed (gpio_output_slice == 1) ? data_out_south[14] : // Center - (gpio_output_slice == 2) ? data_out_south[27] : // Right - data_out_north[3]; // Left - assign io_out[36] = - (gpio_output_slice == 0) ? data_out_south[22] : // Distributed + (gpio_output_slice == 2) ? data_out_south[25] : // Right + data_out_south[3]; // Left + assign io_out[34] = + (gpio_output_slice == 0) ? data_out_south[16] : // Distributed (gpio_output_slice == 1) ? data_out_south[15] : // Center - (gpio_output_slice == 2) ? data_out_south[28] : // Right - data_out_north[4]; // Left - assign io_out[37] = - (gpio_output_slice == 0) ? data_out_south[27] : // Distributed + (gpio_output_slice == 2) ? data_out_south[26] : // Right + data_out_south[4]; // Left + assign io_out[35] = + (gpio_output_slice == 0) ? data_out_south[20] : // Distributed (gpio_output_slice == 1) ? data_out_south[16] : // Center + (gpio_output_slice == 2) ? data_out_south[27] : // Right + data_out_south[5]; // Left + assign io_out[36] = + (gpio_output_slice == 0) ? data_out_south[24] : // Distributed + (gpio_output_slice == 1) ? data_out_south[17] : // Center + (gpio_output_slice == 2) ? data_out_south[28] : // Right + data_out_south[6]; // Left + assign io_out[37] = + (gpio_output_slice == 0) ? data_out_south[28] : // Distributed + (gpio_output_slice == 1) ? data_out_south[18] : // Center (gpio_output_slice == 2) ? data_out_south[29] : // Right - data_out_north[5]; // Left + data_out_south[7]; // Left // Map the output data from the sides to a single array that can be // broken up into 32 bit segments for data transfer. @@ -651,9 +651,7 @@ end else if (data_sel[2]) begin rdata_pre = data_out[95:64]; end else if (data_sel[3]) begin - rdata_pre = data_out[127:96]; - end else if (data_sel[4]) begin - rdata_pre = data_out[159:128]; + rdata_pre = {8'b0, data_out[119:96]}; end end @@ -756,12 +754,6 @@ if (iomem_we[0]) latched_in[103:96] <= wbs_dat_i[7:0]; if (iomem_we[1]) latched_in[111:104] <= wbs_dat_i[15:8]; if (iomem_we[2]) latched_in[119:112] <= wbs_dat_i[23:16]; - if (iomem_we[3]) latched_in[127:120] <= wbs_dat_i[31:24]; - end else if (data_sel[4]) begin - if (iomem_we[0]) latched_in[135:128] <= wbs_dat_i[7:0]; - if (iomem_we[1]) latched_in[143:136] <= wbs_dat_i[15:8]; - if (iomem_we[2]) latched_in[151:144] <= wbs_dat_i[23:16]; - if (iomem_we[3]) latched_in[159:152] <= wbs_dat_i[31:24]; end end else begin xfer_ctrl <= 0; // Immediately self-resetting
diff --git a/verilog/rtl/user_project_wrapper_30x50.v b/verilog/rtl/user_project_wrapper_30x50.v new file mode 100644 index 0000000..2b40284 --- /dev/null +++ b/verilog/rtl/user_project_wrapper_30x50.v
@@ -0,0 +1,1009 @@ +// SPDX-FileCopyrightText: 2020 Efabless Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// SPDX-License-Identifier: Apache-2.0 + +`default_nettype none +/* + *------------------------------------------------------------- + * + * chaos_automaton + * + * This chip is a pure asynchronous cellular automaton. Each cell has + * four inputs from N, S, E, W and generates four outputs to N, S, E, W. + * Each output can be configured for any boolean function of the four + * inputs (16 bits each). + * + * Outputs on the periphery (or some selection thereof) are passed to the + * chip GPIO. Inputs may also come from the chip periphery; choice of + * input or output is programmable like the cell boolean function. + * + * All periphery inputs and outputs may be channeled through the logic + * analyzer to apply input to or monitor output from the array. + * + * The wishbone bus may be used to program the cell functions. + * + * This can be used in a loop with an evolutionary algorithm to tune the + * chip functions to achieve a specific behavior. + * + * Most of the core circuitry is straightforward. The total number of + * cells is parameterized, so that the largest number of cells that will + * fit in the caravel user project space can be determined. + * + * Version v1: To avoid massive amounts of wiring (e.g., 16 or 32 + * data wires + 10 address wires to every single cell), all of the + * LUT configuration memory is stored in a (very long) serial chain + * in a full loop. The scan chain is 64 bits longer than the number + * of cells and allows 64 bits to be transferred to and from the + * wishbone bus independently of the cells. Every cell has 64 latches + * in addition to the 64 flops so that the scan chain can be cycled + * without affecting ongoing operation of the automaton. + * + * Version v2: The logic analyzer is replaced by a local version that + * has the same number of bits as periphery I/O. There are two registers + * per signal, one for output, and one for input. All registers update + * simultaneously. Every periphery input is connected to three sources, + * XOR'd together: A periphery output, a GPIO input, and a register. + * Every periphery output is connected to three sinks: A periphery + * input, a GPIO output, and a register. The periphery output-to-input + * connections can be a loop-back or neighbor loop-back. + * + * Memory mapped address space: + * + * BASE_ADR + 7 to BASE_ADR + 0: Configuration data to read or write + * BASE_ADR + 11 to BASE_ADR + 8: Core cell address for read/write + * BASE_ADR + 12: Triggers + * BASE_ADR + 17 to BASE_ADR + 16: Per-side input configuration + * BASE_ADR + 18: GPIO input and output slice selection + * BASE_ADR + 19: GPIO direction + * BASE_ADR + ?? to BASE_ADR + 20: Operational data + * (BASE_ADR + 39 for 50x30 array) + * + * Trigger bits: + * bit 0: Shift by (address) cells (64 bits). + * bit 1: Finish cycle. Return shift register to run state, toggle "hold" + * + * (to be done:) + * bit 2: Capture data + * bit 3: Apply data + * + * All trigger bits are self-resetting. The trigger bit (as read) remains + * high until the transfer has completed. The trigger bit can be polled to + * determine when the cycle has completed. + * + * The shift cycle bit can be used to load the configuration of the array + * cell by cell. The typical case is to set address = 1 and apply or read + * each cell's configuration in turn. However, it can also be used piecemeal, + * for example, to read out a block of configurations, without having + * to loop a full cycle for each one. The counter tracks what the + * current offset is, and can return to the run-state position on + * application of bit 1, "Finish cycle". At the end of "Finish cycle" + * the hold bit is toggled to latch and apply any new configuration + * data. + * + * Reading and writing a single cell's configuration can be accomplished + * by a sequence of shift cycles and reads/writes. To change the + * configuration of a single cell: (1) Write the cell address, (2) Apply + * the shift cycle, (3) Write the configuration data, (4) Apply the + * finish cycle. To read the configuration of a single cell: (1) Write + * the cell address, (2) Apply the shift cycle, (3) Read the configuration + * data, (4) Apply the finish cycle. + * + * + * This version uses the chaos_subarray, which is intended to be + * prehardened as a macro and tiled in the top level. + *------------------------------------------------------------- + */ + +// NOTE: Uncomment the following lines for syntax checking +// `define MPRJ_IO_PADS 38 +// `include "chaos_subarray.v" + +/* + *----------------------------------------------------------------- + * User project top level + *----------------------------------------------------------------- + */ + +module user_project_wrapper #( + parameter XSIZE = 30, // Total number of cells left to right + parameter YSIZE = 50, // Total number of cells top to bottom + parameter XTOP = 3, // Number of sub-arrays left to right + parameter YTOP = 5, // Number of sub-arrays top to bottom + parameter ASIZE = 11, // Enough bits to count XSIZE * YSIZE + parameter BASE_ADR = 32'h 3000_0000 // Wishbone base address +)( +`ifdef USE_POWER_PINS + inout vdda1, // User area 1 3.3V supply + inout vdda2, // User area 2 3.3V supply + inout vssa1, // User area 1 analog ground + inout vssa2, // User area 2 analog ground + inout vccd1, // User area 1 1.8V supply + inout vccd2, // User area 2 1.8v supply + inout vssd1, // User area 1 digital ground + inout vssd2, // User area 2 digital ground +`endif + + // Wishbone Slave ports (WB MI A) + input wb_clk_i, + input wb_rst_i, + input wbs_stb_i, + input wbs_cyc_i, + input wbs_we_i, + input [3:0] wbs_sel_i, + input [31:0] wbs_dat_i, + input [31:0] wbs_adr_i, + output wbs_ack_o, + output [31:0] wbs_dat_o, + + // Logic Analyzer Signals (unused) + input [127:0] la_data_in, + output [127:0] la_data_out, + input [127:0] la_oenb, + + // IOs + input [`MPRJ_IO_PADS-1:0] io_in, + output [`MPRJ_IO_PADS-1:0] io_out, + output [`MPRJ_IO_PADS-1:0] io_oeb, + + // Analog (direct connection to GPIO pad---use with caution) + // Note that analog I/O is not available on the 7 lowest-numbered + // GPIO pads, and so the analog_io indexing is offset from the + // GPIO indexing by 7 (also upper 2 GPIOs do not have analog_io). + inout [`MPRJ_IO_PADS-10:0] analog_io, + + // Independent clock + input user_clock2, + + // IRQ + output [2:0] user_irq +); + +`define IDLE 3'b000 +`define START 3'b001 +`define FINISH 3'b010 +`define XDATAS 3'b011 +`define XDATAF 3'b100 +`define LOAD 3'b101 + +`define CONFIGL 8'h00 /* Address offset of configuration data low word */ +`define CONFIGH 8'h01 /* Address offset of configuration data high word */ +`define ADDRESS 8'h02 /* Address offset of cell address value */ +`define XFER 8'h03 /* Address offset of transfer bits */ +`define DIRECT 8'h04 /* Address offset of GPIO directions */ +`define SOURCE 8'h05 /* Address offset of GPIO source selection */ +`define DATATOP 8'h06 /* Address offset of start of data section */ + +`define MAXADDR (XSIZE * YSIZE) /* Highest cell address plus one */ + + reg clk; /* serial clock to transfer data */ + reg hold; /* trigger to hold transferred data */ + reg [2:0] xfer_state; /* state of the data transfer */ + reg [1:0] xfer_ctrl; /* Configuration transfer trigger bits */ + reg [63:0] config_data; /* 64 bits to read or write configuration */ + reg local_reset; /* Reset applied from a register */ + + reg [ASIZE - 1:0] cell_addr; /* Core cell to address */ + reg [ASIZE - 1:0] cell_offset; /* Current offset of shift register */ + reg [ASIZE + 6:0] bit_count; /* Full count (cell address + bits) */ + + wire [`MPRJ_IO_PADS-1:0] io_in; + wire [`MPRJ_IO_PADS-1:0] io_out; + wire [`MPRJ_IO_PADS-1:0] io_oeb; + + wire [1:0] config_sel; + wire address_sel; + wire xfer_sel; + wire direct_sel; + wire source_sel; + + // NOTE: This should be parameterized. + // For the 50x30 array, there are 50+50+30+30 = 160 periphery bits = + // 5 words of 32 bits. This is hard-coded for convenience. If the + // array size changes, this needs to be changed as well. Needs to be + // converted to a "generate" block. + wire [4:0] data_sel; + + wire valid; + reg ready; + wire [3:0] iomem_we; + wire selected; + wire [1:0] busy; + reg [31:0] rdata_pre; + wire [63:0] rdata; + reg [31:0] wbs_dat_o; + reg [63:0] wdata; + reg write; + wire all_cell_reset; + + // Direction for each GPIO (32 used) + reg [31:0] gpio_oeb; + + // Data to and from array periphery I/O + wire [YSIZE-1: 0] data_in_east; + wire [YSIZE-1: 0] data_in_west; + wire [XSIZE-1: 0] data_in_north; + wire [XSIZE-1: 0] data_in_south; + + wire [YSIZE-1: 0] data_out_east; + wire [YSIZE-1: 0] data_out_west; + wire [XSIZE-1: 0] data_out_north; + wire [XSIZE-1: 0] data_out_south; + + // Latched output for wishbone read-back (to be done) + // TBD + + // Latched input from wishbone (to do: Make shadow register) + wire [YSIZE-1: 0] latched_in_east; + wire [YSIZE-1: 0] latched_in_west; + wire [XSIZE-1: 0] latched_in_north; + wire [XSIZE-1: 0] latched_in_south; + + // Shadow registers for wishbone input (to be done) + // TBD + + // Register array mapping latched data to 32-bit sections for data + // transfer through the wishbone + reg [XSIZE*2 + YSIZE*2 - 1:0] latched_in; + + // Wire array mapping output data to 32-bit sections for data + // transfer through the wishbone + wire [XSIZE*2 + YSIZE*2 - 1:0] data_out; + + // Periphery output-to-input loop-back selection + reg [2:0] north_loopback; + reg [2:0] east_loopback; + reg [2:0] south_loopback; + reg [2:0] west_loopback; + +// Loopback value definitions + +`define INPUT_LOW 3'b000 +`define INPUT_HIGH 3'b001 +`define LOOPBACK 3'b010 +`define NEIGHBOR_LEFT 3'b011 +`define NEIGHBOR_RIGHT 3'b100 + + // GPIO slicing (because there are many fewer GPIO than array outputs) + // GPIOs can be clustered on either end or in the center of the array + // side, or distributed along the side (1 GPIO per 5 array cells) + reg [1:0] gpio_output_slice; + reg [2:0] gpio_input_slice; + + // Registered GPIO directions go directly to io_oeb[37:6]. Leave the + // lower 6 GPIO to the management processor. + assign io_oeb = {gpio_oeb, 6'b1}; + + // Wishbone address select indicators + assign config_sel[0] = (wbs_adr_i[7:2] == `CONFIGL); + assign config_sel[1] = (wbs_adr_i[7:2] == `CONFIGH); + assign address_sel = (wbs_adr_i[7:2] == `ADDRESS); + assign xfer_sel = (wbs_adr_i[7:2] == `XFER); + assign direct_sel = (wbs_adr_i[7:2] == `DIRECT); + assign source_sel = (wbs_adr_i[7:2] == `SOURCE); + + // Hard-coded to 5 words; see note above + assign data_sel[0] = (wbs_adr_i[7:2] == (`DATATOP + 0)); + assign data_sel[1] = (wbs_adr_i[7:2] == (`DATATOP + 1)); + assign data_sel[2] = (wbs_adr_i[7:2] == (`DATATOP + 2)); + assign data_sel[3] = (wbs_adr_i[7:2] == (`DATATOP + 3)); + assign data_sel[4] = (wbs_adr_i[7:2] == (`DATATOP + 4)); + + assign valid = wbs_cyc_i && wbs_stb_i; + assign wbs_ack_o = ready; + assign iomem_we = wbs_sel_i & {4{wbs_we_i}}; + + assign all_cell_reset = wb_rst_i | local_reset; + + // IRQ + assign user_irq = 3'b000; // Unused + + // Instantiate the chaos cell array + + chaos_array #( + .XSIZE(XSIZE), + .YSIZE(YSIZE), + .XTOP(XTOP), + .YTOP(YTOP), + .BASE_ADR(BASE_ADR) + ) chaos_array_inst ( + `ifdef USE_POWER_PINS + .vccd1(vccd1), + .vssd1(vssd1), + `endif + .clk(clk), + .reset(all_cell_reset), + .hold(hold), + .rdata(rdata), + .wdata(wdata), + .write(write), + .data_in_east(data_in_east), + .data_in_west(data_in_west), + .data_in_north(data_in_north), + .data_in_south(data_in_south), + .data_out_east(data_out_east), + .data_out_west(data_out_west), + .data_out_north(data_out_north), + .data_out_south(data_out_south) + ); + + // Wire definitions mapping the GPIO to the array periphery + wire [YSIZE-1:0] gpio_east, gpio_west; + wire [XSIZE-1:0] gpio_north, gpio_south; + + // Wire definitions mapping the array periphery loop-back connections + wire [YSIZE-1:0] data_muxed_east, data_muxed_west; + wire [XSIZE-1:0] data_muxed_north, data_muxed_south; + + // Hook up array inputs (data_in_*) to an XOR'd combination of + // (1) array outputs (data_out_*, muxed into data_muxed_*), + // (2) the GPIO pads (muxed into gpio_*), and + // (3) data from the wishbone bus (latched_in_*). + + assign data_in_west = latched_in_west ^ gpio_west ^ data_muxed_west; + assign data_in_east = latched_in_east ^ gpio_east ^ data_muxed_east; + assign data_in_south = latched_in_south ^ gpio_south ^ data_muxed_south; + assign data_in_north = latched_in_north ^ gpio_north ^ data_muxed_north; + +`define INPUT_LOW 3'b000 +`define INPUT_HIGH 3'b001 +`define LOOPBACK 3'b010 +`define NEIGHBOR_LEFT 3'b011 +`define NEIGHBOR_RIGHT 3'b100 + + // Define loop-back inputs + assign data_muxed_west = + (west_loopback == `NEIGHBOR_LEFT) ? {data_out_west[YSIZE-2:0], 1'b0} : + (west_loopback == `NEIGHBOR_RIGHT) ? {1'b0, data_out_west[YSIZE-1:1]} : + (west_loopback == `LOOPBACK) ? data_out_west : + (west_loopback == `INPUT_HIGH) ? 'b1 : 'b0; + + assign data_muxed_east = + (east_loopback == `NEIGHBOR_LEFT) ? {data_out_east[YSIZE-2:0], 1'b0} : + (east_loopback == `NEIGHBOR_RIGHT) ? {1'b0, data_out_east[YSIZE-1:1]} : + (east_loopback == `LOOPBACK) ? data_out_east : + (east_loopback == `INPUT_HIGH) ? 'b1 : 'b0; + + assign data_muxed_south = + (south_loopback == `NEIGHBOR_LEFT) ? {data_out_south[XSIZE-2:0], 1'b0} : + (south_loopback == `NEIGHBOR_RIGHT) ? {1'b0, data_out_south[XSIZE-1:1]} : + (south_loopback == `LOOPBACK) ? data_out_south : + (south_loopback == `INPUT_HIGH) ? 'b1 : 'b0; + + assign data_muxed_north = + (north_loopback == `NEIGHBOR_LEFT) ? {data_out_north[XSIZE-2:0], 1'b0} : + (north_loopback == `NEIGHBOR_RIGHT) ? {1'b0, data_out_north[XSIZE-1:1]} : + (north_loopback == `LOOPBACK) ? data_out_north : + (south_loopback == `INPUT_HIGH) ? 'b1 : 'b0; + + // Define I/O input slices + // NOTE: This is hard-coded. There are 38 GPIOs. Assigning 32 of them + // (GPIO 37 to 6) to array inputs and outputs. These are arranged as + // 10 on the sides and 6 on the top and bottom. These are further sub- + // divided into 5 inputs and 5 outputs on the sides, and 3 inputs and + // 3 outputs on top and bottom. Depending on the selection, these + // can be injected into various places around the array. + + // Another note: It probably makes more sense to define vectors for + // io_in_east, io_in_north, etc., and align them in the direction of + // the arrays (high to low index is top to bottom, or right to left). + + assign gpio_east = // I/O 15 to 6 + (gpio_input_slice == 0) ? 50'b0 : // No pad input + (gpio_input_slice == 1) ? // Distributed + {2'b0, io_in[15], 4'b0, io_in[14], 4'b0, io_in[13], + 4'b0, io_in[12], 4'b0, io_in[11], 4'b0, io_in[10], + 4'b0, io_in[9], 4'b0, io_in[8], 4'b0, io_in[7], + 4'b0, io_in[6], 2'b0} : + (gpio_input_slice == 2) ? {40'b0, io_in[15:6]} : // Bottom shifted + (gpio_input_slice == 3) ? {20'b0, io_in[15:6], 20'b0} : // Centered + {io_in[15:6], 40'b0}; // Top shifted + + assign gpio_north = // I/O 21 to 16 + (gpio_input_slice == 0) ? 30'b0 : // No pad input + (gpio_input_slice == 1) ? // Distributed + {2'b0, io_in[16], 4'b0, io_in[17], 4'b0, io_in[18], + 4'b0, io_in[19], 4'b0, io_in[20], 4'b0, io_in[21], 2'b0} : + (gpio_input_slice == 2) ? // Right shifted + {14'b0, io_in[16], io_in[17], io_in[18], io_in[19], + io_in[20], io_in[21]} : + (gpio_input_slice == 3) ? // Centered + {7'b0, io_in[16], io_in[17], io_in[18], io_in[19], + io_in[20], io_in[21], 7'b0} : + {io_in[16], io_in[17], io_in[18], io_in[19], io_in[20], + io_in[21], 4'b0}; // Left shifted + + assign gpio_west = // I/O 22 to 31 + (gpio_input_slice == 0) ? 50'b0 : // No pad input + (gpio_input_slice == 1) ? // Distributed + {2'b0, io_in[22], 4'b0, io_in[23], 4'b0, io_in[24], + 4'b0, io_in[25], 4'b0, io_in[26], 4'b0, io_in[27], + 4'b0, io_in[28], 4'b0, io_in[29], 4'b0, io_in[30], + 4'b0, io_in[31], 2'b0} : + (gpio_input_slice == 2) ? // Bottom shifted + {40'b0, io_in[22], io_in[23], io_in[24], io_in[25], + io_in[26], io_in[27], io_in[28], io_in[29], io_in[31], + io_in[31]} : + (gpio_input_slice == 3) ? // Centered + {20'b0, io_in[22], io_in[23], io_in[24], io_in[25], + io_in[26], io_in[27], io_in[28], io_in[29], io_in[31], + io_in[31], 20'b0} : + {io_in[22], io_in[23], io_in[24], io_in[25], io_in[26], + io_in[27], io_in[28], io_in[29], io_in[31], io_in[31], + 40'b0}; // Top shifted + + assign gpio_south = // I/O 32 to 37 + (gpio_input_slice == 0) ? 30'b0 : // No pad input + (gpio_input_slice == 1) ? // Distributed + {2'b0, io_in[37], 4'b0, io_in[36], 4'b0, io_in[35], + 4'b0, io_in[34], 4'b0, io_in[33], 4'b0, io_in[32], 2'b0} : + (gpio_input_slice == 2) ? {14'b0, io_in[37:32]} : // Right shifted + (gpio_input_slice == 3) ? {7'b0, io_in[37:32], 7'b0} : // Centered + {io_in[37:32], 14'b0}; // Left shifted + + // East side + assign io_out[6] = + (gpio_output_slice == 0) ? data_out_east[2] : // Distributed + (gpio_output_slice == 1) ? data_out_east[20] : // Center + (gpio_output_slice == 2) ? data_out_east[40] : // Top + data_out_east[0]; // Bottom + assign io_out[7] = + (gpio_output_slice == 0) ? data_out_east[7] : // Distributed + (gpio_output_slice == 1) ? data_out_east[21] : // Center + (gpio_output_slice == 2) ? data_out_east[41] : // Top + data_out_east[1]; // Bottom + assign io_out[8] = + (gpio_output_slice == 0) ? data_out_east[12] : // Distributed + (gpio_output_slice == 1) ? data_out_east[22] : // Center + (gpio_output_slice == 2) ? data_out_east[42] : // Top + data_out_east[2]; // Bottom + assign io_out[9] = + (gpio_output_slice == 0) ? data_out_east[17] : // Distributed + (gpio_output_slice == 1) ? data_out_east[23] : // Center + (gpio_output_slice == 2) ? data_out_east[43] : // Top + data_out_east[3]; // Bottom + assign io_out[10] = + (gpio_output_slice == 0) ? data_out_east[22] : // Distributed + (gpio_output_slice == 1) ? data_out_east[24] : // Center + (gpio_output_slice == 2) ? data_out_east[44] : // Top + data_out_east[4]; // Bottom + assign io_out[11] = + (gpio_output_slice == 0) ? data_out_east[27] : // Distributed + (gpio_output_slice == 1) ? data_out_east[25] : // Center + (gpio_output_slice == 2) ? data_out_east[45] : // Top + data_out_east[5]; // Bottom + assign io_out[12] = + (gpio_output_slice == 0) ? data_out_east[32] : // Distributed + (gpio_output_slice == 1) ? data_out_east[26] : // Center + (gpio_output_slice == 2) ? data_out_east[46] : // Top + data_out_east[6]; // Bottom + assign io_out[13] = + (gpio_output_slice == 0) ? data_out_east[37] : // Distributed + (gpio_output_slice == 1) ? data_out_east[27] : // Center + (gpio_output_slice == 2) ? data_out_east[47] : // Top + data_out_east[7]; // Bottom + assign io_out[14] = + (gpio_output_slice == 0) ? data_out_east[42] : // Distributed + (gpio_output_slice == 1) ? data_out_east[28] : // Center + (gpio_output_slice == 2) ? data_out_east[48] : // Top + data_out_east[8]; // Bottom + assign io_out[15] = + (gpio_output_slice == 0) ? data_out_east[47] : // Distributed + (gpio_output_slice == 1) ? data_out_east[29] : // Center + (gpio_output_slice == 2) ? data_out_east[49] : // Top + data_out_east[9]; // Bottom + + // North side + assign io_out[16] = + (gpio_output_slice == 0) ? data_out_north[27] : // Distributed + (gpio_output_slice == 1) ? data_out_north[16] : // Center + (gpio_output_slice == 2) ? data_out_north[29] : // Right + data_out_north[5]; // Left + assign io_out[17] = + (gpio_output_slice == 0) ? data_out_north[22] : // Distributed + (gpio_output_slice == 1) ? data_out_north[15] : // Center + (gpio_output_slice == 2) ? data_out_north[28] : // Right + data_out_north[4]; // Left + assign io_out[18] = + (gpio_output_slice == 0) ? data_out_north[17] : // Distributed + (gpio_output_slice == 1) ? data_out_north[14] : // Center + (gpio_output_slice == 2) ? data_out_north[27] : // Right + data_out_north[3]; // Left + assign io_out[19] = + (gpio_output_slice == 0) ? data_out_north[12] : // Distributed + (gpio_output_slice == 1) ? data_out_north[13] : // Center + (gpio_output_slice == 2) ? data_out_north[26] : // Right + data_out_north[2]; // Left + assign io_out[20] = + (gpio_output_slice == 0) ? data_out_north[7] : // Distributed + (gpio_output_slice == 1) ? data_out_north[12] : // Center + (gpio_output_slice == 2) ? data_out_north[25] : // Right + data_out_north[1]; // Left + assign io_out[21] = + (gpio_output_slice == 0) ? data_out_north[2] : // Distributed + (gpio_output_slice == 1) ? data_out_north[11] : // Center + (gpio_output_slice == 2) ? data_out_north[24] : // Right + data_out_north[0]; // Left + + // West side + assign io_out[22] = + (gpio_output_slice == 0) ? data_out_west[47] : // Distributed + (gpio_output_slice == 1) ? data_out_west[29] : // Center + (gpio_output_slice == 2) ? data_out_west[49] : // Top + data_out_west[9]; // Bottom + assign io_out[23] = + (gpio_output_slice == 0) ? data_out_west[42] : // Distributed + (gpio_output_slice == 1) ? data_out_west[28] : // Center + (gpio_output_slice == 2) ? data_out_west[48] : // Top + data_out_west[8]; // Bottom + assign io_out[24] = + (gpio_output_slice == 0) ? data_out_west[37] : // Distributed + (gpio_output_slice == 1) ? data_out_west[27] : // Center + (gpio_output_slice == 2) ? data_out_west[47] : // Top + data_out_west[7]; // Bottom + assign io_out[25] = + (gpio_output_slice == 0) ? data_out_west[32] : // Distributed + (gpio_output_slice == 1) ? data_out_west[26] : // Center + (gpio_output_slice == 2) ? data_out_west[46] : // Top + data_out_west[6]; // Bottom + assign io_out[26] = + (gpio_output_slice == 0) ? data_out_west[27] : // Distributed + (gpio_output_slice == 1) ? data_out_west[25] : // Center + (gpio_output_slice == 2) ? data_out_west[45] : // Top + data_out_west[5]; // Bottom + assign io_out[27] = + (gpio_output_slice == 0) ? data_out_west[22] : // Distributed + (gpio_output_slice == 1) ? data_out_west[24] : // Center + (gpio_output_slice == 2) ? data_out_west[44] : // Top + data_out_west[4]; // Bottom + assign io_out[28] = + (gpio_output_slice == 0) ? data_out_west[17] : // Distributed + (gpio_output_slice == 1) ? data_out_west[23] : // Center + (gpio_output_slice == 2) ? data_out_west[43] : // Top + data_out_west[3]; // Bottom + assign io_out[29] = + (gpio_output_slice == 0) ? data_out_west[12] : // Distributed + (gpio_output_slice == 1) ? data_out_west[22] : // Center + (gpio_output_slice == 2) ? data_out_west[42] : // Top + data_out_west[2]; // Bottom + assign io_out[30] = + (gpio_output_slice == 0) ? data_out_west[7] : // Distributed + (gpio_output_slice == 1) ? data_out_west[21] : // Center + (gpio_output_slice == 2) ? data_out_west[41] : // Top + data_out_west[1]; // Bottom + assign io_out[31] = + (gpio_output_slice == 0) ? data_out_west[2] : // Distributed + (gpio_output_slice == 1) ? data_out_west[20] : // Center + (gpio_output_slice == 2) ? data_out_west[40] : // Top + data_out_west[0]; // Bottom + + // South side + assign io_out[32] = + (gpio_output_slice == 0) ? data_out_south[2] : // Distributed + (gpio_output_slice == 1) ? data_out_south[11] : // Center + (gpio_output_slice == 2) ? data_out_south[24] : // Right + data_out_south[0]; // Left + assign io_out[33] = + (gpio_output_slice == 0) ? data_out_south[7] : // Distributed + (gpio_output_slice == 1) ? data_out_south[12] : // Center + (gpio_output_slice == 2) ? data_out_south[25] : // Right + data_out_south[1]; // Left + assign io_out[34] = + (gpio_output_slice == 0) ? data_out_south[12] : // Distributed + (gpio_output_slice == 1) ? data_out_south[13] : // Center + (gpio_output_slice == 2) ? data_out_south[26] : // Right + data_out_south[2]; // Left + assign io_out[35] = + (gpio_output_slice == 0) ? data_out_south[17] : // Distributed + (gpio_output_slice == 1) ? data_out_south[14] : // Center + (gpio_output_slice == 2) ? data_out_south[27] : // Right + data_out_south[3]; // Left + assign io_out[36] = + (gpio_output_slice == 0) ? data_out_south[22] : // Distributed + (gpio_output_slice == 1) ? data_out_south[15] : // Center + (gpio_output_slice == 2) ? data_out_south[28] : // Right + data_out_south[4]; // Left + assign io_out[37] = + (gpio_output_slice == 0) ? data_out_south[27] : // Distributed + (gpio_output_slice == 1) ? data_out_south[16] : // Center + (gpio_output_slice == 2) ? data_out_south[29] : // Right + data_out_south[5]; // Left + + // Map the output data from the sides to a single array that can be + // broken up into 32 bit segments for data transfer. + + assign data_out = {data_out_north, data_out_east, data_out_south, data_out_west}; + + /* Read data (only rdata is something that was not written by the processor) */ + + always @* begin + rdata_pre = 'b0; + if (xfer_sel) begin + rdata_pre = {30'b0, busy}; + end else if (config_sel[0]) begin + rdata_pre = rdata[31:0]; + end else if (config_sel[1]) begin + rdata_pre = rdata[63:32]; + end else if (address_sel) begin + /* When ADDRESS is selected, pass back the existing cell */ + /* count rather than what was written into cell_addr. */ + rdata_pre = bit_count[ASIZE + 6: 7]; + end else if (direct_sel) begin + rdata_pre = gpio_oeb; + end else if (source_sel) begin + rdata_pre = {9'b0, gpio_output_slice, 1'b0, gpio_input_slice, + 1'b0, north_loopback, 1'b0, east_loopback, + 1'b0, south_loopback, 1'b0, west_loopback}; + end else if (data_sel[0]) begin + rdata_pre = data_out[31:0]; + end else if (data_sel[1]) begin + rdata_pre = data_out[63:32]; + end else if (data_sel[2]) begin + rdata_pre = data_out[95:64]; + end else if (data_sel[3]) begin + rdata_pre = data_out[127:96]; + end else if (data_sel[4]) begin + rdata_pre = data_out[159:128]; + end + end + + /* Read data */ + + always @(posedge wb_clk_i or posedge wb_rst_i) begin + if (wb_rst_i) begin + wbs_dat_o <= 0; + ready <= 0; + end else begin + ready <= 0; + if (valid && !ready && (wbs_adr_i[31:8] == BASE_ADR[31:8])) begin + ready <= 1'b1; + wbs_dat_o <= rdata_pre; + end + end + end + + // Map the latched data from the sides to a single array that can be + // broken up into 32 bit segments for data transfer. + + assign latched_in_north = latched_in[2*XSIZE+2*YSIZE-1:2*XSIZE+YSIZE]; + assign latched_in_east = latched_in[2*YSIZE+XSIZE-1:YSIZE+XSIZE]; + assign latched_in_south = latched_in[YSIZE+XSIZE-1:YSIZE]; + assign latched_in_west = latched_in[YSIZE-1:0]; + + always @(posedge wb_clk_i or posedge wb_rst_i) begin + if (wb_rst_i) begin + cell_addr <= 0; + gpio_oeb <= 0; + xfer_ctrl <= 0; + local_reset <= 0; + west_loopback <= 0; + east_loopback <= 0; + north_loopback <= 0; + south_loopback <= 0; + gpio_input_slice <= 0; + gpio_output_slice <= 0; + latched_in <= 0; + wdata <= 0; + write <= 1'b0; + end else begin + write <= 1'b0; + if (valid && !ready && wbs_adr_i[31:8] == BASE_ADR[31:8]) begin + if (xfer_sel) begin + if (iomem_we[0]) begin + xfer_ctrl <= wbs_dat_i[1:0]; + local_reset <= wbs_dat_i[2]; + end + end else if (config_sel[0]) begin + if (iomem_we[0]) wdata[7:0] <= wbs_dat_i[7:0]; + if (iomem_we[1]) wdata[15:8] <= wbs_dat_i[15:8]; + if (iomem_we[2]) wdata[23:16] <= wbs_dat_i[23:16]; + if (iomem_we[3]) wdata[31:24] <= wbs_dat_i[31:24]; + if (|iomem_we) write <= 1'b1; + end else if (config_sel[1]) begin + if (iomem_we[0]) wdata[39:32] <= wbs_dat_i[7:0]; + if (iomem_we[1]) wdata[47:40] <= wbs_dat_i[15:8]; + if (iomem_we[2]) wdata[55:48] <= wbs_dat_i[23:16]; + if (iomem_we[3]) wdata[63:56] <= wbs_dat_i[31:24]; + if (|iomem_we) write <= 1'b1; + end else if (address_sel) begin + // NOTE: Assumes MAXADDR > 256 && MAXADDR < 65536 + if (iomem_we[0]) cell_addr[7:0] <= wbs_dat_i[7:0]; + if (iomem_we[1]) cell_addr[ASIZE-1:8] <= wbs_dat_i[ASIZE-1:8]; + end else if (direct_sel) begin + if (iomem_we[0]) gpio_oeb[7:0] <= wbs_dat_i[7:0]; + if (iomem_we[1]) gpio_oeb[15:8] <= wbs_dat_i[15:8]; + if (iomem_we[2]) gpio_oeb[23:16] <= wbs_dat_i[23:16]; + if (iomem_we[3]) gpio_oeb[31:24] <= wbs_dat_i[31:24]; + end else if (source_sel) begin + if (iomem_we[0]) begin + west_loopback <= wbs_dat_i[2:0]; + south_loopback <= wbs_dat_i[6:4]; + end + if (iomem_we[1]) begin + east_loopback <= wbs_dat_i[2:0]; + north_loopback <= wbs_dat_i[6:4]; + end + if (iomem_we[2]) begin + gpio_input_slice <= wbs_dat_i[2:0]; + gpio_output_slice <= wbs_dat_i[6:4]; + end + end else if (data_sel[0]) begin + if (iomem_we[0]) latched_in[7:0] <= wbs_dat_i[7:0]; + if (iomem_we[1]) latched_in[15:8] <= wbs_dat_i[15:8]; + if (iomem_we[2]) latched_in[23:16] <= wbs_dat_i[23:16]; + if (iomem_we[3]) latched_in[31:24] <= wbs_dat_i[31:24]; + end else if (data_sel[1]) begin + if (iomem_we[0]) latched_in[39:32] <= wbs_dat_i[7:0]; + if (iomem_we[1]) latched_in[47:40] <= wbs_dat_i[15:8]; + if (iomem_we[2]) latched_in[55:48] <= wbs_dat_i[23:16]; + if (iomem_we[3]) latched_in[63:56] <= wbs_dat_i[31:24]; + end else if (data_sel[2]) begin + if (iomem_we[0]) latched_in[71:64] <= wbs_dat_i[7:0]; + if (iomem_we[1]) latched_in[79:72] <= wbs_dat_i[15:8]; + if (iomem_we[2]) latched_in[87:80] <= wbs_dat_i[23:16]; + if (iomem_we[3]) latched_in[95:88] <= wbs_dat_i[31:24]; + end else if (data_sel[3]) begin + if (iomem_we[0]) latched_in[103:96] <= wbs_dat_i[7:0]; + if (iomem_we[1]) latched_in[111:104] <= wbs_dat_i[15:8]; + if (iomem_we[2]) latched_in[119:112] <= wbs_dat_i[23:16]; + if (iomem_we[3]) latched_in[127:120] <= wbs_dat_i[31:24]; + end else if (data_sel[4]) begin + if (iomem_we[0]) latched_in[135:128] <= wbs_dat_i[7:0]; + if (iomem_we[1]) latched_in[143:136] <= wbs_dat_i[15:8]; + if (iomem_we[2]) latched_in[151:144] <= wbs_dat_i[23:16]; + if (iomem_we[3]) latched_in[159:152] <= wbs_dat_i[31:24]; + end + end else begin + xfer_ctrl <= 0; // Immediately self-resetting + local_reset <= 0; // Immediately self-resetting + end + end + end + + /* Transfer status */ + + assign busy[0] = (xfer_state == `START || xfer_state == `XDATAS); + assign busy[1] = (xfer_state == `FINISH || xfer_state == `XDATAF || + xfer_state == `LOAD); + + /* Transfer cycles */ + + always @(posedge wb_clk_i or posedge wb_rst_i) begin + if (wb_rst_i == 1'b1) begin + xfer_state <= `IDLE; + bit_count <= 'd0; + cell_offset <= 'd0; + clk <= 1'b0; + hold <= 1'b1; + end else begin + clk <= 1'b0; + hold <= 1'b1; + if (xfer_state == `IDLE) begin + if (xfer_ctrl[0] == 1'b1) begin + xfer_state <= `START; + end else if (xfer_ctrl[1] == 1'b1) begin + xfer_state <= `FINISH; + end + end else if (xfer_state == `START) begin + bit_count[ASIZE + 6:7] <= cell_addr; + bit_count[6:0] <= 7'b1111110; + xfer_state <= `XDATAS; + end else if (xfer_state == `FINISH) begin + bit_count[ASIZE + 6:7] <= `MAXADDR - cell_offset; + bit_count[6:0] <= 7'b1111110; + xfer_state <= `XDATAF; + end else if (xfer_state == `XDATAS) begin + clk <= ~clk; + bit_count <= bit_count - 1; + if (bit_count[6:0] == 0) begin + cell_offset <= cell_offset + 1; + end + if (clk == 1'b0) begin + if (bit_count == 0) begin + xfer_state <= `IDLE; + end + end + end else if (xfer_state == `XDATAF) begin + clk <= ~clk; + bit_count <= bit_count - 1; + if (bit_count[6:0] == 0) begin + cell_offset <= cell_offset + 1; + end + if (clk == 1'b0) begin + if (bit_count == 0) begin + xfer_state <= `LOAD; + end + end + end else if (xfer_state == `LOAD) begin + hold <= 1'b0; + xfer_state <= `IDLE; + cell_offset <= 'd0; + end + end + end +endmodule + +/* + *----------------------------------------------------------------- + * Chaos array (XSIZE * YSIZE) + *----------------------------------------------------------------- + */ + +module chaos_array #( + parameter XSIZE = 30, /* Total number of cells in X */ + parameter YSIZE = 30, /* Total number of cells in Y */ + parameter XTOP = 3, /* Number of sub-arrays in X */ + parameter YTOP = 3, /* Number of sub-arrays in Y */ + parameter BASE_ADR = 32'h3000_0000 +)( +`ifdef USE_POWER_PINS + inout vccd1, // User area 1 1.8V supply + inout vssd1, // User area 1 digital ground +`endif + + input clk, + input reset, + input hold, + input write, + input [63:0] wdata, + output [63:0] rdata, + input [YSIZE-1:0] data_in_east, // Perimeter input + input [YSIZE-1:0] data_in_west, + input [XSIZE-1:0] data_in_north, + input [XSIZE-1:0] data_in_south, + output [YSIZE-1:0] data_out_east, // Perimeter output + output [YSIZE-1:0] data_out_west, + output [XSIZE-1:0] data_out_north, + output [XSIZE-1:0] data_out_south +); + wire [XSIZE - 1: 0] uconn [YTOP: 0]; // Upward moving data + wire [XSIZE - 1: 0] dconn [YTOP: 0]; // Downward moving data + wire [YSIZE - 1: 0] rconn [XTOP: 0]; // Rightward moving data + wire [YSIZE - 1: 0] lconn [XTOP: 0]; // Leftward moving data + + wire [YTOP - 1: 0] shiftreg [XTOP: 0]; + wire [YTOP - 1: 0] clkarray [XTOP: 0]; + + wire io_data_sel; // wishbone select data + wire xfer_sel; // wishbone select transfer + + assign clkarray[0][0] = clk; + + // Sub-array architecture: + // + // dudu dudu dudu + // |^|^ |^|^ |^|^ + // v|v| v|v| v|v| + // +------+ +------+ +------+ + // r->| |->| |->| |->r + // l<-| |<-| |<-| |<-l + // r->| |->| |->| |->r + // l<-| |<-| |<-| |<-l + // +------+ +------+ +------+ + // |^|^ |^|^ |^|^ + // v|v| v|v| v|v| + // +------+ +------+ +------+ + // r->| |->| |->| |->r + // l<-| |<-| |<-| |<-l + // r->| |->| |->| |->r + // l<-| |<-| |<-| |<-l + // +------+ +------+ +------+ + // |^|^ |^|^ |^|^ + // v|v| v|v| v|v| + // dudu dudu dudu + // + // Each box in the above diagram is a sub-array size 2x2. + // The top level has XSIZE = 6, YSIZE = 4 with XTOP = 3 + // and YTOP = 2. + // + // The top-level inputs and outputs are the perimeter values + // on the four edges of the top level array. + // + // To represent all the connections among the sub-arrays, it + // can be seen from the above that d and u (dconn and uconn) + // are arrays of size (XSIZE, YTOP + 1), while l and r (lconn + // and rconn) are arrays of size (XTOP + 1, YSIZE). + + // NOTE: For viewing internal signals in gtkwave, + // some 2D arrays may need to be copied into 1D arrays. + // See the original verilog for examples. + + /* The perimeter inputs and outputs connect the array to the + * parent module. Note that this hides all the interior data, + * which could be an issue with understanding how the circuit + * works. + */ + + assign data_out_north = uconn[YTOP][XSIZE - 1:0]; + assign data_out_south = dconn[0][XSIZE - 1:0]; + assign data_out_east = rconn[XTOP][YSIZE - 1:0]; + assign data_out_west = lconn[0][YSIZE - 1:0]; + + assign dconn[YTOP][XSIZE - 1:0] = data_in_north; + assign uconn[0][XSIZE - 1:0] = data_in_south; + assign rconn[0][YSIZE - 1:0] = data_in_west; + assign lconn[XTOP][YSIZE - 1:0] = data_in_east; + + genvar i, j; + + /* NOTE: To see the internal cell values in gtkwave, it is necessary + * to split out a few individual instances from the 2D array. Loop + * from j = 1 in 2D generate loop, then add a 1D generate loop for + * i = N to XSIZE with j set to zero, then add individual instances for + * i = 0 to N - 1 with j set to zero. + */ + + /* Connected array of subarrays */ + generate + for (j = 0; j < YTOP; j=j+1) begin: subarrayy + for (i = 0; i < XTOP; i=i+1) begin: subarrayx + chaos_subarray #( + .XSIZE(XSIZE / XTOP), + .YSIZE(YSIZE / YTOP) + ) chaos_subarray_inst ( + `ifdef USE_POWER_PINS + .vccd1(vccd1), + .vssd1(vssd1), + `endif + .inorth(dconn[j+1][(i+1)*(XSIZE/XTOP)-1:i*(XSIZE/XTOP)]), + .isouth(uconn[j][(i+1)*(XSIZE/XTOP)-1:i*(XSIZE/XTOP)]), + .ieast(lconn[i+1][(j+1)*(YSIZE/YTOP)-1:j*(YSIZE/YTOP)]), + .iwest(rconn[i][(j+1)*(YSIZE/YTOP)-1:j*(YSIZE/YTOP)]), + .onorth(uconn[j+1][(i+1)*(XSIZE/XTOP)-1:i*(XSIZE/XTOP)]), + .osouth(dconn[j][(i+1)*(XSIZE/XTOP)-1:i*(XSIZE/XTOP)]), + .oeast(rconn[i+1][(j+1)*(YSIZE/YTOP)-1:j*(YSIZE/YTOP)]), + .owest(lconn[i][(j+1)*(YSIZE/YTOP)-1:j*(YSIZE/YTOP)]), + .reset(reset), + .hold(hold), + .iclk(clkarray[i][j]), + .oclk(clkarray[i+1][j]), + .idata(shiftreg[i][j]), + .odata(shiftreg[i+1][j]) + ); + end + end + + /* NOTE: This would work better topologically if each */ + /* row switched the direction of the shift register. */ + + for (j = 0; j < YTOP - 1; j=j+1) begin: shifty + assign shiftreg[0][j+1] = shiftreg[XTOP][j]; + assign clkarray[0][j+1] = clkarray[XTOP][j]; + end + endgenerate + + /* Storage for data transfers to and from the processor. This is */ + /* 64 bits, so can hold the configuration data for one core cell. */ + + reg [63:0] lutdata; + + /* Wire up the lutdata registers as a shift register and connect the */ + /* ends to the array's shift register to form a loop. */ + + always @(posedge clk or posedge write) begin + if (write) begin + /* Copy data from wdata to lutdata on write */ + lutdata <= wdata; + end else begin + /* Shift data on clock when "write" is not raised */ + lutdata[63:1] <= lutdata[62:0]; + lutdata[0] <= shiftreg[XTOP][YTOP-1]; + end + end + + assign shiftreg[0][0] = lutdata[63]; + + assign rdata = lutdata; /* Data to read back */ + +endmodule +`default_nettype wire