diff --git a/doc/README-ZTEX b/doc/README-ZTEX index 8a0ca2c334b..8cac4c8fbfb 100644 --- a/doc/README-ZTEX +++ b/doc/README-ZTEX @@ -3,7 +3,7 @@ Overview --------- If you have ZTEX boards USB-FPGA 1.15y, you can use them with JtR. Available "formats" are descrypt-ztex, bcrypt-ztex, sha512crypt-ztex, -Drupal7-ztex, more are planned. +Drupal7-ztex, sha256crypt-ztex, more are planned. ------------- How to build diff --git a/run/john.conf b/run/john.conf index 8351163cf42..317a87cfade 100644 --- a/run/john.conf +++ b/run/john.conf @@ -376,6 +376,14 @@ Frequency = 141 # This turns off all 10 units (resulting in a timeout). #Config1_04A36E0FD6_0 = \xff\x03 +[ZTEX:sha256crypt] +# Design tools reported possible frequency is 166.3 but tested boards +# miss guesses, often fail unless frequency is decreased. +#Frequency = 165 +Frequency = 135 +#TargetRounds = 1000000 + + [Options:OpenCL] # Set default OpenCL device. Command line option will override this. # If not set, we will search for a GPU or fall-back to the most diff --git a/run/ztex/ztex115y_sha256crypt.bit b/run/ztex/ztex115y_sha256crypt.bit new file mode 100644 index 00000000000..04cb9d8fbeb Binary files /dev/null and b/run/ztex/ztex115y_sha256crypt.bit differ diff --git a/src/Makefile.in b/src/Makefile.in index 76abe8ea50c..0533d9180cf 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -122,7 +122,7 @@ OCL_OBJS = opencl_common.o opencl_autotune.o bt.o bt_hash_type_64.o bt_hash_type OPENCL_PLUGFORMATS_OBJS = @OPENCL_PLUGFORMATS_OBJS@ -ZTEX_OBJS = ztex_descrypt.o ztex_bcrypt.o ztex_sha512crypt.o ztex_drupal7.o +ZTEX_OBJS = ztex_descrypt.o ztex_bcrypt.o ztex_sha512crypt.o ztex_drupal7.o ztex_sha256crypt.o FUZZ_OBJS = fuzz.o diff --git a/src/john.c b/src/john.c index 5e1e96ae2e4..211e0195089 100644 --- a/src/john.c +++ b/src/john.c @@ -163,6 +163,7 @@ extern struct fmt_main fmt_ztex_descrypt; extern struct fmt_main fmt_ztex_bcrypt; extern struct fmt_main fmt_ztex_sha512crypt; extern struct fmt_main fmt_ztex_drupal7; +extern struct fmt_main fmt_ztex_sha256crypt; #endif #include "fmt_externs.h" @@ -368,6 +369,7 @@ static void john_register_all(void) john_register_one(&fmt_ztex_bcrypt); john_register_one(&fmt_ztex_sha512crypt); john_register_one(&fmt_ztex_drupal7); + john_register_one(&fmt_ztex_sha256crypt); #endif john_register_one(&fmt_DES); john_register_one(&fmt_BSDI); diff --git a/src/ztex/fpga-sha256crypt/README.md b/src/ztex/fpga-sha256crypt/README.md new file mode 100644 index 00000000000..617f66a08dd --- /dev/null +++ b/src/ztex/fpga-sha256crypt/README.md @@ -0,0 +1,143 @@ +## Overview + +- sha256crypt for ZTEX 1.15y board allows candidate passwords up to +32 bytes, equipped with on-board mask generator and comparator. +The board computes 600 keys in parallel. + + +## Computing units + +- sha256crypt invokes SHA256 in different ways, sometimes that look +very complex. To accomplish the task, a CPU-based computing unit +was implemented. +- Each unit consists of 3 cores, CPU, memory and I/O subsystem. +The approximate schematic of a computing unit is shown at fig.1. + +``` + --------------+-------------+-------------- + / / / \ + +--------+ +--------+ +--------+ | + | | | | | | | + | SHA256 | | SHA256 | | SHA256 | | + | core | | core | | core | | + | #0 | | #1 | | #2 | | + | | | | | | | + +--------+ +--------+ +--------+ | + ^ ^ ^ | + \ | / | + +----------+----------- | + | | + . . . . . | . . . . . . . . . . . . . . . . . . . . . |. . + | / + | / + +---------------+ ------------- / + | | / \ / + | process_bytes | / "main" \ <------ + | |<--+--| memory | + +---------------+ | \ (16x256b) / <------ + | ^ | \ / \ + +-------+ | / ------------- | + | procb | | / +------------+ + | saved | | / +------------------+ | unit_input | + | state | | / | thread_state(x6) | +------------+ + +-------+ | | +------------------+ ^ + | | | + +-----------+ \ +-----------------------------+ | + | procb_buf | -->| C.P.U. | | + +-----------+ | +-----------------------+ | | + ^ | | integer ops. incl. | | | + \ | | 6 x 16 registers(x16b)| | | + \ | +-----------------------+ | | + ---------| | | + | +----------------------+ | | + | | thread switch (x6) | | | + +--------+ | +----------------------+ | | + | unit | | | instruction pointers | | | + | output |<-------| +----------------------+ | | + | buf | | | instruction memory | | | + +--------+ | +----------------------+ | | + | +-----------------------------+ | + | / + \ / + ---> to arbiter_rx from arbiter_tx +``` + +- SHA256 computations are performed using specialized circuits +("cores"). Each cycle, a core computes one of 64 algorithm rounds. +Additionally 8 cycles it's busy with additions at the end of the block. +Several cycles before a computations is finished and output, +next computation starts loading Initial Values (IVs) and pre-fetching +data from core's input buffer. +- internally cores store result of SHA256, allow to use previously +stored result as IVs for subsequent block. That way, the core +is able to handle input of any length. +- So each core performs 2 blocks in (64+8)*2 = 144 cycles. + +- CPU runs same program in 6 independent hardware threads. +Each thread has 128 bytes of "main" memory (accessible by SHA256 +subsystem), 16 x 16-bit registers. Data movement, integer, +execution flow control operations are available. However there's only +a subset if operations typically implemented in general-purpose CPUs, +enough for the task. +- CPU is heavily integrated with SHA256 subsystem. It has INIT_CTX, +PROCESS_BYTES, FINISH_CTX instructions that are almost equivalent to +init_ctx(), process_bytes(), finish_ctx() from software library. +Each instruction takes 1 cycle to execute. +- SHA256 instructions store instruction data in internal buffer +(procb_buf). A dedicated unit (process_bytes) takes intermediate data, +fetches input data from the memory, creates 16 x 32-bit data blocks +for cores, adds padding and total where necessary. It saves +the state of an unfinished computation, switches to the next core +after each block. +- The program for the CPU is available here. + + +## Design overview + +``` + ------------------+--------+--+--+--------+--------- + / / / / / / \ + +-----------+ +-----------+ +-----------+ | + | | | | X X X | | | + | Computing | | Computing | | Computing | | + | Unit #0 | | Unit #1 | | Unit N | | + | | | | X X X | | | + +-----------+ +-----------+ +-----------+ | + ^ ^ ^ ^ ^ ^ | + | | | | | / | + +---------------+---------+--+--+-------- | + | | + . . . | . . . . . . . . . . . . . . . . . . . . . . . . . .| . + | | + | | + +-----------------+ +----------------+ / + | Arbiter | | Arbiter |<--------- + | (transmit part) |<-------->| (receive part) | + +-----------------+ +----------------+ + ^ | + | +------------+ | +------ + | +---------+ | |<-+->| mode \ + | | cmp. |-->| comparator | | cmp |-- + | | config. | | |---->| ? / \ + | +---------+ +------------+ +------ | + | ^ | + . . . | . . . . .|. . . . . . . . . . . . . . . . . . . . | . + | | Communication framework | + | | / + +-----------+ | / + | candidate | | / + | generator | | / + +-----------+---------+----------------------+ / + | input pkt. handling | output pkt. creation |<----- + +---------------------+----------------------+ + | input FIFO | output FIFO | + +---------------------+----------------------+ + | Prog. clocks | USB I/O | FPGA reset | + +--------------------------------------------+ + +``` +fig.2. Overview, FPGA application + +- Each FPGA has 25 computing units, that's 75 cores, 150 keys are +computed in parallel. + diff --git a/src/ztex/fpga-sha256crypt/fpga-sha256crypt.xise b/src/ztex/fpga-sha256crypt/fpga-sha256crypt.xise new file mode 100644 index 00000000000..235ad1536b1 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/fpga-sha256crypt.xise @@ -0,0 +1,684 @@ + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/ztex/fpga-sha256crypt/fpga_editor.png b/src/ztex/fpga-sha256crypt/fpga_editor.png new file mode 100644 index 00000000000..4c8918ebc31 Binary files /dev/null and b/src/ztex/fpga-sha256crypt/fpga_editor.png differ diff --git a/src/ztex/fpga-sha256crypt/main.vh b/src/ztex/fpga-sha256crypt/main.vh new file mode 100644 index 00000000000..4ea30124838 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/main.vh @@ -0,0 +1,46 @@ +/* + * This software is Copyright (c) 2016-2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// ************************************************************ +// +// ISE Version: 14.5 +// +// Include as Global File in Compile List: main.vh log2.vh +// Set as Top Module: ztex_inouttraffic +// +// ************************************************************ + + +// Parameters for ztex_inouttraffic +`define BITSTREAM_TYPE 16'h256c + +// must be power of 2; actual size for output fifo is 2 bytes less +`define OUTPUT_FIFO_SIZE 4096 + +// Parameters for pkt_comm +`define PKT_COMM_VERSION 2 +`define RANGES_MAX 4 +`define CHAR_BITS 8 +`define PLAINTEXT_LEN 32 + +// outpkt +`define OUTPKT_TYPE_MSB 2 +`define OUTPKT_TYPE_CMP_EQUAL 'b01 +`define OUTPKT_TYPE_PACKET_DONE 'b10 +`define OUTPKT_TYPE_RESULT 'b11 +`define OUTPKT_TYPE_CMP_RESULT 'b100 + +`define RESULT_LEN 32 +//`define OUTPKT_DATA_MAX_LEN (8 + `RESULT_LEN) + +// comparator +`define NUM_HASHES 512 +`define HASH_NUM_MSB `MSB(`NUM_HASHES-1) +`define HASH_COUNT_MSB `MSB(`NUM_HASHES) + diff --git a/src/ztex/fpga-sha256crypt/no-clocks-io.xds b/src/ztex/fpga-sha256crypt/no-clocks-io.xds new file mode 100644 index 00000000000..4e221d7c6a3 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/no-clocks-io.xds @@ -0,0 +1,30 @@ + + + + This Strategy is used for creation of ngc files for "blackbox" modules. + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_config.v b/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_config.v new file mode 100644 index 00000000000..8b780d4e24b --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_config.v @@ -0,0 +1,63 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +module inpkt_config #( + parameter SUBTYPE1_WIDTH = 32 + )( + input CLK, + input [7:0] din, + input wr_en, pkt_end, + output full, + + output reg [SUBTYPE1_WIDTH-1:0] dout1 = 0, + // unsupported subtype, bad length for this subtype + output reg err = 0 + ); + + assign full = 0; + + // Data length in bytes for subtype 1 + localparam SUBTYPE1_N_BYTES = SUBTYPE1_WIDTH[2:0] == 0 + ? SUBTYPE1_WIDTH / 8 : (SUBTYPE1_WIDTH + 1) / 8; + + reg [`MSB(SUBTYPE1_N_BYTES) :0] cnt = 0; + + localparam STATE_SUBTYPE = 0, + STATE_DATA1 = 1; + + (* FSM_EXTRACT="true" *) + reg [1:0] state = STATE_SUBTYPE; + + always @(posedge CLK) if (~err & wr_en) + case(state) + STATE_SUBTYPE: begin + if (din != 1) + err <= 1; + state <= STATE_DATA1; + end + + // Subtype 1: SUBTYPE1_WIDTH-bit value + STATE_DATA1: if (pkt_end) begin + if (cnt != SUBTYPE1_N_BYTES) + err <= 1; + cnt <= 0; + state <= STATE_SUBTYPE; + end + else begin + dout1 [8*cnt +:8] <= din; + cnt <= cnt + 1'b1; + if (cnt == SUBTYPE1_N_BYTES) + err <= 1; + state <= STATE_DATA1; + end + + endcase + +endmodule diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_header.v b/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_header.v new file mode 100644 index 00000000000..c33394d079d --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_header.v @@ -0,0 +1,238 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// processes input (from the point of view from FPGA) headers +// of version VERSION. +// packet header is 10 bytes. +// +// struct pkt { +// unsigned char version; +// unsigned char type; +// unsigned short reserved0; +// unsigned char data_len0; +// unsigned char data_len1; +// unsigned char data_len2; // doesn't count header +// unsigned char reserved1; +// unsigned short id; +// unsigned char data[pkt_data_len]; +// }; +// +// assumes PKT_MAX_LEN is no less than 65536 +// packets not aligned to 2-byte word can be padded with 0 +// +// Checksum is PKT_CHECKSUM_LEN bytes long. Words added and inverted. +// Checksum is not included in data length. +// - inserted after packet header +// - after each PKT_CHECKSUM_INTERVAL bytes <-- not implemented +// - after the end of packet +// +// TODO: some improved CRC check +// + +module inpkt_header #( + parameter VERSION = -1, + parameter PKT_MAX_LEN = 65536, + parameter PKT_MAX_TYPE = -1, + parameter PKT_TYPE_MSB = `MSB(PKT_MAX_TYPE), + parameter DISABLE_CHECKSUM = 0 + )( + input CLK, + input [7:0] din, + input wr_en, + + output reg [PKT_TYPE_MSB:0] pkt_type = 0, + output reg [15:0] pkt_id, + output pkt_data, // asserts when it goes packet data + output pkt_end, // asserts when it goes the last byte of data + output reg err_pkt_version = 0, err_pkt_type = 0, err_pkt_len = 0, err_pkt_checksum = 0 + ); + + + localparam PKT_LEN_MSB = `MSB(PKT_MAX_LEN); + + reg [31:0] checksum = 0; + reg [31:0] checksum_tmp = 0; + reg [1:0] checksum_byte_count = 0; + + // flag is set when checksum_tmp contains checksum value from data-in + reg checksum_check_flag = 0; + // flag is set when header is processed, cleared when data starts + reg pkt_header = 1; + + reg [PKT_LEN_MSB:0] pkt_byte_count_max, pkt_byte_count_max_tmp; + reg [PKT_LEN_MSB:0] pkt_byte_count; + + localparam PKT_STATE_VERSION = 1, + PKT_STATE_TYPE = 2, + PKT_STATE_RESERVED0_0 = 3, + PKT_STATE_RESERVED0_1 = 4, + PKT_STATE_LEN0 = 5, + PKT_STATE_LEN1 = 6, + PKT_STATE_LEN2 = 7, + PKT_STATE_RESERVED1 = 8, + PKT_STATE_ID0 = 9, + PKT_STATE_ID1 = 10, + PKT_STATE_DATA = 11, + PKT_STATE_ERROR = 12, + PKT_STATE_CHECKSUM = 13; + + (* FSM_EXTRACT = "true", FSM_ENCODING = "auto" *) + reg [3:0] pkt_state = PKT_STATE_VERSION; + + // Verify checksum regardless of wr_en + always @(posedge CLK) + if (checksum_check_flag) begin + if (~checksum != checksum_tmp & ~DISABLE_CHECKSUM[0]) + err_pkt_checksum <= 1; + end + + always @(posedge CLK) begin + if (err_pkt_checksum) + pkt_state <= PKT_STATE_ERROR; + + if (wr_en) begin + if (pkt_state != PKT_STATE_CHECKSUM & ~(pkt_state == PKT_STATE_VERSION & !din)) begin + + checksum_check_flag <= 0; + + if (checksum_byte_count == 0) begin + checksum_tmp[31:8] <= 0; + if (~checksum_check_flag) + checksum <= checksum + checksum_tmp; + else + checksum <= 0; + end + + checksum_tmp[8*(checksum_byte_count+1)-1 -:8] <= din; + checksum_byte_count <= checksum_byte_count + 1'b1; + end + + case (pkt_state) + PKT_STATE_VERSION: begin + if (din == 0) begin + // input 0 - skip + end + else begin + if (din != VERSION) begin + // wrong packet version + err_pkt_version <= 1; + pkt_state <= PKT_STATE_ERROR; + end + else + pkt_state <= PKT_STATE_TYPE; + end + end + + PKT_STATE_TYPE: begin + pkt_header <= 1; + pkt_byte_count <= 0; + + if (din == 0 || din[PKT_TYPE_MSB:0] > PKT_MAX_TYPE || din[7:PKT_TYPE_MSB+1]) begin + // wrong packet type + err_pkt_type <= 1; + pkt_state <= PKT_STATE_ERROR; + end + else begin + pkt_type <= din[PKT_TYPE_MSB:0]; + pkt_state <= PKT_STATE_RESERVED0_0; + end + end + + PKT_STATE_RESERVED0_0: begin + pkt_state <= PKT_STATE_RESERVED0_1; + end + + PKT_STATE_RESERVED0_1: begin + pkt_state <= PKT_STATE_LEN0; + end + + PKT_STATE_LEN0: begin + //pkt_byte_count_max[7:0] <= din; + pkt_byte_count_max_tmp[7:0] <= din; + pkt_state <= PKT_STATE_LEN1; + end + + PKT_STATE_LEN1: begin + //pkt_byte_count_max[15:8] <= din; + pkt_byte_count_max_tmp[15:8] <= din; + pkt_state <= PKT_STATE_LEN2; + end + + PKT_STATE_LEN2: begin + //pkt_byte_count_max <= { din[PKT_LEN_MSB-16:0], pkt_byte_count_max[15:0] } - 1'b1; + pkt_byte_count_max <= { din[PKT_LEN_MSB-16:0], pkt_byte_count_max_tmp[15:0] } - 1'b1; + + //if ( din[7:PKT_LEN_MSB-16+1] || !(din[PKT_LEN_MSB-16:0] || pkt_byte_count_max[15:0]) ) begin + if ( din[7:PKT_LEN_MSB-16+1] || !(din[PKT_LEN_MSB-16:0] || pkt_byte_count_max_tmp[15:0]) ) begin + // wrong packet length + err_pkt_len <= 1; + pkt_state <= PKT_STATE_ERROR; + end + else begin + pkt_state <= PKT_STATE_RESERVED1; + end + end + + PKT_STATE_RESERVED1: begin + pkt_state <= PKT_STATE_ID0; + end + + PKT_STATE_ID0: begin + pkt_id[7:0] <= din; + pkt_state <= PKT_STATE_ID1; + end + + PKT_STATE_ID1: begin + pkt_id[15:8] <= din; + checksum_byte_count <= 0; + pkt_state <= PKT_STATE_CHECKSUM; + end + + PKT_STATE_DATA: begin + pkt_header <= 0; + if (pkt_byte_count == pkt_byte_count_max) begin + checksum_byte_count <= 0; + pkt_state <= PKT_STATE_CHECKSUM; + end + else + pkt_byte_count <= pkt_byte_count + 1'b1; + end + + PKT_STATE_CHECKSUM: begin + checksum_tmp[8*(checksum_byte_count+1)-1 -:8] <= din; + checksum_byte_count <= checksum_byte_count + 1'b1; + + if (checksum_byte_count == 0) begin + checksum <= checksum + checksum_tmp; + end + else if (checksum_byte_count == 3) begin + checksum_check_flag <= 1; + // Suppose checksum_byte_count is a power of 2 + //checksum_byte_count <= 0; + if (~pkt_header) //pkt_byte_count == pkt_byte_count_max) <-- bug caused error if pkt_len=1 + pkt_state <= PKT_STATE_VERSION; + else + pkt_state <= PKT_STATE_DATA; + end + end + + PKT_STATE_ERROR: begin + end + endcase + + end // wr_en + end + + assign pkt_data = pkt_state == PKT_STATE_DATA; + + assign pkt_end = pkt_data && pkt_byte_count == pkt_byte_count_max; + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_type_init_1b.v b/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_type_init_1b.v new file mode 100644 index 00000000000..65282dc7342 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/inpkt_type_init_1b.v @@ -0,0 +1,39 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// +// PKT_TYPE_INIT (0x05) typically contain runtime +// initialization data. +// Length of 1 byte is currently supported. +// +module inpkt_type_init_1b( + input CLK, + input [7:0] din, + input wr_en, + output full, + + output reg [7:0] dout = 0, + input rd_en, + output reg empty = 1 + //output reg err = 0 + ); + + assign full = ~empty; + + always @(posedge CLK) begin + if (wr_en & empty) begin + dout <= din; + empty <= 0; + end + if (rd_en & ~empty) + empty <= 1; + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/outpkt.v b/src/ztex/fpga-sha256crypt/pkt_comm/outpkt.v new file mode 100644 index 00000000000..67643f6e3f2 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/outpkt.v @@ -0,0 +1,225 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016-2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// +// Based on outpkt_bcrypt +// +module outpkt #( + parameter [7:0] VERSION = `PKT_COMM_VERSION, + parameter PKT_TYPE_MSB = `OUTPKT_TYPE_MSB, + parameter HASH_NUM_MSB = 15, + parameter SIMULATION = 0 + )( + input CLK, + + output reg full = 1, + input source_not_empty, + // Read from 16-bit wide memory + input [15:0] din, + output reg [`MSB(4 +`RESULT_LEN/2 -1):0] rd_addr = 0, + + input wr_en, + input [PKT_TYPE_MSB:0] pkt_type, + input [15:0] pkt_id, + input [HASH_NUM_MSB:0] hash_num, + input [31:0] num_processed, + + output [15:0] dout, + output pkt_end_out, + input rd_en, + output empty + ); + + + // Type ID appears on host in 'type' field + //localparam [7:0] OUTPKT_TYPE_ID_CMP_EQUAL = 8'hD1; + localparam [7:0] OUTPKT_TYPE_ID_PACKET_DONE = 8'hD2; + localparam [7:0] OUTPKT_TYPE_ID_RESULT = 8'hD3; // result with IDs (w/o hash_num) + localparam [7:0] OUTPKT_TYPE_ID_CMP_RESULT = 8'hD4; // result with IDs & hash_num + + wire [7:0] pkt_type_id = + //pkt_type == `OUTPKT_TYPE_CMP_EQUAL ? OUTPKT_TYPE_ID_CMP_EQUAL : + pkt_type == `OUTPKT_TYPE_PACKET_DONE ? OUTPKT_TYPE_ID_PACKET_DONE : + pkt_type == `OUTPKT_TYPE_RESULT ? OUTPKT_TYPE_ID_RESULT : + pkt_type == `OUTPKT_TYPE_CMP_RESULT ? OUTPKT_TYPE_ID_CMP_RESULT : + 0; + + wire [7:0] pkt_len = // data length in bytes, must be even number + //pkt_type == `OUTPKT_TYPE_CMP_EQUAL ? 8 : + pkt_type == `OUTPKT_TYPE_PACKET_DONE ? 4 : + pkt_type == `OUTPKT_TYPE_RESULT ? 6 + `RESULT_LEN : + pkt_type == `OUTPKT_TYPE_CMP_RESULT ? 8 + `RESULT_LEN : + 0; + + + reg pkt_empty = 1; + reg [15:0] pkt_dout = 0; + reg [2:0] count = 0; + reg pkt_new = 1, pkt_end = 0; + + localparam [3:0] STATE_NONE = 0, + STATE_HEADER = 1, + STATE_NUM_PROC0 = 2, + STATE_NUM_PROC1 = 3, + STATE_WORD_ID = 4, + STATE_GEN_ID0 = 5, + STATE_GEN_ID1 = 6, + STATE_HASH_NUM = 7, + STATE_RESULT = 8, + STATE_RD_PREPARE = 9, + STATE_RD = 10, + STATE_RD_WAIT = 11; + + (* FSM_EXTRACT="true" *) + reg [3:0] state = STATE_NONE; + + always @(posedge CLK) begin + if (~pkt_empty) begin + if (checksum_wr_en) begin + pkt_empty <= 1; + pkt_end <= 0; + end + end + + else // internal register (pkt_dout) is empty + case(state) + STATE_NONE: if (source_not_empty) + state <= STATE_HEADER; + + // Read from Fall-Through type source + STATE_HEADER: begin + pkt_dout <= + // version, type + count == 0 ? { pkt_type_id, VERSION } : + // reserved + count == 1 ? 16'h35b9 : // some arbitrary value for better checksumming + // data length + count == 2 ? { 8'b0, pkt_len } : + count == 3 ? 16'h0 : + // packet id + count == 4 ? pkt_id : + 16'h0; + + pkt_new <= count == 0 ? 1'b1 : 1'b0; + + pkt_empty <= 0; + if (count == 4) begin + count <= 0; + state <= pkt_type == `OUTPKT_TYPE_PACKET_DONE + ? STATE_NUM_PROC0 : STATE_WORD_ID; + end + else + count <= count + 1'b1; + + // 0 - word_id + // 1 - pkt_id + // 2-3 - gen_id + // 4-(4+RESULT_LEN/2) - result + rd_addr <= 0; + end + + STATE_NUM_PROC0: begin + pkt_dout <= num_processed[15:0]; + pkt_empty <= 0; + state <= STATE_NUM_PROC1; + end + + STATE_NUM_PROC1: begin + pkt_dout <= num_processed[31:16]; + pkt_empty <= 0; + pkt_end <= 1; + state <= STATE_RD_PREPARE; + end + + STATE_WORD_ID: begin + pkt_dout <= din; + pkt_empty <= 0; + rd_addr <= 2; + state <= STATE_GEN_ID0; + end + + STATE_GEN_ID0: begin + pkt_dout <= din; + pkt_empty <= 0; + rd_addr <= rd_addr + 1'b1; + state <= STATE_GEN_ID1; + end + + STATE_GEN_ID1: begin + pkt_dout <= din; + pkt_empty <= 0; + rd_addr <= rd_addr + 1'b1; + state <= pkt_type == `OUTPKT_TYPE_CMP_RESULT + ? STATE_HASH_NUM : STATE_RESULT; + end + + STATE_HASH_NUM: begin + pkt_dout <= { {15-HASH_NUM_MSB{1'b0}}, hash_num }; + pkt_empty <= 0; + state <= STATE_RESULT; + end + + STATE_RESULT: begin + pkt_dout <= din; + pkt_empty <= 0; + rd_addr <= rd_addr + 1'b1; + if (rd_addr == 4 +`RESULT_LEN/2 -1) begin + pkt_end <= 1; + state <= STATE_RD_PREPARE; + end + end + + STATE_RD_PREPARE: begin + full <= 0; + state <= STATE_RD; + end + + STATE_RD: if (wr_en) begin + full <= 1; + state <= STATE_RD_WAIT; + end + + STATE_RD_WAIT: + state <= STATE_NONE; + + endcase + end + + + if (SIMULATION) begin + reg [15:0] PKT_count_cmp_eq = 0; + reg [15:0] PKT_count_done = 0; + reg [15:0] PKT_count_result = 0; + reg [15:0] PKT_count_other = 0; + always @(posedge CLK) + if (~full & wr_en) begin + if (pkt_type == `OUTPKT_TYPE_CMP_EQUAL) + PKT_count_cmp_eq <= PKT_count_cmp_eq + 1'b1; + else if (pkt_type == `OUTPKT_TYPE_PACKET_DONE) + PKT_count_done <= PKT_count_done + 1'b1; + else if (pkt_type == `OUTPKT_TYPE_RESULT) + PKT_count_result <= PKT_count_result + 1'b1; + else + PKT_count_other <= PKT_count_other + 1'b1; + end + end + + + assign checksum_wr_en = ~pkt_empty & ~checksum_full; + + outpkt_checksum outpkt_checksum( + .CLK(CLK), + .din(pkt_dout), .pkt_new(pkt_new), .pkt_end(pkt_end), + .wr_en(checksum_wr_en), .full(checksum_full), + + .dout(dout), .pkt_end_out(pkt_end_out), .rd_en(rd_en), .empty(empty) + ); + +endmodule diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/outpkt_checksum.v b/src/ztex/fpga-sha256crypt/pkt_comm/outpkt_checksum.v new file mode 100644 index 00000000000..a79f6b9ec14 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/outpkt_checksum.v @@ -0,0 +1,148 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +module outpkt_checksum( + input CLK, + input [15:0] din, + input pkt_new, // asserted on 1st word of packet header + input pkt_end, // asserted on last word of packet data + input wr_en, + output full, + output [15:0] dout, + output reg pkt_end_out = 0, + input rd_en, + output empty + ); + + localparam PKT_HEADER_LEN = 10; + + // 4-byte checksum: + // + // after packet header + // after each PKT_CHECKSUM_INTERVAL bytes <-- not implemented + // after the end of packet + localparam PKT_CHECKSUM_INTERVAL = 448; + + // Input register. + reg [15:0] input_r; + reg full_r = 0, pkt_new_r = 0, pkt_end_r = 0; + assign full = full_r; + + always @(posedge CLK) begin + if (wr_en & (~full_r | input_rd_en)) begin + input_r <= din; + pkt_new_r <= pkt_new; + pkt_end_r <= pkt_end; + full_r <= 1; + end + else if (input_rd_en) + full_r <= 0; + end + + // Output register. + reg [15:0] output_r; + assign dout = output_r; + reg empty_r = 1; + assign empty = empty_r; + + always @(posedge CLK) + if (rd_en & ~output_wr_en) + empty_r <= 1; + else if (output_wr_en & ~rd_en) + empty_r <= 0; + + + //(* USE_DSP48="true" *) + reg [31:0] checksum = 0; + reg [15:0] checksum_tmp = 0; + reg checksum_counter = 0; + //reg [`MSB(PKT_CHECKSUM_INTERVAL/2):0] word_counter = 0; + reg [`MSB(PKT_HEADER_LEN/2):0] word_counter = 0; + + localparam STATE_PKT_INPUT = 0, + STATE_CHECKSUM0 = 1, + STATE_CHECKSUM1 = 2, + STATE_CHECKSUM2 = 3; + + (* FSM_EXTRACT="true" *) + reg [1:0] state = STATE_PKT_INPUT; + + reg pkt_state = 0; // 0: packet header, 1: packet data + + // Read from input register. + assign input_rd_en = + full_r & (state == STATE_PKT_INPUT) + & (empty_r | ~empty_r & rd_en); + + // Write into output register. + assign output_wr_en = + (full_r & (state == STATE_PKT_INPUT) + | (state == STATE_CHECKSUM1 | state == STATE_CHECKSUM2)) + & (empty_r | ~empty_r & rd_en); + + always @(posedge CLK) begin + if (state == STATE_PKT_INPUT) begin + if (output_wr_en) begin + + output_r <= input_r; + pkt_end_out <= 0; + + if (pkt_new_r | ~checksum_counter) begin + checksum_tmp <= input_r; + checksum_counter <= 1; + end + else if (checksum_counter) begin + checksum <= checksum + {input_r, checksum_tmp}; + checksum_counter <= 0; + end + + if (~pkt_state & word_counter == PKT_HEADER_LEN/2 - 1 + //| word_counter == PKT_CHECKSUM_INTERVAL/2 - 1 + | pkt_end_r + ) begin + if (~checksum_counter) + state <= STATE_CHECKSUM0; + else + state <= STATE_CHECKSUM1; + end + else + word_counter <= word_counter + 1'b1; + end // input_rd_en + end + + else if (state == STATE_CHECKSUM0) begin + checksum <= checksum + checksum_tmp; + state <= STATE_CHECKSUM1; + end + + else if (state == STATE_CHECKSUM1) begin + if (output_wr_en) begin + output_r <= ~checksum[15:0]; + state <= STATE_CHECKSUM2; + end + end + + else if (state == STATE_CHECKSUM2) begin + if (output_wr_en) begin + output_r <= ~checksum[31:16]; + if (pkt_state) + pkt_end_out <= 1; + checksum_counter <= 0; + checksum <= 0; + + pkt_state <= ~pkt_state; + word_counter <= 0; + state <= STATE_PKT_INPUT; + end + end + end + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/pkt_comm_test_helper.vh b/src/ztex/fpga-sha256crypt/pkt_comm/pkt_comm_test_helper.vh new file mode 100644 index 00000000000..5e3bd0cf349 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/pkt_comm_test_helper.vh @@ -0,0 +1,328 @@ +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`ifndef _PKT_COMM_TEST_HELPER_VH_ +`define _PKT_COMM_TEST_HELPER_VH_ + +// *************************************************************** +// +// Helper functions to create pkt_comm packets. +// Operates 8-bit input: +// reg [7:0] din +// reg wr_en +// +// *************************************************************** + + +// *************************************************************** +// +// Packet type PKT_TYPE_CONFIG (0x06) +// +// *************************************************************** +task send_config_packet; + input [7:0] subtype; + input [7:0] len; // data length (excl. subtype & reserved) + input [511:0] data; // 64 max. + begin: doit + integer i; + wr_en <= 1; + din <= 2; #20; din <= 6; #20; // ver, type + din <= 0; #40; // reserved0 + din <= len+2; #20; din <= 0; #20; + din <= 0; #20; + din <= 0; #20; // reserved1 + din <= 8'h00; #40; // IDs in PKT_TYPE_CONFIG not used + din <= 0; #80; // checksum + // body + din <= subtype; #20; + for (i = 0; i < len; i=i+1) begin + din <= data[i*8 +:8]; #20; + end + din <= 0; #20; // reserved + din <= 0; #80; // checksum + wr_en <= 0; + end +endtask + + +// *************************************************************** +// +// Packet type PKT_TYPE_INIT (0x05) +// +// *************************************************************** +task send_init_packet; + input [7:0] data; + begin + wr_en <= 1; + din <= 2; #20; din <= 5; #20; // ver, type + din <= 0; #40; // reserved0 + din <= 1; #20; din <= 0; #20; // len=1 + din <= 0; #20; + din <= 0; #20; // reserved1 + din <= 8'h00; #40; // IDs in PKT_TYPE_INIT not used + din <= 0; #80; // checksum + // body + din <= data; #20; + din <= 0; #80; // checksum + wr_en <= 0; + end +endtask + + +// *************************************************************** +// +// Packet type CMP_CONFIG (0x03) +// +// *************************************************************** +integer cmp_iter_count, cmp_salt_len, cmp_num_hashes; +reg [0:8*16-1] cmp_salt; +reg [0:32*`NUM_HASHES-1] cmp_hashes; + +task cmp_config_create; + input [31:0] iter_count; + input [7:0] salt_len; + input [0:8*16-1] salt; + begin: doit + integer i, salt_ptr; + salt_ptr = 0; + + cmp_iter_count = iter_count; + cmp_salt_len = salt_len; + for (i=0; i < 16; i=i+1) + if (salt[8*i +:8] != 0) begin + cmp_salt[8*salt_ptr +:8] = salt[8*i +:8]; + salt_ptr = salt_ptr + 1; + end + for (i=salt_ptr; i < 16; i=i+1) + cmp_salt[8*i +:8] = 0; + cmp_num_hashes = 0; + end +endtask + + +task cmp_config_add_hash; + input [31:0] hash; + begin + cmp_hashes [cmp_num_hashes*32 +:32] + <= { hash[7:0], hash[15:8], hash[23:16], hash[31:24] }; + cmp_num_hashes = cmp_num_hashes + 1; + end +endtask + + +task send_cmp_config; + begin: doit + integer i, len; + len = 18 + 4 + 2 + 4*cmp_num_hashes + 1; + + wr_en <= 1; + din <= 2; #20; din <= 3; #20; // ver, type + din <= 0; #40; // reserved0 + din <= len[7:0]; #20; din <= len[15:8]; #20; + din <= len[23:16]; #20; + din <= 0; #20; // reserved1 + din <= 8'h00; #40; // IDs in CMP_CONFIG not used + din <= 0; #80; // checksum + // body + din <= 0; #20; // unused (1 byte), must be 0 + din <= cmp_salt_len; #20; // salt_len (1 byte) + for (i=0; i < 16; i=i+1) begin + din <= cmp_salt[i*8 +:8]; #20; + end + din <= cmp_iter_count[7:0]; #20; + din <= cmp_iter_count[15:8]; #20; + din <= cmp_iter_count[23:16]; #20; + din <= cmp_iter_count[31:24]; #20; + + din <= cmp_num_hashes[7:0]; #20; + din <= cmp_num_hashes[15:8]; #20; + for (i=0; i < 4*cmp_num_hashes; i=i+1) begin + din <= cmp_hashes[8*i +:8]; #20; + end + + din <= 8'hCC; #20; + din <= 0; #80; + wr_en <= 0; + end +endtask + + +// *************************************************************** +// +// Packet type WORD_GEN (0x02) +// +// ***************************************************************** +task send_empty_word_gen; + input [15:0] pkt_id; + begin + // WORD_GEN packet (type 2), "empty" (words pass-by) + wr_en <= 1; + din <= 2; #20; din <= 2; #20; din <= 0; #40; + din <= 6; #20; // len[7:0] + din <= 0; #60; + din <= pkt_id[7:0]; #20; din <= pkt_id[15:8]; #20; + din <= 0; #80; // checksum + din <= 0; #20; // num_ranges + din <= 0; #80; din <= 8'hbb; #20; + din <= 0; #80; // checksum + wr_en <= 0; + end +endtask + + +integer word_gen_num_ranges = 0; +integer word_gen_total_num_chars = 0; +reg [8:0] word_gen_range_num_chars [0:3]; +reg [7:0] word_gen_chars [0:1023]; // up to 4 ranges X 256 chars +reg [8:0] num_chars; + +task word_gen_add_range; + input [0 :8*256-1] chars; + begin: doit + integer i, num_chars; + num_chars = 0; + + for (i=0; i < 256; i=i+1) + if (chars[8*i +:8] != 0) begin + word_gen_chars[256*word_gen_num_ranges + num_chars] + = chars[8*i +:8]; + num_chars = num_chars + 1; + word_gen_total_num_chars = word_gen_total_num_chars + 1; + end + + word_gen_range_num_chars [word_gen_num_ranges] = num_chars; + word_gen_num_ranges = word_gen_num_ranges + 1; + end +endtask + +task send_word_gen; + input [15:0] pkt_id; + begin: doit + integer i, j, len; + len = 6 + 2*word_gen_num_ranges + word_gen_total_num_chars; + + wr_en <= 1; + din <= 2; #20; din <= 2; #20; din <= 0; #40; + din <= len[7:0]; #20; din <= len[15:8]; #20; + din <= 0; #40; + din <= pkt_id[7:0]; #20; din <= pkt_id[15:8]; #20; + din <= 0; #80; // checksum + // body + din <= word_gen_num_ranges; #20; + for (i=0; i < word_gen_num_ranges; i=i+1) begin + din <= word_gen_range_num_chars[i]; #20; + din <= 0; #20; + for (j=0; j < word_gen_range_num_chars[i]; j=j+1) begin + din <= word_gen_chars [256*i+j]; #20; + end + end + din <= 0; #80; din <= 8'hbb; #20; + din <= 0; #80; // checksum + wr_en <= 0; + + word_gen_num_ranges = 0; + word_gen_total_num_chars = 0; + end +endtask + + +// *************************************************************** +// +// Packet type WORD_LIST (0x01), TEMPLATE_LIST (0x04) +// +// ***************************************************************** +integer word_list_total_len = 0; +reg [0:2**16-1] word_list_data; // 8 Kbytes +integer is_template_list = 0; + +task word_list_add; + input [0: 8*`PLAINTEXT_LEN-1] word; // up to 64 bytes + begin: doit + integer word_len, cur_off; + word_len = 0; + + for (cur_off=0; cur_off < `PLAINTEXT_LEN; cur_off=cur_off+1) + if (word [8*cur_off +:8] != 0) begin + word_list_data [8*word_list_total_len +:8] + = word [8*cur_off +:8]; + word_len = word_len + 1; + word_list_total_len = word_list_total_len + 1; + end + + // Add trailing '\0' where necessary + if (word_len < `PLAINTEXT_LEN) begin + word_list_data [8*word_list_total_len +:8] = 8'h00; + word_list_total_len = word_list_total_len + 1; + end + end +endtask + +task range_info_add; + input [7:0] pos0, pos1, pos2, pos3; + begin: doit + integer cnt; + cnt = 0; + + wr_en <= 1; + if (pos0 != 0) begin + word_list_data [8*word_list_total_len +:8] = pos0; + word_list_total_len = word_list_total_len + 1; + cnt = cnt + 1; + end + if (pos1 != 0) begin + word_list_data [8*word_list_total_len +:8] = pos1; + word_list_total_len = word_list_total_len + 1; + cnt = cnt + 1; + end + if (pos2 != 0) begin + word_list_data [8*word_list_total_len +:8] = pos2; + word_list_total_len = word_list_total_len + 1; + cnt = cnt + 1; + end + if (pos3 != 0) begin + word_list_data [8*word_list_total_len +:8] = pos3; + word_list_total_len = word_list_total_len + 1; + cnt = cnt + 1; + end + if (cnt < 4) begin + word_list_data [8*word_list_total_len +:8] = 0; + word_list_total_len = word_list_total_len + 1; + end + wr_en <= 0; + is_template_list = 1; + end +endtask + + +task send_word_list; + begin: doit + integer cur_off; + + wr_en <= 1; + // header + din <= 2; #20; + din <= is_template_list ? 4 : 1; #20; + din <= 0; #40; + din <= word_list_total_len[7:0]; #20; // len[7:0] + din <= word_list_total_len[15:8]; #20; // len[15:8] + din <= 0; #40; din <= 8'h07; #40; din <= 0; #80; + // body + for (cur_off=0; cur_off < word_list_total_len; + cur_off=cur_off+1) begin + din <= word_list_data [8*cur_off +:8]; #20; + end + din <= 0; #80; // checksum + wr_en <= 0; + + word_list_total_len = 0; + is_template_list = 0; + end +endtask + + +`endif diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/template_list_b_varlen.v b/src/ztex/fpga-sha256crypt/pkt_comm/template_list_b_varlen.v new file mode 100644 index 00000000000..f2f3f6d1e76 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/template_list_b_varlen.v @@ -0,0 +1,208 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// ******************************************************************** +// +// template_list_b: stores the word into 8-bit wide memory. +// Variable word length: not padded with zeroes, length is output. +// +// template_list is going to replace word_list. +// +// * Designed for usage with word_gen_b +// +// * Accepts both PKT_TYPE_WORD_LIST and PKT_TYPE_TEMPLATE_LIST +// +// * If word length is WORD_MAX_LEN, then it isn't followed by '\0'; +// shorter words are '\0' terminated. +// +// * In PKT_TYPE_TEMPLATE_LIST, each word is followed by +// RANGE_INFO records: RANGES_MAX records 1 byte each. +// If some RANGE_INFO record is zero, then it was the last range_info +// for the template key. +// +// * Last word is followed by a dummy word with word_list_end asserted +// +// ******************************************************************** + +module template_list_b_varlen #( + parameter WORD_MAX_LEN = -1, + parameter RANGES_MAX = -1, + parameter RANGE_INFO_MSB = 1 + `MSB(WORD_MAX_LEN-1) + )( + input CLK, + + input [7:0] din, + input wr_en, + output reg full = 1, + input inpkt_end, + input is_template_list, + + output reg [RANGES_MAX * (RANGE_INFO_MSB+1) - 1 :0] range_info = 0, + output reg [15:0] word_id = 0, + // It produces a dummy word after the end of the list, + // with word_list_end set + output word_list_end, + + // Output from 8-bit wide word_storage + output [7:0] dout, + input [`MSB(WORD_MAX_LEN-1):0] rd_addr, + output reg [`MSB(WORD_MAX_LEN):0] word_len = 0, + input set_empty, + output empty, + output reg totally_empty = 1, + + output reg err_template = 0, err_word_list_count = 0 + ); + + // Storage for output generated word + reg [`MSB(WORD_MAX_LEN-1):0] storage_wr_addr = 0; + reg storage_set_full = 0; + + reg [`MSB(RANGES_MAX-1):0] range_info_count = 0; + reg word_list_end_r = 0; + + localparam [2:0] STATE_INIT = 0, + STATE_WR_WORD = 1, + //STATE_PAD_ZEROES = 2, + STATE_WR_RANGE_INFO = 3, + STATE_RD_START = 4, + STATE_RD_WAIT = 5, + STATE_RD_LIST_END_START = 6, + STATE_RD_LIST_END_WAIT = 7; + + (* FSM_EXTRACT="true" *) + reg [2:0] state = STATE_INIT; + + always @(posedge CLK) begin + case (state) + STATE_INIT: begin + range_info <= 0; + range_info_count <= 0; + word_list_end_r <= 0; + storage_wr_addr <= 0; + full <= 0; + word_len <= 0; + totally_empty <= 1; + state <= STATE_WR_WORD; + end + + STATE_WR_WORD: if (wr_en) begin + totally_empty <= 0; + if (din != 0) begin + word_len <= word_len + 1'b1; + storage_wr_addr <= storage_wr_addr + 1'b1; + end + + if (din == 0 | storage_wr_addr == WORD_MAX_LEN - 1) begin + // word ends; word of zero length - OK, permitted + if (~is_template_list) begin + full <= 1; + storage_set_full <= 1; + state <= STATE_RD_START; + end + else + state <= STATE_WR_RANGE_INFO; + end + + if (inpkt_end) begin + word_list_end_r <= 1; + if ((din != 0 & storage_wr_addr != WORD_MAX_LEN - 1) + | is_template_list) + // inexpected pkt_end + err_template <= 1; + end + end + + STATE_WR_RANGE_INFO: if (wr_en) begin + range_info_count <= range_info_count + 1'b1; + + if (din == 0) begin + // range_info ends + full <= 1; + storage_set_full <= 1; + state <= STATE_RD_START; + end + else begin + // next item of range_info going + range_info[(range_info_count + 1'b1)*(RANGE_INFO_MSB+1)-1 + -:RANGE_INFO_MSB+1] + <= { din[7], din[RANGE_INFO_MSB-1:0] }; + + if (WORD_MAX_LEN < 64 + && din[6 : RANGE_INFO_MSB >= 6 ? 6 : RANGE_INFO_MSB+1] != 0) + // unexpected content in range_info + err_template <= 1; + + if (range_info_count == RANGES_MAX - 1) begin + full <= 1; + storage_set_full <= 1; + state <= STATE_RD_START; + end + end + + if (inpkt_end) begin + word_list_end_r <= 1; + if (din != 0 && range_info_count != RANGES_MAX - 1) + // inexpected pkt_end + err_template <= 1; + end + end + + STATE_RD_START: begin + storage_set_full <= 0; + state <= STATE_RD_WAIT; + end + + // Wait until the reader reads it + STATE_RD_WAIT: if (~storage_full) begin + if (word_list_end_r) begin + storage_set_full <= 1; + word_id <= 0; + state <= STATE_RD_LIST_END_START; + end + else begin + word_id <= word_id + 1'b1; + state <= STATE_INIT; + end + + if ( ~|(word_id + 1'b1) ) + // word_id_r overflows + err_word_list_count <= 1; + end + + // Write dummy word after the end of the list, + // with word_list_end set + STATE_RD_LIST_END_START: begin + storage_set_full <= 0; + state <= STATE_RD_LIST_END_WAIT; + end + + STATE_RD_LIST_END_WAIT: if (~storage_full) + state <= STATE_INIT; + + endcase + end + + assign storage_wr_en = wr_en & state == STATE_WR_WORD; + + assign word_list_end = state == STATE_RD_LIST_END_WAIT; + + word_storage #( .WORD_MAX_LEN(WORD_MAX_LEN) + ) word_storage( + .CLK(CLK), + .din(din), .wr_addr(storage_wr_addr), .wr_en(storage_wr_en), + .set_full(storage_set_full), .full(storage_full), + + .dout(dout), .rd_addr(rd_addr), .set_empty(set_empty), + .empty(empty) + ); + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/word_gen_b_varlen.v b/src/ztex/fpga-sha256crypt/pkt_comm/word_gen_b_varlen.v new file mode 100644 index 00000000000..6c7e06c9e82 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/word_gen_b_varlen.v @@ -0,0 +1,391 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +//********************************************************************** +// +// word_gen_b_varlen: inputs and outputs using 8-bit wide memory. Area optimized. +// Variable word length: not padded with zeroes, length is supplied/output, +// words don't end with '\0'. +// +// Version 2 of word generator. +// +// * Designed to work with template_list. +// * Interface difference is that word_len input is removed, +// range_info input is added. +// * Items removed from configuration: num_words, word_insert_pos +// * Removed mode of operation not based on supplied words. +// +// +// Word Generator +// +// * Words are produced every cycle (as long as reader is not full). +// * Delay when getting a new word from word_list: +// 1 cycle if start_idx's not used, 3 if used. +// * There's a delay when it loads a new configuration for word generator, +// equal to number of bytes in configuration at CLK frequency +// plus few more cycles. +// +//********************************************************************** + +module word_gen_b_varlen #( + parameter RANGES_MAX = -1, + parameter WORD_MAX_LEN = -1, + parameter RANGE_INFO_MSB = 1 + `MSB(WORD_MAX_LEN-1) + )( + input CLK, + + // Word generator configuration. + input [7:0] din, + input [15:0] inpkt_id, + input conf_wr_en, + output reg conf_full = 0, + + // Words are read from byte-wide memory. + input [7:0] word_in, + output reg [`MSB(WORD_MAX_LEN-1):0] word_rd_addr = 0, + input word_empty, + output word_set_empty, + // Each word is supplied with extra data. + input [RANGES_MAX * (RANGE_INFO_MSB+1) - 1 :0] range_info, + input [15:0] word_id, + input [`MSB(WORD_MAX_LEN):0] word_len, + input word_list_end, + + // Output from 8-bit wide word_storage + output [7:0] dout, + input [`MSB(WORD_MAX_LEN-1):0] rd_addr, + input set_empty, + output empty, + + output reg [15:0] pkt_id, + output reg [15:0] word_id_out, + output reg [`MSB(WORD_MAX_LEN):0] word_len_out, + // Number of generated word (resets on each inserted word) + //(* USE_DSP48="true" *) + output reg [31:0] gen_id = 0, + output reg gen_end = 0, // after last candidate from last word in word_list, + // it generates extra dummy candidate with gen_end set + //output word_end, // asserts on last candidate from each word + output reg totally_empty = 1, + + output err_word_gen_conf + ); + + integer k; + + // ******************************************************************* + // + // Configuration (word_gen.h) + // + // struct word_gen_char_range { + // unsigned char num_chars; // number of chars in range + // unsigned char start_idx; // unused + // unsigned char chars[256]; // only num_chars transmitted + // }; + // range must have at least 1 char + // + // struct word_gen { + // unsigned char num_ranges; + // struct word_gen_char_range ranges[RANGES_MAX]; // only num_ranges transmitted + // uint32_t num_generate; // unused + // unsigned char magic; // 0xBB + // }; + // + // example word generator (words pass-by): + // { + // 0, // num_ranges + // 0, // num_generate (unused) + // 0xBB + // }; + // + // ******************************************************************* + + localparam NUM_RANGES_MSB = `MSB(RANGES_MAX-1); + + // Number of the last range (num_ranges - 1) + reg [NUM_RANGES_MSB:0] last_range_num; + reg zero_ranges_active = 1; + + // ******************************************************************* + + (* RAM_STYLE="DISTRIBUTED" *) + reg [7:0] range_counter [RANGES_MAX-1 :0]; // Points at the next char in the range + (* RAM_STYLE="DISTRIBUTED" *) + reg [7:0] range_count_max [RANGES_MAX-1 :0]; // Contains max. value for range_counter + + reg [7:0] cur_range_count = 0; + reg [`MSB(RANGES_MAX-1):0] cur_range = 0; + reg range_carry = 1; + + wire [7:0] range_char; + + // Upper bit indicates range is active + reg [RANGES_MAX * (RANGE_INFO_MSB+1) - 1 :0] range_info_r; + + wire cur_range_active = range_info_r [(cur_range+1)*(RANGE_INFO_MSB+1)-1]; + wire [RANGE_INFO_MSB-1:0] cur_range_pos + = range_info_r [(cur_range+1)*(RANGE_INFO_MSB+1)-2 -:RANGE_INFO_MSB]; + + + wire [7:0] din_minus_1 = din - 1'b1; + + + localparam CONF_NUM_RANGES = 0, + CONF_RANGE_NUM_CHARS = 1, + CONF_RANGE_START_IDX = 2, + CONF_RANGE_CHARS = 3, + CONF_NUM_GENERATE0 = 4, + CONF_NUM_GENERATE1 = 5, + CONF_NUM_GENERATE2 = 6, + CONF_NUM_GENERATE3 = 7, + CONF_MAGIC = 8, + CONF_ERROR = 9, + OP_RESET = 10, + OP_COPY_NEXT_WORD = 11, + OP_NEXT_RANGE_1 = 12, + OP_NEXT_RANGE_2 = 13, + OP_NEXT_RANGE_WR = 14, + OP_WAIT_READ = 15; + + (* FSM_EXTRACT = "true" *) + reg [3:0] state = CONF_NUM_RANGES; + + always @(posedge CLK) begin + case (state) + // + // Generator configuration. + // + CONF_ERROR: begin + end + + CONF_NUM_RANGES: if (conf_wr_en) begin + totally_empty <= 0; + zero_ranges_active <= 1; + pkt_id <= inpkt_id; + last_range_num <= din_minus_1[NUM_RANGES_MSB:0]; + cur_range <= 0; + // Num. of ranges exceeds RANGES_MAX + if (din > RANGES_MAX) + state <= CONF_ERROR; + else if (din[`MSB(RANGES_MAX):0] != 0) + state <= CONF_RANGE_NUM_CHARS; + else + state <= CONF_NUM_GENERATE0; + end + + CONF_RANGE_NUM_CHARS: if (conf_wr_en) begin + zero_ranges_active <= 0; + range_count_max[cur_range] <= din_minus_1; + cur_range_count <= 0; + // Wrong number of chars in range + //if (din == 0) // <-- allow 256 chars + // state <= CONF_ERROR; + //else + state <= CONF_RANGE_START_IDX; + end + + CONF_RANGE_START_IDX: if (conf_wr_en) + state <= CONF_RANGE_CHARS; + + CONF_RANGE_CHARS: if (conf_wr_en) begin + //ranges [{cur_range, cur_range_count}] <= din; + cur_range_count <= cur_range_count + 1'b1; + + if (cur_range_count == range_count_max[cur_range]) begin + cur_range <= cur_range + 1'b1; + + if (cur_range == last_range_num) + state <= CONF_NUM_GENERATE0; + else + state <= CONF_RANGE_NUM_CHARS; + end + end + + CONF_NUM_GENERATE0: if (conf_wr_en) + state <= CONF_NUM_GENERATE1; + + CONF_NUM_GENERATE1: if (conf_wr_en) + state <= CONF_NUM_GENERATE2; + + CONF_NUM_GENERATE2: if (conf_wr_en) + state <= CONF_NUM_GENERATE3; + + CONF_NUM_GENERATE3: if (conf_wr_en) + state <= CONF_MAGIC; + + CONF_MAGIC: if (conf_wr_en) begin + conf_full <= 1; + if (din == 8'hBB) begin + cur_range <= 0; + state <= OP_RESET; + end + else + state <= CONF_ERROR; + end + + // + // Generator operation. + // + OP_RESET: begin // Prepare to process next input word + word_rd_addr <= 0; + storage_wr_addr <= 0; + + range_counter[cur_range] <= 0; + cur_range <= cur_range + 1'b1; + if (cur_range == RANGES_MAX - 1) + state <= OP_COPY_NEXT_WORD; + end + + // Start processing new input word - copy into output word_storage + OP_COPY_NEXT_WORD: if (~word_empty) begin + word_rd_addr <= word_rd_addr + 1'b1; + storage_wr_addr <= storage_wr_addr + 1'b1; + cur_range <= last_range_num; + range_carry <= 1; + + if (word_list_end) + state <= OP_WAIT_READ; + else if (storage_wr_addr + 1'b1 == word_len + | word_len == 0) begin + if (~zero_ranges_active) + state <= OP_NEXT_RANGE_1; + else + state <= OP_WAIT_READ; + end + + range_info_r <= range_info; + + // Also copy IDs + word_id_out <= word_id; + word_len_out <= word_len; + gen_end <= word_list_end; + gen_id <= 0; + end + + OP_NEXT_RANGE_1: begin + cur_range_count <= range_counter[cur_range]; + state <= OP_NEXT_RANGE_2; + end + + OP_NEXT_RANGE_2: begin + if (range_carry) begin // Advance to the next char in the range + if (cur_range_count == range_count_max[cur_range]) begin + range_counter[cur_range] <= 0; + range_carry <= 1; + end + else begin + range_counter[cur_range] <= cur_range_count + 1'b1; + range_carry <= 0; + end + end + storage_wr_addr <= cur_range_pos; + // Get the char from ranges + //range_char <= ranges [{cur_range, cur_range_count}]; + state <= OP_NEXT_RANGE_WR; + end + + OP_NEXT_RANGE_WR: begin // Write word_storage + // Advance pointer to the next range + cur_range <= cur_range - 1'b1; + if (cur_range == 0) + state <= OP_WAIT_READ; + else + state <= OP_NEXT_RANGE_1; + end + + // Wait until the reader reads generated word from the storage + OP_WAIT_READ: if (~storage_full) begin + range_carry <= 1; + gen_id <= gen_id + 1'b1; + + if (gen_end) begin//word_list_end) begin + cur_range <= 0; + conf_full <= 0; + totally_empty <= 1; + state <= CONF_NUM_RANGES; + end + else if (range_carry) begin // Generation for this input word is over + cur_range <= 0; + state <= OP_RESET; + end + else begin + cur_range <= last_range_num; + state <= OP_NEXT_RANGE_1; + end + end + endcase + end + + assign storage_wr_en = state == OP_COPY_NEXT_WORD + | state == OP_NEXT_RANGE_WR; + + assign storage_set_full = (state == OP_NEXT_RANGE_WR & cur_range == 0) + | state == OP_COPY_NEXT_WORD & ~word_empty + & ( (storage_wr_addr + 1'b1 == word_len | word_len == 0) + & zero_ranges_active | word_list_end); + + // set-empty-after-copy + assign word_set_empty = state == OP_COPY_NEXT_WORD & ~word_empty + & (storage_wr_addr + 1'b1 == word_len | word_len == 0 + | word_list_end); + + assign err_word_gen_conf = state == CONF_ERROR; + + + // Storage for range characters + wire ram_wr_en = state == CONF_RANGE_CHARS && conf_wr_en; + + word_gen_ram #( .RANGES_MAX(RANGES_MAX) + ) word_gen_ram( + .CLK(CLK), .din(din), .addr({cur_range, cur_range_count}), + .en(ram_wr_en || state == OP_NEXT_RANGE_2), .wr_en(ram_wr_en), + .dout(range_char) + ); + + + // Storage for output generated word + reg [`MSB(WORD_MAX_LEN-1):0] storage_wr_addr = 0; + + word_storage #( .WORD_MAX_LEN(WORD_MAX_LEN) + ) word_storage( + .CLK(CLK), + .din(state == OP_COPY_NEXT_WORD ? word_in : range_char), + .wr_addr(storage_wr_addr), .wr_en(storage_wr_en), + .set_full(storage_set_full), .full(storage_full), + + .dout(dout), .rd_addr(rd_addr), .set_empty(set_empty), .empty(empty) + ); + +endmodule + + +module word_gen_ram #( + parameter RANGES_MAX = -1 + )( + input CLK, + input [7:0] din, + input [`MSB(RANGES_MAX-1)+1 +7:0] addr, + input en, + input wr_en, + output reg [7:0] dout = 0 + ); + + (* RAM_STYLE="BLOCK" *) + //(* RAM_STYLE="DISTRIBUTED" *) + reg [7:0] ranges [256*RANGES_MAX-1 :0]; + + always @(posedge CLK) if (en) + if (wr_en) + ranges [addr] <= din; + else + dout <= ranges [addr]; + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/pkt_comm/word_storage.v b/src/ztex/fpga-sha256crypt/pkt_comm/word_storage.v new file mode 100644 index 00000000000..f83bab79980 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/pkt_comm/word_storage.v @@ -0,0 +1,64 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// ******************************************************************** +// +// ******************************************************************** + +module word_storage #( + parameter WORD_MAX_LEN = -1 + )( + input CLK, + + input [7:0] din, + input [`MSB(WORD_MAX_LEN-1):0] wr_addr, + input wr_en, + input set_full, + output reg full = 0, + + // Asynchronous read + output [7:0] dout, + input [`MSB(WORD_MAX_LEN-1):0] rd_addr, + //input rd_en, + input set_empty, + output empty + ); + + assign empty = ~full; + + (* RAM_STYLE="DISTRIBUTED" *) + reg [7:0] storage [0: WORD_MAX_LEN-1]; + assign dout = storage [rd_addr]; + + localparam STATE_WR = 0, + STATE_RD = 1; + + (* FSM_EXTRACT="true" *) + reg [1:0] state = STATE_WR; + + always @(posedge CLK) begin + case (state) + STATE_WR: begin + if (wr_en) + storage [wr_addr] <= din; + if (set_full) begin + full <= 1; + state <= STATE_RD; + end + end + + STATE_RD: if (set_empty) begin + full <= 0; + state <= STATE_WR; + end + endcase + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt.xds b/src/ztex/fpga-sha256crypt/sha256crypt.xds new file mode 100644 index 00000000000..f8a3d55c88f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt.xds @@ -0,0 +1,38 @@ + + + + The Default strategy provides a balanced optimization of performance results vs. runtime. The default property values correspond to the default values of each of the underlying implementation tools. This strategy keeps all properties in an unlocked state so that you can modify the values as you wish. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/arbiter_rx.v b/src/ztex/fpga-sha256crypt/sha256crypt/arbiter_rx.v new file mode 100644 index 00000000000..911cb0295f8 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/arbiter_rx.v @@ -0,0 +1,231 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// +// Unit output packet format: +// - header (1 word) +// - IDs (64 bits) +// - SHA256 hash (256 bits) +// +// Total: 32+8 = 40 bytes +// +module arbiter_rx #( + parameter N_UNITS = -1, + parameter UNIT_OUTPUT_WIDTH = -1, + parameter PKT_NUM_WORDS = 20 + )( + input CLK, + input mode_cmp, + // Units + input [UNIT_OUTPUT_WIDTH * N_UNITS -1 :0] unit_dout, + output reg [N_UNITS-1:0] unit_rd_en = 0, + input [N_UNITS-1:0] unit_empty, + // Iteraction with arbiter_tx + input [31:0] num_processed_tx, + input [15:0] pkt_id_tx, + input pkt_tx_done, + output reg pkt_rx_done = 0, + output reg recv_item = 0, // asserts for 1 for every RX item + // Comparator + output reg [31:0] cmp_data, + output reg cmp_start = 0, + input cmp_found, cmp_finished, + input [`HASH_NUM_MSB:0] cmp_hash_num, + // Output + output reg [`OUTPKT_TYPE_MSB:0] outpkt_type, + output [15:0] dout, + input [`MSB(PKT_NUM_WORDS-1):0] rd_addr, + output reg [15:0] pkt_id, + output reg [31:0] num_processed = 0, + output reg [`HASH_NUM_MSB:0] hash_num, + input rd_en, + output reg empty = 1, + + output reg [1:0] err = 0, + output reg [15:0] debug = 0 + ); + + reg [`MSB(N_UNITS-1):0] unit_num = 0; + reg [UNIT_OUTPUT_WIDTH-1 :0] din = 0; + reg unit_empty_r = 1; + always @(posedge CLK) begin + din <= unit_dout [unit_num * UNIT_OUTPUT_WIDTH +:UNIT_OUTPUT_WIDTH]; + unit_empty_r <= unit_empty [unit_num]; + end + + (* RAM_STYLE="DISTRIBUTED" *) + reg [15:0] output_r [0:PKT_NUM_WORDS-1]; + assign dout = output_r [rd_addr]; + + reg rd_tmp_wr_en = 0; + reg [`MSB(PKT_NUM_WORDS-1):0] rd_tmp_wr_addr = 0; + always @(posedge CLK) + if (rd_tmp_wr_en) + output_r [rd_tmp_wr_addr] <= rd_tmp; + + + reg [2:0] rd_count = 0; + reg [15:0] rd_tmp = 0; + reg [`MSB(PKT_NUM_WORDS-1):0] result_word_count = 0; + + reg [31:0] delay_shr = 0; + + localparam STATE_IDLE = 0, + STATE_WAIT = 1, + STATE_WAIT2 = 2, + STATE_READ = 3, + STATE_RX_HEADER = 4, + STATE_RX_DATA = 5, + STATE_RX_END = 6, + STATE_CMP = 7, + STATE_OUTPKT_RESULT = 8, + STATE_PKT_ACCOUNT = 9, + STATE_OUTPKT_PROCESSING_DONE = 10; + + (* FSM_EXTRACT="true" *) + reg [3:0] state = STATE_IDLE; + + always @(posedge CLK) begin + if (rd_tmp_wr_en) + rd_tmp_wr_en <= 0; + + if (cmp_start) + cmp_start <= 0; + + if (pkt_rx_done) + pkt_rx_done <= 0; + + if (recv_item) + recv_item <= 0; + + if (state == STATE_IDLE | delay_shr[31]) + delay_shr <= { delay_shr[30:0], state == STATE_IDLE }; + + case (state) + STATE_IDLE: if (delay_shr[31]) + state <= STATE_WAIT; + + STATE_WAIT: + if (~unit_empty_r)// [unit_num]) + state <= STATE_READ; + else begin + unit_num <= unit_num == N_UNITS-1 + ? {`MSB(N_UNITS-1)+1{1'b0}} : unit_num + 1'b1; + state <= STATE_WAIT2; + end + + STATE_WAIT2: + state <= STATE_WAIT; + + STATE_READ: begin + recv_item <= 1; + unit_rd_en [unit_num] <= 1; + state <= STATE_RX_HEADER; + end + + STATE_RX_HEADER: begin + unit_rd_en <= 0; + result_word_count <= 0; + if (din != 0) begin + if (din != {UNIT_OUTPUT_WIDTH{1'b1}}) begin + err[0] <= 1; + debug [unit_num] <= 1; + end + else + state <= STATE_RX_DATA; + end + end + + // Collect PKT_NUM_WORDS words X 16 bit in output_r + STATE_RX_DATA: begin + rd_tmp [rd_count * UNIT_OUTPUT_WIDTH +:UNIT_OUTPUT_WIDTH] + <= din; + rd_count <= rd_count + 1'b1; + if (rd_count == (16 / UNIT_OUTPUT_WIDTH) -1) begin + rd_tmp_wr_en <= 1; + rd_tmp_wr_addr <= result_word_count; + result_word_count <= result_word_count + 1'b1; + if (result_word_count == PKT_NUM_WORDS-1) + state <= STATE_RX_END; + end + + // 2nd 16-bit word: pkt_id + if (result_word_count == 2 & rd_count == 0) + pkt_id <= rd_tmp; + + // externalize comparator data, start comparison + // before all the data received from a computing unit + if (result_word_count == 5 & rd_count == 0) + cmp_data[15:0] <= rd_tmp; + if (result_word_count == 6 & rd_count == 0) begin + cmp_data[31:16] <= rd_tmp; + cmp_start <= 1; + end + end + + STATE_RX_END: begin + outpkt_type <= `OUTPKT_TYPE_RESULT; + if (din != 0) begin + err[1] <= 1; + debug [unit_num] <= 1; + end + else if (mode_cmp) + state <= STATE_CMP; + else begin + empty <= 0; + state <= STATE_OUTPKT_RESULT; + end + end + + STATE_CMP: begin + if (cmp_found) begin + outpkt_type <= `OUTPKT_TYPE_CMP_RESULT; + hash_num <= cmp_hash_num; + empty <= 0; + state <= STATE_OUTPKT_RESULT; + end + else if (cmp_finished) + state <= STATE_PKT_ACCOUNT; + end + + // output PKT_RESULT or PKT_CMP_RESULT + STATE_OUTPKT_RESULT: if (rd_en) begin + empty <= 1; + if (mode_cmp) + state <= STATE_PKT_ACCOUNT; + else + state <= STATE_WAIT; + end + + STATE_PKT_ACCOUNT: begin + outpkt_type <= `OUTPKT_TYPE_PACKET_DONE; + num_processed <= num_processed + 1'b1; + pkt_id <= pkt_id_tx; + if (num_processed_tx == num_processed + 1'b1 + & pkt_tx_done) begin + empty <= 0; + pkt_rx_done <= 1; + state <= STATE_OUTPKT_PROCESSING_DONE; + end + else + state <= STATE_WAIT; + end + + // output PKT_PROCESSING_DONE + STATE_OUTPKT_PROCESSING_DONE: if (rd_en) begin + empty <= 1; + num_processed <= 0; + state <= STATE_WAIT; + end + endcase + end + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/arbiter_tx.v b/src/ztex/fpga-sha256crypt/sha256crypt/arbiter_tx.v new file mode 100644 index 00000000000..a15ea449583 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/arbiter_tx.v @@ -0,0 +1,392 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// +// Tasks for Arbiter, transmit part: +// +// - Gather up necessary data, create data packets for computing units; +// - Transmit data to units ready for computing; +// - Operate mostly at PKT_COMM frequency, send at CORE frequency. +// - Account number of candidates transmitted, handle changes +// in comparator configuration etc. +// +// Packet content is as follows (everything's LE): +// - cnt (number of rounds) - 32 bit +// - salt_len - 32 bit +// - salt data - 16 bytes (2x64 bits), regardless of salt_len +// - IDs - 64 bit +// - key_len - 32 bit +// - unused - 32 bit +// - key data (rounded up to 32 bits), variable size +// +module arbiter_tx #( + parameter N_UNITS = 1, + parameter WORD_MAX_LEN = 64, // in bytes + parameter PKT_LEN = WORD_MAX_LEN + 40 + )( + input CLK, CORE_CLK, + // Turn off comparator mode (mode_cmp=0): + // - next CMP_CONFIG goes on immediately while candidates + // associated with the previous CMP_CONFIG are still + // being processed; + // - don't count number of candidates + input mode_cmp, + // Input from word_gen + input [31:0] gen_id, + input [15:0] word_id, pkt_id, + input gen_end, + input [`MSB(WORD_MAX_LEN):0] word_len, + // Read from word_gen.word_storage + input [7:0] din, + output reg [`MSB(WORD_MAX_LEN-1):0] word_gen_rd_addr = 0, + output word_set_empty, + input word_empty, src_totally_empty, + // From cmp_config + input new_cmp_config, + output cmp_config_applied, + output reg [4:0] cmp_config_addr = 0, + input [7:0] cmp_config_data, + // From initialization packet (PKT_TYPE_INIT) + input [7:0] init_din, + input init_empty, + output init_rd_en, + input [N_UNITS-1:0] unit_tx_mask, + + // Units (CORE_CLK) + output reg [7:0] unit_in = 0, // broadcast + output reg unit_in_ctrl = 0, // broadcast + output reg bcast_en = 0, + output reg [N_UNITS-1:0] unit_in_wr_en = 0, + input [N_UNITS-1:0] unit_in_afull, unit_in_ready, + + // Iteraction with arbiter_rx + output reg [31:0] num_processed_tx = 0, + output reg [15:0] pkt_id_tx, + output reg pkt_tx_done = 0, + input pkt_rx_done, + input recv_item, + + output idle, + output reg err = 0 + ); + + reg cmp_configured = 0; + + + // *************************************************** + localparam STATE_IN_IDLE = 0, + STATE_IN_PROCESS_WORDS = 1, + STATE_IN_WAIT_TX_IDLE = 2, + STATE_IN_TX_COMPLETE_WAIT = 3, + STATE_IN_WAIT_RX_DONE = 4, + STATE_IN_CMP_CONFIG = 5, + STATE_IN_DELAY1 = 6, + STATE_IN_DELAY2 = 7, + STATE_IN_PKT_INIT = 8, + STATE_IN_START_CLK_GLBL = 9; + + (* FSM_EXTRACT="true" *) + reg [3:0] state_in = STATE_IN_IDLE; + + always @(posedge CLK) begin + case (state_in) + STATE_IN_IDLE: begin + /* + if (~word_empty) begin + if (~idle) + state_in <= STATE_IN_PROCESS_WORDS; + else + state_in <= STATE_IN_START_CLK_GLBL; + end + */ + if (~word_empty) + state_in <= STATE_IN_PROCESS_WORDS; + + // loose checks; expecting init packet after + // fpga startup; transmitter must be idle + /* + if (~init_empty & src_totally_empty) begin + if (~idle) + state_in <= STATE_IN_PKT_INIT; + else + state_in <= STATE_IN_START_CLK_GLBL; + end + */ + if (~init_empty & src_totally_empty) + state_in <= STATE_IN_PKT_INIT; + + // New "comparator configuration" (incl. salt data). + // It has to wait until it finishes processing of words + // associated with the previous comparator configuration. + if (new_cmp_config & src_totally_empty) + state_in <= STATE_IN_CMP_CONFIG; + end + + STATE_IN_PKT_INIT: + state_in <= STATE_IN_IDLE; + + STATE_IN_START_CLK_GLBL: if (start_clk_glbl_delay) begin + if (~word_empty) + state_in <= STATE_IN_PROCESS_WORDS; + else + state_in <= STATE_IN_PKT_INIT; + end + + STATE_IN_PROCESS_WORDS: if (~word_empty) begin + if (~cmp_configured) + err <= 1; + else if (gen_end) begin + pkt_id_tx <= pkt_id; + if (mode_cmp) begin + pkt_tx_done <= 1; + state_in <= STATE_IN_WAIT_RX_DONE; + end + else + state_in <= STATE_IN_IDLE; + end + else begin + num_processed_tx <= num_processed_tx + 1'b1; + state_in <= STATE_IN_WAIT_TX_IDLE; + end + end + + // Wait for transmitter part to be idle + STATE_IN_WAIT_TX_IDLE: if (tx_idle_sync) + state_in <= STATE_IN_DELAY1; + + STATE_IN_DELAY1: + state_in <= STATE_IN_TX_COMPLETE_WAIT; + + // Wait until the transmission is complete + STATE_IN_TX_COMPLETE_WAIT: if (tx_completed_sync) + state_in <= STATE_IN_DELAY2; + + STATE_IN_DELAY2: + state_in <= STATE_IN_PROCESS_WORDS; + + // All words in a packet were processed by the receive arbiter. + STATE_IN_WAIT_RX_DONE: if (pkt_rx_done) begin + pkt_tx_done <= 0; + num_processed_tx <= 0; + state_in <= STATE_IN_IDLE; + end + + STATE_IN_CMP_CONFIG: begin + cmp_configured <= 1; + state_in <= STATE_IN_IDLE; + end + endcase + end + + assign word_set_empty = + state_in == STATE_IN_TX_COMPLETE_WAIT & tx_completed_sync + | state_in == STATE_IN_PROCESS_WORDS & ~word_empty & gen_end; + + sync_pulse sync_tx_ready( .wr_clk(CLK), + .sig(state_in == STATE_IN_WAIT_TX_IDLE & tx_idle_sync), + .busy(), .rd_clk(CORE_CLK), .out(tx_ready_sync) ); + + assign cmp_config_applied = state_in == STATE_IN_CMP_CONFIG; + + assign init_rd_en = state_in == STATE_IN_PKT_INIT; + + sync_pulse sync_pkt_init( .wr_clk(CLK), + .sig(state_in == STATE_IN_PKT_INIT), + .busy(), .rd_clk(CORE_CLK), .out(pkt_init_sync) ); + + + localparam TOTAL_IN_PROCESSING = N_UNITS * (6 + 16) + 1; + reg [`MSB(TOTAL_IN_PROCESSING-1) :0] total_in_processing = 0; + always @(posedge CLK) + if (state_in == STATE_IN_PROCESS_WORDS & ~word_empty & ~gen_end) begin + if (~recv_item) + total_in_processing <= total_in_processing + 1'b1; + end + else if (recv_item) + total_in_processing <= total_in_processing - 1'b1; + + delay #( .NBITS(10) ) delay_start_clk_glbl( + .CLK(CLK), .in(state_in == STATE_IN_START_CLK_GLBL), + .out(start_clk_glbl_delay) ); + + assign idle = state_in == STATE_IN_IDLE & total_in_processing == 0 + | state_in == STATE_IN_CMP_CONFIG; + + + // *************************************************** + reg [`MSB(N_UNITS-1):0] unit_num = 0; + reg afull = 1, ready = 0; + reg unit_tx_mask_r = 0; + always @(posedge CORE_CLK) begin + afull <= unit_in_afull [unit_num]; + ready <= unit_in_ready [unit_num]; + unit_tx_mask_r <= unit_tx_mask [unit_num]; + end + + reg [2:0] cnt = 0; + wire [63:0] ids = { gen_id, pkt_id, word_id }; + + wire [`MSB(WORD_MAX_LEN-1):0] word_len_minus1 = word_len - 1'b1; + reg [`MSB(WORD_MAX_LEN-1):0] word_gen_last_rd_addr; + + + localparam STATE_IDLE = 0, + STATE_SEARCH1 = 1, + STATE_SEARCH2 = 2, + //STATE_READY = 3, + STATE_TX1 = 4, + STATE_TX2 = 5, + STATE_TX3 = 6, + STATE_TX4 = 7, + STATE_TX5 = 8, + STATE_TX6 = 9, + STATE_TX_END = 10, + STATE_TX_PKT_INIT1 = 11, + STATE_TX_PKT_INIT2 = 12, + STATE_TX_PKT_INIT3 = 13; + + (* FSM_EXTRACT="true" *) + reg [3:0] state = STATE_IDLE; + + always @(posedge CORE_CLK) begin + case (state) + STATE_IDLE: begin + bcast_en <= 0; + if (pkt_init_sync) + state <= STATE_TX_PKT_INIT1; + else if (tx_ready_sync) // ready for transmit + state <= STATE_SEARCH1; + end + + STATE_SEARCH1: + if (~ready | unit_tx_mask_r) begin + unit_num <= unit_num == N_UNITS-1 + ? {`MSB(N_UNITS-1)+1{1'b0}} : unit_num + 1'b1; + state <= STATE_SEARCH2; + end + else + state <= STATE_TX1; + + STATE_SEARCH2: + state <= STATE_SEARCH1; + + STATE_TX1: begin // Start transmission + bcast_en <= 1; + unit_in <= 0; // packet header (1 byte). + unit_in_wr_en [unit_num] <= 1; + unit_in_ctrl <= 1; + cmp_config_addr <= 0; + state <= STATE_TX2; + end + + STATE_TX2: begin // Send cnt, salt_len, salt (24 bytes) + unit_in <= cmp_config_data; + unit_in_ctrl <= 0; + if (~afull) begin + unit_in_wr_en [unit_num] <= 1; + cmp_config_addr <= cmp_config_addr + 1'b1; + if (cmp_config_addr == 23) + state <= STATE_TX3; + end + else + unit_in_wr_en [unit_num] <= 0; + end + + STATE_TX3: begin // Send IDs (8 bytes) + unit_in <= ids [cnt*8 +:8]; + if (~afull) begin + unit_in_wr_en [unit_num] <= 1; + cnt <= cnt + 1'b1; + if (cnt == 7) + state <= STATE_TX4; + end + else + unit_in_wr_en [unit_num] <= 0; + end + + STATE_TX4: begin // Send key_len (1 byte) + unit_in <= { {7-`MSB(WORD_MAX_LEN){1'b0}}, word_len }; + if (~afull) begin + unit_in_wr_en [unit_num] <= 1; + cnt <= cnt + 1'b1; + state <= STATE_TX5; + end + else + unit_in_wr_en [unit_num] <= 0; + + word_gen_rd_addr <= 0; + word_gen_last_rd_addr + <= { word_len_minus1 [`MSB(WORD_MAX_LEN-1):2], 2'b11 }; + end + + STATE_TX5: begin // 7 bytes - zeroed + unit_in <= 0; + if (~afull) begin + unit_in_wr_en [unit_num] <= 1; + cnt <= cnt + 1'b1; + if (cnt == 7) + state <= STATE_TX6; + end + else + unit_in_wr_en [unit_num] <= 0; + end + + STATE_TX6: begin // key - rounded up to 32 bits + unit_in <= din; + if (~afull) begin + unit_in_wr_en [unit_num] <= 1; + word_gen_rd_addr <= word_gen_rd_addr + 1'b1; + if (word_gen_rd_addr == word_gen_last_rd_addr) begin + unit_in_ctrl <= 1; + state <= STATE_TX_END; + end + end + else + unit_in_wr_en [unit_num] <= 0; + end + + STATE_TX_END: begin + unit_in_wr_en [unit_num] <= 0; + unit_in_ctrl <= 0; + unit_num <= unit_num == N_UNITS-1 + ? {`MSB(N_UNITS-1)+1{1'b0}} : unit_num + 1'b1; + state <= STATE_IDLE; + end + + + // Broadcast transmission of initialization packet + STATE_TX_PKT_INIT1: begin + bcast_en <= 1; + unit_in <= { init_din[4:0], 3'b001 }; + unit_in_wr_en <= {N_UNITS{1'b1}}; + unit_in_ctrl <= 1; + state <= STATE_TX_PKT_INIT2; + end + + STATE_TX_PKT_INIT2: begin + state <= STATE_TX_PKT_INIT3; + end + + STATE_TX_PKT_INIT3: begin + unit_in_wr_en <= {N_UNITS{1'b0}}; + unit_in_ctrl <= 0; + state <= STATE_IDLE; + end + endcase + end + + sync_sig sync_tx_idle(.sig(state == STATE_IDLE), .clk(CLK), + .out(tx_idle_sync) ); + + sync_pulse sync_tx_completed( .wr_clk(CORE_CLK), + .sig(state == STATE_TX_END), .busy(), + .rd_clk(CLK), .out(tx_completed_sync) ); + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/bcast_net.v b/src/ztex/fpga-sha256crypt/sha256crypt/bcast_net.v new file mode 100644 index 00000000000..8fca01b84fe --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/bcast_net.v @@ -0,0 +1,55 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// +// Network for broadcast signals +// +module bcast_net #( + parameter BCAST_WIDTH = -1, + parameter N_NODES = -1, + parameter [8*N_NODES-1 :0] NODES_CONF = 0 + )( + input CLK, + input en, + // entry to the network + input [BCAST_WIDTH-1 :0] in, + // output from nodes + output [N_NODES*BCAST_WIDTH-1 :0] out + ); + + // Node #0 is the entry to the network (unregistered) + assign out[0 +:BCAST_WIDTH] = in; + + wire [N_NODES-1:0] in_en; + assign in_en[0] = en; + + genvar i; + generate + for (i=1; i < N_NODES; i=i+1) begin:node + + localparam UPPER_NODE = NODES_CONF[8*i +:8]; + + (* SHREG_EXTRACT="no", EQUIVALENT_REGISTER_REMOVAL="no" *) + reg [1 + BCAST_WIDTH-1 :0] r; // +1 for 'en' + assign out [i*BCAST_WIDTH +:BCAST_WIDTH] = r [BCAST_WIDTH-1 :0]; + assign in_en[i] = r[BCAST_WIDTH]; + + always @(posedge CLK) begin + r[BCAST_WIDTH] <= in_en[UPPER_NODE]; + if (in_en[UPPER_NODE]) + r[BCAST_WIDTH-1 :0] + <= out [UPPER_NODE*BCAST_WIDTH +:BCAST_WIDTH]; + end + + end + endgenerate + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/comparator.v b/src/ztex/fpga-sha256crypt/sha256crypt/comparator.v new file mode 100644 index 00000000000..1d1af0d89b4 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/comparator.v @@ -0,0 +1,95 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +module comparator( + input CLK, + + // Input from cmp_config + input [7:0] din, + input wr_en, + input [`HASH_NUM_MSB+2:0] wr_addr, + input [`HASH_COUNT_MSB:0] hash_count, + + // Iteraction with arbiter_rx (comparsion) + input [31:0] cmp_data, + input start, + output reg found = 0, finished = 0, + output reg [`HASH_NUM_MSB:0] hash_num = 0 + ); + + + // ************************************************** + // + // Comparator's memory. + // Input is 8-bit, output is 32-bit. + // + // ************************************************** + localparam DEPTH = 512; + + reg [`MSB(DEPTH):0] rd_addr = 0; + wire [31:0] mem_dout; + + asymm_bram_min_wr #( .minWIDTH(), .RATIO(4), .maxDEPTH(DEPTH) + ) mem( + .wr_clk(CLK), .din(din), .wr_en(wr_en), .wr_addr(wr_addr), + .rd_clk(CLK), .dout(mem_dout), .rd_en(rd_en), + .rd_addr(rd_addr[`MSB(DEPTH-1):0]) + ); + + + // ************************************************** + // + // Comparator's function. + // It iterates the list linearily. + // + // ************************************************** + localparam STATE_IDLE = 0, + STATE_START = 1, + STATE_COMPARE = 2; + + (* FSM_EXTRACT="true" *) + reg [1:0] state = STATE_IDLE; + + always @(posedge CLK) begin + case (state) + STATE_IDLE: if (start) begin + found <= 0; + finished <= 0; + rd_addr <= 0; + state <= STATE_START; + end + + STATE_START: begin + hash_num <= 0; + state <= STATE_COMPARE; + end + + STATE_COMPARE: begin + rd_addr <= rd_addr + 1'b1; + if (rd_addr == hash_count) begin + finished <= 1; + state <= STATE_IDLE; + end + + if (mem_dout == cmp_data) begin + found <= 1; + state <= STATE_IDLE; + end + else + hash_num <= rd_addr[`HASH_NUM_MSB:0]; + end + endcase + end + + assign rd_en = state != STATE_IDLE; + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu.v b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu.v new file mode 100644 index 00000000000..b3ea1dc4531 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu.v @@ -0,0 +1,601 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module cpu #( + parameter WIDTH = 16, + parameter N_CORES = 3, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + input [`ENTRY_PT_MSB:0] entry_pt_curr, + // thread_state (ts) + output [N_THREADS_MSB :0] ts_rd_num, ts_wr_num, // Thread # + output reg ts_wr_en = 0, + output reg [`THREAD_STATE_MSB :0] ts_wr, + input [`THREAD_STATE_MSB :0] ts_rd, + + // comp_buf & procb_buf + output reg comp_wr_en = 0, procb_wr_en = 0, + output reg [N_THREADS_MSB :0] comp_procb_wr_thread_num, + input [`PROCB_A_WIDTH-1 :0] procb_wr_cnt, + output reg [`COMP_DATA1_MSB + `COMP_DATA2_MSB+1 :0] comp_dout, + output reg [`PROCB_D_WIDTH-1 :0] procb_dout, + + // input from the memory + output reg mem_rd_request = 0, + output reg [`MEM_TOTAL_MSB :0] mem_rd_addr, + input mem_rd_valid, + input [2*WIDTH-1:0] mem_din, + + // unit_output_buf + output [15:0] uob_dout, + output uob_wr_en, uob_set_input_complete, + output [`UOB_ADDR_MSB :0] uob_wr_addr, + input uob_ready, uob_full, + output err + ); + + reg z; + + wire INVALIDATE_eqn, INSTR_WAIT_eqn; + reg EXECUTED = 0; + reg NEXT_THREAD = 0; + reg INSTR_WAIT = 0; + reg JUMP = 0; + reg [`IADDR_LEN-1 :0] jump_addr; + + + // Thread State Changed flag. + // A thread runs only in WR_RDY state, when thread_state + // changes it has to switch current thread (that takes 4 cycles). + // + // The feature allows it to continue running until JMP + // or until EXEC_OPT_TS_WR_RDY instruction (that requires WR_RDY state). + // + reg ts_changed = 0; + always @(posedge CLK) + if (thread_almost_switched) + ts_changed <= 0; + else if (thread_state_change) + ts_changed <= 1; + + + // ***************************************************************** + // + // Instruction Execution + // - the instruction right out from memory is available here. + // + // ***************************************************************** + wire [N_THREADS_MSB :0] thread_num; + + wire [`N_STAGES-1:0] stage_allow; + //wire STAGE_INSTR_AVAIL = stage_allow[]; + wire STAGE_RD0 = stage_allow[1]; + wire STAGE_RD1 = stage_allow[2]; + wire STAGE_EXEC = stage_allow[3]; + + wire [`FIELD_A_LEN-1 :0] field_a_in; + wire [`EXEC_OPT_LEN-1: 0] exec_opt_in; + wire [`PARTIAL_INSTR_LEN-1 :0] partial_instruction; + + instruction #( .N_CORES(N_CORES) + ) instruction( + .CLK(CLK), + .entry_pt_curr(entry_pt_curr), + .ts_rd_num(ts_rd_num), .ts_rd(ts_rd), + .thread_num(thread_num), + // Asserts for 1 cycle at STAGE_RD1 + .thread_almost_switched(thread_almost_switched), + .instruction({ field_a_in, exec_opt_in, partial_instruction }), + .INVALIDATE(INVALIDATE_eqn), + .INSTR_WAIT(INSTR_WAIT_eqn | INSTR_WAIT), + .NEXT_THREAD(NEXT_THREAD), .EXECUTED(EXECUTED), + .JUMP(JUMP), .jump_addr(jump_addr), + .stage_allow(stage_allow), + .err(err), + // dummy 2nd port + .wr_en_dummy(1'b0), .wr_addr_dummy(1'b0) + ); + + assign ts_wr_num = thread_num; + + wire op_type_use_reg0 + = `OP_TYPE_USE_REG(partial_instruction [`OP_CODE_LEN-1 :0]); + + + // ***************************************************************** + // + // Input from the memory + // + // ***************************************************************** + reg mem_rd_valid_r = 0, mem_wr_lower = 0; + +`ifdef CPU_MV_R_MEM_2X + // support for MV_R_MEM_2X + reg [2*WIDTH-1:0] mem_r; + reg mem_wr_2x = 0, mem_rd_valid_r2 = 0; + + always @(posedge CLK) begin + if (mem_rd_valid) + mem_r <= mem_din; + mem_rd_valid_r <= mem_rd_valid; + mem_rd_valid_r2 <= mem_rd_valid_r; + end + + wire mem_rd_wr_en = mem_rd_valid_r | mem_wr_2x & mem_rd_valid_r2; + // 0: lower half, 1: upper half + wire mem_wr_select = ~(mem_rd_valid_r & (mem_wr_2x | mem_wr_lower)); + // writing upper half into the next register + wire mem_rd_wr_2x = mem_wr_2x & mem_rd_valid_r2; + wire mem_rd_complete = mem_wr_2x ? mem_rd_valid_r2 : mem_rd_valid_r; + +`else + reg [WIDTH-1:0] mem_r; + + always @(posedge CLK) begin + if (mem_rd_valid) + mem_r <= mem_wr_lower ? mem_din[15:0] : mem_din[31:16]; + mem_rd_valid_r <= mem_rd_valid; + end + + wire mem_rd_wr_en = mem_rd_valid_r; + wire mem_rd_complete = mem_rd_valid_r; + +`endif + + + // ***************************************************************** + // + // Going to stage STAGE_RD0. + // + // ***************************************************************** + reg [`EXEC_OPT_LEN-1: 0] exec_opt; + reg [`CONDITION_LEN-1 :0] op_condition; + reg [`FIELD_B_LEN-1 :0] field_b; + reg [`FIELD_C_LEN-1 :0] field_c; + reg [`OP_CODE_LEN-1:0] op_code; + + always @(posedge CLK) + if (STAGE_RD0) begin + exec_opt <= exec_opt_in; + { op_condition, field_b, field_c, op_code } + <= partial_instruction; + end + + wire op_type_use_reg = `OP_TYPE_USE_REG(op_code); + + + // ***************************************************************** + // + // Registers + // - load is 2 cycles (rd_en0, rd_en1) + // - 4 inputs (controlled with reg_din_select) + // + // ***************************************************************** + wire [WIDTH-1:0] reg_din1, reg_din2, reg_din3, reg_dout; + wire [1:0] reg_din_select; + (* SHREG_EXTRACT="no" *) + // Write enable, for stages 3,4 respectively + reg reg_wr_en3 = 0, reg_wr_en4 = 0; + reg [`REG_ADDR_MSB :0] reg_wr_addr4; + reg [N_THREADS_MSB :0] reg_wr_thread4; + + registers_bram #( .WIDTH(WIDTH), .N_THREADS(N_THREADS) + ) registers( + .CLK(CLK), + .din1(reg_din1), .din2(reg_din2), .din3(reg_din3), + +`ifdef CPU_MV_R_MEM_2X + .mem_din(mem_wr_select ? mem_r[2*WIDTH-1:WIDTH] : mem_r[WIDTH-1:0]), + .wr_addr( { reg_wr_addr4[`REG_ADDR_MSB:1], + mem_rd_wr_2x ? 1'b1 : reg_wr_addr4[0] } ), +`else + .mem_din(mem_r), .wr_addr(reg_wr_addr4), +`endif + + .mem_wr_en(mem_rd_wr_en), .wr_en(reg_wr_en4), + .reg_din_select(reg_din_select), + .wr_thread_num(reg_wr_thread4), + + .rd_addr(field_a_in), + .rd_en0(STAGE_RD0 & op_type_use_reg0), + .rd_en1(STAGE_RD1 & op_type_use_reg), + .rd_thread_num(thread_num), .dout(reg_dout) + ); + + + // ***************************************************************** + // + // Going to stage STAGE_RD1. + // + // ***************************************************************** + reg [`EXEC_OPT_LEN-1: 0] exec_opt1; + reg [`CONDITION_LEN-1 :0] op_condition1; + reg [`FIELD_B_LEN-1 :0] field_b1; + reg [`FIELD_C_LEN-1 :0] field_c1; + reg [N_THREADS_MSB :0] thread_num1; + reg [`OP_CODE_LEN-1:0] op_code1; + + always @(posedge CLK) + if (STAGE_RD1) begin + exec_opt1 <= exec_opt; + op_condition1 <= op_condition; + field_b1 <= field_b; + field_c1 <= field_c; + thread_num1 <= thread_num; + op_code1 <= op_code; + end + + always @(posedge CLK) + if (STAGE_EXEC) begin + reg_wr_addr4 <= field_b1 [`REG_ADDR_MSB :0]; + reg_wr_thread4 <= thread_num1; + end + + + // ***************************************************************** + // + // Integer Operations + // + // - no "reg <- reg (op) reg" operations so far + // + // ***************************************************************** + wire [`N_FLAGS-1 :0] flags; + + // iops (controls for integer operations) + reg iop_addsub = 0, iop_sub = 0, iop_use_cf = 0, + iop_grp2 = 0, iop_grp3 = 0, iop_shr1 = 0; + reg [1:0] iop_grp2_select = 0; + + integer_ops #( .WIDTH(WIDTH) ) integer_ops( + .CLK(CLK), + .dina(reg_dout), .dinb(field_c1), .en(STAGE_EXEC), + .in_cf(`FLAG_CARRY(flags)), + .iops({ iop_addsub, iop_sub, iop_use_cf, + iop_grp2, iop_grp3, iop_shr1 }), + .iop_grp2_select(iop_grp2_select), + + .dout_select(reg_din_select), + .dout1(reg_din1), .dout2(reg_din2), .dout3(reg_din3), + .flag_zf(flag_zf_in), .flag_of(flag_of_in), .flag_cf(flag_cf_in) + ); + + + // ***************************************************************** + // + // Internal CPU Operations - STAGE_RD1 + // + // - op_code is available + // + // ***************************************************************** + reg iop_sets_uf = 0, iop_sets_cf = 0, iop_sets_of = 0, iop_sets_zf = 0; + reg [1:0] iop_flag_code = 0; + reg iop_jmp = 0, iop_halt = 0; + + always @(posedge CLK) + if (STAGE_RD1) begin + iop_addsub <= + op_code == `OP_CODE_ADD_R_C | op_code == `OP_CODE_SUB_R_C + | op_code == `OP_CODE_ADDC_R_C | op_code == `OP_CODE_SUBB_R_C; + iop_sub <= op_code == `OP_CODE_SUB_R_C + | op_code == `OP_CODE_SUBB_R_C; + iop_use_cf <= `OP_TYPE_USE_CF(op_code); + + iop_grp2 <= op_code == `OP_CODE_INC_RST + | op_code == `OP_CODE_MV_R_C | op_code == `OP_CODE_AND; + iop_grp2_select <= + op_code == `OP_CODE_INC_RST ? 2'd1 : + op_code == `OP_CODE_AND ? 2'd2 : + 2'd0; + if (op_code == `OP_CODE_INC_RST) + z <= 1; + + iop_grp3 <= op_code == `OP_CODE_SHR1 | op_code == `OP_CODE_MV_R_R; + iop_shr1 <= op_code == `OP_CODE_SHR1; + + // This op. potentially writes into a register + // (write might not be performed dependent on conditions). + reg_wr_en3 <= `OP_TYPE_WRITE_REG(op_code); + + // It's hardcoded(hardwired?) when instruction checks conditions. + //op_checks_conditions <= OP_TYPE_CHECK_CONDITION(op_code); + + iop_sets_zf <= `OP_TYPE_SETS_ZF(op_code); + iop_sets_of <= `OP_TYPE_SETS_OF(op_code); + iop_sets_cf = `OP_TYPE_SETS_CF(op_code); + + // OP_CODE_FLAG: applicable to UF only + iop_sets_uf <= op_code == `OP_CODE_FLAG; + if (op_code == `OP_CODE_FLAG) + z <= 1; + iop_flag_code <= field_b[1:0]; + + iop_jmp <= op_code == `OP_CODE_JMP; + if (op_code == `OP_CODE_JMP) + z <= 1; + + iop_halt <= op_code == `OP_CODE_HALT; + if (op_code == `OP_CODE_HALT) + z <= 1; + end + + + // ***************************************************************** + // + // Internal CPU Operations - STAGE_EXEC + // + // - writes integer_ops.dout + // - checks conditions + // - sets flags + // + // ***************************************************************** + cpu_flags #( .N(`N_FLAGS), .N_THREADS(N_THREADS) + ) cpu_flags( + .CLK(CLK), + .thread_num(thread_num), + .load_en(thread_almost_switched), .save_en(NEXT_THREAD), + .flags(flags), + .op_condition(op_condition1), .condition_is_true(condition_is_true), + + .set_flags(STAGE_EXEC), + .iop_flag_mask({ iop_sets_uf, iop_sets_cf, iop_sets_of, iop_sets_zf }), + .flags_in({ flag_uf_in, flag_cf_in, flag_of_in, flag_zf_in }) + ); + + assign flag_uf_in = + iop_flag_code == 2'b00 ? `FLAG_USER(flags) : + iop_flag_code == 2'b01 ? 1'b1 : + iop_flag_code == 2'b10 ? 1'b0 : + ~`FLAG_USER(flags); + + + always @(posedge CLK) begin + // Check conditions for all integer operations that write registers + reg_wr_en4 <= STAGE_EXEC & reg_wr_en3 & condition_is_true; + + if (iop_jmp) + jump_addr <= field_c1 [`IADDR_LEN-1 :0]; + + if (op_condition1 == `IF_CARRY) + z <= 1; + end + + + // ***************************************************************** + // + // Input/Output Operations. + // + // - MV_R_MEM_{2X|L|U} (Reg <- Memory) + // - MV_UOB_R (Unit output buf. <- Reg) + // - SET_OUTPUT_COMPLETE + // + // ***************************************************************** + reg op_mv_r_mem = 0, op_mv_r_mem2x = 0, op_mv_r_mem_lower = 0; + + always @(posedge CLK) + if (STAGE_RD1) begin + op_mv_r_mem <= `OP_TYPE_MV_R_MEM(op_code); +`ifdef CPU_MV_R_MEM_2X + op_mv_r_mem2x <= op_code == `OP_CODE_MV_R_MEM_2X; +`endif + op_mv_r_mem_lower <= op_code == `OP_CODE_MV_R_MEM_L; + op_mv_uob_r <= op_code == `OP_CODE_MV_UOB_R; + op_set_output_complete <= op_code == `OP_CODE_SET_OUTPUT_COMPLETE; + end + + always @(posedge CLK) //! + if (STAGE_EXEC & op_mv_r_mem) begin + mem_rd_request <= 1; + mem_rd_addr <= { thread_num, field_c1 [`MEM_ADDR_MSB :0] }; +`ifdef CPU_MV_R_MEM_2X + mem_wr_2x <= op_mv_r_mem2x; +`endif + mem_wr_lower <= op_mv_r_mem_lower; + end + else if (mem_rd_valid) + mem_rd_request <= 0; // data on mem_r; mem_rd_valid_r asserts + + + // UOB (unit's output buffer). (-)Output takes 2 cycles. + // uob_wr_en asserts only on the 1st cycle. + reg op_mv_uob_r = 0, op_set_output_complete = 0; + reg [N_THREADS_MSB :0] uob_thread_num; + //reg mv_uob_r_cycle2 = 0; + reg uob_thread_num_eq_thread_num = 0; + + always @(posedge CLK) begin + if (thread_almost_switched) + uob_thread_num_eq_thread_num <= uob_thread_num == thread_num; + if (uob_eqn) begin + if (uob_ready) + uob_thread_num <= thread_num; + //mv_uob_r_cycle2 <= 1; + uob_thread_num_eq_thread_num <= 1; + end + //else + // mv_uob_r_cycle2 <= 0; + end + + assign uob_dout = reg_dout; + assign uob_wr_addr = field_c1 [`UOB_ADDR_MSB :0]; + assign uob_wr_en = uob_eqn; + + assign uob_eqn = STAGE_EXEC & op_mv_uob_r + & (uob_ready | uob_thread_num_eq_thread_num & ~uob_full); + + + assign uob_set_input_complete = STAGE_EXEC & op_set_output_complete; + + + // ***************************************************************** + // + // Integrated SHA256 Operations - STAGE_RD1 + // + // ***************************************************************** + (* SHREG_EXTRACT="no" *) + reg op_init_ctx = 0, op_init_new = 0, op_procb = 0, op_procb_r = 0; + reg [1:0] op_procb_flags = 0; + + always @(posedge CLK) + if (STAGE_RD1) begin + op_init_ctx <= `OP_TYPE_INIT_CTX(op_code); + op_init_new <= op_code[0];//op_code == `OP_CODE_NEW_CTX; + + op_procb <= `OP_TYPE_PROCB(op_code); + op_procb_r <= `OP_TYPE_PROCB_R(op_code); + op_procb_flags <= op_code[1:0]; + end + + + reg [`PROCB_A_WIDTH-1 :0] procb_wr_cnt_r; + always @(posedge CLK) begin + comp_procb_wr_thread_num <= thread_num; + if (thread_almost_switched) + procb_wr_cnt_r <= procb_wr_cnt; + else if (procb_eqn) + procb_wr_cnt_r <= procb_wr_cnt_r + 1'b1; + end + assign procb_full = procb_wr_cnt_r == `PROCB_N_RECORDS; + assign procb_afull = procb_wr_cnt_r == `PROCB_N_RECORDS - 1; + + + // ***************************************************************** + // + // Integrated SHA256 Operations - STAGE_EXEC + // + // ***************************************************************** + // thread_state disables execution (applicable at STAGE_EXEC) + wire ts_disable_exec = (exec_opt1 & `EXEC_OPT_TS_WR_RDY) != 0 & ts_changed; + + // procb_eqn: writes procb_wr_en if thread_state allows + assign procb_eqn = op_procb & condition_is_true & ~ts_disable_exec;// & ~procb_full; + + always @(posedge CLK) begin + comp_wr_en <= STAGE_EXEC & op_init_ctx & ~ts_disable_exec;//init_ctx_eqn; + if (op_init_ctx) + comp_dout <= { op_init_new, field_c1[7:6], field_c1[5:4], + field_b1, field_c1[3:0] }; + + procb_wr_en <= STAGE_EXEC & procb_eqn; + if (op_procb) + //procb_dout <= { field_b1, reg_dout[7:0], op_procb_flags }; + // Allow constant 'cnt' (length) + procb_dout <= { field_b1, (op_procb_r + ? reg_dout[`PROCB_CNT_MSB:0] : field_c1[`PROCB_CNT_MSB:0]), + op_procb_flags }; + end + + + + // ***************************************************************** + + wire JUMP_eqn = STAGE_EXEC & (iop_jmp & condition_is_true); + + wire NEXT_THREAD_eqn = STAGE_EXEC & (1'b0 + | iop_halt + | ts_disable_exec & condition_is_true + + // Switch to the next thread when: + // - Successful PROCESS_BYTES with fin/stop or procb_buf full + //| procb_eqn & (op_procb_flags != 0 | procb_afull) + + // - move to UOB, UOB is full or used by other thread + | op_mv_uob_r & ~(uob_ready | uob_thread_num_eq_thread_num & ~uob_full) + // + //| op_set_output_complete + // + // - JUMP_eqn forces NEXT_THREAD + ); + + + // Invalidate loaded instructions, start loading from the beginning + // when: + // - Successful jump is performed + // - Thread is switched + assign INVALIDATE_eqn = NEXT_THREAD_eqn | JUMP_eqn; + + // Oops. On INSTR_WAIT, it doesn't preserve reg_dout, field_[b|c]1 etc. + assign INSTR_WAIT_eqn = STAGE_EXEC & (1'b0 + | op_mv_r_mem + //| uob_eqn + ); + + wire INSTR_CONTINUE_eqn = 1'b0 + | mem_rd_complete + //| mv_uob_r_cycle2 + ; + + + // ***************************************************************** + + always @(posedge CLK) begin + + // TODO: improve condition? + if (INSTR_CONTINUE_eqn) + INSTR_WAIT <= 0; + else if (INSTR_WAIT_eqn) + INSTR_WAIT <= 1; + + + NEXT_THREAD <= NEXT_THREAD_eqn | JUMP_eqn; + + JUMP <= JUMP_eqn; + + EXECUTED <= STAGE_EXEC & (1'b0 + // Instruction typically executed when: + // - No Invalidate condition, no Wait condition + | (~INVALIDATE_eqn & ~INSTR_WAIT_eqn) + // Exceptions: + // - execution disabled because of wrong thread_state + & ~(ts_disable_exec & condition_is_true) + //| procb_eqn & (op_procb_flags != 0 | procb_afull) + + ) | (1'b0 + // - It continues after Wait condition + | (INSTR_WAIT & INSTR_CONTINUE_eqn) + ); + + + if (ts_wr_en) + ts_wr_en <= 0; + else if (thread_state_change) + ts_wr_en <= 1; + + ts_wr <= + op_set_output_complete ? `THREAD_STATE_NONE : + `THREAD_STATE_RD_RDY + ; + + end + + assign thread_state_change = STAGE_EXEC & (1'b0 + // Successful PROCESS_BYTES with fin/stop or procb_buf becoming full + | procb_eqn & (op_procb_flags != 0 | procb_afull) + // Sending UOB content for output + | op_set_output_complete + ); + + +`ifdef SIMULATION + reg [23:0] X_THREAD_SWITCHES = 0; + reg [23:0] X_JUMPS = 0; + + always @(posedge CLK) begin + if (NEXT_THREAD) + X_THREAD_SWITCHES <= X_THREAD_SWITCHES + 1'b1; + if (JUMP) + X_JUMPS <= X_JUMPS + 1'b1; + end +`endif + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu_flags.v b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu_flags.v new file mode 100644 index 00000000000..4f2457dc392 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu_flags.v @@ -0,0 +1,74 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +module cpu_flags #( + parameter N = `N_FLAGS, + parameter N_THREADS = 16, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + input [N_THREADS_MSB :0] thread_num, + input load_en, save_en, + output reg [N-1 :0] flags, // Flags themselves + + input [`CONDITION_LEN-1 :0] op_condition, + output condition_is_true, + + input set_flags, + input [N-1 :0] iop_flag_mask, flags_in + ); + + integer k; + + // + // Store flags for each thread + // + (* RAM_STYLE="DISTRIBUTED" *) + reg [N-1 :0] flags_mem [0: N_THREADS-1]; + //reg [N-1 :0] flags_r; + + always @(posedge CLK) begin + //flags_r <= flags_mem [thread_num]; + if (save_en) + flags_mem [thread_num] <= flags; + end + + + // + // Check conditions + // + assign condition_is_true = op_condition == `IF_NONE + | op_condition == `IF_ZERO & `FLAG_ZERO(flags) + | op_condition == `IF_NOT_ZERO & ~`FLAG_ZERO(flags) + | op_condition == `IF_ONE & `FLAG_ONE(flags) + | op_condition == `IF_NOT_ONE & ~`FLAG_ONE(flags) + | op_condition == `IF_CARRY & `FLAG_CARRY(flags) + | op_condition == `IF_NOT_CARRY & ~`FLAG_CARRY(flags) + | op_condition == `IF_UF & `FLAG_USER(flags) + | op_condition == `IF_NOT_UF & ~`FLAG_USER(flags) + ; + + + // + // Set flags + // + always @(posedge CLK) begin + if (load_en) + //flags <= flags_r; + flags <= flags_mem [thread_num]; + else if (set_flags) + for (k=0; k < N; k=k+1) + if (iop_flag_mask[k]) + flags[k] <= flags_in[k]; + end + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu_state.v b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu_state.v new file mode 100644 index 00000000000..62400c981d2 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/cpu_state.v @@ -0,0 +1,75 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +// It takes several stages to load an instruction +// and execute it. +// +// Stages: +// RELOAD. IP_curr (Instruction pointer) for given thread - loaded +// 0. Instruction loaded from the memory +// 1. Read0 from register bank, partial decoding +// 2. Completed reading registers, instruction decoded +// 3. Execution +// +// Controls: +// - instr_wait. No movement through pipeline. Possible only +// when the last stage is available. +// - invalidate. All stages get invalidated. +// +module cpu_state #( + parameter N_STAGES = `N_STAGES + )( + input CLK, + + input invalidate, instr_wait, reload, + + output reg thread_almost_switched = 0, + output reg [N_STAGES-1:0] stage_allow = 0 + ); + + reg [N_STAGES-1:0] stage_reached = 0; + + genvar i; + generate + for (i=0; i < N_STAGES; i=i+1) begin:stages + + if (i==0) begin + + always @(posedge CLK) + if (invalidate) + stage_reached[i] <= 0; + else if (reload) + stage_reached[i] <= 1; + + always @(posedge CLK) + stage_allow[i] <= ~invalidate & ~instr_wait + & (reload | stage_reached[i]); + + end + else begin + + always @(posedge CLK) + stage_reached[i] <= ~invalidate & stage_reached[i<1 ? 0 : i-1]; + + always @(posedge CLK) + stage_allow[i] <= ~invalidate & ~instr_wait + & stage_reached[i<1 ? 0 : i-1]; + + end + + end + endgenerate + + + always @(posedge CLK) + thread_almost_switched <= stage_reached[1] & ~stage_reached[2]; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/instruction.v b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/instruction.v new file mode 100644 index 00000000000..f06cdb4f390 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/instruction.v @@ -0,0 +1,193 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module instruction #( + parameter N_CORES = 3, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + // Program entry point + input [`ENTRY_PT_MSB:0] entry_pt_curr, + output [N_THREADS_MSB :0] ts_rd_num, + input [`THREAD_STATE_MSB :0] ts_rd, + + // current thread_num (being executed) + output [`MSB(N_THREADS-1) :0] thread_num, + // asserts 1 cycle before instruction is available on output + output thread_almost_switched, + + output reg [`INSTR_LEN-1 :0] instruction, // right out from BRAM + // Instruction gets partially decoded here + + input INVALIDATE, // Invalidate partially loaded and decoded + // instructions, pre-fetched data etc. + // INVALIDATE appears 1 cycle before NEXT_THREAD + // (in case JMP switches thread) + input INSTR_WAIT, + // Advance effective Instruction Pointer + // (w/o respect to actual result). + input EXECUTED, // does not apply to JUMP + input NEXT_THREAD, + input JUMP, // assuming NEXT_THREAD always set with JUMP + input [`IADDR_LEN-1 :0] jump_addr, + + output [`N_STAGES-1:0] stage_allow, + output reg err = 0, + + // "dummy" 2nd write-only port for BRAM + (* KEEP="true" *) input wr_en_dummy, + (* KEEP="true" *) input wr_addr_dummy + ); + + + // ********************************************************** + // + // Program entry points + // + // ********************************************************** + reg [`IADDR_LEN-1 :0] entry_pts [2**(`ENTRY_PT_MSB+1)-1 :0]; + initial begin + entry_pts[0] = 0; + entry_pts[1] = 150; + end + + reg [`ENTRY_PT_MSB:0] entry_pt_last = 0; + always @(posedge CLK) + entry_pt_last <= entry_pt_curr; + + wire entry_pt_switch = entry_pt_last != entry_pt_curr; + + + // ********************************************************** + // + // Current thread number, switching threads + // - While it runs the program in some thread, it looks ahead + // for a thread in WR_RDY state. When NEXT_THREAD asserts, + // it doesn't waste time and starts loading Instruction + // Pointer for the next thread immediately. + // + // ********************************************************** + wire [`MSB(N_THREADS-1) :0] thread_num_ahead; + + thread_number #( .N_CORES(N_CORES) + ) thread_number( + .CLK(CLK), + .entry_pt_switch(entry_pt_switch), + .ts_rd_num(ts_rd_num), .ts_rd(ts_rd), + .NEXT_THREAD(NEXT_THREAD), + .RELOAD(RELOAD), // start loading the instruction + .thread_num(thread_num), .thread_num_ahead(thread_num_ahead), + .thread_init(init) + ); + + + // ********************************************************** + // + // Instruction Execution State + // - Currently, INVALIDATE asserts 1 cycle before NEXT_THREAD + // - RELOAD asserts on the same cycle as NEXT_THREAD, or later. + // - On the next cycle after RELOAD, stage_allow=0001 + // + // ********************************************************** + cpu_state cpu_state( + .CLK(CLK), + .invalidate(INVALIDATE), .instr_wait(INSTR_WAIT), .reload(RELOAD), + .thread_almost_switched(thread_almost_switched), + .stage_allow(stage_allow) + ); + + + // ********************************************************** + // + // Instruction pointer + // + // ********************************************************** + reg [`IADDR_LEN-1 :0] IP_curr; + reg [`IADDR_LEN-1 :0] IP_effective; + reg [`IADDR_LEN-1 :0] IP_mem [0: N_THREADS-1]; + wire [`IADDR_LEN-1 :0] IP_mem_dout = IP_mem [thread_num_ahead]; + + // Q. NEXT_THREAD and EXECUTE at the same time - OK + // Q2. INVALIDATE & INSRT_WAIT - can't happen + always @(posedge CLK) + if (init | NEXT_THREAD) + IP_mem [thread_num] <= + JUMP ? jump_addr : + EXECUTED ? IP_effective + 1'b1 : + ~init ? IP_effective : + entry_pts [entry_pt_curr]; + + always @(posedge CLK) + if (RELOAD) begin + IP_curr <= IP_mem_dout; + IP_effective <= IP_mem_dout; + end + else begin + if (stage_allow[0]) + IP_curr <= IP_curr + 1'b1; + if (EXECUTED) + IP_effective <= IP_effective + 1'b1; + end + + + // Simulation / debug + reg z; + always @(posedge CLK) + if (IP_curr == 93) + z <= 1; + + + // ********************************************************** + // + // Instruction memory + // + // ********************************************************** + (* RAM_STYLE="BLOCK" *) + reg [`INSTR_LEN-1 :0] instr_mem [0: 2**`IADDR_LEN-1]; + + always @(posedge CLK) + if (stage_allow[0]) + instruction <= instr_mem [IP_curr]; + + // Partial decoding + //wire op_code = instruction []; + always @(posedge CLK) begin + end + + + always @(posedge CLK) begin + // INVALIDATE asserted 2+ cycles in a row + if (INVALIDATE & RELOAD) + err <= 1; + // ? + //if (INVALIDATE & INSRT_WAIT) + end + + + // ********************************************************** + // + // Declaring "dummy" 2nd write-only port + // to force 1K BRAM in SDP mode (else it infers 2K TDP) + // + // ********************************************************** + always @(posedge CLK) + if (wr_en_dummy) + instr_mem[wr_addr_dummy] <= 1'b0; + +`include "program.vh" + + +endmodule + + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/integer_ops.v b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/integer_ops.v new file mode 100644 index 00000000000..4c408d6030f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/integer_ops.v @@ -0,0 +1,78 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module integer_ops #( + parameter WIDTH = 16 + )( + input CLK, + + input [WIDTH-1:0] dina, + input [7:0] dinb, + input en, in_cf, + + input [5:0] iops, + input [1:0] iop_grp2_select, + + output reg [1:0] dout_select = 0, + output reg [WIDTH-1:0] dout1 = 0, dout3 = 0, + output [WIDTH-1:0] dout2, + output flag_cf, flag_of, flag_zf + ); + + assign { iop_addsub, iop_sub, iop_use_cf, + iop_grp2, iop_grp3, iop_shr1 } = iops; + + + wire [WIDTH-1+1:0] addsub_result = iop_sub + ? dina - dinb - (iop_use_cf ? in_cf : 1'b0) + : dina + dinb + (iop_use_cf ? in_cf : 1'b0); + assign flag_cf = addsub_result[WIDTH-1+1]; + + // grp2 includes INC_RST, MV_R_C, AND_R_C + // 8-bit operation; upper 24 zeroed + reg [7:0] reg_grp2 = 0; + wire [7:0] grp2_result = + iop_grp2_select == 2'd1 ? + (dina[7:0] == dinb ? 8'b0 : dina[7:0] + 1'b1) : + iop_grp2_select == 2'd2 ? (dina[7:0] & dinb) : + dinb; + + // grp3 includes SHR1, MV_R_R + wire [WIDTH-1:0] grp3_result = iop_shr1 ? { 1'b0, dina[WIDTH-1:1] } : dina; + // Removal of MV_R_R (usage of SUB_R_C instead) would save 4 LUT + //wire [31:0] grp3_result = { 1'b0, dina[31:1] }; + + always @(posedge CLK) if (en) begin + if (iop_addsub) + dout1 <= addsub_result[WIDTH-1:0]; + + if (iop_grp2) + reg_grp2 <= grp2_result; + + if (iop_grp3) + dout3 <= grp3_result; + + dout_select <= + iop_addsub ? 2'd1 : + iop_grp2 ? 2'd2 : + iop_grp3 ? 2'd3 : + 2'd0; + end + + assign dout2 = { {WIDTH-8{1'b0}}, reg_grp2 }; + + assign flag_zf = dina[WIDTH-1:8] == 0 + & (iop_shr1 ? dina[7:0] == 0 : dina[7:0] == dinb); + + assign flag_of = dina[0]; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/program.vh b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/program.vh new file mode 100644 index 00000000000..539c884d3a1 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/program.vh @@ -0,0 +1,437 @@ +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +integer i, j; +integer k = 0; + +// +// Memory is 32 words (x32-bit) per thread. +// Memory layout for sha256crypt as delivered via unit_input: +// 0 - cnt +// 1 - salt_len +// 2..5 - salt +// 6..7 - IDs +// 8 - key_len +// 9 - unused +// 10..10+(key_len/4-1) - key +// +`define ADDR_cnt 0 +`define ADDR_salt_len 1 +`define ADDR_salt 2 +`define ADDR_s_bytes `ADDR_salt +`define ADDR_ids0 6 +`define ADDR_ids1 7 +`define ADDR_key_len 8 +`define ADDR_key 10 +`define ADDR_p_bytes `ADDR_key +`define ADDR_alt_result 24 +// +// 16 (x32-bit) registers per thread. +// +`define R_salt_len `R12 +`define R_key_len `R13 +`define R_cnt_l `R14 +`define R_cnt_u `R15 +// +// +initial begin + // ************************************************************ + // + // Algorithm notes: + // - key_len=0 is supported + // - max. key_len is 32 + // - salt_len=0, cnt=0 NOT supported + // + // ************************************************************ + + // ************************************************************ + // + // - Execution of a thread starts when it receives + // an input data packet, that sets thread_state to WR_RDY + // + // ************************************************************ + instr_mem[00] = `NOP; + instr_mem[01] = `NOP; + instr_mem[02] = `NOP; + instr_mem[03] = `NOP; + instr_mem[04] = `NOP; + // - Read from the memory: MV_R_MEM_L, MV_R_MEM_U read + // lower,upper halves of 32-bit word, respectively. + // Takes 4 cycles to execute (if memory is not busy - + // read for block formation has priority over CPU). + // + // - MV_R_MEM_2X reads full 32-bit word, stores + // into 2 registers. Takes 5+ cycles to execute. + // (disabled) + // + //instr_mem[05] = `MV_R_MEM_2X(`R_cnt_l,`ADDR_cnt); + instr_mem[05] = `MV_R_MEM_L(`R_cnt_l,`ADDR_cnt); + instr_mem[06] = `MV_R_MEM_U(`R_cnt_u,`ADDR_cnt); + instr_mem[07] = `MV_R_MEM_L(`R_salt_len,`ADDR_salt_len); + instr_mem[08] = `MV_R_MEM_L(`R_key_len,`ADDR_key_len); + instr_mem[09] = `NOP; + instr_mem[10] = `NOP;//`JMP(80); + + + // ************************************************************ + // + // "Compute alternate SHA256 sum with input KEY, SALT, and KEY. The + // final result will be added to the first context." + // + // ************************************************************ + + // - Usage: NEW_CTX(save_addr,save_len) + instr_mem[11] = `NEW_CTX(`ADDR_alt_result,8); + instr_mem[12] = `PROCESS_BYTES_R(`ADDR_key,`R_key_len); + instr_mem[13] = `PROCESS_BYTES_R(`ADDR_salt,`R_salt_len); + instr_mem[14] = `PROCESS_BYTES_R_FINISH_CTX(`ADDR_key,`R_key_len); + +/* + // - HALT works as expected only after JMP. + instr_mem[15] = `JMP(16); + instr_mem[16] = `HALT; + instr_mem[17] = `NOP; + instr_mem[18] = `NOP; +*/ + + + // ************************************************************ + // + // "Prepare for the real work." + // + // ************************************************************ + + // - We have data at `ADDR_alt_result and we set the same address + // for output. Data is safe until FINISH_CTX. + instr_mem[15] = `NEW_CTX(`ADDR_alt_result,8); + + // - Update value in a register: new value is not available immediately. + // If an instruction at address ADDR modifies a register, new value + // is available for an instruction at ADDR+4, or after successful JMP. + // Until that the previous value is available if there was + // no thread switch. + instr_mem[16] = `MV_R_R(`R0,`R_key_len); + + // "Add the key string." + // "The last part is the salt string." + // "Add for any character in the key one byte of the alternate sum." + instr_mem[17] = `PROCESS_BYTES_R(`ADDR_key,`R_key_len); + instr_mem[18] = `PROCESS_BYTES_R(`ADDR_salt,`R_salt_len); + instr_mem[19] = `PROCESS_BYTES_R(`ADDR_alt_result,`R_key_len); + + + + // ************************************************************ + // + // "Take the binary representation of the length of the key and + // for every 1 add the alternate sum, for every 0 the key." + // + // ************************************************************ + + // - On SHR1, Zero Flag (ZF) sets if operand A equals to 0. + // - One Flag (OF). Operand A, bit 0 is copied into OF. +// 24 -> + instr_mem[20] = `SHR1(`R0); + // - Many instruction types may have execution condition + // (if condition is not met then the instruction is skipped). + `IF(`IF_ZERO) + instr_mem[21] = `JMP(25); `IF(`IF_NONE) + + `IF(`IF_ONE) + instr_mem[22] = `PROCESS_BYTES_C(`ADDR_alt_result,32); `IF(`IF_NONE) + `IF(`IF_NOT_ONE) + instr_mem[23] = `PROCESS_BYTES_R(`ADDR_key,`R_key_len); `IF(`IF_NONE) + instr_mem[24] = `JMP(20); + +// 21 -> + instr_mem[25] = `FINISH_CTX; + instr_mem[26] = `NOP; + + + + // ************************************************************ + // + // "Start computation of P byte sequence." + // "For every character in the password add the entire password." + // + // ************************************************************ + instr_mem[27] = `MV_R_R(`R0,`R_key_len); + instr_mem[28] = `NOP; + instr_mem[29] = `NOP; + instr_mem[30] = `NEW_CTX(`ADDR_p_bytes,8); + // - On subtraction, ZF is set if operand A equals to operand B. + instr_mem[31] = `SUB_R_C(`R0,`R0,0); + `IF(`IF_ZERO) + instr_mem[32] = `JMP(37); `IF(`IF_NONE) +// 35 -> + instr_mem[33] = `PROCESS_BYTES_R(`ADDR_key,`R_key_len); + instr_mem[34] = `SUB_R_C(`R0,`R0,1); + `IF(`IF_NOT_ZERO) + instr_mem[35] = `JMP(33); `IF(`IF_NONE) + + instr_mem[36] = `NOP; +// 32 -> + instr_mem[37] = `FINISH_CTX; + instr_mem[38] = `NOP; + + + + // ************************************************************ + // + // "Start computation of S byte sequence." + // "for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) + // sha512_process_bytes (salt, salt_len, &alt_ctx);" + // + // ************************************************************ + + // - Only 4 words (x32 bit) are saved into memory (save_len=4) + instr_mem[39] = `NEW_CTX(`ADDR_s_bytes,4); + // + // - *_FINISH_CTX/STOP_CTX is a non-blocking instruction. + // - NEW_CTX is a blocking one (it waits until the previous + // computation is finished). + // + instr_mem[40] = `MV_R_MEM_L(`R0,`ADDR_alt_result + 5'd0); + instr_mem[41] = `NOP; + instr_mem[42] = `NOP; + instr_mem[43] = `NOP; + // - AND is an 8-bit instruction. Upper bits are zeroed. + // - Integer instructions are able to read from one register + // and save into other one. + instr_mem[44] = `AND_R_C(`R0,`R0,255); + instr_mem[45] = `NOP; + instr_mem[46] = `NOP; + instr_mem[47] = `NOP; + instr_mem[48] = `ADD_R_C(`R0,16); + instr_mem[49] = `NOP; + instr_mem[50] = `NOP; + instr_mem[51] = `NOP; + +// 59 -> + instr_mem[52] = `SUB_R_C(`R1,`R0,4); + `IF(`IF_CARRY) + instr_mem[53] = `JMP(60); `IF(`IF_NONE) + // Internal buffer for process_bytes is 4 elements. + instr_mem[54] = `PROCESS_BYTES_R(`ADDR_salt,`R_salt_len); + instr_mem[55] = `PROCESS_BYTES_R(`ADDR_salt,`R_salt_len); + instr_mem[56] = `PROCESS_BYTES_R(`ADDR_salt,`R_salt_len); + instr_mem[57] = `PROCESS_BYTES_R(`ADDR_salt,`R_salt_len); + instr_mem[58] = `SUB_R_C(`R0,`R0,4); + `IF(`IF_NOT_CARRY) + instr_mem[59] = `JMP(52); `IF(`IF_NONE) + +// 53 -> + instr_mem[60] = `SUB_R_C(`R0,`R0,0); + `IF(`IF_ZERO) + instr_mem[61] = `JMP(65); `IF(`IF_NONE) +// 64 -> + instr_mem[62] = `PROCESS_BYTES_R(`ADDR_salt,`R_salt_len); + instr_mem[63] = `SUB_R_C(`R0,`R0,1); + `IF(`IF_NOT_ZERO) + instr_mem[64] = `JMP(62); `IF(`IF_NONE) +// 61 -> + instr_mem[65] = `FINISH_CTX; + + instr_mem[66] = `JMP(76); + + + + // ************************************************************ + // + // "Repeatedly run the collected hash value through SHA256 to burn + // CPU cycles." + // + // ************************************************************ +// 66 -> + instr_mem[76] = `MV_R_R(`R0,`R_cnt_l); + instr_mem[77] = `MV_R_R(`R1,`R_cnt_u); + instr_mem[78] = `MV_R_C(`R2,2); + instr_mem[79] = `MV_R_C(`R3,6); + instr_mem[80] = `RST_UF; + instr_mem[81] = `NOP; + instr_mem[82] = `SUB_R_C(`R0,`R0,1); + instr_mem[83] = `SUBB_R_C(`R1,`R1,0); + // TODO: some error handling / reporting + // - IF_CARRY -> raise error (cnt == 0) + + // "New context." + // - Arguments to NEW_CTX remain in internal registers, + // the instruction can be skipped if arguments remain the same. + // Computation starts after PROCESS_BYTES. + instr_mem[84] = `NEW_CTX(`ADDR_alt_result,8); + + // "Add key or last result." +// 96 -> + `IF(`IF_UF) + instr_mem[85] = `PROCESS_BYTES_R(`ADDR_p_bytes,`R_key_len); `IF(`IF_NONE) + `IF(`IF_NOT_UF) + instr_mem[86] = `PROCESS_BYTES_C(`ADDR_alt_result,32); `IF(`IF_NONE) + + // "Add salt for numbers not divisible by 3." + // + // - INC_RST instruction: + // 1) loads value from given register, compares with supplied constant; + // 2) if equals, saves 0, sets ZF, else saves value incremented by 1; + // 3) is 8-bit instruction. + instr_mem[87] = `INC_RST(`R2,2); + `IF(`IF_NOT_ZERO) + instr_mem[88] = `PROCESS_BYTES_R(`ADDR_s_bytes,`R_salt_len); `IF(`IF_NONE) + + // "Add key for numbers not divisible by 7." + instr_mem[89] = `INC_RST(`R3,6); + `IF(`IF_NOT_ZERO) + instr_mem[90] = `PROCESS_BYTES_R(`ADDR_p_bytes,`R_key_len); `IF(`IF_NONE) + + // "Add key or last result." + `IF(`IF_UF) + instr_mem[91] = `PROCESS_BYTES_C_FINISH_CTX(`ADDR_alt_result,32); `IF(`IF_NONE) + `IF(`IF_NOT_UF) + instr_mem[92] = `PROCESS_BYTES_R_FINISH_CTX(`ADDR_p_bytes,`R_key_len); `IF(`IF_NONE) + + instr_mem[93] = `INV_UF; + instr_mem[94] = `SUB_R_C(`R0,`R0,1); + instr_mem[95] = `SUBB_R_C(`R1,`R1,0); + `IF(`IF_NOT_CARRY) + instr_mem[96] = `JMP(85); `IF(`IF_NONE) + + // - On FINISH_CTX, it sets thread_state to BUSY and it continues + // running until JMP or EXEC_OPT_TS_WR_RDY-flagged instruction. + // On such instruction, thread switches. It restores back + // only after thread_state changes to WR_RDY, that happens + // after computation is complete. + // We need computation to be complete before output. +/* + instr_mem[97] = `JMP(100); + instr_mem[98] = `NOP; + instr_mem[99] = `NOP; + + // ************************************************************ + // + // - Unit's Output Buffer (UOB) is designed for collecting + // output data. There's a single UOB instance for all threads. + // 16-bit storage operation (UOB <- Reg) is available. + // Constant UOB address (for 16-bit word) must be supplied. + // 20 first words from the UOB are output. + // First 4 words must contain IDs. + // + // ************************************************************ + instr_mem[100] = `MV_R_MEM_2X(`R0,`ADDR_ids0); + instr_mem[101] = `MV_R_MEM_2X(`R2,`ADDR_ids1); + instr_mem[102] = `MV_R_MEM_2X(`R4,`ADDR_alt_result + 5'd0); + instr_mem[103] = `MV_R_MEM_2X(`R6,`ADDR_alt_result + 5'd1); + instr_mem[104] = `MV_R_MEM_2X(`R8,`ADDR_alt_result + 5'd2); + instr_mem[105] = `MV_R_MEM_2X(`R10,`ADDR_alt_result + 5'd3); + + instr_mem[106] = `MV_UOB_R(0,`R0); + instr_mem[107] = `MV_UOB_R(1,`R1); + instr_mem[108] = `MV_UOB_R(2,`R2); + instr_mem[109] = `MV_UOB_R(3,`R3); + instr_mem[110] = `MV_UOB_R(4,`R4); + instr_mem[111] = `MV_UOB_R(5,`R5); + instr_mem[112] = `MV_UOB_R(6,`R6); + instr_mem[113] = `MV_UOB_R(7,`R7); + instr_mem[114] = `MV_UOB_R(8,`R8); + instr_mem[115] = `MV_UOB_R(9,`R9); + instr_mem[116] = `MV_UOB_R(10,`R10); + instr_mem[117] = `MV_UOB_R(11,`R11); + + instr_mem[118] = `MV_R_MEM_2X(`R0,`ADDR_alt_result + 5'd4); + instr_mem[119] = `MV_R_MEM_2X(`R2,`ADDR_alt_result + 5'd5); + instr_mem[120] = `MV_R_MEM_2X(`R4,`ADDR_alt_result + 5'd6); + instr_mem[121] = `MV_R_MEM_2X(`R6,`ADDR_alt_result + 5'd7); + + instr_mem[122] = `MV_UOB_R(12,`R0); + instr_mem[123] = `MV_UOB_R(13,`R1); + instr_mem[124] = `MV_UOB_R(14,`R2); + instr_mem[125] = `MV_UOB_R(15,`R3); + instr_mem[126] = `MV_UOB_R(16,`R4); + instr_mem[127] = `MV_UOB_R(17,`R5); + instr_mem[128] = `MV_UOB_R(18,`R6); + instr_mem[129] = `MV_UOB_R(19,`R7); + + instr_mem[130] = `SET_OUTPUT_COMPLETE; + instr_mem[131] = `JMP(01); +*/ + + instr_mem[97] = `JMP(98); + instr_mem[98] = `MV_R_MEM_L(`R0,`ADDR_ids0); + instr_mem[99] = `MV_R_MEM_U(`R1,`ADDR_ids0); + instr_mem[100] = `MV_R_MEM_L(`R2,`ADDR_ids1); + instr_mem[101] = `MV_R_MEM_U(`R3,`ADDR_ids1); + instr_mem[102] = `MV_R_MEM_L(`R4,`ADDR_alt_result + 5'd0); + instr_mem[103] = `MV_R_MEM_U(`R5,`ADDR_alt_result + 5'd0); + instr_mem[104] = `MV_R_MEM_L(`R6,`ADDR_alt_result + 5'd1); + instr_mem[105] = `MV_R_MEM_U(`R7,`ADDR_alt_result + 5'd1); + instr_mem[106] = `MV_R_MEM_L(`R8,`ADDR_alt_result + 5'd2); + instr_mem[107] = `MV_R_MEM_U(`R9,`ADDR_alt_result + 5'd2); + instr_mem[108] = `MV_R_MEM_L(`R10,`ADDR_alt_result + 5'd3); + instr_mem[109] = `MV_R_MEM_U(`R11,`ADDR_alt_result + 5'd3); + + instr_mem[110] = `MV_UOB_R(0,`R0); + instr_mem[111] = `MV_UOB_R(1,`R1); + instr_mem[112] = `MV_UOB_R(2,`R2); + instr_mem[113] = `MV_UOB_R(3,`R3); + instr_mem[114] = `MV_UOB_R(4,`R4); + instr_mem[115] = `MV_UOB_R(5,`R5); + instr_mem[116] = `MV_UOB_R(6,`R6); + instr_mem[117] = `MV_UOB_R(7,`R7); + instr_mem[118] = `MV_UOB_R(8,`R8); + instr_mem[119] = `MV_UOB_R(9,`R9); + instr_mem[120] = `MV_UOB_R(10,`R10); + instr_mem[121] = `MV_UOB_R(11,`R11); + + instr_mem[122] = `MV_R_MEM_L(`R0,`ADDR_alt_result + 5'd4); + instr_mem[123] = `MV_R_MEM_U(`R1,`ADDR_alt_result + 5'd4); + instr_mem[124] = `MV_R_MEM_L(`R2,`ADDR_alt_result + 5'd5); + instr_mem[125] = `MV_R_MEM_U(`R3,`ADDR_alt_result + 5'd5); + instr_mem[126] = `MV_R_MEM_L(`R4,`ADDR_alt_result + 5'd6); + instr_mem[127] = `MV_R_MEM_U(`R5,`ADDR_alt_result + 5'd6); + instr_mem[128] = `MV_R_MEM_L(`R6,`ADDR_alt_result + 5'd7); + instr_mem[129] = `MV_R_MEM_U(`R7,`ADDR_alt_result + 5'd7); + + instr_mem[130] = `MV_UOB_R(12,`R0); + instr_mem[131] = `MV_UOB_R(13,`R1); + instr_mem[132] = `MV_UOB_R(14,`R2); + instr_mem[133] = `MV_UOB_R(15,`R3); + instr_mem[134] = `MV_UOB_R(16,`R4); + instr_mem[135] = `MV_UOB_R(17,`R5); + instr_mem[136] = `MV_UOB_R(18,`R6); + instr_mem[137] = `MV_UOB_R(19,`R7); + + + // ************************************************************ + // + // - SET_OUTPUT_COMPLETE instruction: + // 1) to be called after there was at least 1 write to the UOB; + // 2) enqueues UOB content for output; + // 3) changes thread_state to NONE, that excludes the thread + // from execution and makes it available for input; + // 4) Suggested JMP immediately after the instruction. + // + // ************************************************************ + instr_mem[138] = `SET_OUTPUT_COMPLETE; + instr_mem[139] = `JMP(01); + + + // ************************************************************ + // + // + // ************************************************************ + + + +/* + instr_mem[] = `JMP(); + instr_mem[] = `HALT; + instr_mem[] = `NOP; + instr_mem[] = `NOP; +*/ + +end + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/registers_bram.v b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/registers_bram.v new file mode 100644 index 00000000000..0ba5dc27cc6 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/registers_bram.v @@ -0,0 +1,52 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +module registers_bram #( + parameter WIDTH = 16, + parameter N_THREADS = 6, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + // input into register file from the memory + input [WIDTH-1:0] mem_din, + input [WIDTH-1:0] din1, din2, din3, + input [1:0] reg_din_select, + input mem_wr_en, wr_en, + input [`REG_ADDR_MSB:0] wr_addr, rd_addr, + input [N_THREADS_MSB :0] wr_thread_num, rd_thread_num, + input rd_en0, rd_en1, + output [WIDTH-1:0] dout + ); + + (* RAM_STYLE="BLOCK" *) + reg [WIDTH-1:0] reg_mem [0: 16*N_THREADS-1]; + reg [WIDTH-1:0] reg_mem_r; + + // Prevent inference of BRAM output register + ff16 ff_reg( .CLK(CLK), .en(rd_en1), + .rst(1'b0), .i(reg_mem_r), .o(dout) ); + + wire [WIDTH-1:0] reg_input = + reg_din_select == 2'd1 ? din1 : + reg_din_select == 2'd2 ? din2 : + reg_din_select == 2'd3 ? din3 : + mem_din; + + always @(posedge CLK) begin + if (mem_wr_en | wr_en) + reg_mem [{ wr_thread_num, wr_addr }] <= reg_input; + + if (rd_en0) + reg_mem_r <= reg_mem [{ rd_thread_num, rd_addr }]; + end + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/cpu/thread_number.v b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/thread_number.v new file mode 100644 index 00000000000..f6d7d67a5c5 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/cpu/thread_number.v @@ -0,0 +1,113 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module thread_number #( + parameter N_CORES = -1, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + input entry_pt_switch, + + output [N_THREADS_MSB :0] ts_rd_num, + input [`THREAD_STATE_MSB :0] ts_rd, + + input NEXT_THREAD, + output RELOAD, + + output reg [`MSB(N_THREADS-1) :0] thread_num = 0, thread_num_ahead = 1, + output reg thread_init = 1 + ); + + reg suspended_r = 1; + + // Next thread (in sequence) + wire [`MSB(N_THREADS-1) :0] thread_num_next; + next_thread_num #( .N_CORES(N_CORES) + ) next_thread_num( .in(thread_num), .out(thread_num_next) ); + + + // Look ahead for WR_RDY thread + assign ts_rd_num = thread_num_ahead; + wire thread_ahead_not_ready = ts_rd != `THREAD_STATE_WR_RDY; + + wire [`MSB(N_THREADS-1) :0] thread_num_ahead_next; + next_thread_num #( .N_CORES(N_CORES) + ) next_thread_num_ahead( .in(thread_num_ahead), .out(thread_num_ahead_next) ); + + + // Allow to select the same thread after thread_state propagates + localparam TS_DELAY = 2; + reg [TS_DELAY-1:0] allow_same_thread = {TS_DELAY{1'b0}}; + always @(posedge CLK) + allow_same_thread <= { allow_same_thread[TS_DELAY-2:0], suspended_r }; + + task thread_num_ahead_next_set; + begin + thread_num_ahead <= (thread_num_ahead_next == thread_num + & ~allow_same_thread[TS_DELAY-1]) + ? thread_num_next : thread_num_ahead_next; + end + endtask + + + always @(posedge CLK) begin + if (entry_pt_switch) + thread_init <= 1; + + if (thread_init) begin // traverse all threads on init + thread_num <= thread_num_next; + if (thread_num == N_THREADS-1) + thread_init <= 0; + end + else begin + if (suspended_r & ~thread_ahead_not_ready) begin + suspended_r <= 0; + thread_num <= thread_num_ahead; + thread_num_ahead_next_set(); + end + + else if (NEXT_THREAD) begin + if (thread_ahead_not_ready) begin + suspended_r <= 1; + end + else begin + thread_num <= thread_num_ahead; + thread_num_ahead_next_set(); + end + end + + else begin + if (thread_ahead_not_ready) + thread_num_ahead_next_set(); + end + end + end + + assign RELOAD = ~thread_init & ( + suspended_r & ~thread_ahead_not_ready + | NEXT_THREAD & ~thread_ahead_not_ready + ); + + +`ifdef SIMULATION + reg [31:0] X_CYCLES_TOTAL = 0; + reg [31:0] X_CYCLES_SUSPENDED = 0; + + always @(posedge CLK) begin + X_CYCLES_TOTAL <= X_CYCLES_TOTAL + 1'b1; + if (suspended_r) + X_CYCLES_SUSPENDED <= X_CYCLES_SUSPENDED + 1'b1; + end +`endif + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256.vh b/src/ztex/fpga-sha256crypt/sha256crypt/sha256.vh new file mode 100644 index 00000000000..cc3127f9267 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256.vh @@ -0,0 +1,329 @@ +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// Include Verilog code for "blackbox" modules +// (ISE Project Navigator requires restart after switching this) +`define SIMULATION + + +// ===== Algorithm constants and operations ===== +// +`define CYCLIC(w,s) ((w >> s) | (w << (32 - s))) + +`define SWAP(n) (((n) << 24) \ + | (((n) & 16'hff00) << 8) \ + | (((n) >> 8) & 16'hff00) \ + | ((n) >> 24)) + +`define SHA256_IV { 128'h_5be0cd19_1f83d9ab_9b05688c_510e527f, \ + 128'h_a54ff53a_3c6ef372_bb67ae85_6a09e667 } + + +// ===== Block processing options ===== +// +`define BLK_OP_MSB 5 +// New/load context: 1 - new, 0 - load +`define BLK_OP_IF_NEW_CTX(r) r[0] +// If load context: 0..N - load saved context from slot 0..N +`define BLK_OP_LOAD_CTX_NUM(r) r[2:1] +// Where to save the context: 0..N - save into slot 0..N +`define BLK_OP_SAVE_CTX_NUM(r) r[4:3] +// 1) Output computed result; +// 2) Used to set thread state. +`define BLK_OP_END_COMP_OUTPUT(r) r[5] + + +// ===== sha256crypt engine (services several cores) ===== +// +// "Main" memory (per thread; in 32-bit words) +// 2**(4+1) x4 = 32 x4 = 128 bytes +`define MEM_ADDR_MSB 4 +// "Main" memory (per engine) [0: 2**(`MEM_TOTAL_MSB+1)-1] +`define MEM_TOTAL_MSB (`MEM_ADDR_MSB + 3) + +// process_bytes (in bytes) +// max.key_len=32 (comp.len <2k) +`define PROCB_CNT_MSB 5 +// max. S-bytes comp. is ~4.3k (PROCB_TOTAL_MSB = 12) +`define PROCB_TOTAL_MSB 12 + +// unit's I/O +`define UNIT_INPUT_WIDTH 8 +`define UNIT_OUTPUT_WIDTH 2 +// Address in Unit's output buffer (UOB) memory in 16-bit words +`define UOB_ADDR_MSB 4 + + +// ===== computation state (per thread) ===== +// +`define THREAD_STATE_MSB 1 + +`define THREAD_STATE_NONE 2'd0 +`define THREAD_STATE_WR_RDY 2'd1 +`define THREAD_STATE_RD_RDY 2'd2 +`define THREAD_STATE_BUSY 2'd3 + + +// ===== comp_buf, procb_buf, saved_procb_state ===== +// +`define COMP_DATA1_MSB (1 + 2 + 2)-1 +`define COMP_DATA2_MSB (`MEM_ADDR_MSB+1 + 4)-1 + +// address width for procb records (per thread) +`define PROCB_N_RECORDS 4 +`define PROCB_A_WIDTH 3 +// width of each procb record +`define PROCB_D_WIDTH (`MEM_ADDR_MSB+1 + `PROCB_CNT_MSB+1 +2) + +`define PROCB_SAVE_WIDTH (`MEM_ADDR_MSB+2+1 + `PROCB_CNT_MSB+1 \ + + `PROCB_TOTAL_MSB+1 + 5) + + +// ===== CPU ===== +// +`define N_STAGES 4 +// 16 registers +`define REG_ADDR_MSB 3 +// Program entry points +`define ENTRY_PT_MSB 0 +// +// Each instruction consists of: +`define OP_CODE_LEN 5 +`define OP_CODE 5'd +// Field A contains exclusively register to read from +`define FIELD_A_LEN (`REG_ADDR_MSB+1) +`define FIELD_A 4'd +// Field B contains register for write, memory address or other data +`define FIELD_B_LEN (`MEM_ADDR_MSB+1) +// OMG - adjust this if MEM_ADDR_MSB changes +`define FIELD_B 5'd +// Field C typically contains a constant. +`define FIELD_C_LEN 8 +`define FIELD_C 8'd +// Conditions determine the result of instruction execution. +`define CONDITION_LEN 4 +// Instruction execution options. +`define EXEC_OPT_LEN 1 + +`define PARTIAL_INSTR_LEN (`CONDITION_LEN \ + + `FIELD_B_LEN + `FIELD_C_LEN + `OP_CODE_LEN) +`define INSTR_LEN (`FIELD_A_LEN + `EXEC_OPT_LEN + `PARTIAL_INSTR_LEN) + + +// Instruction Address length: must fit into field_c +`define IADDR_LEN 8 + +// *** Instruction execution options *** +`define EXEC_OPT_NONE 1'b0 +// EXEC_OPT_TS_WR_RDY - requires thread_state to be WR_RDY +`define EXEC_OPT_TS_WR_RDY 1'b1 + +// *** CPU flags *** +`define N_FLAGS 4 +`define FLAG_ZERO(r) r[0] +`define FLAG_ONE(r) r[1] +`define FLAG_CARRY(r) r[2] +`define FLAG_USER(r) r[3] + +// *** Conditions *** +`define IF_NONE 4'b0000 + +`define IF_ONE 4'b0010 +`define IF_NOT_ONE 4'b0011 +`define IF_ZERO 4'b0100 +`define IF_NOT_ZERO 4'b0101 +`define IF_CARRY 4'b0110 +`define IF_NOT_CARRY 4'b0111 +`define IF_UF 4'b1000 +`define IF_NOT_UF 4'b1001 +//`define IF + +`define CONDITION `IF_NONE +`define IF(cond) \ +`undef CONDITION \ +`define CONDITION cond + +// *** Operation codes *** +`define OP_CODE_PROCB_C `OP_CODE 8 +`define OP_CODE_PROCB_C_FIN `OP_CODE 10 +`define OP_CODE_PROCB_C_STOP `OP_CODE 9 +`define OP_CODE_PROCB_R `OP_CODE 12 +`define OP_CODE_PROCB_R_FIN `OP_CODE 14 +`define OP_CODE_PROCB_R_STOP `OP_CODE 13 + +`define OP_TYPE_PROCB(c) (c >= 8 & c <= 15) +`define OP_TYPE_PROCB_R(c) (c >= 12 & c <= 15) + +`define OP_CODE_NEW_CTX `OP_CODE 7 +`define OP_CODE_LOAD_CTX `OP_CODE 6 + +`define OP_TYPE_INIT_CTX(c) (c == 6 | c == 7) + +`define OP_CODE_NOP `OP_CODE 0 +`define OP_CODE_HALT `OP_CODE 1 + +`define OP_CODE_ADD_R_C `OP_CODE 16 +`define OP_CODE_ADDC_R_C `OP_CODE 17 +`define OP_CODE_SUB_R_C `OP_CODE 18 +`define OP_CODE_SUBB_R_C `OP_CODE 19 +`define OP_CODE_INC_RST `OP_CODE 20 +`define OP_CODE_MV_R_C `OP_CODE 21 +`define OP_CODE_SHR1 `OP_CODE 22 +`define OP_CODE_MV_R_R `OP_CODE 23 +`define OP_CODE_AND `OP_CODE 24 + +// op:a[1:0](1-set, 2-reset, 3-invert) mask:b +// currently applicable to UF only +`define OP_CODE_FLAG `OP_CODE 25 + +`define OP_CODE_MV_UOB_R `OP_CODE 26 +`define OP_CODE_SET_OUTPUT_COMPLETE `OP_CODE 27 + +`define OP_CODE_MV_R_MEM_U `OP_CODE 28 +`define OP_CODE_MV_R_MEM_L `OP_CODE 29 +//`define OP_CODE_MV_R_MEM_2X `OP_CODE 30 + +`define OP_TYPE_MV_R_MEM(c) (c == 28 | c == 29 | c == 30) + +`define OP_CODE_JMP `OP_CODE 31 + +//`define OP_CODE_ILLEGAL(c) ( ~( \ +// c == + +`define OP_TYPE_SETS_ZF(c) ( \ + c == `OP_CODE_SUB_R_C | c == `OP_CODE_INC_RST | c == `OP_CODE_SHR1) + +`define OP_TYPE_SETS_OF(c) ( \ + c == `OP_CODE_SHR1) + +`define OP_TYPE_SETS_CF(c) ( \ + c == `OP_CODE_ADD_R_C | c == `OP_CODE_SUB_R_C \ + | c == `OP_CODE_ADDC_R_C | c == `OP_CODE_SUBB_R_C) + +`define OP_TYPE_USE_CF(c) ( \ + c == `OP_CODE_ADDC_R_C | c == `OP_CODE_SUBB_R_C) + + +// This op. potentially writes into a register +// (write might not be performed because of conditions). +// MV_R_MEM_* processed independently. +`define OP_TYPE_WRITE_REG(c) ( \ + c == `OP_CODE_ADD_R_C | c == `OP_CODE_SUB_R_C \ + | c == `OP_CODE_ADDC_R_C | c == `OP_CODE_SUBB_R_C \ + | c == `OP_CODE_INC_RST \ + | c == `OP_CODE_MV_R_C | c == `OP_CODE_SHR1 | c == `OP_CODE_MV_R_R \ + | c == `OP_CODE_AND) + +// Reads a register +`define OP_TYPE_USE_REG(c) ( \ + `OP_TYPE_WRITE_REG(c) & c != `OP_CODE_MV_R_C \ + | c == `OP_CODE_PROCB_R | c == `OP_CODE_PROCB_R_FIN \ + | c == `OP_CODE_MV_UOB_R) + +// read register only from field_a (timing issue) + +// These ops check conditions (hardcoded) +//`define OP_TYPE_CHECK_CONDITION(c) ( \ +// `OP_TYPE_WRITE_REG(c) | `OP_TYPE_PROCB(c) | c == `OP_CODE_JMP) + + +// ===== Instructions ===== +// +// *** Instructions - SHA256 subsystem *** +`define NEW_CTX(save_addr,save_len) {`FIELD_A 0, `EXEC_OPT_TS_WR_RDY, \ + `IF_NONE, `FIELD_B save_addr, `FIELD_C save_len, `OP_CODE_NEW_CTX} + +`define PROCESS_BYTES_C(addr,cnt) \ + {`FIELD_A 0, `EXEC_OPT_TS_WR_RDY, \ + `CONDITION, `FIELD_B addr, `FIELD_C cnt, `OP_CODE_PROCB_C} +`define PROCESS_BYTES_C_FINISH_CTX(addr,cnt) \ + {`FIELD_A 0, `EXEC_OPT_TS_WR_RDY, \ + `CONDITION, `FIELD_B addr, `FIELD_C cnt, `OP_CODE_PROCB_C_FIN} + +`define PROCESS_BYTES_R(addr,r) \ + {`FIELD_A r, `EXEC_OPT_TS_WR_RDY, \ + `CONDITION, `FIELD_B addr, `FIELD_C 0, `OP_CODE_PROCB_R} +`define PROCESS_BYTES_R_FINISH_CTX(addr,r) \ + {`FIELD_A r, `EXEC_OPT_TS_WR_RDY, \ + `CONDITION, `FIELD_B addr, `FIELD_C 0, `OP_CODE_PROCB_R_FIN} + +`define FINISH_CTX `PROCESS_BYTES_C_FINISH_CTX(0,0) + + +// *** Instructions - integer *** +`define ADD_R_C(r,const) {`FIELD_A r, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B r, `FIELD_C const, `OP_CODE_ADD_R_C} +`define ADDC_R_C(r,const) {`FIELD_A r, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B r, `FIELD_C const, `OP_CODE_ADDC_R_C} +`define SUB_R_C(dst,src,const) {`FIELD_A src, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B dst, `FIELD_C const, `OP_CODE_SUB_R_C} +`define SUBB_R_C(dst,src,const) {`FIELD_A src, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B dst, `FIELD_C const, `OP_CODE_SUBB_R_C} +`define INC_RST(r,const) {`FIELD_A r, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B r, `FIELD_C const, `OP_CODE_INC_RST} +`define MV_R_C(r,const) {`FIELD_A r, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B r, `FIELD_C const, `OP_CODE_MV_R_C} +`define SHR1(r) {`FIELD_A r, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B r, `FIELD_C 0, `OP_CODE_SHR1} +// We can read from one register and store into other one +`define MV_R_R(dst,src) {`FIELD_A src, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B dst, `FIELD_C 0, `OP_CODE_MV_R_R} +`define AND_R_C(dst,src,const) {`FIELD_A src, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B dst, `FIELD_C const, `OP_CODE_AND} + + +// *** Instructions - I/O *** +//`define MV_R_MEM_2X(r,addr) {`FIELD_A 0, `EXEC_OPT_NONE, \ +// `IF_NONE, `FIELD_B r, `FIELD_C addr, `OP_CODE_MV_R_MEM_2X} +`define MV_R_MEM_L(r,addr) {`FIELD_A 0, `EXEC_OPT_NONE, \ + `IF_NONE, `FIELD_B r, `FIELD_C addr, `OP_CODE_MV_R_MEM_L} +`define MV_R_MEM_U(r,addr) {`FIELD_A 0, `EXEC_OPT_NONE, \ + `IF_NONE, `FIELD_B r, `FIELD_C addr, `OP_CODE_MV_R_MEM_U} + +`define MV_UOB_R(uob_addr,r) {`FIELD_A r, `EXEC_OPT_TS_WR_RDY, \ + `IF_NONE, `FIELD_B 0, `FIELD_C uob_addr, `OP_CODE_MV_UOB_R} +`define SET_OUTPUT_COMPLETE {`FIELD_A 0, `EXEC_OPT_TS_WR_RDY, \ + `IF_NONE, `FIELD_B 0, `FIELD_C 0, `OP_CODE_SET_OUTPUT_COMPLETE} + + +// *** Instructions - execution control *** +`define NOP {`FIELD_A 0, `EXEC_OPT_NONE, \ + `IF_NONE, `FIELD_B 0, `FIELD_C 0, `OP_CODE_NOP} +`define HALT {`FIELD_A 0, `EXEC_OPT_NONE, \ + `IF_NONE, `FIELD_B 0, `FIELD_C 0, `OP_CODE_HALT} + +`define JMP(addr) {`FIELD_A 0, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B 0, `FIELD_C addr, `OP_CODE_JMP} + +`define SET_UF {`FIELD_A 0, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B 1, `FIELD_C 0, `OP_CODE_FLAG} +`define RST_UF {`FIELD_A 0, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B 2, `FIELD_C 0, `OP_CODE_FLAG} +`define INV_UF {`FIELD_A 0, `EXEC_OPT_NONE, \ + `CONDITION, `FIELD_B 3, `FIELD_C 0, `OP_CODE_FLAG} + + +// *** Registers - BRAM *** +`define R0 0 +`define R1 1 +`define R2 2 +`define R3 3 +`define R4 4 +`define R5 5 +`define R6 6 +`define R7 7 +`define R8 8 +`define R9 9 +`define R10 10 +`define R11 11 +`define R12 12 +`define R13 13 +`define R14 14 +`define R15 15 + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/add3.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/add3.v new file mode 100644 index 00000000000..bd3189e5661 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/add3.v @@ -0,0 +1,50 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +`include "../sha256.vh" + +// +// Synthesis: Optimization: Area +// +`ifndef SIMULATION + +module add3 #( + parameter WIDTH = 32, + parameter [WIDTH-1:0] IV = 0 + )( + input CLK, + input [WIDTH-1:0] a, b, c, + input en, rst, + output reg [WIDTH-1:0] o = IV + ); + +endmodule + +`else + +module add3 #( + parameter WIDTH = 32, + parameter [WIDTH-1:0] IV = 0 + )( + input CLK, + input [WIDTH-1:0] a, b, c, + input en, rst, + output reg [WIDTH-1:0] o = IV + ); + + always @(posedge CLK) + if (rst) + o <= IV; + else if (en) + o <= a + b + c; + +endmodule + +`endif diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/add3_unreg.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/add3_unreg.v new file mode 100644 index 00000000000..e7bb8fecd0f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/add3_unreg.v @@ -0,0 +1,40 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +`include "../sha256.vh" + +// +// Synthesis: Optimization: Area +// +`ifndef SIMULATION + +module add3_unreg #( + parameter WIDTH = 32 + )( + input [WIDTH-1:0] a, b, c, + output [WIDTH-1:0] o + ); + +endmodule + +`else + +module add3_unreg #( + parameter WIDTH = 32 + )( + input [WIDTH-1:0] a, b, c, + output [WIDTH-1:0] o + ); + + assign o = a + b + c; + +endmodule + +`endif diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/core_input_buf.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/core_input_buf.v new file mode 100644 index 00000000000..68581082f5e --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/core_input_buf.v @@ -0,0 +1,36 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module core_input_buf( + input CLK, + + input [31:0] din, + input [3:0] wr_addr, + input wr_en, + + output reg [31:0] dout = 0, + input rd_en, + input [3:0] rd_addr + ); + + // Data block 512-bit (2x) + (* RAM_STYLE="DISTRIBUTED" *) + reg [31:0] input_buf [0:15]; + + always @(posedge CLK) begin + if (rd_en) + dout <= input_buf [rd_addr]; + if (wr_en) + input_buf [wr_addr] <= `SWAP(din); + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/core_output_buf_bram.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/core_output_buf_bram.v new file mode 100644 index 00000000000..84aa459088c --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/core_output_buf_bram.v @@ -0,0 +1,136 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module core_output_buf_bram( + input CLK, + + input [31:0] din, + input wr_en, + input [3:0] wr_addr, + input wr_seq, + + // ============================================================== + // + // OUTPUT OPERATION + // + // 1. At some stage, 'core_out_ready' asserts. + // core_out_ctx_num, core_out_seq_num are set accordingly. + // 2. Wait for input rd_en, then transmit 16 x 16-bit + // + // ============================================================== + output reg [15:0] dout, + output reg core_out_ready = 0, core_out_start = 0, + output reg core_out_ctx_num, core_out_seq_num, + input rd_en + ); + + (* RAM_STYLE="BLOCK" *) + reg [31:0] mem [31:0]; + + reg full0 = 0, full1 = 0; + wire rst_full0, rst_full1; + reg seq0, seq1; + reg [15:0] X_INPUT_ERRORS = 0; + + + // ***************************************************** + // + // Input + // + // ***************************************************** + always @(posedge CLK) begin + if (wr_en) + mem [wr_addr] <= din; + + if (wr_en & wr_addr == 0) begin + full0 <= 1; + seq0 <= wr_seq; + end + if (rst_full0) + full0 <= 0; + + if (wr_en & wr_addr == 8) begin + full1 <= 1; + seq1 <= wr_seq; + end + if (rst_full1) + full1 <= 0; + +`ifdef SIMULATION + // Output has enough bandwith, there should be no errors + if (wr_en & wr_addr == 0 & full0 + | wr_en & wr_addr == 8 & full1) + X_INPUT_ERRORS <= X_INPUT_ERRORS + 1'b1; +`endif + end + + + // ***************************************************** + // + // Output + // + // ***************************************************** + reg [3:0] output_cnt = 0; // output are 16 words X 16 bit + + reg [31:0] mem_r; + + localparam STATE_OUTPUT_NONE = 0, + STATE_OUTPUT_READY = 1, + STATE_OUTPUT_START = 2, + STATE_OUTPUT_READ_MEM = 3; + + (* FSM_EXTRACT="true", FSM_ENCODING="one-hot" *) + reg [1:0] state_output = STATE_OUTPUT_NONE; + + always @(posedge CLK) begin + + case(state_output) + STATE_OUTPUT_NONE: if (full0 | full1) begin + core_out_ready <= 1; + core_out_ctx_num <= full0 ? 1'b0 : 1'b1; + core_out_seq_num <= full0 ? seq0 : seq1; + state_output <= STATE_OUTPUT_READY; + end + + STATE_OUTPUT_READY: if (rd_en) begin + state_output <= STATE_OUTPUT_START; + end + + STATE_OUTPUT_START: begin + core_out_ready <= 0; + state_output <= STATE_OUTPUT_READ_MEM; + end + + STATE_OUTPUT_READ_MEM: begin + core_out_start <= output_cnt == 0; + mem_r <= mem [{ core_out_ctx_num, output_cnt[3:1] }]; + + output_cnt <= output_cnt + 1'b1; + if (output_cnt == 15) + state_output <= STATE_OUTPUT_NONE; + end + endcase + end + + reg dout_en = 0; + + always @(posedge CLK) begin + dout_en <= state_output == STATE_OUTPUT_READ_MEM; + if (dout_en) + dout <= output_cnt[0] ? mem_r[31:16] : mem_r[15:0]; + end + + assign rst_full0 = ~core_out_ctx_num & state_output == STATE_OUTPUT_START; + assign rst_full1 = core_out_ctx_num & state_output == STATE_OUTPUT_START; + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/ff16.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/ff16.v new file mode 100644 index 00000000000..aafa5565e22 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/ff16.v @@ -0,0 +1,45 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +`include "../sha256.vh" + +`ifndef SIMULATION + +module ff16 #( + parameter N = 16 + )( + input CLK, + input en, rst, + input [N-1:0] i, + output reg [N-1:0] o = 0 + ); + +endmodule + +`else + +module ff16 #( + parameter N = 16 + )( + input CLK, + input en, rst, + input [N-1:0] i, + output reg [N-1:0] o = 0 + ); + + always @(posedge CLK) + if (rst) + o <= 0; + else if (en) + o <= i; + +endmodule + +`endif diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/ff32.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/ff32.v new file mode 100644 index 00000000000..d0477c700bd --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/ff32.v @@ -0,0 +1,45 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +`include "../sha256.vh" + +`ifndef SIMULATION + +module ff32 #( + parameter N = 32 + )( + input CLK, + input en, rst, + input [N-1:0] i, + output reg [N-1:0] o = 0 + ); + +endmodule + +`else + +module ff32 #( + parameter N = 32 + )( + input CLK, + input en, rst, + input [N-1:0] i, + output reg [N-1:0] o = 0 + ); + + always @(posedge CLK) + if (rst) + o <= 0; + else if (en) + o <= i; + +endmodule + +`endif diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256_Kt_bram.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256_Kt_bram.v new file mode 100644 index 00000000000..760c1efbcda --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256_Kt_bram.v @@ -0,0 +1,88 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +`define Kt_N_CYCLES 72 + +`define Kt(x) (K[32*(`Kt_N_CYCLES-(x))-1 -:32]) + + +module sha256_Kt_bram( + input CLK, + input en, + input [6:0] t, + output [31:0] Kt, + + // "dummy" 2nd write-only port + input wr_en, + input wr_addr + ); + + localparam [32*`Kt_N_CYCLES-1 :0] K = { + 32'h0, 32'h0, 32'h0, 32'h0, + 32'h0, 32'h0, 32'h0, + 32'h428a2f98, 32'h71374491, 32'hb5c0fbcf, 32'he9b5dba5, + 32'h3956c25b, 32'h59f111f1, 32'h923f82a4, 32'hab1c5ed5, + 32'hd807aa98, 32'h12835b01, 32'h243185be, 32'h550c7dc3, + 32'h72be5d74, 32'h80deb1fe, 32'h9bdc06a7, 32'hc19bf174, + 32'he49b69c1, 32'hefbe4786, 32'h0fc19dc6, 32'h240ca1cc, + 32'h2de92c6f, 32'h4a7484aa, 32'h5cb0a9dc, 32'h76f988da, + 32'h983e5152, 32'ha831c66d, 32'hb00327c8, 32'hbf597fc7, + 32'hc6e00bf3, 32'hd5a79147, 32'h06ca6351, 32'h14292967, + 32'h27b70a85, 32'h2e1b2138, 32'h4d2c6dfc, 32'h53380d13, + 32'h650a7354, 32'h766a0abb, 32'h81c2c92e, 32'h92722c85, + 32'ha2bfe8a1, 32'ha81a664b, 32'hc24b8b70, 32'hc76c51a3, + 32'hd192e819, 32'hd6990624, 32'hf40e3585, 32'h106aa070, + 32'h19a4c116, 32'h1e376c08, 32'h2748774c, 32'h34b0bcb5, + 32'h391c0cb3, 32'h4ed8aa4a, 32'h5b9cca4f, 32'h682e6ff3, + 32'h748f82ee, 32'h78a5636f, 32'h84c87814, 32'h8cc70208, + 32'h90befffa, 32'ha4506ceb, 32'hbef9a3f7, 32'hc67178f2, + 32'h0 + }; + + integer i; + + (* RAM_STYLE="block" *) + reg [31:0] mem [127:0]; + initial + for (i = 0; i < 72; i = i+1) + mem[i] = `Kt(i); + + reg [31:0] mem_r; + always @(posedge CLK) + if (en) + mem_r <= mem[t]; + + + reg en_r = 0, en_r2 = 0; + always @(posedge CLK) begin + en_r <= en; + en_r2 <= en_r; + end + + wire rst = en_r2 & ~en_r; + + // Prevent inference of BRAM output regs + ff32 ff_reg( + .CLK(CLK), .en(en_r), .rst(rst), + .i(mem_r), .o(Kt) + ); + + + + // + // Declaring "dummy" 2nd write-only port + // + (* KEEP="true" *) wire wr_en_keep = wr_en; + (* KEEP="true" *) wire wr_addr_keep = wr_addr; + always @(posedge CLK) + if (wr_en_keep) + mem[wr_addr_keep] <= 1'b0; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256block.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256block.v new file mode 100644 index 00000000000..42feed364c4 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256block.v @@ -0,0 +1,200 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +`include "../sha256.vh" + +`define SHA256_R0(x) (`CYCLIC (x, 7) ^ `CYCLIC (x, 18) ^ (x >> 3)) +`define SHA256_R1(x) (`CYCLIC (x, 17) ^ `CYCLIC (x, 19) ^ (x >> 10)) + + +module sha256block( + input CLK, + + input external_input_en, // select external input + input ctx_save_en, // select save into memory from context + //input save_en, + input [31:0] in, + + // memory ops + input mem_wr_en, + input mem_rd_en0, mem_rd_en1, + input [6:0] wr_addr, rd_addr0, rd_addr1, + + //input R0_en, R1_rst, R1_en, W16_rst, W16_en, + input R0_en, R1_en, W16_rst, W16_en, Wt_2_en, + + // Kt unit + input Kt_en, + input [6:0] K_round_num, + + // Context unit + input S1_CH_I_rst, S1_CH_I_en, + input S0_en, MAJ_en, block2ctx_en, + input ctx_en, + + input output_en, + output [31:0] o + ); + + //reg [31:0] save_r = 0; + wire [31:0] mem_input; + + wire [31:0] mem0_out, mem1_out; + + w_mem w_mem( + .CLK(CLK), + //.in(save_r), + .in(mem_input), + .wr_en(mem_wr_en), .wr_addr(wr_addr), + + .rd_addr0(rd_addr0), .rd_addr1(rd_addr1), + .rd_en0(mem_rd_en0), .rd_en1(mem_rd_en1), + .out0(mem0_out), .out1(mem1_out) // right out from BRAM + ); + + // + // Prevent usage of BRAM output registers + // + reg mem_rd_en0_r = 0, mem_rd_en1_r = 0; + always @(posedge CLK) begin + mem_rd_en0_r <= mem_rd_en0; + mem_rd_en1_r <= mem_rd_en1; + end + + wire [31:0] mem0, mem1; + + ff32 ff_reg0( + .CLK(CLK), .en(mem_rd_en0_r), .rst(1'b0), + .i(mem0_out), .o(mem0) + ); + + ff32 ff_reg1( + .CLK(CLK), .en(mem_rd_en1_r), .rst(1'b0), + .i(mem1_out), .o(mem1) + ); + + + wire [31:0] Wtmp = + external_input_en ? in : + R0_en ? `SHA256_R0(mem1) + mem0 : + mem0; + + reg [31:0] W16 = 0; + always @(posedge CLK) + if (W16_rst) + W16 <= 0; + else if (W16_en) + W16 <= mem1; +/* + reg [31:0] R1 = 0; + always @(posedge CLK) + if (R1_rst) + R1 <= 0; + else if (R1_en) + R1 <= `SHA256_R1(Wt); +*/ + wire [31:0] R1; + + wire [31:0] Wt; + add3 Wt_inst (.CLK(CLK), .en(1'b1), .rst(1'b0), + .a(Wtmp), .b(W16), .c(R1), .o(Wt) ); + + reg [31:0] Wt_2; + always @(posedge CLK) + if (Wt_2_en) + Wt_2 <= Wt; + + assign R1 = R1_en ? `SHA256_R1(Wt_2) : 0; + + wire [31:0] ctx2block; + assign mem_input = ctx_save_en ? ctx2block : Wt_2;//Wt; + //always @(posedge CLK) + // if (save_en) + // save_r <= ctx_save_en ? ctx2block : Wt; + + + wire [31:0] Kt; + sha256_Kt_bram sha256_Kt( + .CLK(CLK), + .en(Kt_en), .t(K_round_num), .Kt(Kt), + .wr_en(1'b0), .wr_addr(1'b0) + ); + + + sha256ctx sha256ctx( + .CLK(CLK), + .S1_CH_I_rst(S1_CH_I_rst), .S1_CH_I_en(S1_CH_I_en), + .S0_en(S0_en), .MAJ_en(MAJ_en), .block2ctx_en(block2ctx_en), + .en(ctx_en),// .D2E_en(1'b0), + .block2ctx(mem1), .Wt(Wt), .Kt(Kt), + .output_en(output_en), .o(ctx2block) + ); + + assign o = ctx2block; + +endmodule + + +// Memory for W[t], IVs and saved contexts. +// 1 write channel, 2 read channels. +// Expecting 2 BRAM x 1 Kbyte. +// +// outputs: +// mem0 - W[t-7], values for post-block additions +// mem1 - W[t-15], IVs & saved contexts (via block2ctx) +// +// content +// 0..15 - current block +// 24..31 - IVs in reverse order (H..A) +// 32..63 - context save slots (0..3) for seq0 +// 96..127 - context save slots (0..3) for seq1 +// +module w_mem( + input CLK, + + input [31:0] in, + input wr_en, + input [6:0] wr_addr, + + input [6:0] rd_addr0, rd_addr1, + input rd_en0, rd_en1, + output [31:0] out0, out1 + ); + + localparam [255:0] SHA256_IV = `SHA256_IV; + + integer k; + + (* RAM_STYLE="BLOCK" *) + reg [31:0] mem0 [127:0], mem1 [127:0]; + initial + for (k=24; k <= 31; k=k+1) begin + mem0[k] = SHA256_IV[(31-k)*32 +:32]; + mem1[k] = SHA256_IV[(31-k)*32 +:32]; + end + + reg [31:0] mem0_r = 0, mem1_r = 0; + + always @(posedge CLK) begin + if (wr_en) begin + mem0 [wr_addr] <= in; + mem1 [wr_addr] <= in; + end + + if (rd_en0) + mem0_r <= mem0 [rd_addr0]; + if (rd_en1) + mem1_r <= mem1 [rd_addr1]; + end + + assign out0 = mem0_r; + assign out1 = mem1_r; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256core.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256core.v new file mode 100644 index 00000000000..6f51b689fa9 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256core.v @@ -0,0 +1,335 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +`ifdef SIMULATION +// +// - fully performs SHA-256 computation, incl. addition after each block +// - it's able for multiple blocks +// - 2 blocks are performed in 2*(64+8) = 144 cycles, given +// input buffer always has supply of data in time. +// +module sha256core #( + parameter ID = -1 + )( + input CLK, + // Synchronization of several cores + input start, // asserts on cycle 0 of each sequence + output reg ready = 1, // input buffer is ready for data + + input wr_en, + input [31:0] in, + input [3:0] wr_addr, + input [`BLK_OP_MSB:0] input_blk_op, // registered on set_input_ready + input input_seq, // registered on set_input_ready + input set_input_ready, // valid only when wr_en is asserted + + output [31:0] dout, + output dout_seq, + output reg dout_en = 0 + //output dout_en // Asserts 1 cycle before actual data + ); + + + // *************************************************************** + // + // STATE, ROUND COUNTERS + // + // *************************************************************** + reg [6:0] cnt = 72; // round count 0..71. (72 - idle) + + wire start_eqn = start & input_ready & (cnt == 71 | cnt == 72) + // Same sequence, same computation - wait until IVs are saved + & (`BLK_OP_IF_NEW_CTX(input_blk_op_r) + | input_seq_num_r != dout_seq + | after_cnt >= 6); + + always @(posedge CLK) + if (start_eqn) begin + // If new block has same sequence number - wait + cnt <= 0; + blk_op <= input_blk_op_r; + seq_num <= input_seq_num_r; + end + else if (cnt != 72) + cnt <= cnt + 1'b1; + + // it requires to finish operation after "main" counter is done + reg [3:0] after_cnt = 12; + always @(posedge CLK) + if (cnt == 69) begin + after_cnt <= 0; + after_blk_op <= blk_op; + after_seq_num <= seq_num; + end + else if (after_cnt < 12) + after_cnt <= after_cnt + 1'b1; + + reg ctx_en = 0; // clock enable for A..G + always @(posedge CLK) + if (input_ready) + ctx_en <= 1; + else if (cnt == 72 & after_cnt == 12) + ctx_en <= 0; + + + // *************************************************************** + // + // INPUT CONTROLS + // + // *************************************************************** + always @(posedge CLK) + if (wr_en) + ready <= 0; + else if (cnt == 8) + ready <= 1; + + reg input_ready = 0; // input buffer has required data + always @(posedge CLK) + if (wr_en & set_input_ready) + input_ready <= 1; + else if (start_eqn) + input_ready <= 0; + +`ifdef SIMULATION + reg z = 0; + reg [16:0] X_BLK_NUM = 0; + always @(posedge CLK) + if (wr_en & set_input_ready) begin + X_BLK_NUM <= X_BLK_NUM + 1'b1; + if (X_BLK_NUM == 9 | X_BLK_NUM == 10 | X_BLK_NUM == 11 | X_BLK_NUM == 12) + z <= 1; + if (ID==0 & input_seq==1) + z <= 1; + end +`endif + + // Options for block computation + reg [`BLK_OP_MSB:0] input_blk_op_r, blk_op, after_blk_op; + reg input_seq_num_r, seq_num, after_seq_num; + always @(posedge CLK) + if (wr_en & set_input_ready) begin + input_blk_op_r <= input_blk_op; + input_seq_num_r <= input_seq; + end + + assign dout_seq = after_seq_num; + + + // *************************************************************** + // + // INPUT - BUFFER & OTHER DATA + // + // allows to perform input independently from other operations. + // If input data is ready, computaion for the next block + // starts before it finishes the current block. + // + // *************************************************************** + + wire input_buf_rd_en = cnt >= 7 & cnt <= 22; + wire [3:0] input_buf_rd_addr = cnt - 7; + wire [31:0] input_buf_dout; + + core_input_buf core_input_buf( + .CLK(CLK), .din(in), .wr_en(wr_en), + .wr_addr(wr_addr), + .dout(input_buf_dout), .rd_en(input_buf_rd_en), + .rd_addr(input_buf_rd_addr) + ); + + + + // *************************************************************** + // + // BLOCK & CONTEXT OPERATION. + // + // *************************************************************** + + // Block controls - read from input buffer & memory + reg external_input_en = 0; + always @(posedge CLK) + external_input_en <= input_buf_rd_en; + + wire mem_rd_en1 = + // Read starts 1 cycle before mem0 to fill-in W[t-16] + cnt >= 21 & cnt <= 69 + // load context from mem1 via block2ctx + | cnt >= 0 & cnt <= 7; + + wire [3:0] rd_addr1_16_63 = cnt - 22 - 15; + wire [6:0] rd_addr1 = + // Load context from mem1 via block2ctx + cnt >= 0 & cnt <= 7 ? + ( `BLK_OP_IF_NEW_CTX(blk_op) ? { 4'b0011, cnt[2:0] } : + { seq_num, 1'b1, `BLK_OP_LOAD_CTX_NUM(blk_op), cnt[2:0] } + ) + : { 3'b000, rd_addr1_16_63 }; // Read W[t-15] + + + wire mem_rd_en0 = //cnt >= 22 & cnt <= 69 + cnt >= 21 & cnt <= 69 // opt. + | after_cnt >= 0 & after_cnt <= 7; // Load IVs for post-additions + + wire [3:0] rd_addr0_16_63 = cnt - 22 - 7; + wire [6:0] rd_addr0 = + // Load IVs for post-additions + after_cnt >= 0 & after_cnt <= 7 ? + ( `BLK_OP_IF_NEW_CTX(after_blk_op) ? { 4'b0011, after_cnt[2:0] } : + { after_seq_num, 1'b1, `BLK_OP_LOAD_CTX_NUM(after_blk_op), + after_cnt[2:0] } + ) + : { 3'b000, rd_addr0_16_63 }; // Read W[t-7] + + + // Block controls - write into memory + reg ctx_save_en = 0; + always @(posedge CLK) + ctx_save_en <= after_cnt >= 3 & after_cnt <= 10; + + wire mem_wr_en = + cnt >= 10 & cnt <= 66 // Write W[t] for t in 0..47 + //| after_cnt >= 4 & after_cnt <= 11; // write result + | ctx_save_en;// & ~BLK_OP_END_COMP_OUTPUT(after_blk_op); + + wire [3:0] mem_wr_addr_0_56 = cnt - 10; + wire [2:0] mem_wr_addr_result = after_cnt - 4; + + wire [6:0] mem_wr_addr = + ctx_save_en ? + // Save context into slot 0..N + { after_seq_num, 1'b1, `BLK_OP_SAVE_CTX_NUM(after_blk_op), + mem_wr_addr_result } + : { 3'b000, mem_wr_addr_0_56 }; + + + // Block controls - R0, R1, W[t-2], W[t-15] + //wire R0_en = cnt >= 23 & cnt <= 71; + reg R0_en = 0; + always @(posedge CLK) + R0_en <= cnt >= 22 & cnt <= 70; + + wire Wt_2_en = cnt >= 9 & cnt <= 70; + + //wire R1_rst = cnt == 71; + //wire R1_en = cnt >= 23 & cnt <= 70; + reg R1_en = 0; + always @(posedge CLK) + R1_en <= cnt >= 23 & cnt <= 70; + + wire W16_rst = cnt == 71; + wire W16_en = cnt >= 23 & cnt <= 70; + + // K unit controls + wire Kt_en = cnt >= 7 & cnt <= 70; + wire [6:0] K_round_num = cnt; + + + // Context controls + reg block2ctx_en = 0; + always @(posedge CLK) + block2ctx_en <= cnt >= 1 & cnt <= 8; + + wire MAJ_en = ~block2ctx_en; + + wire S0_en = ~block2ctx_en; + + wire S1_CH_I_rst = after_cnt == 3; + reg S1_CH_I_en = 0; + always @(posedge CLK) + S1_CH_I_en <= cnt >= 8 & cnt <= 71; + + reg output_en = 0; + always @(posedge CLK) + output_en <= after_cnt >= 2 & after_cnt <= 9; + + always @(posedge CLK) + dout_en <= after_cnt >= 2 & after_cnt <= 9 + & `BLK_OP_END_COMP_OUTPUT(after_blk_op); + + //assign dout_en = output_en; + + + wire [31:0] block_output; + sha256block sha256block( + .CLK(CLK), + .external_input_en(external_input_en), .ctx_save_en(ctx_save_en), + .in(input_buf_dout),// .save_en(1'b1), + + .mem_wr_en(mem_wr_en), .wr_addr(mem_wr_addr), + .mem_rd_en0(mem_rd_en0), .mem_rd_en1(mem_rd_en1), + .rd_addr0(rd_addr0), .rd_addr1(rd_addr1), + + .R0_en(R0_en), .R1_en(R1_en),// .R1_rst(R1_rst), + .W16_rst(W16_rst), .W16_en(W16_en), .Wt_2_en(Wt_2_en), + + .Kt_en(Kt_en), .K_round_num(K_round_num), + + .S1_CH_I_rst(S1_CH_I_rst), .S1_CH_I_en(S1_CH_I_en), + .S0_en(S0_en), .MAJ_en(MAJ_en), .block2ctx_en(block2ctx_en), + .ctx_en(ctx_en), .output_en(output_en), + .o(block_output) + ); + + assign dout = `SWAP(block_output); + +endmodule + +`else + +module sha256core #( + parameter ID = -1 + )( + input CLK, + // Synchronization of several cores + input start, // asserts on cycle 0 of each sequence + output reg ready = 1, // input buffer is ready for data + + input wr_en, + input [31:0] in, + input [3:0] wr_addr, + input [`BLK_OP_MSB:0] input_blk_op, // registered on set_input_ready + input input_seq, // registered on set_input_ready + input set_input_ready, // valid only when wr_en is asserted + + output [31:0] dout, + output dout_seq, + output reg dout_en = 0 + ); + +endmodule + +`endif + + +module sha256core_dummy( + input CLK, + // Synchronization of several cores + input start, // asserts on cycle 0 of each sequence + output ready, // input buffer is ready for data + + input wr_en, + input [31:0] in, + input [3:0] wr_addr, + input [`BLK_OP_MSB:0] input_blk_op, // registered on set_input_ready + input input_seq, // registered on set_input_ready + input set_input_ready, // valid only when wr_en is asserted + + output [31:0] dout, + output dout_seq, + output dout_en + ); + + (* KEEP="true" *) assign ready = 1'b1; + //(* KEEP="true" *) assign dout = 1'b0; + (* KEEP="true" *) assign dout_seq = 1'b0; + (* KEEP="true" *) assign dout_en = 1'b0; + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256core_test.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256core_test.v new file mode 100644 index 00000000000..6dbfcea2de0 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256core_test.v @@ -0,0 +1,215 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +`include "../sha256.vh" + +module sha256core_test(); + + integer k; + + reg CLK = 0; // Each cycle is 20ns + + reg start = 0; + reg [6:0] round_cnt = 0; + always @(posedge CLK) begin + if (start) + start <= 0; + + if (round_cnt == 71) begin + round_cnt <= 0; + start <= 1; + end + else + round_cnt <= round_cnt + 1'b1; + end + + + reg wr_en = 0; + reg [31:0] i; + reg [3:0] wr_addr; + reg [`BLK_OP_MSB:0] blk_op = 0; + reg set_input_ready = 0; + + wire [15:0] core_dout; + reg rd_en = 0; + + sha256core sha256core( + .CLK(CLK), + + .start(start), .input_seq_num(), + .ready(ready), + + .wr_en(wr_en), .in(i), .wr_addr(wr_addr), + .input_blk_op(blk_op), + .input_seq(1'b0), .set_input_ready(set_input_ready), + + .dout(core_dout), .dout_en(core_dout_en), + ); + + + initial begin + #20; + // + // TEST 1. + // + // Sending 1st block from the 1st element from the test vector + // from sha256crypt reference implementation [1] as follows: + // + // { "$5$saltstring", "Hello world!", + // "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5" }, + // + // Sending 16 words X 32 bit. + // Actually that's concatenated "Hello world!", salt "saltstring" + // and one more "Hello world!" plus SHA512 padding and data length. + // Data size is 1 block. + // + wr_en <= 1; + //`BLK_OP_IF_CONTINUE_CTX(blk_op) <= 0; // unused + `BLK_OP_IF_NEW_CTX(blk_op) <= 1; // new context + //`BLK_OP_LOAD_CTX_NUM(blk_op) <= 0; // default 0 + `BLK_OP_SAVE_CTX_NUM(blk_op) <= 0; // save to slot 0 + `BLK_OP_END_COMP_OUTPUT(blk_op) <= 1; // output result + i <= 32'h6c6c6548; wr_addr <= 0; #20; + i <= 32'h6f77206f; wr_addr <= 1; #20; + i <= 32'h21646c72; wr_addr <= 2; #20; + i <= 32'h746c6173; wr_addr <= 3; #20; + i <= 32'h69727473; wr_addr <= 4; #20; + i <= 32'h6548676e; wr_addr <= 5; #20; + i <= 32'h206f6c6c; wr_addr <= 6; #20; + i <= 32'h6c726f77; wr_addr <= 7; #20; + i <= 32'h00802164; wr_addr <= 8; #20; + + for (k=9; k <= 14; k=k+1) begin + i <= 32'h0; wr_addr <= k; #20; + end + set_input_ready <= 1; + i <= 32'h10010000; wr_addr <= 15; #20; + set_input_ready <= 0; + wr_en <= 0; + #20; + //start <= 1; #20; + //start <= 0; + + // + // After the run, memory must contain: (no SWAP) + // (cells 32-39 of sha256block.w_mem.mem0) + // [39] 4b30312f + // [38] 1a4b690a + // ... + // [33] 6a322253 + // [32] bd37bfc1 + // + + while (~ready) #20; + + // + // TEST 2. + // + // Performing 2nd computation from the 1st element from the reference + // implementation. + // The content also begins with "Hello world!saltstring" + // Follows binary data derived from the previous computation: + // - 12 first bytes (=key_len) from the previous result ("alternate sum") + // - "Take the binary representation of the length of the key and for every + // 1 add the alternate sum, for every 0 the key." + // Data size is 2 blocks. + // + wr_en <= 1; + //`BLK_OP_IF_CONTINUE_CTX(blk_op) <= 0; + `BLK_OP_IF_NEW_CTX(blk_op) <= 1; // new context + //`BLK_OP_LOAD_CTX_NUM(blk_op) <= 0; + `BLK_OP_SAVE_CTX_NUM(blk_op) <= 1; // save into slot 1 + i <= 32'h6c6c6548; wr_addr <= 0; #20; + i <= 32'h6f77206f; wr_addr <= 1; #20; + i <= 32'h21646c72; wr_addr <= 2; #20; + i <= 32'h746c6173; wr_addr <= 3; #20; + i <= 32'h69727473; wr_addr <= 4; #20; + i <= 32'h304b676e; wr_addr <= 5; #20; + i <= 32'h4b1a2f31; wr_addr <= 6; #20; + i <= 32'he12f0a69; wr_addr <= 7; #20; + i <= 32'h65488c9a; wr_addr <= 8; #20; + i <= 32'h206f6c6c; wr_addr <= 9; #20; + i <= 32'h6c726f77; wr_addr <= 10; #20; + i <= 32'h65482164; wr_addr <= 11; #20; + i <= 32'h206f6c6c; wr_addr <= 12; #20; + i <= 32'h6c726f77; wr_addr <= 13; #20; + i <= 32'h304b2164; wr_addr <= 14; #20; + set_input_ready <= 1; + i <= 32'h4b1a2f31; wr_addr <= 15; #20; + set_input_ready <= 0; + wr_en <= 0; + // [7] 4d2bbb07 + // [0] b3c2ba3e + + while (~ready) #20; +/* + // Sending the 2nd block (final) + wr_en <= 1; + //`BLK_OP_IF_CONTINUE_CTX(blk_op) <= 1; // the next block, continue context + `BLK_OP_IF_NEW_CTX(blk_op) <= 0; + `BLK_OP_LOAD_CTX_NUM(blk_op) <= 1; // slot# with values from previous block + `BLK_OP_SAVE_CTX_NUM(blk_op) <= 3; // save into slot 3 + set_input_ready <= 1; + i <= 64'h06ad7ce39ea3893f; wr_addr <= 0; #20; + set_input_ready <= 0; + i <= 64'hedff998f3b647fb3; wr_addr <= 1; #20; + i <= 64'hd5cfed28ff76201b; wr_addr <= 2; #20; + i <= 64'h6e12f50c6dce61bc; wr_addr <= 3; #20; + i <= 64'he19f993d7cd8e59a; wr_addr <= 4; #20; + i <= 64'h0bf90ddc132c1287; wr_addr <= 5; #20; + i <= 64'h93d246618124ee15; wr_addr <= 6; #20; + i <= 64'h0000000000802cf9; wr_addr <= 7; #20; + for (k=8; k <= 14; k=k+1) begin + i <= 64'h0; wr_addr <= k; #20; + end + i <= 64'hd005000000000000; wr_addr <= 15; #20; + wr_en <= 0; + // memory: + // [7] d31227da_ebe0b43e + // [0] d8a1cff2_fbd26c81 + + while (~ready) #20; +*/ + end + + // ***************************************************** + // + // Collect output from the core (16 x 16) + // + // ***************************************************** +/* + reg [15:0] CORE_OUTPUT [15:0]; + + initial begin + #20; + while (~core_out_ready) #20; + rd_en <= 1; #20; + rd_en <= 0; + // Using: core_output_buf_bram + // core_rd_en to core_out_start delay: 2 cycles + // core_out_start to 1st data word delay: 1 cycle + while (~core_out_start) #20; + #20; + for (k=0; k < 16; k=k+1) begin + CORE_OUTPUT [k] <= core_dout; #20; + end + + end +*/ + + initial begin + #5; + while(1) begin + CLK <= ~CLK; #10; + end + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256ctx.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256ctx.v new file mode 100644 index 00000000000..99485858aa6 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256core/sha256ctx.v @@ -0,0 +1,125 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +`include "../sha256.vh" + +`define SHA256_CH(x, y, z) ((x & y) ^ (~x & z)) +`define SHA256_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +`define SHA256_S0(x) (`CYCLIC (x, 2) ^ `CYCLIC (x, 13) ^ `CYCLIC (x, 22)) +`define SHA256_S1(x) (`CYCLIC (x, 6) ^ `CYCLIC (x, 11) ^ `CYCLIC (x, 25)) + + +// Notes. +// +// - At the same time 2 contexts are running, in 2 clock cycles +// each one performs one round. +// - Both contexts are independent one from another. +// +// - Performs SHA256 block (64 rounds) in 64 + 8 cycles +// - It performs operations other than 64 rounds, such as post-addition +// and output of computed result for save. To accomplish that, +// it has ability to set passby I->A and D->E via adders +// (other inputs of adders are set to 0 at that time). +// - For 8 cycles after 64 rounds, it performs addition with values +// from the previous block (input via Wt) and output of computed +// result for save. Also the result remains in registers and is +// used for subsequent block. +// +// Synthesis option: "Optimization Goal: Area" +// Map option: "LUT Combining: Auto" +// +//`ifdef SIMULATION + +module sha256ctx( + input CLK, + + input S1_CH_I_rst, S1_CH_I_en, + input S0_en, MAJ_en, block2ctx_en, + //input D2E_en, // enable D2->E pass-by + input en, + + input [31:0] block2ctx, // loading context from mem1 + input [31:0] Wt, Kt, + + input output_en, + output reg [31:0] o + //output [31:0] o + ); + + reg [31:0] B = 0, C = 0, D = 0, E = 0, F = 0, G = 0; + + wire [31:0] I; + //add3 I_inst ( .CLK(CLK), .en(1'b1), .rst(1'b0), + // .a(G), .b(Wt), .c(Kt), .o(I) ); + add3_unreg I_inst( .a(G), .b(Wt), .c(Kt), .o(I) ); + + reg [31:0] S1 = 0, CH = 0, I_r = 0; + always @(posedge CLK) + if (S1_CH_I_rst) begin + S1 <= 0; + CH <= 0; + I_r <= 0; + end + else if (S1_CH_I_en) begin + S1 <= `SHA256_S1(E_input); + CH <= `SHA256_CH(E_input, E, F); + I_r <= I; + end + + wire [31:0] T1; + add3_unreg T1_inst( .a(I_r), .b(S1), .c(CH), .o(T1) ); + + //wire [31:0] E_input = D + (D2E_en ? 0 : T1); // 1 LUT/bit + wire [31:0] E_input = D + T1; + + wire [31:0] S0 = ~S0_en ? 0 : `SHA256_S0(A); + + wire [31:0] MAJ = block2ctx_en ? block2ctx : + MAJ_en ? `SHA256_MAJ(A, B, C) : 0; + + wire [31:0] A; + add3 A_inst (.CLK(CLK), .en(1'b1), .rst(1'b0), + .a(T1), .b(S0), .c(MAJ), .o(A) ); + + always @(posedge CLK) if (en) begin + B <= A; + C <= B; + D <= C; + E <= E_input; + F <= E; + G <= F; + end + + //assign o = I; + always @(posedge CLK) + if (output_en) + o <= I; + + +endmodule +/* +`else + +module sha256ctx( + input CLK, + + input S1_CH_rst, S0_rst, MAJ_rst, + input D2E_en, + input block2ctx_en, T1_rst, + + input [31:0] block2ctx, + input [31:0] Wt, Kt, + output [31:0] o + ); + +endmodule + +`endif +*/ diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt.ucf b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt.ucf new file mode 100644 index 00000000000..ea65412cbf9 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt.ucf @@ -0,0 +1,586 @@ +# +# This software is Copyright (c) 2018 Denis Burykin +# [denis_burykin yahoo com], [denis-burykin2014 yandex ru] +# and it is hereby released to the general public under the following terms: +# Redistribution and use in source and binary forms, with or without +# modification, are permitted. +# + + +// =========================================================== +// Nodes (input to units) - left side +AREA_GROUP "node1" RANGE=SLICE_X22Y26:SLICE_X39Y29; +INST "pkt_comm/bcast_net/node[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[0].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[1].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[2].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[3].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[4].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[5].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[6].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[7].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[8].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[9].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; +INST "pkt_comm/units[10].unit_in_regs/stage[1].r*" AREA_GROUP="node1"; + +AREA_GROUP "node2" RANGE=SLICE_X18Y76:SLICE_X42Y85; +INST "pkt_comm/bcast_net/node[2].r*" AREA_GROUP="node2"; +INST "pkt_comm/units[0].unit_in_regs/stage[2].r*" AREA_GROUP="node2"; +INST "pkt_comm/units[1].unit_in_regs/stage[2].r*" AREA_GROUP="node2"; +INST "pkt_comm/units[2].unit_in_regs/stage[2].r*" AREA_GROUP="node2"; +INST "pkt_comm/units[3].unit_in_regs/stage[2].r*" AREA_GROUP="node2"; +INST "pkt_comm/units[4].unit_in_regs/stage[2].r*" AREA_GROUP="node2"; +INST "pkt_comm/units[5].unit_in_regs/stage[2].r*" AREA_GROUP="node2"; +INST "pkt_comm/units[6].unit_in_regs/stage[2].r*" AREA_GROUP="node2"; + +AREA_GROUP "node3" RANGE=SLICE_X20Y135:SLICE_X43Y139; +INST "pkt_comm/bcast_net/node[3].r*" AREA_GROUP="node3"; +INST "pkt_comm/units[0].unit_in_regs/stage[3].r*" AREA_GROUP="node3"; +INST "pkt_comm/units[1].unit_in_regs/stage[3].r*" AREA_GROUP="node3"; +INST "pkt_comm/units[2].unit_in_regs/stage[3].r*" AREA_GROUP="node3"; + + +// =========================================================== +// Nodes - right side +AREA_GROUP "node4" RANGE=SLICE_X89Y33:SLICE_X107Y38; +INST "pkt_comm/bcast_net/node[4].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[11].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[12].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[13].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[14].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[15].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[16].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[17].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[18].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[19].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[20].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[21].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; +INST "pkt_comm/units[23].unit_in_regs/stage[1].r*" AREA_GROUP="node4"; + +AREA_GROUP "node5" RANGE=SLICE_X83Y63:SLICE_X107Y92; +INST "pkt_comm/bcast_net/node[5].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[11].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[12].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[13].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[14].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[15].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[16].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[17].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; +INST "pkt_comm/units[18].unit_in_regs/stage[2].r*" AREA_GROUP="node5"; + +AREA_GROUP "node6" RANGE=SLICE_X80Y129:SLICE_X107Y147; +INST "pkt_comm/bcast_net/node[6].r*" AREA_GROUP="node6"; +INST "pkt_comm/units[11].unit_in_regs/stage[3].r*" AREA_GROUP="node6"; +INST "pkt_comm/units[12].unit_in_regs/stage[3].r*" AREA_GROUP="node6"; +INST "pkt_comm/units[13].unit_in_regs/stage[3].r*" AREA_GROUP="node6"; + + +// =========================================================== +// Output from units +// stage 1, left side +AREA_GROUP "unit_out_1l" RANGE=SLICE_X38Y17:SLICE_X43Y62; +INST "pkt_comm/units[7].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; +INST "pkt_comm/units[6].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; +INST "pkt_comm/units[5].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; +INST "pkt_comm/units[4].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; +INST "pkt_comm/units[3].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; +INST "pkt_comm/units[2].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; +INST "pkt_comm/units[1].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; +INST "pkt_comm/units[0].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1l"; + +// stage 2, left side +AREA_GROUP "unit_out_2l" RANGE=SLICE_X38Y104:SLICE_X43Y131; +INST "pkt_comm/units[3].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2l"; +INST "pkt_comm/units[2].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2l"; +INST "pkt_comm/units[1].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2l"; +INST "pkt_comm/units[0].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2l"; + +// stage 1, right side +AREA_GROUP "unit_out_1r" RANGE=SLICE_X62Y50:SLICE_X107Y71; +INST "pkt_comm/units[19].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[18].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[17].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[16].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[15].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[14].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[13].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[12].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; +INST "pkt_comm/units[11].unit_out_regs/stage[1].r*" AREA_GROUP="unit_out_1r"; + +// stage 2, right side +AREA_GROUP "unit_out_2r" RANGE=SLICE_X62Y106:SLICE_X107Y119; +INST "pkt_comm/units[14].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2r"; +INST "pkt_comm/units[13].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2r"; +INST "pkt_comm/units[12].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2r"; +INST "pkt_comm/units[11].unit_out_regs/stage[2].r*" AREA_GROUP="unit_out_2r"; + + +// =========================================================== +// Units - left side +// Unit 0 +AREA_GROUP "u0_0" RANGE=SLICE_X0Y180:SLICE_X20Y187; # 21x8=672 +AREA_GROUP "u0_0" RANGE=RAMB8_X0Y90:RAMB8_X0Y93; +INST "pkt_comm/units[0].unit/cores[0].core" AREA_GROUP="u0_0"; + +AREA_GROUP "u0_1" RANGE=SLICE_X0Y172:SLICE_X20Y179; # 21x8=672 +AREA_GROUP "u0_1" RANGE=RAMB8_X0Y86:RAMB8_X0Y89; +INST "pkt_comm/units[0].unit/cores[1].core" AREA_GROUP="u0_1"; + +AREA_GROUP "u0_2" RANGE=SLICE_X0Y164:SLICE_X20Y171; # 21x8=672 +AREA_GROUP "u0_2" RANGE=RAMB8_X0Y82:RAMB8_X0Y85; +INST "pkt_comm/units[0].unit/cores[2].core" AREA_GROUP="u0_2"; + +AREA_GROUP "c0" RANGE=SLICE_X21Y176:SLICE_X33Y191,SLICE_X21Y168:SLICE_X39Y175; +AREA_GROUP "c0" RANGE=RAMB8_X1Y86:RAMB8_X1Y95; +INST "pkt_comm/units[0].unit/ctrl" AREA_GROUP="c0"; + +// Unit 1 +AREA_GROUP "u1_0" RANGE=SLICE_X0Y156:SLICE_X20Y163; +AREA_GROUP "u1_0" RANGE=RAMB8_X0Y78:RAMB8_X0Y81; +INST "pkt_comm/units[1].unit/cores[0].core" AREA_GROUP="u1_0"; + +AREA_GROUP "u1_1" RANGE=SLICE_X0Y148:SLICE_X20Y155; +AREA_GROUP "u1_1" RANGE=RAMB8_X0Y74:RAMB8_X0Y77; +INST "pkt_comm/units[1].unit/cores[1].core" AREA_GROUP="u1_1"; + +AREA_GROUP "u1_2" RANGE=SLICE_X43Y152:SLICE_X63Y159; # RAMB X2 +AREA_GROUP "u1_2" RANGE=RAMB8_X2Y76:RAMB8_X2Y79; +INST "pkt_comm/units[1].unit/cores[2].core" AREA_GROUP="u1_2"; + +AREA_GROUP "c1" RANGE=SLICE_X21Y160:SLICE_X39Y167,SLICE_X21Y151:SLICE_X42Y159; +AREA_GROUP "c1" RANGE=RAMB8_X1Y78:RAMB8_X1Y83; +INST "pkt_comm/units[1].unit/ctrl" AREA_GROUP="c1"; + +// Unit 2 +AREA_GROUP "u2_0" RANGE=SLICE_X0Y140:SLICE_X20Y147; +AREA_GROUP "u2_0" RANGE=RAMB8_X0Y70:RAMB8_X0Y73; +INST "pkt_comm/units[2].unit/cores[0].core" AREA_GROUP="u2_0"; + +AREA_GROUP "u2_1" RANGE=SLICE_X43Y144:SLICE_X63Y151; # RAMB X2 +AREA_GROUP "u2_1" RANGE=RAMB8_X2Y72:RAMB8_X2Y75; +INST "pkt_comm/units[2].unit/cores[1].core" AREA_GROUP="u2_1"; + +AREA_GROUP "u2_2" RANGE=SLICE_X43Y136:SLICE_X63Y143; # RAMB X2 +AREA_GROUP "u2_2" RANGE=RAMB8_X2Y68:RAMB8_X2Y71; +INST "pkt_comm/units[2].unit/cores[2].core" AREA_GROUP="u2_2"; + +AREA_GROUP "c2" RANGE=SLICE_X21Y137:SLICE_X42Y150; # 22x14=1232* (+1 down) +AREA_GROUP "c2" RANGE=RAMB8_X1Y70:RAMB8_X1Y75; +INST "pkt_comm/units[2].unit/ctrl" AREA_GROUP="c2"; + +// Unit 3 +AREA_GROUP "u3_0" RANGE=SLICE_X0Y132:SLICE_X20Y139; +AREA_GROUP "u3_0" RANGE=RAMB8_X0Y66:RAMB8_X0Y69; +INST "pkt_comm/units[3].unit/cores[0].core" AREA_GROUP="u3_0"; + +AREA_GROUP "u3_1" RANGE=SLICE_X0Y124:SLICE_X20Y131; +AREA_GROUP "u3_1" RANGE=RAMB8_X0Y62:RAMB8_X0Y65; +INST "pkt_comm/units[3].unit/cores[1].core" AREA_GROUP="u3_1"; + +AREA_GROUP "u3_2" RANGE=SLICE_X43Y128:SLICE_X63Y135; # RAMB X2 +AREA_GROUP "u3_2" RANGE=RAMB8_X2Y64:RAMB8_X2Y67; +INST "pkt_comm/units[3].unit/cores[2].core" AREA_GROUP="u3_2"; + +AREA_GROUP "c3" RANGE=SLICE_X21Y121:SLICE_X42Y135; # 22x15=1320* 22x14=1232 +AREA_GROUP "c3" RANGE=RAMB8_X1Y62:RAMB8_X1Y67; +INST "pkt_comm/units[3].unit/ctrl" AREA_GROUP="c3"; + +// Unit 4 +AREA_GROUP "u4_0" RANGE=SLICE_X0Y116:SLICE_X20Y123; +AREA_GROUP "u4_0" RANGE=RAMB8_X0Y58:RAMB8_X0Y61; +INST "pkt_comm/units[4].unit/cores[0].core" AREA_GROUP="u4_0"; + +AREA_GROUP "u4_1" RANGE=SLICE_X0Y108:SLICE_X20Y115; +AREA_GROUP "u4_1" RANGE=RAMB8_X0Y54:RAMB8_X0Y57; +INST "pkt_comm/units[4].unit/cores[1].core" AREA_GROUP="u4_1"; + +AREA_GROUP "u4_2" RANGE=SLICE_X43Y96:SLICE_X63Y103; # RAMB X2 +AREA_GROUP "u4_2" RANGE=RAMB8_X2Y48:RAMB8_X2Y51; +INST "pkt_comm/units[4].unit/cores[2].core" AREA_GROUP="u4_2"; + +AREA_GROUP "c4" RANGE=SLICE_X21Y106:SLICE_X42Y120; # 22x15=1320* +AREA_GROUP "c4" RANGE=RAMB8_X1Y54:RAMB8_X1Y59; +INST "pkt_comm/units[4].unit/ctrl" AREA_GROUP="c4"; + +// Unit 5 +AREA_GROUP "u5_0" RANGE=SLICE_X0Y100:SLICE_X20Y107; +AREA_GROUP "u5_0" RANGE=RAMB8_X0Y50:RAMB8_X0Y53; +INST "pkt_comm/units[5].unit/cores[0].core" AREA_GROUP="u5_0"; + +AREA_GROUP "u5_1" RANGE=SLICE_X0Y92:SLICE_X20Y99; +AREA_GROUP "u5_1" RANGE=RAMB8_X0Y46:RAMB8_X0Y49; +INST "pkt_comm/units[5].unit/cores[1].core" AREA_GROUP="u5_1"; + +AREA_GROUP "u5_2" RANGE=SLICE_X43Y88:SLICE_X63Y95; # RAMB X2 +AREA_GROUP "u5_2" RANGE=RAMB8_X2Y44:RAMB8_X2Y47; +INST "pkt_comm/units[5].unit/cores[2].core" AREA_GROUP="u5_2"; + +AREA_GROUP "c5" RANGE=SLICE_X21Y91:SLICE_X42Y105; # 22x15=1320* +AREA_GROUP "c5" RANGE=RAMB8_X1Y46:RAMB8_X1Y53; +INST "pkt_comm/units[5].unit/ctrl" AREA_GROUP="c5"; + +// Unit 6 +AREA_GROUP "u6_0" RANGE=SLICE_X0Y84:SLICE_X19Y91; +AREA_GROUP "u6_0" RANGE=RAMB8_X0Y42:RAMB8_X0Y45; +INST "pkt_comm/units[6].unit/cores[0].core" AREA_GROUP="u6_0"; + +AREA_GROUP "u6_1" RANGE=SLICE_X0Y76:SLICE_X19Y83; +AREA_GROUP "u6_1" RANGE=RAMB8_X0Y38:RAMB8_X0Y41; +INST "pkt_comm/units[6].unit/cores[1].core" AREA_GROUP="u6_1"; + +AREA_GROUP "u6_2" RANGE=SLICE_X43Y80:SLICE_X63Y87; # RAMB X2 +AREA_GROUP "u6_2" RANGE=RAMB8_X2Y40:RAMB8_X2Y43; +INST "pkt_comm/units[6].unit/cores[2].core" AREA_GROUP="u6_2"; + +AREA_GROUP "c6" RANGE=SLICE_X21Y75:SLICE_X42Y90; # 22x15=1320* +AREA_GROUP "c6" RANGE=RAMB8_X1Y38:RAMB8_X1Y45; +INST "pkt_comm/units[6].unit/ctrl" AREA_GROUP="c6"; + +// Unit 7 +AREA_GROUP "u7_0" RANGE=SLICE_X0Y68:SLICE_X20Y75; +AREA_GROUP "u7_0" RANGE=RAMB8_X0Y34:RAMB8_X0Y37; +INST "pkt_comm/units[7].unit/cores[0].core" AREA_GROUP="u7_0"; + +AREA_GROUP "u7_1" RANGE=SLICE_X0Y60:SLICE_X20Y67; +AREA_GROUP "u7_1" RANGE=RAMB8_X0Y30:RAMB8_X0Y33; +INST "pkt_comm/units[7].unit/cores[1].core" AREA_GROUP="u7_1"; + +AREA_GROUP "u7_2" RANGE=SLICE_X43Y72:SLICE_X63Y79; # RAMB X2 +AREA_GROUP "u7_2" RANGE=RAMB8_X2Y36:RAMB8_X2Y39; +INST "pkt_comm/units[7].unit/cores[2].core" AREA_GROUP="u7_2"; + +AREA_GROUP "c7" RANGE=SLICE_X21Y60:SLICE_X42Y74; # 22x15=1320* +AREA_GROUP "c7" RANGE=RAMB8_X1Y30:RAMB8_X1Y37; +INST "pkt_comm/units[7].unit/ctrl" AREA_GROUP="c7"; + +// Unit 8 +AREA_GROUP "u8_0" RANGE=SLICE_X0Y52:SLICE_X20Y59; +AREA_GROUP "u8_0" RANGE=RAMB8_X0Y26:RAMB8_X0Y29; +INST "pkt_comm/units[8].unit/cores[0].core" AREA_GROUP="u8_0"; + +AREA_GROUP "u8_1" RANGE=SLICE_X0Y44:SLICE_X20Y51; +AREA_GROUP "u8_1" RANGE=RAMB8_X0Y22:RAMB8_X0Y25; +INST "pkt_comm/units[8].unit/cores[1].core" AREA_GROUP="u8_1"; + +AREA_GROUP "u8_2" RANGE=SLICE_X43Y48:SLICE_X63Y55; # RAMB X2 +AREA_GROUP "u8_2" RANGE=RAMB8_X2Y24:RAMB8_X2Y27; +INST "pkt_comm/units[8].unit/cores[2].core" AREA_GROUP="u8_2"; + +AREA_GROUP "c8" RANGE=SLICE_X21Y45:SLICE_X42Y59; # 22x15=1320* +AREA_GROUP "c8" RANGE=RAMB8_X1Y24:RAMB8_X1Y29; +INST "pkt_comm/units[8].unit/ctrl" AREA_GROUP="c8"; + +// Unit 9 +AREA_GROUP "u9_0" RANGE=SLICE_X0Y36:SLICE_X19Y43; +AREA_GROUP "u9_0" RANGE=RAMB8_X0Y18:RAMB8_X0Y21; +INST "pkt_comm/units[9].unit/cores[0].core" AREA_GROUP="u9_0"; + +AREA_GROUP "u9_1" RANGE=SLICE_X0Y28:SLICE_X20Y35; +AREA_GROUP "u9_1" RANGE=RAMB8_X0Y14:RAMB8_X0Y17; +INST "pkt_comm/units[9].unit/cores[1].core" AREA_GROUP="u9_1"; + +AREA_GROUP "u9_2" RANGE=SLICE_X43Y40:SLICE_X63Y47; # RAMB X2 +AREA_GROUP "u9_2" RANGE=RAMB8_X2Y20:RAMB8_X2Y23; +INST "pkt_comm/units[9].unit/cores[2].core" AREA_GROUP="u9_2"; + +AREA_GROUP "c9" RANGE=SLICE_X21Y30:SLICE_X42Y44; # 22x15=1320* +AREA_GROUP "c9" RANGE=RAMB8_X1Y16:RAMB8_X1Y21; +INST "pkt_comm/units[9].unit/ctrl" AREA_GROUP="c9"; + +// Unit 10 +AREA_GROUP "u10_0" RANGE=SLICE_X0Y20:SLICE_X19Y27; +AREA_GROUP "u10_0" RANGE=RAMB8_X0Y10:RAMB8_X0Y13; +INST "pkt_comm/units[10].unit/cores[0].core" AREA_GROUP="u10_0"; + +AREA_GROUP "u10_1" RANGE=SLICE_X0Y12:SLICE_X20Y19; +AREA_GROUP "u10_1" RANGE=RAMB8_X0Y6:RAMB8_X0Y9; +INST "pkt_comm/units[10].unit/cores[1].core" AREA_GROUP="u10_1"; + +AREA_GROUP "u10_2" RANGE=SLICE_X0Y4:SLICE_X20Y11; +AREA_GROUP "u10_2" RANGE=RAMB8_X0Y2:RAMB8_X0Y5; +INST "pkt_comm/units[10].unit/cores[2].core" AREA_GROUP="u10_2"; + +AREA_GROUP "c10" RANGE=SLICE_X21Y2:SLICE_X33Y27,SLICE_X34Y16:SLICE_X37Y27; +AREA_GROUP "c10" RANGE=RAMB8_X1Y2:RAMB8_X1Y13; +INST "pkt_comm/units[10].unit/ctrl" AREA_GROUP="c10"; + + +// =========================================================== +// Units - right side +// Unit 11 +AREA_GROUP "u11_0" RANGE=SLICE_X107Y180:SLICE_X127Y187; +AREA_GROUP "u11_0" RANGE=RAMB8_X5Y90:RAMB8_X5Y93; +INST "pkt_comm/units[11].unit/cores[0].core" AREA_GROUP="u11_0"; + +AREA_GROUP "u11_1" RANGE=SLICE_X107Y172:SLICE_X127Y179; +AREA_GROUP "u11_1" RANGE=RAMB8_X5Y86:RAMB8_X5Y89; +INST "pkt_comm/units[11].unit/cores[1].core" AREA_GROUP="u11_1"; + +AREA_GROUP "u11_2" RANGE=SLICE_X107Y164:SLICE_X127Y171; +AREA_GROUP "u11_2" RANGE=RAMB8_X5Y82:RAMB8_X5Y85; +INST "pkt_comm/units[11].unit/cores[2].core" AREA_GROUP="u11_2"; + +AREA_GROUP "c11" RANGE=SLICE_X86Y165:SLICE_X106Y189; +AREA_GROUP "c11" RANGE=RAMB8_X4Y84:RAMB8_X4Y93; +INST "pkt_comm/units[11].unit/ctrl" AREA_GROUP="c11"; + +// Unit 12 +AREA_GROUP "u12_0" RANGE=SLICE_X64Y168:SLICE_X85Y175; +AREA_GROUP "u12_0" RANGE=RAMB8_X3Y84:RAMB8_X3Y87; # RAMB X3 +INST "pkt_comm/units[12].unit/cores[0].core" AREA_GROUP="u12_0"; + +AREA_GROUP "u12_1" RANGE=SLICE_X86Y157:SLICE_X105Y164; +AREA_GROUP "u12_1" RANGE=RAMB8_X4Y78:RAMB8_X4Y81; # RAMB X4 +INST "pkt_comm/units[12].unit/cores[1].core" AREA_GROUP="u12_1"; + +AREA_GROUP "u12_2" RANGE=SLICE_X64Y145:SLICE_X85Y152; +AREA_GROUP "u12_2" RANGE=RAMB8_X3Y72:RAMB8_X3Y75; # RAMB X3 +INST "pkt_comm/units[12].unit/cores[2].core" AREA_GROUP="u12_2"; + +AREA_GROUP "c12" RANGE=SLICE_X64Y153:SLICE_X85Y167; +AREA_GROUP "c12" RANGE=RAMB8_X3Y78:RAMB8_X3Y83; # RAMB X3 +INST "pkt_comm/units[12].unit/ctrl" AREA_GROUP="c12"; + +// Unit 13 +AREA_GROUP "u13_0" RANGE=SLICE_X107Y156:SLICE_X127Y163; +AREA_GROUP "u13_0" RANGE=RAMB8_X5Y78:RAMB8_X5Y81; +INST "pkt_comm/units[13].unit/cores[0].core" AREA_GROUP="u13_0"; + +AREA_GROUP "u13_1" RANGE=SLICE_X107Y148:SLICE_X127Y155; +AREA_GROUP "u13_1" RANGE=RAMB8_X5Y74:RAMB8_X5Y77; +INST "pkt_comm/units[13].unit/cores[1].core" AREA_GROUP="u13_1"; + +AREA_GROUP "u13_2" RANGE=SLICE_X107Y140:SLICE_X127Y147; +AREA_GROUP "u13_2" RANGE=RAMB8_X5Y70:RAMB8_X5Y73; +INST "pkt_comm/units[13].unit/cores[2].core" AREA_GROUP="u13_2"; + +AREA_GROUP "c13" RANGE=SLICE_X86Y141:SLICE_X106Y156; # 21x16=1344* +AREA_GROUP "c13" RANGE=RAMB8_X4Y70:RAMB8_X4Y77; # RAMB X4 +INST "pkt_comm/units[13].unit/ctrl" AREA_GROUP="c13"; + +// Unit 14 +AREA_GROUP "u14_0" RANGE=SLICE_X65Y137:SLICE_X85Y144; +AREA_GROUP "u14_0" RANGE=RAMB8_X3Y68:RAMB8_X3Y71; # RAMB X3 +INST "pkt_comm/units[14].unit/cores[0].core" AREA_GROUP="u14_0"; + +AREA_GROUP "u14_1" RANGE=SLICE_X86Y133:SLICE_X106Y140; +AREA_GROUP "u14_1" RANGE=RAMB8_X4Y66:RAMB8_X4Y69; # RAMB X4 +INST "pkt_comm/units[14].unit/cores[1].core" AREA_GROUP="u14_1"; + +AREA_GROUP "u14_2" RANGE=SLICE_X43Y120:SLICE_X63Y127; +AREA_GROUP "u14_2" RANGE=RAMB8_X2Y60:RAMB8_X2Y63; # RAMB X2 +INST "pkt_comm/units[14].unit/cores[2].core" AREA_GROUP="u14_2"; + +AREA_GROUP "c14" RANGE=SLICE_X64Y122:SLICE_X85Y136; # 22x15 +AREA_GROUP "c14" RANGE=RAMB8_X3Y62:RAMB8_X3Y67; # RAMB X3 +INST "pkt_comm/units[14].unit/ctrl" AREA_GROUP="c14"; + +// Unit 15 +AREA_GROUP "u15_0" RANGE=SLICE_X107Y132:SLICE_X127Y139; +AREA_GROUP "u15_0" RANGE=RAMB8_X5Y66:RAMB8_X5Y69; +INST "pkt_comm/units[15].unit/cores[0].core" AREA_GROUP="u15_0"; + +AREA_GROUP "u15_1" RANGE=SLICE_X108Y124:SLICE_X127Y131; +AREA_GROUP "u15_1" RANGE=RAMB8_X5Y62:RAMB8_X5Y65; +INST "pkt_comm/units[15].unit/cores[1].core" AREA_GROUP="u15_1"; + +AREA_GROUP "u15_2" RANGE=SLICE_X107Y116:SLICE_X127Y123; +AREA_GROUP "u15_2" RANGE=RAMB8_X5Y58:RAMB8_X5Y61; +INST "pkt_comm/units[15].unit/cores[2].core" AREA_GROUP="u15_2"; + +AREA_GROUP "c15" RANGE=SLICE_X86Y117:SLICE_X106Y132; # 21x16=1344* +AREA_GROUP "c15" RANGE=RAMB8_X4Y60:RAMB8_X4Y65; # RAMB X4 +INST "pkt_comm/units[15].unit/ctrl" AREA_GROUP="c15"; + +// Unit 16 +AREA_GROUP "u16_0" RANGE=SLICE_X43Y112:SLICE_X63Y119; +AREA_GROUP "u16_0" RANGE=RAMB8_X2Y56:RAMB8_X2Y59; # RAMB X2 +INST "pkt_comm/units[16].unit/cores[0].core" AREA_GROUP="u16_0"; + +AREA_GROUP "u16_1" RANGE=SLICE_X43Y104:SLICE_X63Y111; +AREA_GROUP "u16_1" RANGE=RAMB8_X2Y52:RAMB8_X2Y55; # RAMB X2 +INST "pkt_comm/units[16].unit/cores[1].core" AREA_GROUP="u16_1"; + +AREA_GROUP "u16_2" RANGE=SLICE_X64Y99:SLICE_X85Y106; +AREA_GROUP "u16_2" RANGE=RAMB8_X3Y50:RAMB8_X3Y53; # RAMB X3 +INST "pkt_comm/units[16].unit/cores[2].core" AREA_GROUP="u16_2"; + +AREA_GROUP "c16" RANGE=SLICE_X64Y107:SLICE_X85Y121; # 22x15 +AREA_GROUP "c16" RANGE=RAMB8_X3Y54:RAMB8_X3Y61; # RAMB X3 +INST "pkt_comm/units[16].unit/ctrl" AREA_GROUP="c16"; + +// Unit 17 +AREA_GROUP "u17_0" RANGE=SLICE_X107Y108:SLICE_X127Y115; +AREA_GROUP "u17_0" RANGE=RAMB8_X5Y54:RAMB8_X5Y57; +INST "pkt_comm/units[17].unit/cores[0].core" AREA_GROUP="u17_0"; + +AREA_GROUP "u17_1" RANGE=SLICE_X107Y100:SLICE_X127Y107; +AREA_GROUP "u17_1" RANGE=RAMB8_X5Y50:RAMB8_X5Y53; +INST "pkt_comm/units[17].unit/cores[1].core" AREA_GROUP="u17_1"; + +AREA_GROUP "u17_2" RANGE=SLICE_X107Y92:SLICE_X127Y99; +AREA_GROUP "u17_2" RANGE=RAMB8_X5Y46:RAMB8_X5Y49; +INST "pkt_comm/units[17].unit/cores[2].core" AREA_GROUP="u17_2"; + +AREA_GROUP "c17" RANGE=SLICE_X86Y101:SLICE_X106Y116; # 21x16=1344* +AREA_GROUP "c17" RANGE=RAMB8_X4Y52:RAMB8_X4Y57; # RAMB X4 +INST "pkt_comm/units[17].unit/ctrl" AREA_GROUP="c17"; + +// Unit 18 +AREA_GROUP "u18_0" RANGE=SLICE_X65Y91:SLICE_X85Y98; +AREA_GROUP "u18_0" RANGE=RAMB8_X3Y46:RAMB8_X3Y49; # RAMB X3 +INST "pkt_comm/units[18].unit/cores[0].core" AREA_GROUP="u18_0"; + +AREA_GROUP "u18_1" RANGE=SLICE_X65Y83:SLICE_X85Y90; +AREA_GROUP "u18_1" RANGE=RAMB8_X3Y42:RAMB8_X3Y45; # RAMB X3 +INST "pkt_comm/units[18].unit/cores[1].core" AREA_GROUP="u18_1"; + +AREA_GROUP "u18_2" RANGE=SLICE_X107Y84:SLICE_X127Y91; +AREA_GROUP "u18_2" RANGE=RAMB8_X5Y42:RAMB8_X5Y45; +INST "pkt_comm/units[18].unit/cores[2].core" AREA_GROUP="u18_2"; + +AREA_GROUP "c18" RANGE=SLICE_X86Y85:SLICE_X106Y100; # 21x16=1344* +AREA_GROUP "c18" RANGE=RAMB8_X4Y44:RAMB8_X4Y51; # RAMB X4 +INST "pkt_comm/units[18].unit/ctrl" AREA_GROUP="c18"; + +// Unit 19 +AREA_GROUP "u19_0" RANGE=SLICE_X65Y75:SLICE_X85Y82; +AREA_GROUP "u19_0" RANGE=RAMB8_X3Y38:RAMB8_X3Y41; # RAMB X3 +INST "pkt_comm/units[19].unit/cores[0].core" AREA_GROUP="u19_0"; + +AREA_GROUP "u19_1" RANGE=SLICE_X107Y76:SLICE_X127Y83; +AREA_GROUP "u19_1" RANGE=RAMB8_X5Y38:RAMB8_X5Y41; +INST "pkt_comm/units[19].unit/cores[1].core" AREA_GROUP="u19_1"; + +AREA_GROUP "u19_2" RANGE=SLICE_X107Y68:SLICE_X127Y75; +AREA_GROUP "u19_2" RANGE=RAMB8_X5Y34:RAMB8_X5Y37; +INST "pkt_comm/units[19].unit/cores[2].core" AREA_GROUP="u19_2"; + +AREA_GROUP "c19" RANGE=SLICE_X86Y69:SLICE_X106Y84; # 21x16=1344* +AREA_GROUP "c19" RANGE=RAMB8_X4Y34:RAMB8_X4Y41; # RAMB X4 +INST "pkt_comm/units[19].unit/ctrl" AREA_GROUP="c19"; + +// Unit 20 +AREA_GROUP "u20_0" RANGE=SLICE_X43Y64:SLICE_X63Y71; # RAMB X2 +AREA_GROUP "u20_0" RANGE=RAMB8_X2Y32:RAMB8_X2Y35; +INST "pkt_comm/units[20].unit/cores[0].core" AREA_GROUP="u20_0"; + +AREA_GROUP "u20_1" RANGE=SLICE_X43Y56:SLICE_X63Y63; # RAMB X2 +AREA_GROUP "u20_1" RANGE=RAMB8_X2Y28:RAMB8_X2Y31; +INST "pkt_comm/units[20].unit/cores[1].core" AREA_GROUP="u20_1"; + +AREA_GROUP "u20_2" RANGE=SLICE_X64Y52:SLICE_X85Y59; +AREA_GROUP "u20_2" RANGE=RAMB8_X3Y26:RAMB8_X3Y29; # RAMB X3 +INST "pkt_comm/units[20].unit/cores[2].core" AREA_GROUP="u20_2"; + +AREA_GROUP "c20" RANGE=SLICE_X64Y60:SLICE_X85Y74; # 22x15 +AREA_GROUP "c20" RANGE=RAMB8_X3Y30:RAMB8_X3Y37; # RAMB X3 +INST "pkt_comm/units[20].unit/ctrl" AREA_GROUP="c20"; + +// Unit 21 +AREA_GROUP "u21_0" RANGE=SLICE_X107Y60:SLICE_X127Y67; +AREA_GROUP "u21_0" RANGE=RAMB8_X5Y30:RAMB8_X5Y33; +INST "pkt_comm/units[21].unit/cores[0].core" AREA_GROUP="u21_0"; + +AREA_GROUP "u21_1" RANGE=SLICE_X107Y52:SLICE_X127Y59; +AREA_GROUP "u21_1" RANGE=RAMB8_X5Y26:RAMB8_X5Y29; +INST "pkt_comm/units[21].unit/cores[1].core" AREA_GROUP="u21_1"; + +AREA_GROUP "u21_2" RANGE=SLICE_X107Y44:SLICE_X127Y51; +AREA_GROUP "u21_2" RANGE=RAMB8_X5Y22:RAMB8_X5Y25; +INST "pkt_comm/units[21].unit/cores[2].core" AREA_GROUP="u21_2"; + +AREA_GROUP "c21" RANGE=SLICE_X86Y53:SLICE_X106Y68; # 21x16=1344* +AREA_GROUP "c21" RANGE=RAMB8_X4Y28:RAMB8_X4Y35; # RAMB X4 +INST "pkt_comm/units[21].unit/ctrl" AREA_GROUP="c21"; + +// Unit 22 +AREA_GROUP "u22_0" RANGE=SLICE_X43Y32:SLICE_X63Y39; # RAMB X2 +AREA_GROUP "u22_0" RANGE=RAMB8_X2Y16:RAMB8_X2Y19; +INST "pkt_comm/units[22].unit/cores[0].core" AREA_GROUP="u22_0"; + +AREA_GROUP "u22_1" RANGE=SLICE_X43Y24:SLICE_X63Y31; # RAMB X2 +AREA_GROUP "u22_1" RANGE=RAMB8_X2Y12:RAMB8_X2Y15; +INST "pkt_comm/units[22].unit/cores[1].core" AREA_GROUP="u22_1"; + +AREA_GROUP "u22_2" RANGE=SLICE_X44Y16:SLICE_X63Y23; # RAMB X2 +AREA_GROUP "u22_2" RANGE=RAMB8_X2Y8:RAMB8_X2Y11; +INST "pkt_comm/units[22].unit/cores[2].core" AREA_GROUP="u22_2"; + +AREA_GROUP "c22" RANGE=SLICE_X64Y21:SLICE_X85Y35; # 22x15 +AREA_GROUP "c22" RANGE=RAMB8_X3Y14:RAMB8_X3Y17; # RAMB X3 +INST "pkt_comm/units[22].unit/ctrl" AREA_GROUP="c22"; + +// Unit 23 +AREA_GROUP "u23_0" RANGE=SLICE_X65Y44:SLICE_X85Y51; +AREA_GROUP "u23_0" RANGE=RAMB8_X3Y22:RAMB8_X3Y25; # RAMB X3 +INST "pkt_comm/units[23].unit/cores[0].core" AREA_GROUP="u23_0"; + +AREA_GROUP "u23_1" RANGE=SLICE_X65Y36:SLICE_X85Y43; +AREA_GROUP "u23_1" RANGE=RAMB8_X3Y18:RAMB8_X3Y21; # RAMB X3 +INST "pkt_comm/units[23].unit/cores[1].core" AREA_GROUP="u23_1"; + +AREA_GROUP "u23_2" RANGE=SLICE_X107Y36:SLICE_X127Y43; +AREA_GROUP "u23_2" RANGE=RAMB8_X5Y18:RAMB8_X5Y21; +INST "pkt_comm/units[23].unit/cores[2].core" AREA_GROUP="u23_2"; + +AREA_GROUP "c23" RANGE=SLICE_X86Y37:SLICE_X106Y52; # 21x16=1344* +AREA_GROUP "c23" RANGE=RAMB8_X4Y20:RAMB8_X4Y27; # RAMB X4 +INST "pkt_comm/units[23].unit/ctrl" AREA_GROUP="c23"; + +// Unit 24 +AREA_GROUP "u24_0" RANGE=SLICE_X107Y28:SLICE_X127Y35; +AREA_GROUP "u24_0" RANGE=RAMB8_X5Y14:RAMB8_X5Y17; +INST "pkt_comm/units[24].unit/cores[0].core" AREA_GROUP="u24_0"; + +AREA_GROUP "u24_1" RANGE=SLICE_X107Y20:SLICE_X127Y27; +AREA_GROUP "u24_1" RANGE=RAMB8_X5Y10:RAMB8_X5Y13; +INST "pkt_comm/units[24].unit/cores[1].core" AREA_GROUP="u24_1"; + +AREA_GROUP "u24_2" RANGE=SLICE_X107Y12:SLICE_X127Y19; +AREA_GROUP "u24_2" RANGE=RAMB8_X5Y6:RAMB8_X5Y9; +INST "pkt_comm/units[24].unit/cores[2].core" AREA_GROUP="u24_2"; + +AREA_GROUP "c24" RANGE=SLICE_X86Y21:SLICE_X106Y36; # 21x16=1344* +AREA_GROUP "c24" RANGE=RAMB8_X4Y14:RAMB8_X4Y17; # RAMB X4 +INST "pkt_comm/units[24].unit/ctrl" AREA_GROUP="c24"; + + +// =========================================================== +// pkt_comm +AREA_GROUP "pkt_comm" RANGE=SLICE_X52Y0:SLICE_X81Y14,SLICE_X66Y15:SLICE_X97Y19; +AREA_GROUP "pkt_comm" RANGE=RAMB16_X3Y8:RAMB16_X3Y8; # 1 +AREA_GROUP "pkt_comm" RANGE=RAMB8_X3Y10:RAMB8_X3Y10; # 1 +INST "pkt_comm/inpkt_header*" AREA_GROUP="pkt_comm"; +INST "pkt_comm/word_gen*" AREA_GROUP="pkt_comm"; +INST "pkt_comm/cmp_config*" AREA_GROUP="pkt_comm"; +INST "pkt_comm/arbiter_tx*" AREA_GROUP="pkt_comm"; +INST "pkt_comm/arbiter_rx*" AREA_GROUP="pkt_comm"; +INST "pkt_comm/comparator*" AREA_GROUP="pkt_comm"; +INST "pkt_comm/outpkt*" AREA_GROUP="pkt_comm"; + +AREA_GROUP "io1" RANGE=SLICE_X98Y11:SLICE_X105Y19; +AREA_GROUP "io1" RANGE=RAMB16_X4Y6:RAMB16_X4Y8; +INST "input_fifo/fifo_input1*" AREA_GROUP="io1"; +INST "pkt_comm/word_list*" AREA_GROUP="io1"; + +AREA_GROUP "io0" RANGE=SLICE_X98Y0:SLICE_X127Y10; +AREA_GROUP "io0" RANGE=RAMB16_X4Y0:RAMB16_X5Y4; # 6 +AREA_GROUP "io0" RANGE=DSP48_X3Y0:DSP48_X3Y2; # 3 +INST "input_fifo/fifo_input0*" AREA_GROUP="io0"; +INST "hs_io_inst*" AREA_GROUP="io0"; +INST "vcr_inst*" AREA_GROUP="io0"; +INST "output_fifo*" AREA_GROUP="io0"; + + +// =========================================================== +// procb +NET "pkt_comm/units[*].unit/ctrl/engine/process_bytes/saved_addr_t*" TIG; +NET "pkt_comm/units[*].unit/ctrl/engine/process_bytes/saved_total_t*" TIG; +NET "pkt_comm/units[*].unit/ctrl/engine/process_bytes/saved_comp_active_t" TIG; +NET "pkt_comm/units[*].unit/ctrl/engine/process_bytes/saved_procb_active_t" TIG; +// cpu +NET "pkt_comm/units[*].unit/ctrl/cpu/uob_thread_num*" TIG; + +NET "pkt_comm/mode_cmp" TIG; + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt.v new file mode 100644 index 00000000000..2c4d9d04b3f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt.v @@ -0,0 +1,577 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +module sha256crypt #( + parameter VERSION = `PKT_COMM_VERSION, + parameter PKT_MAX_LEN = 16*65536, + parameter PKT_LEN_MSB = `MSB(PKT_MAX_LEN), + parameter WORD_MAX_LEN = `PLAINTEXT_LEN, + parameter CHAR_BITS = `CHAR_BITS, + parameter RANGES_MAX = `RANGES_MAX, + parameter RANGE_INFO_MSB = 1 + `MSB(WORD_MAX_LEN-1), + parameter DISABLE_CHECKSUM = 0 + )( + input PKT_COMM_CLK, + input CORE_CLK, + + // read from some internal FIFO (recieved via high-speed interface) + input [7:0] din, + output rd_en, + input empty, + + // write into some internal FIFO (to be send via high-speed interface) + output [15:0] dout, + output wr_en, + input full, + + // control input (VCR interface) + input [7:0] app_mode, + // status output (VCR interface) + output cores_idle, + output [7:0] app_status, + output [7:0] pkt_comm_status, + output [7:0] debug2, debug3 + ); + + + // ************************************************************ + // + // The design is divided into units. + // Configuration for each unit define unit-specific properties + // such as number of cores, node# the unit is connected to, etc. + // + // ************************************************************ + + localparam N_UNITS = 25; + localparam [64*N_UNITS-1 :0] UNITS_CONF = { + // unit_dummy| reserved| core_dummy| n_cores| in_r| out_r| node# + // warning: in_r must match the count of pass-by nodes + + // right half of fpga + 1'b0, 40'd0, 3'b000, 4'd3, 4'd0, 4'd0, 8'd0, // unit #24 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd0, 8'd4, // unit #23 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd0, 4'd0, 8'd0, // unit #22 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd0, 8'd4, // unit #21 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd0, 8'd4, // unit #20 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd1, 8'd4, // unit #19 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd1, 8'd5, // unit #18 n2 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd1, 8'd5, // unit #17 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd1, 8'd5, // unit #16 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd1, 8'd5, // unit #15 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd2, 8'd5, // unit #14 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd3, 4'd2, 8'd6, // unit #13 n3 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd3, 4'd2, 8'd6, // unit #12 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd3, 4'd2, 8'd6, // unit #11 + // left half of fpga + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd0, 8'd1, // unit #10 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd0, 8'd1, // unit #9 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd0, 8'd1, // unit #8 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd1, 4'd1, 8'd1, // unit #7 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd1, 8'd2, // unit #6 n2 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd1, 8'd2, // unit #5 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd1, 8'd2, // unit #4 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd2, 4'd2, 8'd2, // unit #3 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd3, 4'd2, 8'd3, // unit #2 n3 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd3, 4'd2, 8'd3, // unit #1 + 1'b0, 40'd0, 3'b000, 4'd3, 4'd3, 4'd2, 8'd3 // unit #0 +/* + 1'b1, 40'd0, 3'b111, 4'd3, 4'd0, 4'd1, 8'd0, // unit #24 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd4, // unit #23 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd0, 4'd1, 8'd0, // unit #22 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd4, // unit #21 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd4, // unit #20 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd4, // unit #19 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd1, 8'd5, // unit #18 n2 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd1, 8'd5, // unit #17 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd1, 8'd5, // unit #16 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd2, 8'd5, // unit #15 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd2, 8'd5, // unit #14 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd3, 4'd2, 8'd6, // unit #13 n3 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd3, 4'd2, 8'd6, // unit #12 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd3, 4'd2, 8'd6, // unit #11 + // left half of fpga + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd1, // unit #10 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd1, // unit #9 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd1, // unit #8 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd1, 4'd1, 8'd1, // unit #7 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd2, 8'd2, // unit #6 n2 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd2, 8'd2, // unit #5 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd2, 8'd2, // unit #4 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd2, 4'd2, 8'd2, // unit #3 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd3, 4'd2, 8'd3, // unit #2 n3 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd3, 4'd2, 8'd3, // unit #1 + 1'b1, 40'd0, 3'b111, 4'd3, 4'd3, 4'd2, 8'd3 // unit #0 +*/ + }; + + + // There's a network for broadcast signals to units. + // The network consists of nodes. The configuration for each node + // points to the upper level node. + localparam N_NODES = 7; + localparam [8*N_NODES-1 :0] NODES_CONF = { + 8'd5, // #6 + 8'd4, // #5: connected #6 + 8'd0, // #4: connected #5 + + 8'd2, // #3 + 8'd1, // #2: connected #3 + 8'd0, // #1: connected #2 + + 8'd255 // #0 is the entry to the network + }; + + + // ************************************************************ + // + // pkt_comm error codes: + // + // 0x01 - wrong input packet checksum + // 0x02 - bad input packet length + // 0x04 - bad input packet type + // 0x08 - unsupported pkt_comm version + // 0x10 - number of words in WORD_LIST/TEMPLATE_LIST exceeds 2**16-1 + // 0x20 - error in WORD_LIST/TEMPLATE_LIST packet + // 0x40 - error in WORD_GEN packet + // 0x80 - error in CMP_CONFIG packet + // + // ************************************************************ + assign pkt_comm_status = { + err_cmp_config, err_word_gen_conf, err_template, err_word_list_count, + err_pkt_version, err_inpkt_type, err_inpkt_len, err_inpkt_checksum + }; + + + // ************************************************************ + // + // app_status error codes: + // + // 0x01 - candidates received, comparator is unconfigured (arbiter_tx) + // 0x02, 0x04 - bad output from a computing unit (arbiter_rx) + // 0x08 - error in PKT_TYPE_CONFIG + // + // ************************************************************ + assign app_status[7:4] = 0; + + + (* KEEP="true" *) wire mode_cmp = ~app_mode[6]; // Use comparator + + reg error_r = 0; + // Application error or pkt_comm error - disable further processing + always @(posedge PKT_COMM_CLK) + if (|app_status | |pkt_comm_status) + error_r <= 1; + + delay #( .INIT(1), .NBITS(6) ) delay_cores_idle( + .CLK(PKT_COMM_CLK), .in(arbiter_tx_idle), .out(cores_idle) ); + + + // ************************************************** + // + // Application: read packets + // process data base on packet type + // + // ************************************************** + localparam PKT_TYPE_WORD_LIST = 1; + localparam PKT_TYPE_WORD_GEN = 2; + localparam PKT_TYPE_CMP_CONFIG = 3; + localparam PKT_TYPE_TEMPLATE_LIST = 4; + localparam PKT_TYPE_INIT = 5; + localparam PKT_TYPE_CONFIG = 6; + + localparam PKT_MAX_TYPE = 6; + + + wire [`MSB(PKT_MAX_TYPE):0] inpkt_type; + wire [15:0] inpkt_id; + + inpkt_header #( + .VERSION(VERSION), + .PKT_MAX_LEN(PKT_MAX_LEN), + .PKT_MAX_TYPE(PKT_MAX_TYPE), + .DISABLE_CHECKSUM(DISABLE_CHECKSUM) + ) inpkt_header( + .CLK(PKT_COMM_CLK), + .din(din), + .wr_en(rd_en), + .pkt_type(inpkt_type), .pkt_id(inpkt_id), .pkt_data(inpkt_data), + .pkt_end(inpkt_end), + .err_pkt_version(err_pkt_version), .err_pkt_type(err_inpkt_type), + .err_pkt_len(err_inpkt_len), .err_pkt_checksum(err_inpkt_checksum) + ); + + // input packet processing: read enable + assign rd_en = ~empty & ~error_r & (~inpkt_data + | word_gen_conf_en | word_list_wr_en | cmp_config_wr_en + | inpkt_init_rd_en | inpkt_config_rd_en + ); + + + // ************************************************** + // + // input packet type PKT_TYPE_CONFIG (0x06) + // + // ************************************************** + wire inpkt_config_rd_en = ~empty & ~error_r + & inpkt_type == PKT_TYPE_CONFIG & inpkt_data & ~inpkt_config_full; + + wire [N_UNITS-1:0] config_data1; // used to mask units in arbiter_tx + + inpkt_config #( .SUBTYPE1_WIDTH(N_UNITS) + ) inpkt_config( + .CLK(PKT_COMM_CLK), + .din(din), .wr_en(inpkt_config_rd_en), .pkt_end(inpkt_end), + .full(inpkt_config_full), + .dout1(config_data1), .err(app_status[3]) + ); + + + // ************************************************** + // + // input packet type PKT_TYPE_INIT (0x05) + // + // ************************************************** + wire inpkt_init_rd_en = ~empty & ~error_r + & inpkt_type == PKT_TYPE_INIT & inpkt_data & ~inpkt_init_full; + + wire [7:0] init_data; + + inpkt_type_init_1b inpkt_init( + .CLK(PKT_COMM_CLK), + .din(din), .wr_en(inpkt_init_rd_en), .full(inpkt_init_full), + .dout(init_data), .rd_en(init_rd_en), .empty(init_empty) + ); + + + // ************************************************** + // + // input packet types PKT_TYPE_WORD_LIST (0x01), + // PKT_TYPE_TEMPLATE_LIST (0x04) + // + // ************************************************** + wire word_list_wr_en = ~empty & ~error_r + & (inpkt_type == PKT_TYPE_WORD_LIST + | inpkt_type == PKT_TYPE_TEMPLATE_LIST) + & inpkt_data & ~word_list_full; + + + wire [7:0] word_list_dout; + wire [`MSB(WORD_MAX_LEN-1):0] word_rd_addr; + wire [`MSB(WORD_MAX_LEN):0] word_len; + wire [RANGES_MAX * (RANGE_INFO_MSB+1) - 1 :0] range_info; + wire [15:0] word_id; + + // template_list_b: stores input words in 8-bit wide memory + // Variable word length: not padded with zeroes, length is output. + template_list_b_varlen #( + .WORD_MAX_LEN(WORD_MAX_LEN), .RANGES_MAX(RANGES_MAX) + ) word_list( + .CLK(PKT_COMM_CLK), .din(din), + .wr_en(word_list_wr_en), .full(word_list_full), .inpkt_end(inpkt_end), + .is_template_list(inpkt_type == PKT_TYPE_TEMPLATE_LIST), + + .dout(word_list_dout), .rd_addr(word_rd_addr), + .set_empty(word_list_set_empty), .empty(word_list_empty), + .range_info(range_info), .word_id(word_id), .word_len(word_len), + .word_list_end(word_list_end), .totally_empty(word_list_totally_empty), + + .err_template(err_template), .err_word_list_count(err_word_list_count) + ); + + + // ************************************************** + // + // input packet type PKT_TYPE_WORD_GEN (0x02) + // + // ************************************************** + wire word_gen_conf_en = ~empty & ~error_r + & inpkt_type == PKT_TYPE_WORD_GEN & inpkt_data & ~word_gen_conf_full; + + wire [7:0] word_gen_dout; + wire [`MSB(WORD_MAX_LEN-1):0] word_gen_rd_addr; + wire [`MSB(WORD_MAX_LEN):0] word_len_out; + wire [15:0] pkt_id, word_id_out; + wire [31:0] gen_id; + + word_gen_b_varlen #( + .RANGES_MAX(RANGES_MAX), .WORD_MAX_LEN(WORD_MAX_LEN) + ) word_gen( + .CLK(PKT_COMM_CLK), .din(din), + .inpkt_id(inpkt_id), .conf_wr_en(word_gen_conf_en), + .conf_full(word_gen_conf_full), + + .word_in(word_list_dout), .word_rd_addr(word_rd_addr), + .word_set_empty(word_list_set_empty), .word_empty(word_list_empty), + .range_info(range_info), .word_id(word_id), .word_len(word_len), + .word_list_end(word_list_end), + + .dout(word_gen_dout), .rd_addr(word_gen_rd_addr), + .set_empty(word_gen_set_empty), .empty(word_gen_empty), + .pkt_id(pkt_id), .word_id_out(word_id_out), + .word_len_out(word_len_out), .gen_id(gen_id), .gen_end(gen_end), + .totally_empty(word_gen_totally_empty), + + .err_word_gen_conf(err_word_gen_conf) + ); + + + // OK. Got words with ID's. + // + //wire [7:0] word_gen_dout; <-- in memory accessed with word_gen_rd_addr + //wire [15:0] pkt_id, word_id_out; + //wire [31:0] gen_id; + //wire gen_end; + + //assign debug2 = 8'hd2; + //assign debug3 = 8'hd3; + + // ************************************************************* + + + // ************************************************** + // + // input packet type CMP_CONFIG (0x03) + // + // ************************************************** + wire cmp_config_wr_en = ~empty & ~error_r + & inpkt_type == PKT_TYPE_CMP_CONFIG & inpkt_data & ~cmp_config_full; + + wire [`HASH_COUNT_MSB:0] hash_count; + wire [`HASH_NUM_MSB+2:0] cmp_wr_addr; + wire [7:0] cmp_din; + + wire [4:0] cmp_config_addr; + wire [7:0] cmp_config_data; + + sha256crypt_cmp_config cmp_config( + .CLK(PKT_COMM_CLK), .mode_cmp(mode_cmp), + .din(din), .wr_en(cmp_config_wr_en), + .full(cmp_config_full), .error(err_cmp_config), + + .hash_count(hash_count), .cmp_wr_addr(cmp_wr_addr), + .cmp_wr_en(cmp_wr_en), .cmp_din(cmp_din), + + .new_cmp_config(new_cmp_config), + .cmp_config_applied(cmp_config_applied), + .addr(cmp_config_addr), .dout(cmp_config_data) + ); + + + // ************************************************** + // + // Arbiter, transmit part + // - Gather up necessary data, create data packets for computing units; + // - Transmit data to units ready for computing; + // - Operate mostly at PKT_COMM frequency, send at CORE frequency. + // - Account number of candidates transmitted, handle changes + // in comparator configuration etc. + // + // ************************************************** + wire [7:0] unit_in; + wire [N_UNITS-1:0] unit_in_wr_en, unit_in_afull, unit_in_ready; + + wire [31:0] num_processed_tx; + wire [15:0] pkt_id_tx; + + arbiter_tx #( + .N_UNITS(N_UNITS), .WORD_MAX_LEN(WORD_MAX_LEN) + ) arbiter_tx( + .CLK(PKT_COMM_CLK), .CORE_CLK(CORE_CLK), .mode_cmp(mode_cmp), + .pkt_id(pkt_id), .word_id(word_id_out), .gen_id(gen_id), + .gen_end(gen_end), .word_len(word_len_out), + + .din(word_gen_dout), .word_gen_rd_addr(word_gen_rd_addr), + .word_set_empty(word_gen_set_empty), .word_empty(word_gen_empty), + .src_totally_empty(word_list_totally_empty & word_gen_totally_empty), + + .new_cmp_config(new_cmp_config), + .cmp_config_applied(cmp_config_applied), + .cmp_config_addr(cmp_config_addr), .cmp_config_data(cmp_config_data), + + .init_din(init_data), .init_rd_en(init_rd_en), + .init_empty(init_empty), + .unit_tx_mask(config_data1[N_UNITS-1:0]), + + .unit_in(unit_in), .unit_in_ctrl(unit_in_ctrl), .bcast_en(bcast_en), + .unit_in_wr_en(unit_in_wr_en), + .unit_in_afull(unit_in_afull), .unit_in_ready(unit_in_ready), + + .num_processed_tx(num_processed_tx), .pkt_id_tx(pkt_id_tx), + .pkt_tx_done(pkt_tx_done), .pkt_rx_done(pkt_rx_done), + .recv_item(recv_item), + + .idle(arbiter_tx_idle), .err(app_status[0]) + ); + + + + // ************************************************** + // + // Network for broadcast signals + // + // ************************************************** + localparam BCAST_WIDTH = 9; + wire [N_NODES*BCAST_WIDTH-1 :0] bcast; + + bcast_net #( .BCAST_WIDTH(BCAST_WIDTH), + .N_NODES(N_NODES), .NODES_CONF(NODES_CONF) + ) bcast_net( + .CLK(CORE_CLK), .en(bcast_en), + .in({ unit_in, unit_in_ctrl }), .out(bcast) + ); + + + // ************************************************** + // + // Units + // + // ************************************************** + localparam UNIT_OUTPUT_WIDTH = 2; + wire [UNIT_OUTPUT_WIDTH * N_UNITS -1 :0] unit_dout; + wire [N_UNITS-1:0] unit_rd_en, unit_empty; + + genvar i; + generate + for (i=0; i < N_UNITS; i=i+1) begin:units + + // input registers in both directions + wire unit_in_wr_en_u, unit_in_afull_u, unit_in_ready_u; + regs2d #( .IN_WIDTH(1), .OUT_WIDTH(2), .STAGES(UNIT_CONF[12 +:4]) + ) unit_in_regs( .CLK(CORE_CLK), + .enter_in(unit_in_wr_en[i]), + .enter_out({ unit_in_afull[i], unit_in_ready[i] }), + .exit_in(unit_in_wr_en_u), + .exit_out({ unit_in_afull_u, unit_in_ready_u }) + ); + + // output registers in both directions + wire [UNIT_OUTPUT_WIDTH-1 :0] dout_u; + wire rd_en_u, empty_u; + regs2d #( .IN_WIDTH(1), .OUT_WIDTH(UNIT_OUTPUT_WIDTH+1), + .STAGES(UNIT_CONF[8 +:4]) + ) unit_out_regs( .CLK(PKT_COMM_CLK), + .enter_in(unit_rd_en[i]), + .enter_out({ unit_empty[i], + unit_dout[UNIT_OUTPUT_WIDTH*i +:UNIT_OUTPUT_WIDTH] }), + .exit_in(rd_en_u), + .exit_out({ empty_u, dout_u }) + ); + + localparam [63:0] UNIT_CONF = UNITS_CONF [64*i +:64]; + localparam NODE_NUM = UNIT_CONF [0 +:8]; + localparam N_CORES = UNIT_CONF [16 +:4]; + + (* KEEP_HIERARCHY="true" *) + sha256unit #( .UNIT_CONF(UNIT_CONF), .N_CORES(N_CORES) + ) unit( + .CLK(CORE_CLK), + .unit_in(bcast[NODE_NUM*BCAST_WIDTH+1 +:BCAST_WIDTH-1]), + .unit_in_ctrl(bcast[NODE_NUM*BCAST_WIDTH]), + //.unit_in_wr_en(unit_in_wr_en[i]), + //.unit_in_afull(unit_in_afull[i]), .unit_in_ready(unit_in_ready[i]), + .unit_in_wr_en(unit_in_wr_en_u), + .unit_in_afull(unit_in_afull_u), .unit_in_ready(unit_in_ready_u), + + .PKT_COMM_CLK(PKT_COMM_CLK), + //.dout(unit_dout[UNIT_OUTPUT_WIDTH*i +:UNIT_OUTPUT_WIDTH]), + //.rd_en(unit_rd_en[i]), .empty(unit_empty[i]) + .dout(dout_u), .rd_en(rd_en_u), .empty(empty_u) + ); + + end + endgenerate + + + // ************************************************** + // + // Arbiter, receive part + // + // ************************************************** + wire [31:0] cmp_data; + wire [`HASH_NUM_MSB:0] cmp_hash_num; + + wire [`OUTPKT_TYPE_MSB:0] outpkt_type; + wire [15:0] arbiter_pkt_id; + wire [31:0] arbiter_num_processed; + wire [`HASH_NUM_MSB:0] hash_num; + wire [15:0] arbiter_dout; + wire [`MSB(4 +`RESULT_LEN/2 -1):0] arbiter_rd_addr; + + arbiter_rx #( + .N_UNITS(N_UNITS), .UNIT_OUTPUT_WIDTH(UNIT_OUTPUT_WIDTH), + .PKT_NUM_WORDS(4 +`RESULT_LEN/2) + ) arbiter_rx( + .CLK(PKT_COMM_CLK), .mode_cmp(mode_cmp), + .unit_dout(unit_dout), + .unit_rd_en(unit_rd_en), .unit_empty(unit_empty), + // Iteraction with arbiter_tx + .num_processed_tx(num_processed_tx), .pkt_id_tx(pkt_id_tx), + .pkt_tx_done(pkt_tx_done), .pkt_rx_done(pkt_rx_done), + .recv_item(recv_item), + // Comparator + .cmp_data(cmp_data), .cmp_start(cmp_start), + .cmp_found(cmp_found), .cmp_finished(cmp_finished), + .cmp_hash_num(cmp_hash_num), + // Output + .dout(arbiter_dout), .rd_addr(arbiter_rd_addr), + .outpkt_type(outpkt_type), .pkt_id(arbiter_pkt_id), + .num_processed(arbiter_num_processed), .hash_num(hash_num), + .empty(arbiter_empty), .rd_en(arbiter_rd_en), + .err(app_status[2:1]), .debug({debug3, debug2}) + ); + + + // ************************************************** + // + // Comparator + // if mode_cmp=1 (the default) then computed hashes + // appear in the comparator. + // + // ************************************************** + comparator comparator( + .CLK(PKT_COMM_CLK), + // cmp_config + .din(cmp_din), .wr_en(cmp_wr_en), + .wr_addr(cmp_wr_addr), .hash_count(hash_count), + // arbiter_rx + .cmp_data(cmp_data), .start(cmp_start), + .found(cmp_found), .finished(cmp_finished), .hash_num(cmp_hash_num) + ); + + + // ************************************************ + // + // Create application packets from output data + // + // ************************************************ + assign arbiter_rd_en = ~arbiter_empty & ~outpkt_full; + assign outpkt_wr_en = arbiter_rd_en; + + outpkt #( + .HASH_NUM_MSB(`HASH_NUM_MSB), .SIMULATION(DISABLE_CHECKSUM) + ) outpkt( + .CLK(PKT_COMM_CLK), + .din(arbiter_dout), .rd_addr(arbiter_rd_addr), + .source_not_empty(~arbiter_empty), + .wr_en(outpkt_wr_en), .full(outpkt_full), + + .pkt_type(outpkt_type), .pkt_id(arbiter_pkt_id), + .hash_num(hash_num), .num_processed(arbiter_num_processed), + + .dout(dout), .rd_en(wr_en), .empty(outpkt_empty), .pkt_end_out() + ); + + + // Write data into output FIFO + assign wr_en = ~outpkt_empty & ~full; + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt_cmp_config.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt_cmp_config.v new file mode 100644 index 00000000000..95aa6436a99 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt_cmp_config.v @@ -0,0 +1,191 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +module sha256crypt_cmp_config( + // + // CMP_CONFIG packet: + // + // * 18 bytes salt: 1 byte unused, 1 salt_len, 16 bytes salt itself + // (if actual salt_len is less than 16 then it's padded) + // * 4 bytes: "tunable cost 0" (iteration count) + // * 2 bytes: hash count for comparator (up to `NUM_HASHES) + // * 4*(hash count) bytes: comparator data (bits 0-31 of hash). + // * ends with 0xCC + // + input CLK, + // When asserted, it accepts packets without comparator data. + input mode_cmp, + + input [7:0] din, + input wr_en, + output reg full = 0, + output reg error = 0, + + // Iteraction with other subsystems. + output reg new_cmp_config = 0, // asserted on a new cmp_config packet. + + // do not finish processing, block processing next packets by pkt_comm + // until cmp_config_applied asserts (requires mode_cmp=1). + input cmp_config_applied, + + // Output into comparator + output reg [`HASH_COUNT_MSB:0] hash_count, + output reg [`HASH_NUM_MSB+2:0] cmp_wr_addr = {`HASH_NUM_MSB+3{1'b1}}, + output reg cmp_wr_en = 0, + output reg [7:0] cmp_din, + + // Output + input [4:0] addr, + output [7:0] dout + ); + + integer k; + + // + // CMP_CONFIG data, except for hashes, is stored in distributed RAM. + // DRAM is accessible asynchronously with addr,dout + // Content: + // 0..3 - iter_cnt + // 4..7 - salt_len + // 8..23 - salt + // + (* RAM_STYLE="DISTRIBUTED" *) + reg [7:0] data [0:31]; + initial + for (k=0; k <= 31; k=k+1) + data[k] = 0; + + assign dout = data [addr]; + wire [4:0] data_wr_addr; + + always @(posedge CLK) + if (data_wr_en) + data [data_wr_addr] <= din; + + + reg [4:0] salt_addr = 8; + reg [1:0] iter_cnt = 0; + + + localparam STATE_NONE = 0, + STATE_SALT_LEN = 1, + STATE_SALT = 2, + STATE_ITER_COUNT = 3, + STATE_HASH_COUNT0 = 4, + STATE_HASH_COUNT1 = 5, + STATE_CMP_DATA = 6, + STATE_WAIT_CMP_CONFIG_APPLIED = 7, + STATE_MAGIC = 8; + + (* FSM_EXTRACT="true" *) + reg [3:0] state = STATE_NONE; + + always @(posedge CLK) begin + if (error) begin + end + + else if (state == STATE_WAIT_CMP_CONFIG_APPLIED) begin + if (cmp_config_applied) begin + new_cmp_config <= 0; + full <= 0; + state <= STATE_SALT_LEN; + end + end + + else if (~wr_en) + cmp_wr_en <= 0; + + else if (wr_en) + case (state) + STATE_NONE: + if (din != 0) + error <= 1; + else begin + new_cmp_config <= 1; + full <= 1; + state <= STATE_WAIT_CMP_CONFIG_APPLIED; + end + + STATE_SALT_LEN: begin + if (din > 16 | din == 0) + error <= 1; + else + state <= STATE_SALT; + salt_addr <= 8; + end + + STATE_SALT: begin + salt_addr <= salt_addr + 1'b1; + if (salt_addr == 23) + state <= STATE_ITER_COUNT; + end + + STATE_ITER_COUNT: begin + // TODO: raise error on rounds=0 + iter_cnt <= iter_cnt + 1'b1; + if (iter_cnt == 3) + state <= STATE_HASH_COUNT0; + end + + STATE_HASH_COUNT0: begin + hash_count[7:0] <= din; + if (~mode_cmp & din != 0) + error <= 1; + else + state <= STATE_HASH_COUNT1; + end + + STATE_HASH_COUNT1: begin + hash_count[`HASH_COUNT_MSB:8] <= din[`HASH_COUNT_MSB-8:0]; + cmp_wr_addr <= {`HASH_NUM_MSB+3{1'b1}}; + + if (~mode_cmp & din != 0) + error <= 1; + else if (mode_cmp) + state <= STATE_CMP_DATA; + else + state <= STATE_MAGIC; + + /* + if (hash_count[7:0] == 0 & din == 0) + state <= STATE_MAGIC; + else + state <= STATE_CMP_DATA; + */ + end + + STATE_CMP_DATA: begin + cmp_wr_en <= 1; + cmp_din <= din; + cmp_wr_addr <= cmp_wr_addr + 1'b1; + if (cmp_wr_addr + 2'b10 == { hash_count, 2'b00 } ) + state <= STATE_MAGIC; + end + + STATE_MAGIC: begin + cmp_wr_en <= 0; + if (din == 8'hCC) + state <= STATE_NONE; + else + error <= 1; + end + endcase + end + + assign data_wr_en = wr_en & (state == STATE_SALT_LEN + | state == STATE_SALT | state == STATE_ITER_COUNT); + + assign data_wr_addr = + state == STATE_SALT_LEN ? 5'd4 : + state == STATE_SALT ? salt_addr : + iter_cnt; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt_test.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt_test.v new file mode 100644 index 00000000000..c2102ef6349 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256crypt_test.v @@ -0,0 +1,185 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +module sha256crypt_test(); + + reg READ_ALL_FROM_OUTPUT_FIFO = 0; + + genvar i; + integer k, k1, k2; + reg [7:0] char; + + reg [7:0] app_mode = 0; + + initial begin + + // ***************************************************************** + // + // Send data packets exactly as they arrive from USB controller. + // + // Output packets appear in output_fifo.fifo_output0.ram + // exactly as before they leave FPGA. + // On errors it sets pkt_comm_status and app_status available + // via low-speed interface. + // + // It has no internal check for the count of rounds. + // + // ***************************************************************** + #500; + + + // ***************************************************************** + // + // Test #1. + // + // Hash formatted as in reference implementation: + // { "$5$rounds=10$0//3456789//edef", "key_len=11.", + // "$5$rounds=10$0//3456789//edef$PSqu85Ls/ajCpozZe" + // "xq3yEZhffR0avwyFklOQhdAgD5" }, + // + // Data packet for computing unit (sha512unit_test.v): + // send_data_packet(10,16,11,"0//3456789//edef","key_len=11."); + // + // Hash (MSB 1st): 73ec5c1c ... 978171eb + // + // ***************************************************************** + + // Usage: send_config_packet(subtype,data_len,data); + // exclude units 0,6,7,12 + //send_config_packet(1,2,32'b_0000_0000_0001_0000_1100_0001); + + // Usage: cmp_config_create(cnt,salt_len,"salt"); + cmp_config_create(10,16,"0//3456789//edef"); + cmp_config_add_hash(32'h978171eb); + send_cmp_config(); + + send_empty_word_gen(1); + + word_list_add("mypwd123"); + word_list_add("mypwd1234"); + word_list_add("mypwd12345"); + word_list_add("pass_len_is15.."); + + //for (k=0; k < 180; k=k+1) + //for (k=0; k < 60; k=k+1) + word_list_add("0123456789abc"); + //word_list_add("abc"); + + word_list_add("key_len=11z"); + word_list_add("key_len=11."); + word_list_add("key_len=12."); + // 8 candidates total + send_word_list(); + + end + + + + // *************************************************************** + // + // + // + // *************************************************************** + reg CORE_CLK = 0, PKT_COMM_CLK = 0, IFCLK = 0; + + reg [7:0] din; + reg wr_en = 0; + +`include "../pkt_comm/pkt_comm_test_helper.vh" + + + // *************************************************************** + // + // Simulating input via USB controller, FPGA's Input fifo + // + // *************************************************************** + wire [15:0] app_dout; + wire [7:0] app_status, pkt_comm_status, debug2, debug3; + wire [7:0] hs_input_dout; + + fifo_sync_small #( .A_WIDTH(16), .D_WIDTH(8) + ) fifo_input1( + .CLK(PKT_COMM_CLK), + .din(din), + .wr_en(wr_en), + .full(), + + .dout(hs_input_dout), + .rd_en(hs_input_rd_en), + .empty(hs_input_empty) + ); + + sha256crypt #(.DISABLE_CHECKSUM(1)) pkt_comm( + //pkt_comm_v2 pkt_comm( + .PKT_COMM_CLK(PKT_COMM_CLK), + .CORE_CLK(CORE_CLK), + // High-Speed FPGA input + .din(hs_input_dout), + .rd_en(hs_input_rd_en), + .empty(hs_input_empty), + // High-Speed FPGA output + .dout(app_dout), + .wr_en(app_wr_en), + .full(app_full), + // Application control (via VCR I/O). Set with fpga_set_app_mode() + .app_mode(app_mode), + // Application status. Available at fpga->wr.io_state.app_status + .cores_idle(cores_idle), + .app_status(app_status), .pkt_comm_status(pkt_comm_status), + .debug2(debug2), .debug3(debug3) + ); + + + // ******************************************************** + // + // Output buffer (via High-Speed interface) + // + // ******************************************************** + output_fifo output_fifo( + .wr_clk(PKT_COMM_CLK), + .din(app_dout), + .wr_en(app_wr_en), + .full(app_full), + + .rd_clk(IFCLK), + .dout(), // to Cypress IO, + .rd_en(READ_ALL_FROM_OUTPUT_FIFO), // to Cypress IO, + .empty(), // to Cypress IO + .mode_limit(1'b1), + .reg_output_limit(READ_ALL_FROM_OUTPUT_FIFO), + .output_limit(), + .output_limit_not_done() + ); + + + // This does not reflect actual timing + initial begin + #3; + while (1) begin + CORE_CLK <= ~CORE_CLK; #6; + end + end + + initial begin + #5; + while (1) begin + PKT_COMM_CLK <= ~PKT_COMM_CLK; #10; + end + end + + initial begin + #35; + while (1) begin + IFCLK <= ~IFCLK; #70; + end + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/core_input.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/core_input.v new file mode 100644 index 00000000000..42caec5371c --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/core_input.v @@ -0,0 +1,70 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +// +// Extracted from realign4: +// everything dependent on N_CORES +// +module core_input #( + parameter N_CORES = 3, + parameter N_CORES_MSB = `MSB(N_CORES-1), + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + // from realign + input realign_wr_en_r, realign_valid_eqn, realign_valid, + + input [N_THREADS_MSB :0] thread_num, + input [`BLK_OP_MSB:0] blk_op, + + output reg [N_CORES-1:0] core_wr_en = 0, + output reg [3:0] core_wr_addr = 0, + output reg [`BLK_OP_MSB:0] core_blk_op, + output reg core_seq, + output reg set_input_ready = 0 + ); + + genvar i; + + reg [N_THREADS_MSB :0] thread_num1; + reg [`BLK_OP_MSB:0] blk_op1; + always @(posedge CLK) begin + thread_num1 <= thread_num; + blk_op1 <= blk_op; + end + + wire [N_CORES_MSB :0] core_num; + assign { core_num, seq_num } = thread_num1; + + generate + for (i=0; i < N_CORES; i=i+1) begin:cores_wr_en + always @(posedge CLK) + core_wr_en[i] <= i == core_num & realign_valid_eqn; + end + endgenerate + + + always @(posedge CLK) if (realign_wr_en_r) begin + core_seq <= seq_num; + core_blk_op <= blk_op1; + end + + + always @(posedge CLK) if (realign_valid) begin + core_wr_addr <= core_wr_addr + 1'b1; + + set_input_ready <= core_wr_addr == 14; + end + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/create_blk.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/create_blk.v new file mode 100644 index 00000000000..5ddac6e80b7 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/create_blk.v @@ -0,0 +1,304 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +// +// Task: given procb records and other data, +// create datasets for memory read and further processing. +// +// That was divided into 2 parts: +// - Part I (process_bytes) form datasets for memory reads +// without respect to blocks; +// - Part II (this one) operates with respect to blocks, +// cuts datasets and saves state after the end of a block. +// It's also responsible for padding and addition of total. +// +module create_blk #( + parameter N_THREADS = 6, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + input wr_en, + input [2:0] in_len, + input [`MEM_ADDR_MSB+2 :0] in_addr, + input [`PROCB_CNT_MSB :0] in_bytes_left_prev, + input in_fin, in_stop, in_padded0x80, + input [`PROCB_TOTAL_MSB :0] in_total, + input [N_THREADS_MSB :0] in_thread_num, + input [`BLK_OP_MSB:0] in_blk_op, + input blk_start, new_comp, + // the last portion of bytes in the current procb record. + // At the same time 'in_len' can be 0. + input bytes_end, + + output reg full = 0, // busy with padding + output reg blk_end = 0, // asserts for 1 cycle at the end of the block + + output reg save_wr_en = 1, // initialize procb_saved_state on startup + output reg [N_THREADS_MSB :0] save_thread_num = 0, + output [`PROCB_SAVE_WIDTH-1 :0] save_data, + + output reg mem_rd_en = 0, + output reg [N_THREADS_MSB :0] thread_num, + output reg [`MEM_ADDR_MSB :0] mem_rd_addr, + output reg [2:0] len = 4, + output reg [1:0] off = 0, + output reg add0x80pad = 0, add0pad = 0, add_total = 0, + output reg [`PROCB_TOTAL_MSB :0] total = 0, + output reg [`BLK_OP_MSB:0] blk_op = 0, + + output reg err = 0 + ); + + // + // State for save + // + reg [`MEM_ADDR_MSB+2 :0] save_addr = 0; + reg [`PROCB_CNT_MSB :0] save_bytes_left = 0; + reg save_fin = 0, save_stop = 0, save_padded0x80 = 0; + reg comp_active = 0, procb_active = 0; + + assign save_data = { save_addr, save_bytes_left, total, + save_fin, save_stop, save_padded0x80, comp_active, procb_active }; + + + // + // Current block state + // + reg [6:0] blk_left = 64, blk_left2 = 60; + + + localparam STATE_INIT = 0, + STATE_PROCB = 2, + STATE_PAD_0x80 = 3, + STATE_PAD0 = 4, + STATE_TOTAL1 = 5, + STATE_TOTAL2 = 6; + + (* FSM_EXTRACT="true" *)//, FSM_ENCODING="one-hot" *) + reg [2:0] state = STATE_INIT; + + wire wr_en_effective = wr_en & ~full & ~blk_end; + + wire [2:0] len_effective = in_len >= blk_left ? blk_left : in_len; + + always @(posedge CLK) begin + if (blk_end) + blk_end <= 0; + + save_wr_en <= save_eqn; + + if (blk_start) begin + save_padded0x80 <= 1'b0; + thread_num <= in_thread_num; + blk_op <= in_blk_op; + end + + case(state) + STATE_INIT: begin + save_thread_num <= save_thread_num == N_THREADS-1 + ? {N_THREADS_MSB+1{1'b0}} : save_thread_num + 1'b1; + if (save_thread_num == N_THREADS-1) begin + //save_wr_en <= 0; + state <= STATE_PROCB; + end + end + + STATE_PROCB: begin + + if (wr_en_effective) begin + mem_rd_addr <= in_addr[`MEM_ADDR_MSB+2 :2]; + off <= in_addr[1:0]; + len <= len_effective; + end + mem_rd_en <= wr_en_effective & in_len > 0 & blk_left > 0; + + if (blk_start) + save_thread_num <= in_thread_num; + + if (blk_start & ~new_comp & in_len == 0) begin + if (in_padded0x80) + add0x80pad <= 0; + else + add0x80pad <= 1; + + add0pad <= 1; + off <= 0; + len <= 4; + blk_left2 <= 60; + full <= 1; + state <= STATE_PAD0; + end + + // block ends + else if (wr_en_effective & in_len >= blk_left) begin + //save_wr_en <= 1; + blk_end <= 1; + blk_left <= 64; + blk_left2 <= blk_left - in_len; + add0x80pad <= 0; + add0pad <= 0; + + // bytes end exactly at the end of the block + if (bytes_end & in_len == blk_left) begin + if (in_fin) begin + comp_active <= 1; procb_active <= 1; + end + else if (in_stop) begin // stop computation + `BLK_OP_END_COMP_OUTPUT(blk_op) <= 1; + comp_active <= 0; procb_active <= 0; + end + else begin // computation continues at the next block + comp_active <= 1; procb_active <= 0; + end + end + + // more bytes remain for processing (for the next block) + else begin + comp_active <= 1; procb_active <= 1; + end + end + + // block doesn't end + else if (wr_en_effective) begin + + blk_left <= blk_left - in_len; + blk_left2 <= blk_left - in_len; + add0x80pad <= 0; + add0pad <= 0; + + // stop_ctx is set, bytes don't end + // exactly at the end of the block + if (bytes_end & in_stop) + err <= 1; + if (bytes_end & in_fin) begin + full <= 1; + state <= STATE_PAD_0x80; + end + end + + else begin + add0x80pad <= 0; + add0pad <= 0; + end + + add_total <= 0; + end + + // pad with 0x80 and optionally 0's; align to 8 bytes + STATE_PAD_0x80: begin + mem_rd_en <= 0; + add0x80pad <= 1; + add0pad <= 1; + save_padded0x80 <= 1; + off <= 0; + + //save_bytes_left <= 0; + + if (blk_left2[1:0] != 0) begin + len <= blk_left2[1:0]; + blk_left2 <= { blk_left2[6:2], 2'b00 }; + end + else begin // at 8-byte boundary + len <= 4; + blk_left2 <= blk_left2 - 3'd4; + end + + comp_active <= 1; + procb_active <= 1; + if (blk_left2 <= 4) begin // block is finished + //save_wr_en <= 1; + full <= 0; + blk_end <= 1; + blk_left <= 64; + state <= STATE_PROCB; + end + else if (blk_left2 >= 9 & blk_left2 <= 12) + state <= STATE_TOTAL1; + else + state <= STATE_PAD0; + end + + STATE_PAD0: begin + add0x80pad <= 0; + add0pad <= 1; + len <= 4; + + //save_bytes_left <= 0; + + blk_left2 <= blk_left2 - 3'd4; + + comp_active <= 1; + procb_active <= 1; + if (blk_left2 <= 4) begin + // block is finished (padded with 0x80 and 0-15 zero bytes) + //save_wr_en <= 1; + full <= 0; + blk_end <= 1; + blk_left <= 64; + state <= STATE_PROCB; + end + else if (blk_left2 >= 9 & blk_left2 <= 12) + state <= STATE_TOTAL1; + end + + STATE_TOTAL1: begin + add0x80pad <= 0; + len <= 4; + state <= STATE_TOTAL2; + end + + STATE_TOTAL2: begin + add0pad <= 0; + add0x80pad <= 0; + add_total <= 1; + + `BLK_OP_END_COMP_OUTPUT(blk_op) <= 1; + comp_active <= 0; // Computation is finished + + procb_active <= 0; + //save_wr_en <= 1; // Block is finished + full <= 0; + blk_end <= 1; + blk_left <= 64; + state <= STATE_PROCB; + end + endcase + end + + always @(posedge CLK) + if (wr_en_effective) + total <= ( + (blk_start & new_comp) ? {`PROCB_TOTAL_MSB+1{1'b0}} : + blk_start ? in_total : + total + ) + len_effective; + + assign save_eqn = (1'b0 + | state == STATE_INIT + | state == STATE_PROCB & wr_en_effective & in_len >= blk_left + | state == STATE_PAD_0x80 & blk_left2 <= 4 + | state == STATE_PAD0 & blk_left2 <= 4 + | state == STATE_TOTAL2 + ); + + always @(posedge CLK) if (save_eqn) begin + save_addr <= in_addr + blk_left[2:0]; + save_bytes_left <= (state == STATE_PAD_0x80 + | state == STATE_PAD0 | state == STATE_TOTAL2) + ? {`PROCB_CNT_MSB+1{1'b0}} : in_bytes_left_prev - blk_left[2:0]; + save_fin <= in_fin; + save_stop <= in_stop; + //save_thread_num <= in_thread_num; + end + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/engine.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/engine.v new file mode 100644 index 00000000000..6059db18a7f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/engine.v @@ -0,0 +1,262 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module engine #( + parameter N_CORES = 3, + parameter N_CORES_MSB = `MSB(N_CORES-1), + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(2*N_CORES-1) + )( + input CLK, + + // *** CPU Interface *** + // procb_buf + input [N_THREADS_MSB:0] procb_wr_thread_num, + input procb_wr_en, + input [`PROCB_D_WIDTH-1 :0] procb_wr_data, + output [`PROCB_A_WIDTH-1 :0] procb_wr_cnt, + input comp_data1_wr_en, + input [`COMP_DATA1_MSB :0] comp_wr_data1, + // thread_state + input [N_THREADS_MSB :0] ts_wr_num1, ts_rd_num1, ts_num4, + input [`THREAD_STATE_MSB :0] ts_wr1, ts_wr4, + input ts_wr_en1, ts_wr_en4, + output [`THREAD_STATE_MSB :0] ts_rd1, ts_rd4, + // memory + input comp_data2_wr_en, + input [`COMP_DATA2_MSB :0] comp_wr_data2, + input [31:0] ext_din, + input [`MEM_TOTAL_MSB :0] ext_wr_addr, + input ext_wr_en, + output ext_full, + input mem_rd_cpu_request, + input [`MEM_TOTAL_MSB :0] mem_rd_addr_cpu, + output [31:0] mem_dout, + output mem_rd_cpu_valid, + + // *** Cores *** + // (are kept separate because of Placement & Routing issues) + output [N_CORES-1:0] core_wr_en, core_start, + input [N_CORES-1:0] core_ready, core_dout_en, core_dout_seq, + output [31:0] core_din, + output [3:0] core_wr_addr, + output [`BLK_OP_MSB:0] core_blk_op, + output core_seq, core_set_input_ready, + input [32*N_CORES-1 :0] core_dout, + + output [4:0] err + ); + + + // ********************************************************** + // + // ENGINE's CONTROLS + // + // ********************************************************** + //wire [N_THREADS_MSB:0] thread_num, core_mem_thread_num; + + engine_ctrl #( .N_CORES(N_CORES) + ) engine_ctrl( + .CLK(CLK), + .core_start(core_start)// .mem_thread_num(core_mem_thread_num), + + //.thread_num(thread_num), + //.cpu_start(cpu_start), .procb_start(procb_start) + ); + + + // ********************************************************** + // + // THREAD STATE (TS) + // + // Each thread is in some defined state. There're multiple + // channels to read/modify state of threads. + // + // ********************************************************** + wire [N_THREADS_MSB :0] ts_wr_num2, ts_rd_num2, ts_num3; + wire [`THREAD_STATE_MSB :0] ts_wr2, ts_wr3, ts_rd2, ts_rd3; + + thread_state #( .N_THREADS(N_THREADS) + ) thread_state( + .CLK(CLK), + .wr_num1(ts_wr_num1), .wr_en1(ts_wr_en1), // channel 1 - CPU + .wr_state1(ts_wr1), .rd_num1(ts_rd_num1), .rd_state1(ts_rd1), + .wr_num2(ts_wr_num2), .wr_en2(ts_wr_en2), // channel 2 - procb + .wr_state2(ts_wr2), .rd_num2(ts_rd_num2), .rd_state2(ts_rd2), + .wr_num3(ts_num3), .wr_en3(ts_wr_en3), // 3 - memory + .wr_state3(ts_wr3), .rd_num3(ts_num3), .rd_state3(ts_rd3), + .wr_num4(ts_num4), .wr_en4(ts_wr_en4), // 4 - unit_input + .wr_state4(ts_wr4), .rd_num4(ts_num4), .rd_state4(ts_rd4), + .err(err[0]) + ); + + + // ********************************************************** + // + // "MAIN" MEMORY (128 bytes / thread) + // + // ********************************************************** + wire [`MEM_TOTAL_MSB :0] mem_rd_addr_procb; + + memory #( .N_CORES(N_CORES) + ) memory( + .CLK(CLK), + // comp. data set #2 + .comp_data2_thread_num(procb_wr_thread_num), + .comp_data2_wr_en(comp_data2_wr_en), .comp_wr_data2(comp_wr_data2), + // Write + .core_din(core_dout), .core_dout_en(core_dout_en), + .core_dout_seq(core_dout_seq), + .ext_din(ext_din), .ext_wr_addr(ext_wr_addr), .ext_wr_en(ext_wr_en), + .ext_full(ext_full), + // Thread State + .ts_num(ts_num3), .ts_wr_en(ts_wr_en3), .ts_wr(ts_wr3), + // Read + .rd_en_procb(mem_rd_en_procb), .rd_cpu_request(mem_rd_cpu_request), + .rd_addr_procb(mem_rd_addr_procb), .rd_addr_cpu(mem_rd_addr_cpu), + .dout(mem_dout), .rd_cpu_valid(mem_rd_cpu_valid), + .err(err[1]) + ); + + + // ********************************************************** + // + // realign & core_input + // + // ********************************************************** + wire [2:0] len; + wire [1:0] off; + wire [`PROCB_TOTAL_MSB :0] total; + wire [N_THREADS_MSB :0] core_thread_num; + wire [`BLK_OP_MSB:0] blk_op; + + reg [2:0] len_r = 4; + reg [1:0] off_r = 0; + reg add0x80pad_r = 0, add0pad_r = 0, add_total_r = 0; + reg [`PROCB_TOTAL_MSB :0] total_r = 0; + reg [N_THREADS_MSB :0] core_thread_num_r; + reg [`BLK_OP_MSB:0] blk_op_r; + + always @(posedge CLK) begin + len_r <= len; off_r <= off; + add0x80pad_r <= add0x80pad; add0pad_r <= add0pad; + add_total_r <= add_total; core_thread_num_r <= core_thread_num; + blk_op_r <= blk_op; + if (add_total) + total_r <= total; + end + + + reg realign_wr_en = 0; + always @(posedge CLK) + realign_wr_en <= mem_rd_en_procb; + + realign4_pad realign4_pad( + .CLK(CLK), + .wr_en(realign_wr_en), + .din(mem_dout), + + .len(len_r), .off(off_r), + .add0x80pad(add0x80pad_r), .add0pad(add0pad_r), + .add_total(add_total_r), .in_total(total_r), + + .valid_eqn(realign_valid_eqn), .valid(realign_valid), + .wr_en_r(realign_wr_en_r), + .err(err[2]), .out(core_din) + ); + + core_input #( .N_CORES(N_CORES) + ) core_input( + .CLK(CLK), + .realign_wr_en_r(realign_wr_en_r), + .realign_valid_eqn(realign_valid_eqn), .realign_valid(realign_valid), + + .thread_num(core_thread_num_r), .blk_op(blk_op_r), + + .core_wr_en(core_wr_en), .core_wr_addr(core_wr_addr), + .core_blk_op(core_blk_op), + .core_seq(core_seq), .set_input_ready(core_set_input_ready) + ); + + + // ********************************************************** + // + // procb_buf + // + // A write into the buffer resembles the call to process_bytes() + // software function. + // So-called "procb records" are written. + // + // ********************************************************** + wire [N_THREADS_MSB :0] procb_rd_thread_num; + //wire [`PROCB_D_WIDTH-1 :0] procb_wr_data, procb_dout; + wire [`PROCB_D_WIDTH-1 :0] procb_dout; + //wire [`PROCB_A_WIDTH-1 :0] procb_wr_cnt; + + procb_buf #( .N_THREADS(N_THREADS) + ) procb_buf( + .CLK(CLK), + .wr_thread_num(procb_wr_thread_num), .wr_en(procb_wr_en), + .din(procb_wr_data), .wr_cnt(procb_wr_cnt), + // read by process_bytes + .rd_thread_num(procb_rd_thread_num), + .rd_en(procb_rd_en), .rd_rst(procb_rd_rst), + // read-ahead + .lookup_en(procb_lookup_en), .lookup_empty(procb_lookup_empty), + .aempty(procb_aempty), .dout(procb_dout), + .err(err[3]) + ); + + + // ********************************************************** + // + // process_bytes. + // - operates controls for realign4, core_input. + // That allows to create 16x32-bit data blocks out of + // procb records and send them to cores. Padding & total are + // added where required. + // + // ********************************************************** + process_bytes #( .N_CORES(N_CORES) + ) process_bytes( + .CLK(CLK), + // thread_state (ts) - using channel 2 + .ts_wr_num(ts_wr_num2), .ts_wr_en(ts_wr_en2), + .ts_wr(ts_wr2), .ts_rd_num(ts_rd_num2), .ts_rd(ts_rd2), + + // comp_buf + .comp_data1_thread_num(procb_wr_thread_num), + .comp_data1_wr_en(comp_data1_wr_en), .comp_wr_data1(comp_wr_data1), + + // procb_buf + .procb_rd_thread_num(procb_rd_thread_num), + .procb_rd_en(procb_rd_en), .procb_rd_rst(procb_rd_rst), + //.procb_aempty(procb_aempty), + .procb_dout(procb_dout), + .procb_lookup_en(procb_lookup_en), + .procb_lookup_empty(procb_lookup_empty), + + // Memory read, supplementary data for realign4_pad, core_input + .mem_rd_addr(mem_rd_addr_procb), .mem_rd_en(mem_rd_en_procb), + .len(len), .off(off), + .add0x80pad(add0x80pad), .add0pad(add0pad), + .add_total(add_total), .total(total), + .core_thread_num(core_thread_num), .blk_op(blk_op), + + // Connections from cores + .ready(core_ready), + .err(err[4]) + ); + + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/engine_ctrl.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/engine_ctrl.v new file mode 100644 index 00000000000..85997b4a31f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/engine_ctrl.v @@ -0,0 +1,44 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module engine_ctrl #( + parameter N_CORES = 3, + parameter N_CORES_MSB = `MSB(N_CORES-1), + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(2*N_CORES-1), + parameter COMP_INTERVAL = 144 / N_THREADS + )( + input CLK, + output reg [N_CORES-1:0] core_start = 0 + ); + + reg [7:0] cnt = 0; + always @(posedge CLK) + cnt <= cnt == 143 ? 8'b0 : cnt + 1'b1; + + + genvar i; + generate + for (i=0; i < N_CORES; i=i+1) begin:for_start + + always @(posedge CLK) begin + if (core_start[i]) + core_start[i] <= 0; + if (cnt == i * COMP_INTERVAL + || cnt == 72 + i * COMP_INTERVAL) + core_start[i] <= 1; + end + + end + endgenerate + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/memory.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/memory.v new file mode 100644 index 00000000000..0a10a2ddef3 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/memory.v @@ -0,0 +1,224 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +module memory #( + parameter N_CORES = 3, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + // *** Computation data set #2 *** + input [N_THREADS_MSB :0] comp_data2_thread_num, + input comp_data2_wr_en, + input [`COMP_DATA2_MSB :0] comp_wr_data2, + + // Write + input [32*N_CORES-1 :0] core_din, + input [N_CORES-1 :0] core_dout_en, + input [N_CORES-1 :0] core_dout_seq, + + input [31:0] ext_din, + input [`MEM_TOTAL_MSB :0] ext_wr_addr, + input ext_wr_en, + output reg ext_full = 0, + + // Thread State + output [N_THREADS_MSB :0] ts_num, + //output reg ts_wr_en = 0, + output ts_wr_en, + output [`THREAD_STATE_MSB :0] ts_wr, + + // Read + input rd_en_procb, rd_cpu_request, + input [`MEM_TOTAL_MSB :0] rd_addr_procb, rd_addr_cpu, + output reg [31:0] dout, + output reg rd_cpu_valid = 0, + + output reg err = 0 + ); + + + // ================================================================= + // + reg [31:0] mem [0: 2**(`MEM_TOTAL_MSB+1)-1]; + initial begin +`ifdef SIMULATION + // For simulation with engine_test.v, memory for thread #0 + // contains key and salt from the 1st element from + // the reference implementation. + mem[0] = 32'h746c6173; // salt + mem[1] = 32'h69727473; // stri + mem[2] = 32'h0000676e; // ng + mem[3] = 32'h6c6c6548; // Hell + mem[4] = 32'h6f77206f; // o wo + mem[5] = 32'h21646c72; // rld! +`endif + end + + + // ================================================================= + // *** Computation data (set #2) *** + // + (* RAM_STYLE="DISTRIBUTED" *) + reg [`COMP_DATA2_MSB :0] comp_data2 [0: N_THREADS-1]; + always @(posedge CLK) + if (comp_data2_wr_en) + comp_data2 [comp_data2_thread_num] <= comp_wr_data2; + + wire [`MEM_ADDR_MSB :0] comp_save_addr; + wire [3:0] comp_save_len; + assign { comp_save_addr, comp_save_len } + = comp_data2 [ {core_num_r, seq_num_r} ]; + + + // ================================================================= + // *** Input core selection *** + // + wire [`MSB(N_CORES-1):0] core_num; + encoder4 #( .N_CORES(N_CORES) + ) encoder( .in(core_dout_en), .out(core_num) ); + + reg [2:0] cnt = 0; + reg [`MSB(N_CORES-1):0] core_num_r; + reg seq_num_r; + + localparam STATE_NONE = 0, + STATE_WR = 1; + + (* FSM_EXTRACT="true" *) + reg [1:0] state = STATE_NONE; + + always @(posedge CLK) begin + case(state) + STATE_NONE: if (|core_dout_en) begin + core_num_r <= core_num; + seq_num_r <= core_dout_seq [core_num]; + state <= STATE_WR; + end + + // Actual data is 1 cycle behind 'core_dout_en' + STATE_WR: begin + cnt <= cnt - 1'b1; + if (cnt == 1) + state <= STATE_NONE; + end + endcase + end + + // Update thread_state + assign ts_num = {core_num_r, seq_num_r}; + assign ts_wr = `THREAD_STATE_WR_RDY; + //always @(posedge CLK) + // ts_wr_en <= cnt == 1; + assign ts_wr_en = cnt == 1; + + // FULL flag for external input + always @(posedge CLK) + ext_full <= |core_dout_en; + + + // ================================================================= + // *** Write *** + // + reg [31:0] input_r; + reg [`MEM_TOTAL_MSB :0] ext_wr_addr_r; + reg wr_en = 0, ext_wr_en_r = 0; + + if (N_CORES == 3) begin + + // Optimization for N_CORES=3 (saves 15 LUT) + wire [32 + 32*N_CORES-1 :0] input_mux = {ext_din, core_din}; + (* KEEP="true" *) wire [1:0] input_mux_addr = ext_wr_en + ? 2'b11 : core_num_r; + wire input_r_wr_en = ext_wr_en | state == STATE_WR + & ({1'b0, cnt - 1'b1}) < comp_save_len; + + always @(posedge CLK) + if (input_r_wr_en) begin + input_r <= input_mux [32*input_mux_addr +:32]; + wr_en <= 1; + end + else + wr_en <= 0; + + end else begin // N_CORES != 3 + + always @(posedge CLK) + if (ext_wr_en) begin + wr_en <= 1; + input_r <= ext_din; + end + else if ( ({1'b0, cnt - 1'b1}) < comp_save_len + & state == STATE_WR) begin + wr_en <= 1; + input_r <= core_din [32*core_num_r +:32]; + end + else + wr_en <= 0; + + end // N_CORES + + + always @(posedge CLK) begin + ext_wr_en_r <= ext_wr_en; + if (ext_wr_en) + ext_wr_addr_r <= ext_wr_addr; + end + + wire [`MEM_ADDR_MSB :0] wr_addr_local = comp_save_addr + cnt; + wire [`MEM_TOTAL_MSB :0] wr_addr + = {core_num_r, seq_num_r, wr_addr_local}; + + always @(posedge CLK) + if (wr_en) + mem [ext_wr_en_r ? ext_wr_addr_r : wr_addr] <= input_r; + + + // ================================================================= + // *** Read *** + // + wire rd_en = rd_en_procb | (rd_cpu_request & ~rd_cpu_valid); + + wire [`MEM_TOTAL_MSB :0] rd_addr = + rd_en_procb ? rd_addr_procb : rd_addr_cpu; + + always @(posedge CLK) + if (rd_en) + dout <= mem [rd_addr]; + + always @(posedge CLK) begin + if (rd_cpu_valid) + rd_cpu_valid <= 0; + else if (rd_cpu_request & ~rd_en_procb) + rd_cpu_valid <= 1; + end + +endmodule + + +module encoder4 #( + parameter N_CORES = 4 + )( + input [N_CORES-1 :0] in, + output [1:0] out + ); + + assign out = + in[0] ? 2'b00 : + //in[1] & N_CORES > 1 ? 2'b01 : // generates out-of-bound warnings + in[N_CORES > 1 ? 1 :0] & N_CORES > 1 ? 2'b01 : + in[N_CORES > 2 ? 2 :0] & N_CORES > 2 ? 2'b10 : + in[N_CORES > 3 ? 3 :0] & N_CORES > 3 ? 2'b11 : 2'b00; + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/next_thread_num.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/next_thread_num.v new file mode 100644 index 00000000000..480c24165d0 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/next_thread_num.v @@ -0,0 +1,32 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +module next_thread_num #( + parameter N_CORES = 3, + parameter N_CORES_MSB = `MSB(N_CORES-1), + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input [`MSB(N_THREADS-1) :0] in, + output [`MSB(N_THREADS-1) :0] out + ); + + wire [N_CORES_MSB :0] core_num; + assign { core_num, seq_num } = in; + + wire [N_CORES_MSB :0] core_num_next = + core_num == N_CORES-1 ? {N_CORES_MSB+1{1'b0}} + : core_num + 1'b1; + + wire seq_num_next = core_num == N_CORES-1 ? ~seq_num : seq_num; + + assign out = { core_num_next, seq_num_next }; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/procb_buf.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/procb_buf.v new file mode 100644 index 00000000000..8a6482ffa51 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/procb_buf.v @@ -0,0 +1,149 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + + +// +// process_bytes (procb) records (several elements per thread) +// +// The task for an engine is to accumulate a sequence of +// procb elements for each thread +// so formation of SHA data blocks goes w/o interruption. +// +// Read-ahead buffer. +// +module procb_buf #( + parameter N_THREADS = 6, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + input [N_THREADS_MSB :0] wr_thread_num, + input wr_en, + input [`PROCB_D_WIDTH-1 :0] din, + // Number of procb records currently in the buffer + output reg [`PROCB_A_WIDTH-1 :0] wr_cnt = 0, + output reg err = 0, + + input [N_THREADS_MSB :0] rd_thread_num, + input rd_en, rd_rst, lookup_en, + output aempty, lookup_empty, + output [`PROCB_D_WIDTH-1 :0] dout + ); + + (* RAM_STYLE="DISTRIBUTED" *) + reg [`PROCB_D_WIDTH-1 :0] mem [0: `PROCB_N_RECORDS*N_THREADS-1]; + + (* RAM_STYLE="DISTRIBUTED" *) + reg [`PROCB_A_WIDTH-1 :0] wr_addr_mem [0 :N_THREADS-1], + rd_addr_mem [0 :N_THREADS-1]; + + reg [`PROCB_A_WIDTH-1 :0] wr_addr_rd = 0, rd_addr = 0; + + + // ***************************************************************** + // + // Read procb records + // + // - 1st Word Fall-Through + // - Data appears on output on the next cycle after changing rd_thread_num. + // - After read is complete, read pointer resets. Reader is expected + // to set thread_status or take other measures to evade + // more reads from itself. + // + // - Read-ahead operation. Read-ahead pointer resets to actually + // read values after rd_thread changes. + // + // ***************************************************************** + + assign dout = mem [{ rd_thread_num, lookup_addr[`PROCB_A_WIDTH-2 :0] }]; + + reg [N_THREADS_MSB :0] rd_thread_prev = 0; + always @(posedge CLK) + rd_thread_prev <= rd_thread_num; + + reg [`PROCB_A_WIDTH-1 :0] lookup_addr = 0; + + always @(posedge CLK) begin + wr_addr_rd <= wr_addr_mem [rd_thread_num]; + + rd_addr <= rd_en ? rd_addr + 1'b1 : rd_addr_mem [rd_thread_num]; + + if (rd_en) + rd_addr_mem [rd_thread_num] + <= (aempty | empty | rd_rst) ? {`PROCB_A_WIDTH{1'b0}} : rd_addr + 1'b1; + + // lookup (read-ahead) + if (rd_thread_prev != rd_thread_num) + lookup_addr <= rd_addr_mem [rd_thread_num]; + + // lookup addr resets after read thread change + // or on write + if (wr_en & wr_thread_num == rd_thread_num) begin + lookup_addr <= 0; + end + + if (lookup_en) + lookup_addr <= lookup_addr + 1'b1; + + end + + assign empty = wr_addr_rd == rd_addr; + + assign aempty = wr_addr_rd == rd_addr + 1'b1; // opt! + + //assign lookup_aempty = wr_addr_rd == lookup_addr + 1'b1; + + assign lookup_empty = wr_addr_rd == lookup_addr | wr_addr_rd == 0; + + + // ***************************************************************** + // + // Write procb records - new approach + // (more CPU friendly interface) + // + // 1. Writer is expected to read wr_cnt (count of procb records + // currently in the buffer), write until finish/stop record + // or until `PROCB_N_RECORDS. + // 2. Reader resets wr_cnt on startup and after read is complete. + // + // ***************************************************************** + reg [N_THREADS_MSB :0] wr_rst_thread_num; + reg wr_rst_en = 0; + + wire wr_rst_enqueue = rd_en & (aempty | rd_rst); + + always @(posedge CLK) begin + if (wr_rst_enqueue) begin + wr_rst_en <= 1; // enqueued reset of wr_cnt + wr_rst_thread_num <= rd_thread_num; + end + + wr_cnt <= wr_addr_mem [wr_thread_num]; + + if (wr_en | wr_rst_en) begin + if (~wr_en & ~wr_rst_enqueue) + wr_rst_en <= 0; + + wr_addr_mem [wr_en ? wr_thread_num : wr_rst_thread_num] + <= wr_en ? wr_cnt + 1'b1 : {`PROCB_A_WIDTH{1'b0}}; + end + + if (wr_en & wr_rst_en & wr_rst_enqueue) + err <= 1; + + if (wr_en) begin + mem [{ wr_thread_num, wr_cnt[`PROCB_A_WIDTH-2 :0] }] <= din; + wr_cnt <= wr_cnt + 1'b1; + end + end + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/procb_saved_state.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/procb_saved_state.v new file mode 100644 index 00000000000..45cabb1dc0d --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/procb_saved_state.v @@ -0,0 +1,46 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +// +// Keep state for each thread in between blocks. +// - bytes_total of unfinished computation; +// - data for unfinished process_bytes record (including padding) +// +module procb_saved_state #( + parameter N_THREADS = 6, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + input [N_THREADS_MSB :0] wr_thread_num, + input wr_en, + input [`PROCB_SAVE_WIDTH-1 :0] din, + + input [N_THREADS_MSB :0] rd_thread_num, + //input rd_en, + //output reg [`PROCB_SAVE_WIDTH-1 :0] dout = 0 + output [`PROCB_SAVE_WIDTH-1 :0] dout + ); + + + (* RAM_STYLE="DISTRIBUTED" *) + reg [`PROCB_SAVE_WIDTH-1 :0] mem [0: N_THREADS-1]; + + always @(posedge CLK) + if (wr_en) + mem [wr_thread_num] <= din; + + //always @(posedge CLK) + // if (rd_en) + // dout <= mem [rd_thread_num]; + assign dout = mem [rd_thread_num]; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/process_bytes.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/process_bytes.v new file mode 100644 index 00000000000..5335985972c --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/process_bytes.v @@ -0,0 +1,497 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +// +// The task is: +// +// - perform "process_bytes" ("procb") actions for each thread; +// - form blocks, send to cores; +// - after 1 block is sent, it switches to the next core/context, +// keeps internal state. +// +module process_bytes #( + parameter N_CORES = 3, + parameter N_CORES_MSB = `MSB(N_CORES-1), + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + // thread_state (ts) + output [N_THREADS_MSB :0] ts_wr_num, ts_rd_num, // Thread # + output reg ts_wr_en = 1, + output reg [`THREAD_STATE_MSB :0] ts_wr = `THREAD_STATE_NONE, + input [`THREAD_STATE_MSB :0] ts_rd, + + // *** Computation data set #1 *** + input [N_THREADS_MSB :0] comp_data1_thread_num, + input comp_data1_wr_en, + input [`COMP_DATA1_MSB :0] comp_wr_data1, + + // *** process_bytes records *** + output [N_THREADS_MSB :0] procb_rd_thread_num, + output procb_rd_en, procb_rd_rst, procb_lookup_en, + //input procb_aempty, procb_lookup_aempty, + input procb_lookup_empty, + input [`PROCB_D_WIDTH-1 :0] procb_dout, + + // *** Input to cores *** + // Memory connection. + output [`MEM_TOTAL_MSB :0] mem_rd_addr, // in 8-byte words + output mem_rd_en, + // Realign connection + output [2:0] len, + output [1:0] off, + output add0x80pad, add0pad, add_total, + output [`PROCB_TOTAL_MSB :0] total, + // "core_input" + output [N_THREADS_MSB :0] core_thread_num, + output [`BLK_OP_MSB:0] blk_op, + + // Ready flags from cores + input [N_CORES-1:0] ready, + + // stop_ctx_end_blk | bad_saved_procb + //output reg [1:0] err = 0 + output err + ); + + genvar i; + integer k; + + + reg [N_THREADS_MSB :0] thread_num = 0; + wire [N_THREADS_MSB :0] thread_num_next; + next_thread_num #( .N_CORES(N_CORES) + ) next_thread_num( .in(thread_num), .out(thread_num_next) ); + + always @(posedge CLK) + if (set_next_thread_num) + thread_num <= thread_num_next; + + assign procb_rd_thread_num = thread_num; + + // Thread Status + assign ts_rd_num = thread_num; + assign ts_wr_num = thread_num; + + + // ================================================================= + // *** ready flags from cores *** + // + // Using procb_rd_thread_num to get status of the + // next core,context in advance + // + reg core_ready_r = 0; // Next core/context is ready for input + always @(posedge CLK) + core_ready_r <= ready [ thread_num[N_THREADS_MSB:1] ]; + + + // ================================================================= + // *** Computation data (set #1) *** + // + (* RAM_STYLE="DISTRIBUTED" *) + reg [`COMP_DATA1_MSB :0] comp_data1 [0: N_THREADS-1]; + always @(posedge CLK) + if (comp_data1_wr_en) + comp_data1 [comp_data1_thread_num] <= comp_wr_data1; + + wire [1:0] comp_load_ctx_num, comp_save_ctx_num; + assign { comp_if_new_ctx, comp_load_ctx_num, comp_save_ctx_num } + = comp_data1 [thread_num]; + + + // ================================================================= + // *** Current computation data *** + // + // - It forms data for memory read, realign and core_input + // almost every cycle; keeps previous dataset for the case + // if the current dataset doesn't go on. + // + reg [`BLK_OP_MSB:0] cur_blk_op = 0; + + // *** Current process_bytes (procb) data *** + // + // Data for the current process_bytes. We include padding and + // total length in process_bytes (if flag finish_ctx is set). + // These are saved in saved_procb_state when block is finished + // and current thread changes. + // + reg [`MEM_ADDR_MSB+2 :0] cur_addr; + reg [2:0] cur_len = 4; + reg [`PROCB_CNT_MSB :0] cur_bytes_left, prev_bytes_left; + reg finish_ctx = 0; + // Stop context w/o padding and total. The developer must ensure + // there's exactly full block (total % 128 == 0). The context + // remains in the core and can be loaded later to continue computation. + reg stop_ctx = 0; + reg bytes_end = 0; // End portion of bytes for the current procb record + // Start of a new block - asserts on the 1st write + reg blk_start = 0; + + + // ================================================================= + // *** saved process_bytes (procb) data *** + // + // When a block is done, unfinished procb record is saved here. + // It still counts if bytes are over and padding/total remain. + // + wire [`PROCB_SAVE_WIDTH-1 :0] save_data; + wire [N_THREADS_MSB:0] save_thread_num; + + wire [`MEM_ADDR_MSB+2 :0] saved_addr; + wire [`PROCB_CNT_MSB :0] saved_bytes_left; + wire [`PROCB_TOTAL_MSB :0] saved_total; + wire saved_finish_ctx, saved_stop_ctx, saved_padded0x80, + saved_comp_active, saved_procb_active; + // + // Some outputs from procb_saved_state are not + // required on the next cycle (KEEP,TIG) + // + (* KEEP="true" *) wire [`MEM_ADDR_MSB+2 :0] saved_addr_t = saved_addr; + (* KEEP="true" *) wire [`PROCB_TOTAL_MSB :0] saved_total_t = saved_total; + (* KEEP="true" *) wire saved_finish_ctx_t = saved_finish_ctx; + (* KEEP="true" *) wire saved_stop_ctx_t = saved_stop_ctx; + (* KEEP="true" *) wire saved_padded0x80_t = saved_padded0x80; + (* KEEP="true" *) wire saved_comp_active_t = saved_comp_active; + (* KEEP="true" *) wire saved_procb_active_t = saved_procb_active; + + procb_saved_state #( .N_THREADS(N_THREADS) + ) procb_saved_state( + .CLK(CLK), + .wr_thread_num(save_thread_num), .wr_en(save_wr_en), + .din(save_data), + .rd_thread_num(thread_num), + .dout({ saved_addr, saved_bytes_left, saved_total, + saved_finish_ctx, saved_stop_ctx, saved_padded0x80, + saved_comp_active, saved_procb_active }) + ); + + + // ================================================================= + // *** Create data blocks out of procb data *** + // + reg blk_wr_en = 0; + + create_blk #( .N_THREADS(N_THREADS) + ) create_blk( + .CLK(CLK), + .wr_en(blk_wr_en), .full(blk_full), + .in_len(cur_len), + .in_addr(cur_addr), .in_bytes_left_prev(prev_bytes_left), + .in_fin(finish_ctx), .in_stop(stop_ctx), + .in_padded0x80(saved_padded0x80_t), .in_total(saved_total_t), + .blk_start(blk_start), .new_comp(~saved_comp_active_t), + .bytes_end(bytes_end), + .in_thread_num(thread_num), .in_blk_op(cur_blk_op), + // save state when block is done + .blk_end(blk_end), .save_thread_num(save_thread_num), + .save_data(save_data), .save_wr_en(save_wr_en), + // output for memory read, realign, core_input + .mem_rd_en(mem_rd_en), .mem_rd_addr(mem_rd_addr[`MEM_ADDR_MSB:0]), + .len(len), .off(off), .total(total), + .add0x80pad(add0x80pad), .add0pad(add0pad), .add_total(add_total), + .thread_num(core_thread_num), .blk_op(blk_op), + .err(err) + ); + + assign mem_rd_addr[`MEM_TOTAL_MSB:`MEM_ADDR_MSB+1] = core_thread_num; + + + // ================================================================= + // *** Load data from procb_saved_state *** + // + // Pre-loaded data remain on the following registers: + //reg [`MEM_ADDR_MSB+2 :0] loaded_addr; + reg [`PROCB_CNT_MSB :0] loaded_bytes_left; + reg [2:0] loaded_bytes_limit = 4; + + // join align_limit and bytes_limit + wire [2:0] align_limit = 3'd4 - saved_addr[1:0]; + wire align_limit_effective = align_limit < saved_bytes_left; + + wire [2:0] bytes_limit = align_limit_effective ? align_limit : + saved_bytes_left < 4 ? saved_bytes_left[1:0] : 3'd4; + + always @(posedge CLK) if (en_load_saved_state) begin + loaded_bytes_left <= saved_bytes_left - bytes_limit; + loaded_bytes_limit <= bytes_limit; + end + + + // ================================================================= + // Load data for the next internal state + // + // Data can be loaded from: + // - from saved_procb_state (loaded_*) + // - from procb_buf + // + // each process_bytes (procb) element consists of 4 items: + // starting address; count of bytes; 2 flags. + // + wire load_from_saved; + + wire [`MEM_ADDR_MSB :0] procb_addr; + wire [`PROCB_CNT_MSB :0] procb_bytes_left; + assign { procb_addr, procb_bytes_left, + procb_finish_ctx, procb_stop_ctx } = procb_dout; + + + task do_load_state; + begin + cur_addr <= load_from_saved + ? saved_addr_t//loaded_addr + : { procb_addr, 2'b00 }; + cur_bytes_left <= load_from_saved + //? (loaded_bytes_left - loaded_bytes_limit) + ? loaded_bytes_left + : procb_bytes_left < 4 + ? {`PROCB_CNT_MSB+1{1'b0}} : procb_bytes_left - 3'd4; + cur_len <= load_from_saved + ? loaded_bytes_limit + : procb_bytes_left < 4 + ? procb_bytes_left[1:0] : 3'd4; + + bytes_end <= load_from_saved + //? (loaded_bytes_left - loaded_bytes_limit) == 0 + ? loaded_bytes_left == 0 + : procb_bytes_left <= 4; + + // prev_bytes_left is meaningful only at the end of the block + prev_bytes_left <= procb_bytes_left; + + finish_ctx <= load_from_saved + ? saved_finish_ctx_t//loaded_finish_ctx + : procb_finish_ctx; + stop_ctx <= load_from_saved + ? saved_stop_ctx_t//loaded_stop_ctx + : procb_stop_ctx; + + blk_wr_en <= 1; + end + endtask + + + task do_update_state; + begin + cur_addr <= cur_addr + cur_len; + cur_len <= cur_bytes_left <= 4 ? cur_bytes_left[2:0] : 3'd4; + cur_bytes_left <= cur_bytes_left <= 4 + ? {`PROCB_CNT_MSB+1{1'b0}} : cur_bytes_left - 3'd4; + bytes_end <= cur_bytes_left <= 4; + prev_bytes_left <= cur_bytes_left; + + blk_wr_en <= 1; + end + endtask + + + // ================================================================= + localparam STATE_INIT = 0, + STATE_INIT2 = 1, + STATE_NEXT_THREAD1 = 2, + STATE_NEXT_THREAD2 = 3, + STATE_NEXT_THREAD3 = 4, + STATE_PROCESS_BYTES = 5, + STATE_CHECK_BLK_END = 6, + STATE_PROCB_WAIT = 7; + + (* FSM_EXTRACT="true", FSM_ENCODING="one-hot" *) + reg [3:0] state = STATE_INIT; + + reg init_going = 1; + reg [N_THREADS-1 :0] init_cnt = 0; + + reg [7:0] procb_empty_wait = 0; + reg procb_loaded = 0; + + assign en_load_saved_state = state == STATE_NEXT_THREAD1; + +`ifdef SIMULATION + reg [23:0] X_THREAD_SWITCH_OK = 0; + reg [23:0] X_THREAD_NOT_RDY = 0; + reg [31:0] X_CYCLES = 0; + reg [31:0] X_CYCLES_WAIT = 0; +`endif + + always @(posedge CLK) begin +`ifdef SIMULATION + X_CYCLES <= X_CYCLES + 1'b1; +`endif + init_cnt <= { init_cnt[N_THREADS-2 :0], init_going }; + + if (ts_wr_en & ~init_going) + ts_wr_en <= 0; + + if (blk_start) + blk_start <= 0; + + procb_empty_wait[7:0] + <= { procb_empty_wait[6:0], state == STATE_PROCB_WAIT }; + + case(state) + // Initialize: procb_buf, procb_saved_state, ts + STATE_INIT: if (init_cnt[N_THREADS-1]) + state <= STATE_INIT2; + + STATE_INIT2: begin + init_going <= 0; + ts_wr_en <= 0; + state <= STATE_NEXT_THREAD1; + end + + STATE_NEXT_THREAD1: begin // next cycle after thread switch + state <= STATE_NEXT_THREAD2; + end + +/* +`ifdef SIMULATION + X_CYCLES_WAIT <= X_CYCLES_WAIT + 1'b1; +`endif + +`ifdef SIMULATION + X_THREAD_SWITCH_OK <= X_THREAD_SWITCH_OK + 1'b1; +`endif + +`ifdef SIMULATION + X_THREAD_NOT_RDY <= X_THREAD_NOT_RDY + 1'b1; +`endif +*/ + + STATE_NEXT_THREAD2: begin + if (ts_rd == `THREAD_STATE_NONE) + state <= STATE_NEXT_THREAD1; + + else if (~core_ready_r) begin // wait until core's ready + end + //else if ( ~(saved_comp_active_t & saved_procb_active_t) + // & (ts_rd == `THREAD_STATE_NONE) ) begin + //| ts_rd == `THREAD_STATE_BUSY) ) begin + // state <= STATE_NEXT_THREAD1; + //end + else if ( ~(saved_comp_active_t & saved_procb_active_t) + & ts_rd != `THREAD_STATE_RD_RDY) begin // wait for core/CPU + end + + else begin + // load saved state or next procb record + // if saved state is inactive - procb records can't be empty + do_load_state; + procb_loaded <= ~(saved_comp_active_t & saved_procb_active_t); + blk_start <= 1; + + `BLK_OP_LOAD_CTX_NUM(cur_blk_op) <= comp_load_ctx_num; + `BLK_OP_SAVE_CTX_NUM(cur_blk_op) <= comp_save_ctx_num; + + if (saved_comp_active_t) + `BLK_OP_IF_NEW_CTX(cur_blk_op) <= 0; + else // New computation + `BLK_OP_IF_NEW_CTX(cur_blk_op) <= comp_if_new_ctx; + + state <= STATE_PROCESS_BYTES; + end + end + + STATE_PROCESS_BYTES: begin + if (blk_end) begin // data from the previous cycle didn't go + procb_loaded <= 0; + blk_wr_en <= 0; + //set_next_core_ctx_num <= 1; + state <= STATE_NEXT_THREAD1; + end + else if (blk_full) begin // create_blk is busy with padding + procb_loaded <= 0; + blk_wr_en <= 0; + end + else if (bytes_end) begin + if (~finish_ctx & ~stop_ctx) begin + if (~procb_lookup_empty) begin + do_load_state; + procb_loaded <= 1; + end + else begin + // It has to load procb record, procb records empty. + procb_loaded <= 0; + blk_wr_en <= 0; + state <= STATE_CHECK_BLK_END; + ts_wr_en <= 1; + ts_wr <= `THREAD_STATE_WR_RDY; + end + end + else begin // bytes_end, finish/stop + // blk_{end|full} must assert on the next cycle + procb_loaded <= 0; + blk_wr_en <= 0; + ts_wr_en <= 1; + ts_wr <= `THREAD_STATE_BUSY; + end + end + else begin // bytes, block didn't end + do_update_state; + procb_loaded <= 0; + end + end + + STATE_CHECK_BLK_END: begin + if (blk_end) begin + // no fin/stop here + //if (finish_ctx | stop_ctx) + state <= STATE_NEXT_THREAD1; + end + else + // data is stuck in realign8 - all threads suspend + state <= STATE_PROCB_WAIT; + end + + STATE_PROCB_WAIT: if (procb_empty_wait[7] & ~procb_lookup_empty + & ts_rd == `THREAD_STATE_RD_RDY) begin + state <= STATE_PROCESS_BYTES; + end + endcase + end + + + assign load_from_saved = + state == STATE_NEXT_THREAD2 + & saved_comp_active_t & saved_procb_active_t; + + + assign set_next_thread_num = (1'b0 + | state == STATE_INIT + | state == STATE_NEXT_THREAD2 & ts_rd == `THREAD_STATE_NONE + | blk_end + ); + + // Read-ahead procb records + wire load_next_procb_record = (1'b0 + | state == STATE_PROCESS_BYTES & ~procb_lookup_empty + & bytes_end & ~(finish_ctx | stop_ctx) + | state == STATE_NEXT_THREAD2 & core_ready_r + & ~(saved_comp_active_t & saved_procb_active_t) + & (ts_rd == `THREAD_STATE_RD_RDY) + ); + + assign procb_lookup_en = + | load_next_procb_record + ; + + // Read procb record 1 cycle after lookup, if data went for processing + assign procb_rd_en = (1'b0 + | state == STATE_INIT + | procb_loaded & ~blk_end + ); + + assign procb_rd_rst = state == STATE_INIT; + + +endmodule + + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/realign4_pad.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/realign4_pad.v new file mode 100644 index 00000000000..8200a845bc5 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/realign4_pad.v @@ -0,0 +1,232 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +// +// Task: +// +// - With the help from an upper level wrapper, send a number +// of bytes from 32-bit memory in 32-bit words. Starting address +// may not be aligned to 4 bytes. +// - Add padding and total length when required +// - Allow input ~1 word/cycle +// +// Limitations: +// - only the 1st word in the block may be unaligned. +// (typically becuse of resumed process_bytes). +// - it doesn't handle correctly len=0 (just don't send) +// + +module realign4_pad ( + input CLK, + + input wr_en, + input [2:0] len, // 1..4 + input [1:0] off, // can be used only on the 1st word + input [31:0] din, + + // Following controls don't require wr_en + input add0x80pad, // ignore 'in'; set in0 to 0x80; used with add0pad + input add0pad, // add 8x 0x0 + input add_total, + input [`PROCB_TOTAL_MSB:0] in_total, + + output valid_eqn, + output reg valid = 0, // r1_len == 4 + output reg wr_en_r = 0, + output [31:0] out, // always transmit + + output reg err = 0 + ); + + genvar i; + + wire [31:0] total = + `SWAP({ {28-`PROCB_TOTAL_MSB{1'b0}}, in_total, 3'b0 }); + + // 'in' register. + //reg wr_en_r = 0; + reg [7:0] in0 = 8'h80, in1 = 0, in2 = 0, in3 = 0; + + always @(posedge CLK) begin + wr_en_r <= wr_en | add0pad | add_total; + + if (add0x80pad) + in0 <= 8'h80; + else if (add0pad | add_total) // in0 + in0 <= 0; + else if (wr_en) + in0 <= din[7:0]; + + if (add0pad) begin // in1..3 + in1 <= 0; in2 <= 0; in3 <= 0; + end + else if (add_total) begin + in1 <= total[15:8]; in2 <= total[23:16]; in3 <= total[31:24]; + end + else if (wr_en) begin + in1 <= din[15:8]; in2 <= din[23:16]; in3 <= din[31:24]; + end + end + + + reg [2:0] in_len = 0; + reg [1:0] in_off = 0; + reg off_eq0 = 1; + always @(posedge CLK) begin + in_len <= len; + in_off <= off; + off_eq0 <= off == 0; + end + + + // ================================================================= + // 'r1', 'r2' registers + // + reg [7:0] r10 = 0, r11 = 0, r12 = 0, r13 = 0; + reg [7:0] r20, r21, r22; + + assign out = { r13, r12, r11, r10 }; + + reg [2:0] r1_len = 0; // 0..4 + //reg r1_len_eq0_or8 = 1; + reg [1:0] r2_len = 0; // 0..3 + //reg r2_len_eq0 = 1; + + wire [2:0] r1_plus_in_len = r1_len + in_len; + wire [2:0] r2_plus_in_len = r2_len + in_len; + + always @(posedge CLK) begin + if (wr_en_r & in_len == 0) + err <= 1; + + if (r2_len != 0) begin + if (~wr_en_r) begin + r2_len <= 0; + r1_len <= r2_len; + end + else if (wr_en_r & ~off_eq0) + // The previous block was not aligned to 4-byte + err <= 1; + + // wr_en; r2 written + else if (wr_en_r & r2_plus_in_len[2]) begin//(r2_len + in_len > 4)) begin + r2_len <= r2_plus_in_len[1:0];//r2_len + in_len - 4; + //r2_len_eq0 <= r2_plus_in_len[2:0] == 0; + r1_len <= 4; + //r1_len_eq0_or8 <= 1; + end + + else begin // wr_en; r2 not written + r2_len <= 0; + //r2_len_eq0 <= 1; + r1_len <= r2_plus_in_len;//r2_len + in_len; + //r1_len_eq0_or8 <= r2_plus_in_len[3];//r2_len + in_len == 8; + end + end + + else begin // r2_len == 0 + if (wr_en_r) begin + if (~off_eq0) begin + if (in_len[2]) // off > 0, in_len >= 4 + err <= 1; + r2_len <= in_len[1:0]; + //r2_len_eq0 <= 0; + // Starting new data block; ensure the previous block + // was aligned to 32-bit + //if (~r1_len_eq0_or8) + if (~(r1_len == 0 | r1_len == 4)) + err <= 1; + r1_len <= 0; + //r1_len_eq0_or8 <= 1; + end + else if (r1_len == 0 | r1_len == 4) begin + r1_len <= in_len; + //r1_len_eq0_or8 <= in_len == 0 | in_len == 8; + end + else begin // r2_len=0, r1_len!=0 & r1_len!=8 + r2_len <= r1_plus_in_len[2] ? r1_plus_in_len[1:0] : 2'b0; + //r2_len_eq0 <= r1_plus_in_len <= 8; + + r1_len <= r1_plus_in_len[2] ? 3'd4 : r1_plus_in_len[1:0]; + //r1_len_eq0_or8 <= r1_plus_in_len[3]; + end + end + else if (~wr_en_r & valid) begin + r1_len <= 0; + //r1_len_eq0_or8 <= 1; + end + + end + + end + + + assign valid_eqn = r2_len != 0 ? (//~r2_len_eq0 ? ( + ~wr_en_r ? 1'b0 : + //wr_en_r & r2_plus_in_len[2] ? 1'b1 : + r2_plus_in_len[2] + ) : ( + wr_en_r & ~off_eq0 ? 1'b0 : + //wr_en_r & r1_len_eq0_or8 ? (in_len == 0 | in_len == 8) : + wr_en_r & (r1_len == 0 | r1_len == 4) ? in_len[2] : + wr_en_r ? r1_plus_in_len[2] : + 1'b0 + ); + + always @(posedge CLK) + valid <= valid_eqn; + + + wire [1:0] wr_off = + ~off_eq0 ? 3'd4 - in_off : + (r1_len == 0 | r1_len == 4) ? r2_len : + r1_len[1:0]; + + + always @(posedge CLK) begin + if (r2_len != 0) + r10 <= r20; + else if (wr_en_r & (r1_len == 0 | r1_len == 4)) + r10 <= in0; + + if (r2_len > 1) + r11 <= r21; + else if (wr_en_r & (r1_len <= 1 | r1_len == 4)) + r11 <= wr_off == 0 ? in1 : in0; + + if (r2_len > 2) + r12 <= r22; + else if (wr_en_r & (r1_len <= 2 | r1_len == 4)) + r12 <= + wr_off == 0 ? in2 : + wr_off == 1 ? in1 : + in0; + + if (wr_en_r) + r13 <= + wr_off == 0 ? in3 : + wr_off == 1 ? in2 : + wr_off == 2 ? in1 : + in0; + end + + + always @(posedge CLK) if (wr_en_r) begin + r20 <= + wr_off == 1 ? in3 : + wr_off == 2 ? in2 : + in1; + r21 <= wr_off == 2 ? in3 : in2; + r22 <= in3; + end + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/sha256engine_test.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/sha256engine_test.v new file mode 100644 index 00000000000..9c81eeb9835 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/sha256engine_test.v @@ -0,0 +1,189 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +`include "../sha256.vh" + +module sha256engine_test(); + + integer k; + + reg CLK = 0; // Each cycle is 20ns + + localparam N_CORES = 3; + localparam N_THREADS_MSB = 2; + + // procb + reg [N_THREADS_MSB:0] procb_wr_thread_num = 0; + reg procb_wr_en = 0; + reg [`PROCB_D_WIDTH-1 :0] procb_wr_data = 0; + reg comp_data1_wr_en = 0; + reg [`COMP_DATA1_MSB :0] comp_wr_data1 = 0; + // thread_state + reg [N_THREADS_MSB :0] ts_wr_num1 = 0, ts_rd_num1 = 0; + reg [`THREAD_STATE_MSB :0] ts_wr1 = 0; + reg ts_wr_en1 = 0; + // memory + reg comp_data2_wr_en = 0; + reg [`COMP_DATA2_MSB :0] comp_wr_data2 = 0; + + wire [`PROCB_A_WIDTH-1 :0] procb_wr_cnt; + wire [`THREAD_STATE_MSB :0] ts_rd1; + + + initial begin + #1000; + // + // Doing the 1st block from the reference implementation: + // "Hello world!" | "saltstring" | "Hello world!" + // Using thread #0. + // + comp_data1_wr_en <= 1; comp_data2_wr_en <= 1; + comp_wr_data1 <= 5'b10000; // new context, load/save slot #0 + comp_wr_data2 <= { 5'd24, 4'd8 }; // save_addr=24, save_len=8 + #20; + comp_data1_wr_en <= 0; comp_data2_wr_en <= 0; + + procb_wr_en <= 1; + // Expecting MEM_ADDR_MSB=4, PROCB_CNT_MSB=5 + procb_wr_data <= { 5'd3, 6'd12, 2'b00 }; #20; + procb_wr_data <= { 5'd0, 6'd10, 2'b00 }; #20; + procb_wr_data <= { 5'd3, 6'd12, 2'b10 }; #20; + procb_wr_en <= 0; + + ts_wr_num1 <= 0; ts_wr1 <= `THREAD_STATE_RD_RDY; ts_wr_en1 <= 1; #20; + ts_wr_en1 <= 0; + #80; + while (ts_rd1 != `THREAD_STATE_WR_RDY) #20; + + // + // Result appears in rows 24-31. + // + // Performing the 2nd computation (3 blocks): + // "Hello world!" | "saltstring" | result(first 12 bytes) + // | "Hello world!" | "Hello world!" + // | result(32 bytes) | result(32 bytes) + // + // The outcome would be + // "unsigned char alt_result[32]", "Create intermediate result" + // in reference implementation + // + comp_data1_wr_en <= 1; comp_data2_wr_en <= 1; + comp_wr_data1 <= 5'b10000; // new context, load/save slot #0 + comp_wr_data2 <= { 5'd8, 4'd8 }; // save_addr=8, save_len=8 + #20; + comp_data1_wr_en <= 0; comp_data2_wr_en <= 0; + + procb_wr_en <= 1; + procb_wr_data <= { 5'd3, 6'd12, 2'b00 }; #20; + procb_wr_data <= { 5'd0, 6'd10, 2'b00 }; #20; + procb_wr_data <= { 5'd24, 6'd12, 2'b00 }; #20; + procb_wr_data <= { 5'd3, 6'd12, 2'b00 }; #20; + procb_wr_en <= 0; + // procb_buf has 4 elements/thread. CPU would check 'procb_wr_cnt'. + + ts_wr_num1 <= 0; ts_wr1 <= `THREAD_STATE_RD_RDY; ts_wr_en1 <= 1; #20; + ts_wr_en1 <= 0; + #80; + while (ts_rd1 != `THREAD_STATE_WR_RDY) #20; + + // Ready for the next 4 procb elements. + procb_wr_en <= 1; + procb_wr_data <= { 5'd3, 6'd12, 2'b00 }; #20; + procb_wr_data <= { 5'd24, 6'd32, 2'b00 }; #20; + procb_wr_data <= { 5'd24, 6'd32, 2'b10 }; #20; // finish_ctx flag + procb_wr_en <= 0; + + ts_wr_num1 <= 0; ts_wr1 <= `THREAD_STATE_RD_RDY; ts_wr_en1 <= 1; #20; + ts_wr_en1 <= 0; + #80; + while (ts_rd1 != `THREAD_STATE_WR_RDY) #20; + + // Result appears in rows 8-15: + // [8] f5697bf1 + // ... + // [15] d5e5a8b4 + #20; + end + + + + genvar i; + // ********************************************************** + // + // SHA256 CORES + // + // ********************************************************** + wire [N_CORES-1:0] core_wr_en, core_start; + wire [31:0] core_din; + wire [3:0] core_wr_addr; + wire [`BLK_OP_MSB:0] core_blk_op; + + wire core_seq, core_set_input_ready; + wire [N_CORES-1:0] core_ready, core_dout_en, core_dout_seq; + wire [32*N_CORES-1 :0] core_dout; + + generate + for (i=0; i < N_CORES; i=i+1) begin:cores + + sha256core core( + .CLK(CLK), + + .start(core_start[i]), .ready(core_ready[i]), + + .wr_en(core_wr_en[i]), .in(core_din), .wr_addr(core_wr_addr), + .input_blk_op(core_blk_op), + .input_seq(core_seq), .set_input_ready(core_set_input_ready), + + .dout(core_dout[32*i +:32]), .dout_en(core_dout_en[i]), + .dout_seq(core_dout_seq[i]) + ); + + end + endgenerate + + + // ********************************************************** + // + // ENGINE + // + // ********************************************************** + + engine engine( + .CLK(CLK), + // procb_buf + .procb_wr_thread_num(procb_wr_thread_num), .procb_wr_en(procb_wr_en), + .procb_wr_data(procb_wr_data), .procb_wr_cnt(procb_wr_cnt), + .comp_data1_wr_en(comp_data1_wr_en), .comp_wr_data1(comp_wr_data1), + // thread_state + .ts_wr_num1(ts_wr_num1), .ts_rd_num1(ts_rd_num1), + .ts_wr1(ts_wr1), .ts_wr_en1(ts_wr_en1), .ts_rd1(ts_rd1), + // memory + .comp_data2_wr_en(comp_data2_wr_en), .comp_wr_data2(comp_wr_data2), + // cores + .core_wr_en(core_wr_en), .core_start(core_start), + .core_ready(core_ready), + .core_din(core_din), .core_wr_addr(core_wr_addr), + .core_blk_op(core_blk_op), .core_seq(core_seq), + .core_set_input_ready(core_set_input_ready), + .core_dout(core_dout), .core_dout_en(core_dout_en), + .core_dout_seq(core_dout_seq) + ); + + + + initial begin + #5; + while(1) begin + CLK <= ~CLK; #10; + end + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/thread_state.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/thread_state.v new file mode 100644 index 00000000000..27fdc398724 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256engine/thread_state.v @@ -0,0 +1,197 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "../sha256.vh" + +// +// +module thread_state #( + parameter N_THREADS = 6, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + + input [N_THREADS_MSB :0] wr_num1, rd_num1, + input wr_en1, + input [`THREAD_STATE_MSB :0] wr_state1, + //output reg [`THREAD_STATE_MSB :0] rd_state1 = 0, + output [`THREAD_STATE_MSB :0] rd_state1, // #1 - asynchronous read + + input [N_THREADS_MSB :0] wr_num2, rd_num2, + input wr_en2, + input [`THREAD_STATE_MSB :0] wr_state2, + output reg [`THREAD_STATE_MSB :0] rd_state2 = 0, + + input [N_THREADS_MSB :0] wr_num3, rd_num3, + input wr_en3, + input [`THREAD_STATE_MSB :0] wr_state3, + output reg [`THREAD_STATE_MSB :0] rd_state3 = 0, + + input [N_THREADS_MSB :0] wr_num4, rd_num4, + input wr_en4, + input [`THREAD_STATE_MSB :0] wr_state4, + output reg [`THREAD_STATE_MSB :0] rd_state4 = 0, + + output reg err = 0 + ); + + // + // Note. + // With more than 3 read channels, it doesn't infer memory but FFs. + // Split the memory into 2 parts. + // + (* RAM_STYLE="DISTRIBUTED" *) + reg [`THREAD_STATE_MSB :0] mem [0:N_THREADS-1], mem2 [0:N_THREADS-1]; + //mem3 [0:N_THREADS-1], mem4 [0:N_THREADS-1]; + + reg [N_THREADS_MSB :0] wr_num1_r = 0, wr_num2_r = 0, + wr_num3_r = 0, wr_num4_r = 0; + + reg [`THREAD_STATE_MSB :0] wr_state1_r = 0, + wr_state2_r = 0, wr_state3_r = 0, wr_state4_r = 0; + + reg wr_en1_r = 0, wr_en2_r = 0, wr_en3_r = 0, wr_en4_r = 0; + + //reg init_done = 0; + + always @(posedge CLK) begin + if (wr_en1 & wr_en1_r & (wr_en2_r & wr_en2 | wr_en3_r & wr_en3) + | wr_en2 & wr_en2_r & (wr_en1_r & wr_en1 | wr_en3_r & wr_en3) + | wr_en3 & wr_en3_r & (wr_en1_r & wr_en1 | wr_en2_r & wr_en2) + ) + // TODO: wr_en4 + err <= 1; + + if (wr_en1) begin + wr_en1_r <= 1; + wr_state1_r <= wr_state1; + wr_num1_r <= wr_num1; + end + + if (wr_en2) begin + wr_en2_r <= 1; + wr_state2_r <= wr_state2; + wr_num2_r <= wr_num2; + end + + if (wr_en3) begin + wr_en3_r <= 1; + wr_state3_r <= wr_state3; + wr_num3_r <= wr_num3; + end + + if (wr_en4) begin + wr_en4_r <= 1; + wr_state4_r <= wr_state4; + wr_num4_r <= wr_num4; + end + + if (wr_en1_r & ~wr_en1) + wr_en1_r <= 0; + if (~wr_en1_r & wr_en2_r & ~wr_en2) + wr_en2_r <= 0; + if (~wr_en1_r & ~wr_en2_r & wr_en3_r & ~wr_en3) + wr_en3_r <= 0; + if (~wr_en1_r & ~wr_en2_r & ~wr_en3_r & wr_en4_r & ~wr_en4) + wr_en4_r <= 0; + /* + if (~init_done) begin + thread_num3_r <= thread_num3_r + 1'b1; + if (thread_num3_r == N_THREADS - 1) + init_done <= 1; + end + */ + // 1 write channel + /* + // Infers FFs + if (wr_en1_r | wr_en2_r | wr_en3_r | wr_en4_r)// | ~init_done) + mem [ + wr_en1_r ? wr_num1_r : + wr_en2_r ? wr_num2_r : + wr_en3_r ? wr_num3_r : wr_num4_r + ] <= + wr_en1_r ? wr_state1_r : + wr_en2_r ? wr_state2_r : + wr_en3_r ? wr_state3_r : wr_state4_r; + */ + + // Infers RAM64M (36 LUT) + if (wr_en1_r | wr_en2_r | wr_en3_r | wr_en4_r) begin + mem [ + wr_en1_r ? wr_num1_r : + wr_en2_r ? wr_num2_r : + wr_en3_r ? wr_num3_r : wr_num4_r + ] <= + wr_en1_r ? wr_state1_r : + wr_en2_r ? wr_state2_r : + wr_en3_r ? wr_state3_r : wr_state4_r; + + mem2 [ + wr_en1_r ? wr_num1_r : + wr_en2_r ? wr_num2_r : + wr_en3_r ? wr_num3_r : wr_num4_r + ] <= + wr_en1_r ? wr_state1_r : + wr_en2_r ? wr_state2_r : + wr_en3_r ? wr_state3_r : wr_state4_r; + end + + // 4 read channels (1 of them is async) + //rd_state1 <= mem [rd_num1]; + rd_state2 <= mem [rd_num2]; + rd_state3 <= mem2 [rd_num3]; + rd_state4 <= mem2 [rd_num4]; + end + + assign rd_state1 = mem [rd_num1]; + + +/* +`ifdef SIMULATION + integer k; + + wire [N_THREADS-1:0] state_wr_rdy, state_rd_rdy; + wire [`MSB(N_THREADS-1):0] wr_rdy_cnt; + + genvar i; + generate + for (i=0; i < N_THREADS; i=i+1) begin: state_gen + assign state_wr_rdy[i] = mem[i] == `THREAD_STATE_WR_RDY; + assign state_rd_rdy[i] = mem[i] == `THREAD_STATE_RD_RDY; + end + endgenerate + + assign wr_rdy_cnt = + state_wr_rdy[0] + state_wr_rdy[1] + state_wr_rdy[2] + state_wr_rdy[3] + + state_wr_rdy[4] + state_wr_rdy[5] + state_wr_rdy[6] + state_wr_rdy[7] + + state_wr_rdy[8] + state_wr_rdy[9] + state_wr_rdy[10] + state_wr_rdy[11] + + state_wr_rdy[12] + state_wr_rdy[13] + state_wr_rdy[14] + state_wr_rdy[15]; + + reg [31:0] X_CYCLES_TOTAL = 0; + reg [31:0] X_CYCLES_WR_RDY = 0; + reg [31:0] X_CYCLES_RD_RDY = 0; + + reg [23:0] X_WR_RDY_CNT [0: N_THREADS-1]; + initial + for (k=0; k < N_THREADS; k=k+1) + X_WR_RDY_CNT[k] = 0; + + always @(posedge CLK) begin + X_CYCLES_TOTAL <= X_CYCLES_TOTAL + 1'b1; + if (|state_wr_rdy) + X_CYCLES_WR_RDY <= X_CYCLES_WR_RDY + 1'b1; + if (|state_rd_rdy) + X_CYCLES_RD_RDY <= X_CYCLES_RD_RDY + 1'b1; + + X_WR_RDY_CNT[wr_rdy_cnt] <= X_WR_RDY_CNT[wr_rdy_cnt] + 1'b1; + end +`endif +*/ + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256unit.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256unit.v new file mode 100644 index 00000000000..5e4e152c507 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256unit.v @@ -0,0 +1,146 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "sha256.vh" + + +module sha256unit #( + parameter [63:0] UNIT_CONF = 0, + parameter N_CORES = 3, + parameter N_CORES_MSB = `MSB(N_CORES-1), + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, + // Unit Input + input [`UNIT_INPUT_WIDTH-1 :0] unit_in, + input unit_in_ctrl, unit_in_wr_en, + output unit_in_afull, unit_in_ready, + + // Unit Output + input PKT_COMM_CLK, + output [`UNIT_OUTPUT_WIDTH-1 :0] dout, + input rd_en, + output empty + ); + + localparam UNIT_IS_DUMMY = UNIT_CONF[63]; + + genvar i; + + + // ********************************************************** + // + // SHA256 CORES + // + // ********************************************************** + wire [N_CORES-1:0] core_wr_en, core_start; + wire [31:0] core_din; + wire [3:0] core_wr_addr; + wire [`BLK_OP_MSB:0] core_blk_op; + wire core_seq, core_set_input_ready; + wire [N_CORES-1:0] core_ready, core_dout_en, core_dout_seq; + wire [32*N_CORES-1 :0] core_dout; + + generate + for (i=0; i < N_CORES; i=i+1) begin:cores + + localparam [0:0] CORE_IS_DUMMY = UNIT_CONF[20 + i]; + + if (~CORE_IS_DUMMY) begin + + (* KEEP_HIERARCHY="true" *) + //`ifdef SIMULATION + // sha256core #( .ID(i) ) core( + //`else + sha256core core( + //`endif + .CLK(CLK), + .start(core_start[i]), .ready(core_ready[i]), + .wr_en(core_wr_en[i]), .in(core_din), .wr_addr(core_wr_addr), + .input_blk_op(core_blk_op), + .input_seq(core_seq), .set_input_ready(core_set_input_ready), + .dout(core_dout[32*i +:32]), .dout_en(core_dout_en[i]), + .dout_seq(core_dout_seq[i]) + ); + + end else begin // CORE_IS_DUMMY + + (* KEEP_HIERARCHY="true" *) + sha256core_dummy core( + .CLK(CLK), + .start(core_start[i]), .ready(core_ready[i]), + .wr_en(core_wr_en[i]), .in(core_din), .wr_addr(core_wr_addr), + .input_blk_op(core_blk_op), + .input_seq(core_seq), .set_input_ready(core_set_input_ready), + .dout(core_dout[32*i +:32]), .dout_en(core_dout_en[i]), + .dout_seq(core_dout_seq[i]) + ); + + end + + end + endgenerate + + + // ********************************************************** + // + // UNIT CONTROLS + // + // ********************************************************** + + if (~UNIT_IS_DUMMY) begin + + (* KEEP_HIERARCHY="true" *) + unit_ctrl #( .N_CORES(N_CORES) + ) ctrl( + .CLK(CLK), .PKT_COMM_CLK(PKT_COMM_CLK), + // Unit Input + .unit_in(unit_in), .unit_in_ctrl(unit_in_ctrl), + .unit_in_wr_en(unit_in_wr_en), + .unit_in_afull(unit_in_afull), .unit_in_ready(unit_in_ready), + // Unit Output + .dout(dout), .rd_en(rd_en), .empty(empty), + // Cores + .core_wr_en(core_wr_en), .core_start(core_start), + .core_ready(core_ready), + .core_din(core_din), .core_wr_addr(core_wr_addr), + .core_blk_op(core_blk_op), .core_seq(core_seq), + .core_set_input_ready(core_set_input_ready), + .core_dout(core_dout), .core_dout_en(core_dout_en), + .core_dout_seq(core_dout_seq), + .err() // 5:0 + ); + + end else begin // UNIT_IS_DUMMY + + (* KEEP_HIERARCHY="true" *) + unit_ctrl_dummy #( .N_CORES(N_CORES) + ) ctrl( + .CLK(CLK), .PKT_COMM_CLK(PKT_COMM_CLK), + // Unit Input + .unit_in(unit_in), .unit_in_ctrl(unit_in_ctrl), + .unit_in_wr_en(unit_in_wr_en), + .unit_in_afull(unit_in_afull), .unit_in_ready(unit_in_ready), + // Unit Output + .dout(dout), .rd_en(rd_en), .empty(empty), + // Cores + .core_wr_en(core_wr_en), .core_start(core_start), + .core_ready(core_ready), + .core_din(core_din), .core_wr_addr(core_wr_addr), + .core_blk_op(core_blk_op), .core_seq(core_seq), + .core_set_input_ready(core_set_input_ready), + .core_dout(core_dout), .core_dout_en(core_dout_en), + .core_dout_seq(core_dout_seq), + .err() // 5:0 + ); + + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/sha256unit_test.v b/src/ztex/fpga-sha256crypt/sha256crypt/sha256unit_test.v new file mode 100644 index 00000000000..04a1ed796a3 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/sha256unit_test.v @@ -0,0 +1,280 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "sha256.vh" + + +module sha256unit_test(); + + reg READ_ALL_FROM_UOB = 1; + + localparam N_CORES = 3; + + integer i; + + initial begin + // ***************************************************************** + // + // Send an internal data packet exactly as from pkt_comm.arbiter_tx + // to the unit. + // + // Usage: send_data_packet(cnt,salt_len,key_len,"salt","key"); + // + // Data is written to the beginning of the first idle thread's + // memory, then program starts. + // + // Result from 1 thread appears in the UOB, the rest remains + // in unit's main memory. + // The unit has no internal check for the count of rounds. + // + // ***************************************************************** + #1000; + // + // SMALL ROUND COUNT + // + + // { "$5$rounds=3$saltstring", "Hello world!", + // "$5$rounds=3$saltstring$xMhNpyTgkOg7GDuj2Z5DDLiNiI9DgAITfm86Y82iqxB" }, + // + // Hash (MSB 1st): + // df76a4ac 7d2ee53c ... 433ccf79 bfb0ff66 + //send_data_packet(3,10,12,"saltstring","Hello world!"); + + // { "$5$rounds=10$=", "salt_len1", + // "$5$rounds=10$=$6xbUmUoT3ar.pSyHy3wyYp1.PFjzlnvdhokMQn14449" }, + // b186dc0d ... 4f854882 + send_data_packet(10,1,9,"=","salt_len1"); + + // { "$5$rounds=10$.", "abc", + // "$5$rounds=10$.$RqqFgOjl6uw9cciogvv9qYLzWJu5JgBivoh1TDMJTj3" }, + // 5bdfdfdd ... d288f647 + send_data_packet(10,1,3,".","abc"); + + // { "$5$rounds=7$012/4567/9ab/def", "abc", + // "$5$rounds=7$012/4567/9ab/def$PuWZaW9xjN7hQqLxTwMi.LSDm9xztq00tGdz8khP/wC" }, + // ef010a94 ... f56fb896 + send_data_packet(7,16,3,"012/4567/9ab/def","abc"); + + // { "$5$rounds=10$012.456789.bedef", "test #3: salt_len=16, key_len=32", + // "$5$rounds=10$012.456789.bedef$XMH8OphJozuO.eUybsWi33AKE9Gigj6JwNLyjp6MYY8" }, + // a9246f76 ... faf4dd29 + send_data_packet(10,16,32,"012.456789.bedef","test #3: salt_len=16, key_len=32"); + + // { "$5$rounds=10$0//3456789//edef", "key_len=11.", + // "$5$rounds=10$0//3456789//edef$PSqu85Ls/ajCpozZexq3yEZhffR0avwyFklOQhdAgD5" }, + // 73ec5c1c ... 978171eb + send_data_packet(10,16,11,"0//3456789//edef","key_len=11."); + + // { "$5$rounds=10$0.2.456789.bede", "key_len8", + // "$5$rounds=10$0.2.456789.bede$Oa3.7QX2HSXd/8uxwAEGULC2/GdKxiaUhYkCeeXtSo4" }, + // 6d1eaa09 ... f7933700 + send_data_packet(10,15,8,"0.2.456789.bede","key_len8"); + + #20; + + // + // DEFAULT ROUND COUNT + // +/* + // { "$5$saltstring", "Hello world!", + // "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5"}, + // 7a104d5d ... 7f80e9ec + send_data_packet(5000,10,12,"saltstring","Hello world!"); + + // { "$5$rounds=5019$0.2345.789.bede", "salt15,key=13", + // "$5$rounds=5019$0.2345.789.bede$MkvvIivtYEIOJcDzMEvma3ParB1/s9Ht02poIWA1RK7"}, + // 959d9451 ... fc24bbef + send_data_packet(5019,15,13,"0.2345.789.bede","salt15,key=13"); + + // { "$5$=", "salt1,key11", + // "$5$=$Qh125aRhMbwg8Phe/jIjQwos/v9I.vR/e7R1rjiYfBC"}, + // e36bf7d2 ... aad8d910 + send_data_packet(5000,1,11,"=","salt1,key11"); + + // { "$5$rounds=4970$0.234.6789.bc/ef", "12345678", + // "$5$rounds=4970$0.234.6789.bc/ef$7NDazjArUHJs988r5ovAyd5tIkJybwD9JOibJfzgWuD"}, + // fea2d5e6 ... dce0cb98 + send_data_packet(4970,16,8,"0.234.6789.bc/ef","12345678"); + + // { "$5$rounds=4972$0/2345.789//edef", "abc", + // "$5$rounds=4972$0/2345.789//edef$DDPKQRM7xJkpe4pdf13My8qCJPeFmXn6nNiwYk.R.wB"}, + // df0024e6 ... a77d8759 + send_data_packet(4972,16,3,"0/2345.789//edef","abc"); + + // { "$5$012/45.7/9ab/def", "test #3: salt_len=16, key_len=32", + // "$5$012/45.7/9ab/def$wz2Bni8S/YVASQHPTNWPiUd17QwYow5qLbmSUvgZhd1"}, + // 3a6de029 ... 6d01ab34 + send_data_packet(5000,16,32,"012/45.7/9ab/def","test #3: salt_len=16, key_len=32"); +*/ + + + // ***************************************************************** + // + // Send internal initialization packet. + // Restrictions: + // - must wait ~16 cycles after startup (wouldn't happen + // on a real device) + // - units must be idle (typically init packet is sent after GSR) + // + // Arguments: + // 0 - default program (entry pt.0) + // + // ***************************************************************** + #1000; + + //send_int_init_packet(1); + + end + + + // *************************************************************** + integer k, k1, salt_real_len, key_real_len; + + reg CLK = 0; // Each cycle is 20ns + + reg [`UNIT_INPUT_WIDTH-1 :0] in; + reg ctrl = 0, wr_en = 0; + + + sha256unit #( .N_CORES(N_CORES) ) sha256unit( + .CLK(CLK), + .unit_in(in), .unit_in_ctrl(ctrl), + .unit_in_wr_en(wr_en), .unit_in_afull(afull), + .unit_in_ready(ready), + + .PKT_COMM_CLK(CLK), + .dout(), .rd_en(READ_ALL_FROM_UOB), .empty() + ); + + + // *************************************************************** + task check_afull; + begin + while (afull) begin + wr_en <=0; #20; + end + wr_en <= 1; + end + endtask + + + // ************************************************************* + // + // Unit accepts packets. + // - packet header (1 input word). It isn't written into memory. + // - cnt (number of rounds) - 32 bit + // - salt_len - 32 bit + // - salt data - 16 bytes (2x64 bits), regardless of salt_len + // - IDs - 64 bit + // - key_len - 32 bit + // - unused - 32 bit + // - key data (rounded up to 32 bits), variable size + // + // Packet is written to the beginning of thread's memory. + // If packet length is not divisible by 4 bytes, excess + // bytes get trashed. + // + // ************************************************************* + task send_data_packet; + input [31:0] cnt; + input [7:0] salt_len, key_len; + input [0:127] salt; + input [0:511] key; // 64 bytes max. + begin + while (~ready) #20; + check_afull(); + + // word #0: packet type (0 - data packet) + ctrl <= 1; in <= 0; #20; + ctrl <= 0; + + check_afull(); + for (k=0; k < 4; k=k+1) begin + in <= cnt[k*8 +:8]; #20; + end + + check_afull(); + in <= salt_len; #20; in <= 8'h00; #(3*20);//#(7*20); + + check_afull(); + salt_real_len = 0; + for (k=0; k < 16; k=k+1) begin + check_afull(); + if (salt[k*8 +:8] != 0) begin + in <= salt[k*8 +:8]; + salt_real_len = salt_real_len+1; + #20; + end + end + + for (k=salt_real_len; k < 16; k=k+1) begin + check_afull(); + in <= 8'h00; + #20; + end + + check_afull(); + for (k=0; k < 8; k=k+1) begin + in <= 8'h0f; #20; // IDs (64-bit) + end + + check_afull(); + in <= key_len; #20; in <= 8'h00; #(7*20); + + key_real_len = 0; + for (k=0; k < 64; k=k+1) begin + check_afull(); + if (key[k*8 +:8] != 0) begin + in <= key[k*8 +:8]; + key_real_len = key_real_len+1; + #20; + end + end + + for (k=key_real_len; k < 64; k=k+1) begin + check_afull(); + in <= 8'h00; + #20; + end + + ctrl <= 1; #20; + ctrl <= 0; wr_en <= 0; #20; + #(4*20); + end + endtask + + + // ************************************************************* + // + // Initialization packet. + // Contains only header (1 word). + // 3 lowest bits are 3'b001, bits 7-4 contain init data. + // + // ************************************************************* + task send_int_init_packet; + input [7:0] din; + begin + ctrl <= 1; wr_en <= 1; + in <= { din[4:0], 3'b001 }; #20; + #20; + ctrl <= 0; wr_en <= 0; + end + endtask + + + // *************************************************************** + + initial begin + #5; + while(1) begin + CLK <= ~CLK; #10; + end + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/unit_ctrl.v b/src/ztex/fpga-sha256crypt/sha256crypt/unit_ctrl.v new file mode 100644 index 00000000000..f9da1354b54 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/unit_ctrl.v @@ -0,0 +1,256 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "sha256.vh" + +`ifdef SIMULATION +// +// Unit Controls +// +// Everything in the unit except for cores is placed here +// because of Placement & Routing issues. +// +module unit_ctrl #( + parameter N_CORES = 3, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, PKT_COMM_CLK, + // Unit Input + input [`UNIT_INPUT_WIDTH-1 :0] unit_in, + input unit_in_ctrl, unit_in_wr_en, + output unit_in_afull, unit_in_ready, + // Unit Output + output [`UNIT_OUTPUT_WIDTH-1 :0] dout, + input rd_en, + output empty, + // *** Cores *** + // (are kept separate because of Placement & Routing issues) + output [N_CORES-1:0] core_wr_en, core_start, + input [N_CORES-1:0] core_ready, core_dout_en, core_dout_seq, + output [31:0] core_din, + output [3:0] core_wr_addr, + output [`BLK_OP_MSB:0] core_blk_op, + output core_seq, core_set_input_ready, + input [32*N_CORES-1 :0] core_dout, + + output [5:0] err + ); + + + // ********************************************************** + // + // ENGINE + // + // ********************************************************** + // engine - procb + wire [N_THREADS_MSB:0] comp_procb_wr_thread_num; + wire [`PROCB_D_WIDTH-1 :0] procb_wr_data; + wire [`PROCB_A_WIDTH-1 :0] procb_wr_cnt; + wire [`COMP_DATA1_MSB :0] comp_wr_data1; + // engine - thread_state + wire [N_THREADS_MSB :0] ts_wr_num1, ts_rd_num1, ts_num4; + wire [`THREAD_STATE_MSB :0] ts_wr1, ts_wr4; + wire ts_wr_en1, ts_wr_en4; + wire [`THREAD_STATE_MSB :0] ts_rd1, ts_rd4; + // engine - memory + wire [`COMP_DATA2_MSB :0] comp_wr_data2; + wire [31:0] ext_din; + wire [`MEM_TOTAL_MSB :0] ext_wr_addr; + wire [`MEM_TOTAL_MSB :0] mem_rd_addr_cpu; + wire [31:0] mem_dout; + + + engine #( .N_CORES(N_CORES) ) engine( + .CLK(CLK), + // procb_buf + .procb_wr_thread_num(comp_procb_wr_thread_num), + .procb_wr_en(procb_wr_en), + .procb_wr_data(procb_wr_data), .procb_wr_cnt(procb_wr_cnt), + .comp_data1_wr_en(comp_wr_en), .comp_wr_data1(comp_wr_data1), + // thread_state + .ts_wr_num1(ts_wr_num1), .ts_rd_num1(ts_rd_num1), .ts_num4(ts_num4), + .ts_wr1(ts_wr1), .ts_wr_en1(ts_wr_en1), .ts_rd1(ts_rd1), + .ts_wr4(ts_wr4), .ts_wr_en4(ts_wr_en4), .ts_rd4(ts_rd4), + // memory + .comp_data2_wr_en(comp_wr_en), .comp_wr_data2(comp_wr_data2), + .ext_din(ext_din), .ext_wr_addr(ext_wr_addr), .ext_wr_en(ext_wr_en), + .ext_full(ext_full), + .mem_rd_cpu_request(mem_rd_cpu_request), + .mem_rd_addr_cpu(mem_rd_addr_cpu), + .mem_dout(mem_dout), .mem_rd_cpu_valid(mem_rd_cpu_valid), + // cores (kept separately because of P & R issues) + .core_wr_en(core_wr_en), .core_start(core_start), + .core_ready(core_ready), + .core_din(core_din), .core_wr_addr(core_wr_addr), + .core_blk_op(core_blk_op), .core_seq(core_seq), + .core_set_input_ready(core_set_input_ready), + .core_dout(core_dout), .core_dout_en(core_dout_en), + .core_dout_seq(core_dout_seq), + .err(err[4:0]) + ); + + + // ********************************************************** + // + // UNIT INPUT + // + // - operates independently from the CPU + // - finds idle thread (THREAD_STATE_NONE) + // - accepts data packet, writes into the beginning of the + // thread's memory, sets THREAD_STATE_WR_RDY + // + // ********************************************************** + wire [`ENTRY_PT_MSB:0] entry_pt_curr; + + unit_input #( .N_CORES(N_CORES) + ) unit_input( + .CLK(CLK), + .in(unit_in), .ctrl(unit_in_ctrl), .wr_en(unit_in_wr_en), + .afull(unit_in_afull), .ready(unit_in_ready), + + .out(ext_din), .mem_addr(ext_wr_addr), + .rd_en(ext_wr_en), .empty(unit_input_empty), + + .ts_num(ts_num4), .ts_wr_en(ts_wr_en4), + .ts_wr(ts_wr4), .ts_rd(ts_rd4), + + .entry_pt_curr(entry_pt_curr) + ); + + assign ext_wr_en = ~unit_input_empty & ~ext_full; + + + // ********************************************************** + // + // UNIT OUTPUT BUFFER + // + // ********************************************************** + wire [15:0] uob_data; + wire [`UOB_ADDR_MSB :0] uob_wr_addr; + + uob16pq unit_output_buf( + .clk_wr(CLK), + .din(uob_data), .wr_en(uob_wr_en), .wr_addr(uob_wr_addr), + .full(uob_full), .ready(uob_ready), + .set_input_complete(uob_set_input_complete), + + .clk_rd(PKT_COMM_CLK), + .dout(dout), .rd_en(rd_en), .empty(empty) + ); + + + // ********************************************************** + // + // CPU + // + // ********************************************************** + + cpu #( .WIDTH(16), .N_CORES(N_CORES) ) cpu( + .CLK(CLK), + .entry_pt_curr(entry_pt_curr), + // thread_state (ts) - using channel 1 + .ts_wr_num(ts_wr_num1), .ts_rd_num(ts_rd_num1), .ts_wr_en(ts_wr_en1), + .ts_wr(ts_wr1), .ts_rd(ts_rd1), + // comp_buf & procb_buf + .comp_wr_en(comp_wr_en), .procb_wr_en(procb_wr_en), + .procb_wr_cnt(procb_wr_cnt), + .comp_procb_wr_thread_num(comp_procb_wr_thread_num), + .comp_dout({ comp_wr_data1, comp_wr_data2 }), + .procb_dout(procb_wr_data), + // memory read + .mem_rd_request(mem_rd_cpu_request), .mem_rd_addr(mem_rd_addr_cpu), + .mem_rd_valid(mem_rd_cpu_valid), .mem_din(mem_dout), + // unit_output_buf + .uob_dout(uob_data), .uob_wr_en(uob_wr_en), + .uob_wr_addr(uob_wr_addr), .uob_ready(uob_ready), .uob_full(uob_full), + .uob_set_input_complete(uob_set_input_complete), + .err(err[5]) + ); + + +endmodule + +`else + +module unit_ctrl #( + parameter N_CORES = 3, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, PKT_COMM_CLK, + // Unit Input + input [`UNIT_INPUT_WIDTH-1 :0] unit_in, + input unit_in_ctrl, unit_in_wr_en, + output unit_in_afull, unit_in_ready, + // Unit Output + output [`UNIT_OUTPUT_WIDTH-1 :0] dout, + input rd_en, + output empty, + // *** Cores *** + // (are kept separate because of Placement & Routing issues) + output [N_CORES-1:0] core_wr_en, core_start, + input [N_CORES-1:0] core_ready, core_dout_en, core_dout_seq, + output [31:0] core_din, + output [3:0] core_wr_addr, + output [`BLK_OP_MSB:0] core_blk_op, + output core_seq, core_set_input_ready, + input [32*N_CORES-1 :0] core_dout, + + output [5:0] err + ); + +endmodule + +`endif + + +module unit_ctrl_dummy #( + parameter N_CORES = 3, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1) + )( + input CLK, PKT_COMM_CLK, + // Unit Input + input [`UNIT_INPUT_WIDTH-1 :0] unit_in, + input unit_in_ctrl, unit_in_wr_en, + output unit_in_afull, unit_in_ready, + // Unit Output + output [`UNIT_OUTPUT_WIDTH-1 :0] dout, + input rd_en, + output empty, + // *** Cores *** + // (are kept separate because of Placement & Routing issues) + output [N_CORES-1:0] core_wr_en, core_start, + input [N_CORES-1:0] core_ready, core_dout_en, core_dout_seq, + output [31:0] core_din, + output [3:0] core_wr_addr, + output [`BLK_OP_MSB:0] core_blk_op, + output core_seq, core_set_input_ready, + input [32*N_CORES-1 :0] core_dout, + + output [5:0] err + ); + + (* KEEP="true" *) assign unit_in_afull = 0; + (* KEEP="true" *) assign unit_in_ready = 0; + (* KEEP="true" *) assign dout = 0; + (* KEEP="true" *) assign empty = 1; + (* KEEP="true" *) assign core_wr_en = 0; + (* KEEP="true" *) assign core_dout_en = 0; + (* KEEP="true" *) assign core_dout_seq = 0; + (* KEEP="true" *) assign core_din = 0; + (* KEEP="true" *) assign core_wr_addr = 0; + (* KEEP="true" *) assign core_blk_op = 0; + (* KEEP="true" *) assign core_seq = 0; + (* KEEP="true" *) assign core_set_input_ready = 0; + (* KEEP="true" *) assign err = 0; + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/unit_input.v b/src/ztex/fpga-sha256crypt/sha256crypt/unit_input.v new file mode 100644 index 00000000000..6380c47c093 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/unit_input.v @@ -0,0 +1,191 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "sha256.vh" + +// Unit input is designed to minimize unit space, +// at possible expense in arbiter +// Input is over UNIT_INPUT_WIDTH -bit bus into main memory. +// +// Input is divided into packets. +// Each packet consists of: +// - Packet type (1 input word). +// - Data. Data is stored at the beginning of thread's memory. +// Data size must be divisible by 4 bytes. +// - The start and the end word of the packet is determined +// by 'ctrl' signal. +// + +module unit_input #( + parameter N_CORES = 3, + parameter N_THREADS = 2 * N_CORES, + parameter N_THREADS_MSB = `MSB(N_THREADS-1), + parameter INPUT_WIDTH = `UNIT_INPUT_WIDTH, + parameter RATIO = 32 / INPUT_WIDTH, + parameter RATIO_MSB = `MSB(RATIO), + parameter AFULL_SIZE = 13 + )( + input CLK, + + input [INPUT_WIDTH-1:0] in, + input wr_en, ctrl, + output reg afull = 0, ready = 1, + + output reg [31:0] out, + output [`MEM_TOTAL_MSB :0] mem_addr, + input rd_en, + output reg empty = 1, + + // thread_state (ts) + output [N_THREADS_MSB :0] ts_num, // Thread # + output reg ts_wr_en = 0, + output [`THREAD_STATE_MSB :0] ts_wr, + input [`THREAD_STATE_MSB :0] ts_rd, + + output reg [`ENTRY_PT_MSB:0] entry_pt_curr = 0 + ); + + assign ts_wr = `THREAD_STATE_WR_RDY; + + + (* RAM_STYLE="DISTRIBUTED" *) + reg [INPUT_WIDTH-1:0] input_buf [31:0]; + reg [4:0] input_addr = 0, output_addr = 0; + reg [RATIO_MSB-1:0] output_cnt = 0; + + reg [N_THREADS_MSB :0] thread_num = 0; + assign ts_num = thread_num; + reg [`MEM_ADDR_MSB :0] thread_mem_addr = 0; + assign mem_addr = { thread_num, thread_mem_addr }; + + wire [`MSB(N_THREADS-1) :0] thread_num_next; + next_thread_num #( .N_CORES(N_CORES) + ) next_thread_num( .in(thread_num), .out(thread_num_next) ); + + wire [4:0] size = input_addr - output_addr; + + + localparam STATE_IN_NONE = 0, + STATE_IN_GOING = 1, + STATE_IN_WAIT_WRITE_MEM = 2, + STATE_IN_SEARCH1 = 3, + STATE_IN_SEARCH2 = 4, + STATE_IN_SEARCH3 = 5, + STATE_IN_WAIT_PKT_END = 6; + + (* FSM_EXTRACT="true", FSM_ENCODING="auto" *) + reg [2:0] state_in = STATE_IN_NONE; + + always @(posedge CLK) begin + if (ts_wr_en) + ts_wr_en <= 0; + + case(state_in) + // Wait for the start of input packet. + STATE_IN_NONE: begin + afull <= 0; + if (wr_en & ctrl & in[2:0] == 0) + state_in <= STATE_IN_GOING; + else if (wr_en & ctrl & in[2:0] == 1) begin + entry_pt_curr <= in [`ENTRY_PT_MSB+3 :3]; + state_in <= STATE_IN_WAIT_PKT_END; + end + end + + STATE_IN_WAIT_PKT_END: if (wr_en & ctrl) + state_in <= STATE_IN_NONE; + + STATE_IN_GOING: begin + ready <= 0; + + if (wr_en) begin + input_buf [input_addr] <= in; + input_addr <= input_addr + 1'b1; + end + + afull <= size >= 32 - AFULL_SIZE; + + if (wr_en & ctrl) + state_in <= STATE_IN_WAIT_WRITE_MEM; + end + + STATE_IN_WAIT_WRITE_MEM: begin + if (empty & output_addr == input_addr) begin + ts_wr_en <= 1; + state_in <= STATE_IN_SEARCH1; + end + end + + STATE_IN_SEARCH1: begin // Search for idle thread + thread_num <= thread_num_next; + state_in <= STATE_IN_SEARCH2; + end + + STATE_IN_SEARCH2: + state_in <= STATE_IN_SEARCH3; + + STATE_IN_SEARCH3: begin + if (ts_rd == `THREAD_STATE_NONE) begin + ready <= 1; + state_in <= STATE_IN_NONE; + end + else + state_in <= STATE_IN_SEARCH1; + end + endcase + end + + + localparam STATE_OUT_NONE = 0, + STATE_OUT_NEXT_WORD = 1; + + (* FSM_EXTRACT="true", FSM_ENCODING="auto" *) + reg [1:0] state_out = STATE_OUT_NONE; + + always @(posedge CLK) + case(state_out) + STATE_OUT_NONE: if (state_in == STATE_IN_GOING) begin + thread_mem_addr <= 0; + output_cnt <= 0; + state_out <= STATE_OUT_NEXT_WORD; + end + + STATE_OUT_NEXT_WORD: begin + if (empty & output_addr != input_addr) begin + output_addr <= output_addr + 1'b1; + output_cnt <= output_cnt + 1'b1; + + out [output_cnt*INPUT_WIDTH +:INPUT_WIDTH] + <= input_buf [output_addr]; + + if (output_cnt == RATIO - 1) + empty <= 0; + end + if (~empty & rd_en) begin + thread_mem_addr <= thread_mem_addr + 1'b1; + empty <= 1; + end + if (empty & output_addr == input_addr + & state_in == STATE_IN_WAIT_WRITE_MEM) + state_out <= STATE_OUT_NONE; + end + endcase + +/* +`ifdef SIMULATION + reg [9:0] X_BYTES_RECEIVED = 0; + always @(posedge CLK) + if (state_in == STATE_IN_NONE) + X_BYTES_RECEIVED <= 0; + else if (wr_en) + X_BYTES_RECEIVED <= X_BYTES_RECEIVED + 1'b1; +`endif +*/ + +endmodule diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/uob16.v b/src/ztex/fpga-sha256crypt/sha256crypt/uob16.v new file mode 100644 index 00000000000..5ef679e4670 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/uob16.v @@ -0,0 +1,150 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "sha256.vh" + +// +// Unit's Output Buffer (UOB) +// +// +// Input (into the buffer) operation. +// +// 1. Multi-threaded environment. At any given time UOB may +// contain data for 1 given thread. +// 2. Using 16-bit output from the CPU. +// 3. CPU memorizes which thread it writes. +// +// +// Output (from the buffer) operation. +// +// 1. After 'rd_en' assertion, it starts output its content, +// 'rd_en' no longer controls the data flow. +// 2. Output are header (1 word) and (OUT_N_WORDS * OUT_WIDTH) bits. +// +module uob16 #( + parameter N_THREADS = 6, + parameter N_THREADS_MSB = `MSB(N_THREADS-1), + parameter OUT_WIDTH = 2, + parameter OUT_N_WORDS = 128 + 32, + parameter RATIO = 16 / OUT_WIDTH + )( + input clk_wr, + + input [15:0] din, + input wr_en, set_input_complete, + input [`UOB_ADDR_MSB :0] wr_addr, + output reg ready = 1, // buffer is empty, ready for write + output reg full = 0, // buffer can't accept data + // Briefly: + // ready=1: any thread can start write + // full=0: thread that started can continue writing + + input clk_rd, + output reg [`UNIT_OUTPUT_WIDTH-1 :0] dout = 0, + input rd_en, + output reg empty = 1 + ); + + + // *********************************** + // + // Input + // + // *********************************** + always @(posedge clk_wr) begin + if (wr_en) + ready <= 0; + + if (set_input_complete) + full <= 1; + else if (read_complete_sync) begin + full <= 0; + ready <= 1; + end + end + + sync_pulse sync_input_complete( .wr_clk(clk_wr), + .sig(set_input_complete), .busy(), + .rd_clk(clk_rd), .out(input_complete_sync) ); + + + // ****************************************************** + // + // Memory (BRAM) + // 32 words X 16 bits from the point of view from the CPU + // Output is 2-bit wide + // + // ****************************************************** + reg [`MSB(OUT_N_WORDS-1) :0] output_addr = 0; + wire [`UNIT_OUTPUT_WIDTH-1 :0] doutb; + + asymm_bram_min_rd #( + .minWIDTH(2), .RATIO(8), .maxDEPTH(2**(`UOB_ADDR_MSB+1)) + ) mem( + .wr_clk(clk_wr), .wr_en(wr_en), + .wr_addr(wr_addr), .din(din), + // 2-cycle write + //.wr_clk(clk_wr), .wr_en(wr_en_r | wr_en_r2), + //.wr_addr(wr_addr_r), .din(din_r), + + .rd_clk(clk_rd), .rd_en(enb), + .rd_addr(output_addr), .dout(doutb) + ); + + + // *********************************** + // + // Output + // + // *********************************** + + localparam STATE_NONE = 0, + STATE_RD_READY = 1, + STATE_RD = 2, + STATE_RD_END = 3; + + (* FSM_EXTRACT="true" *) + reg [2:0] state_rd = STATE_NONE; + + always @(posedge clk_rd) + case (state_rd) + STATE_NONE: if (input_complete_sync) begin + empty <= 0; + state_rd <= STATE_RD_READY; + end + + STATE_RD_READY: if (rd_en) begin + dout <= 2'b11; + output_addr <= output_addr + 1'b1; + empty <= 1; + state_rd <= STATE_RD; + end + + STATE_RD: begin + dout <= doutb; + output_addr <= output_addr + 1'b1; + if (output_addr == OUT_N_WORDS) + state_rd <= STATE_RD_END; + end + + STATE_RD_END: begin + dout <= 0; + output_addr <= 0; + state_rd <= STATE_NONE; + end + endcase + + assign enb = state_rd != STATE_NONE; + + sync_pulse sync_read_complete( .wr_clk(clk_rd), + .sig(state_rd == STATE_RD_END), .busy(), + .rd_clk(clk_wr), .out(read_complete_sync) ); + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/sha256crypt/uob16pq.v b/src/ztex/fpga-sha256crypt/sha256crypt/uob16pq.v new file mode 100644 index 00000000000..a7f8dfa1a1e --- /dev/null +++ b/src/ztex/fpga-sha256crypt/sha256crypt/uob16pq.v @@ -0,0 +1,173 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`include "sha256.vh" + +// +// Unit's Output Buffer (UOB) with Packet Queue +// +// +// Input (into the buffer) operation. +// +// 1. Multi-threaded environment. At any given time UOB may +// accept data for 1 given thread. +// 2. Using 16-bit output from the CPU. +// 3. CPU memorizes which thread it writes. +// 4. After 'set_input_complete' asserts, the packet goes into output +// queue, making UOB available for write immediately. +// +// Output (from the buffer) operation. +// +// 1. After 'rd_en' assertion, it starts output its content, +// 'rd_en' no longer controls the data flow. +// 2. Output are header (1 word) and (OUT_N_WORDS * OUT_WIDTH) bits. +// +module uob16pq #( + parameter N_THREADS = 6, + parameter N_THREADS_MSB = `MSB(N_THREADS-1), + parameter IN_WIDTH = 16, + parameter PKT_LEN = 20, // in input words + parameter PKT_QUEUE_MSB = 3, // 16 packets + parameter OUT_WIDTH = `UNIT_OUTPUT_WIDTH, + parameter RATIO = IN_WIDTH / OUT_WIDTH, + parameter OUT_N_WORDS = PKT_LEN * RATIO //128 + 32 + )( + input clk_wr, + + input [IN_WIDTH-1:0] din, + input wr_en, set_input_complete, + input [`UOB_ADDR_MSB :0] wr_addr, + output reg ready = 1, // buffer is empty, ready for write + output reg full = 0, // buffer can't accept data + // Briefly: + // ready=1: any thread can start write + // full=0: thread that started can continue writing + + input clk_rd, + output reg [OUT_WIDTH-1 :0] dout = 0, + input rd_en, + output reg empty = 1 + ); + + + // *********************************** + // + // Input + // + // *********************************** + + always @(posedge clk_wr) begin + if (wr_en) + ready <= 0; + + if (set_input_complete) + full <= 1; + else if (read_complete_sync) begin + full <= 0; + ready <= 1; + end + end + + // sync'd after packet is enqueued + sync_pulse sync_input_complete( .wr_clk(clk_wr), + .sig(set_input_complete), .busy(), + .rd_clk(clk_rd), .out(input_complete_sync) ); + + reg [PKT_QUEUE_MSB:0] base_addr_wr = 0; // sync'd with clk_rd + reg [PKT_QUEUE_MSB:0] base_addr_rd = 0; + + + // ****************************************************** + // + // Memory (BRAM) + // + // ****************************************************** + reg [`MSB(OUT_N_WORDS-1) :0] output_addr = 0; + wire [`UNIT_OUTPUT_WIDTH-1 :0] doutb; + + asymm_bram_min_rd #( + .minWIDTH(OUT_WIDTH), .RATIO(RATIO), + .maxDEPTH( 2**(PKT_QUEUE_MSB+1 + `UOB_ADDR_MSB+1) ) + ) mem( + .wr_clk(clk_wr), .wr_en(wr_en), + .wr_addr({base_addr_wr, wr_addr}), .din(din), + + .rd_clk(clk_rd), .rd_en(enb), + .rd_addr({base_addr_rd, output_addr}), .dout(doutb) + ); + + + // *********************************** + // + // Output + // + // *********************************** + + localparam STATE_NONE = 0, + STATE_RD_READY = 1, + STATE_RD = 2, + STATE_RD_END = 3; + + (* FSM_EXTRACT="true" *) + reg [2:0] state_rd = STATE_NONE; + + wire queue_empty = base_addr_wr == base_addr_rd; + wire queue_full = base_addr_wr + 1'b1 == base_addr_rd; + reg enqueued = 0; + + always @(posedge clk_rd) begin + if (input_complete_sync) begin + base_addr_wr <= base_addr_wr + 1'b1; + enqueued <= 1; + end + + if (state_rd == STATE_RD_END) begin + base_addr_rd <= base_addr_rd + 1'b1; + end + + if (enqueued & ~queue_full) + enqueued <= 0; + + // Read from UOB. 'empty' deasserts after 'rd_en'. + case (state_rd) + STATE_NONE: if (~queue_empty) begin + empty <= 0; + state_rd <= STATE_RD_READY; + end + + STATE_RD_READY: if (rd_en) begin + dout <= {OUT_WIDTH{1'b1}}; + output_addr <= output_addr + 1'b1; + empty <= 1; + state_rd <= STATE_RD; + end + + STATE_RD: begin + dout <= doutb; + output_addr <= output_addr + 1'b1; + if (output_addr == OUT_N_WORDS) + state_rd <= STATE_RD_END; + end + + STATE_RD_END: begin + dout <= 0; + output_addr <= 0; + state_rd <= STATE_NONE; + end + endcase + end + + assign enb = state_rd != STATE_NONE; + + sync_pulse sync_read_complete( .wr_clk(clk_rd), + .sig(enqueued & ~queue_full), .busy(), + .rd_clk(clk_wr), .out(read_complete_sync) ); + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/util/asymm_bram.v b/src/ztex/fpga-sha256crypt/util/asymm_bram.v new file mode 100644 index 00000000000..9d7a3c1ff5f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/util/asymm_bram.v @@ -0,0 +1,124 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +/* +INFO:Xst:3229 - The RAM description will not be implemented on the device block RAM because actual implementation does not support asymetric block RAM larger than one block. + ----------------------------------------------------------------------- + | ram_type | Distributed | | + ----------------------------------------------------------------------- + | Port A | + | aspect ratio | 1024-word x 32-bit | | + | clkA | connected to signal | rise | + | weA | connected to signal | high | + | addrA | connected to signal | | + | diA | connected to signal | | + ----------------------------------------------------------------------- + | Port B | + | aspect ratio | 512-word x 64-bit | | + | addrB | connected to signal | | + | doB | connected to internal node | | + ----------------------------------------------------------------------- +*/ + +// +// Asymmetric BRAM, 1 write port, 1 read port +// Write port has smaller data width +// +module asymm_bram_min_wr #( + parameter minWIDTH = 8, + parameter RATIO = 4, + parameter maxDEPTH = 512, + parameter INIT = 0 + )( + input wr_clk, + input [minWIDTH-1:0] din, + input wr_en, + input [`MSB(maxDEPTH*RATIO-1) :0] wr_addr, + + input rd_clk, + output reg [minWIDTH*RATIO-1:0] dout = INIT, + input rd_en, + input [`MSB(maxDEPTH-1) :0] rd_addr + ); + + localparam log2RATIO = `MSB(RATIO); + + (* RAM_STYLE="BLOCK" *) + reg [minWIDTH-1:0] mem [0:RATIO*maxDEPTH-1]; + + genvar i; + + // Describe the port with the smaller data width exactly as you are used to + // for symmetric block RAMs + always @(posedge wr_clk) + if (wr_en) + mem[wr_addr] <= din; + + // A generate-for is used to describe the port with the larger data width in a + // generic and compact way + generate for (i = 0; i < RATIO; i = i+1) + begin: portB + localparam [log2RATIO-1:0] lsbaddr = i; + always @(posedge rd_clk) + if (rd_en) + dout[(i+1)*minWIDTH-1:i*minWIDTH] <= mem[{rd_addr, lsbaddr}]; + end + endgenerate + +endmodule + + +// +// Asymmetric BRAM, 1 write port, 1 read port +// Read port has smaller data width +// +module asymm_bram_min_rd #( + parameter minWIDTH = 8, + parameter RATIO = 4, + parameter maxDEPTH = 512, + parameter INIT = 0 + )( + input wr_clk, + input [minWIDTH*RATIO-1:0] din, + input wr_en, + input [`MSB(maxDEPTH-1) :0] wr_addr, + + input rd_clk, + output reg [minWIDTH-1:0] dout = INIT, + input rd_en, + input [`MSB(maxDEPTH*RATIO-1) :0] rd_addr + ); + + localparam log2RATIO = `MSB(RATIO); + + (* RAM_STYLE="BLOCK" *) + reg [minWIDTH-1:0] mem [0:RATIO*maxDEPTH-1]; + + genvar i; + + // Describe the port with the smaller data width exactly as you are used to + // for symmetric block RAMs + always @(posedge rd_clk) + if (rd_en) + dout <= mem[rd_addr]; + + // A generate-for is used to describe the port with the larger data width in a + // generic and compact way + generate for (i = 0; i < RATIO; i = i+1) + begin: portB + localparam [log2RATIO-1:0] lsbaddr = i; + always @(posedge wr_clk) + if (wr_en) + mem[{wr_addr, lsbaddr}] <= din[(i+1)*minWIDTH-1:i*minWIDTH]; + end + endgenerate + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/util/delay.v b/src/ztex/fpga-sha256crypt/util/delay.v new file mode 100644 index 00000000000..4a288bf808a --- /dev/null +++ b/src/ztex/fpga-sha256crypt/util/delay.v @@ -0,0 +1,42 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// +// After 'in' is asserted for about 2**NBITS cycles, +// 'out' gets asserted. +// Deassertion of 'in' resets the counter and +// deasserts 'out' in 1 cycle. +// +module delay #( + parameter [0:0] INIT = 0, + parameter NBITS = 4, + parameter CMP_NUM_MSBITS = 4 + )( + input CLK, + input in, + output reg out = INIT + ); + + localparam CMP_NUM_BITS = NBITS > CMP_NUM_MSBITS ? CMP_NUM_MSBITS : NBITS; + + reg [NBITS-1:0] counter = {NBITS{INIT}}; + + always @(posedge CLK) + if (~in) begin + counter <= 0; + out <= 0; + end + else if (&counter[NBITS-1 -:CMP_NUM_BITS]) + out <= 1; + else + counter <= counter + 1'b1; + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/util/fifo_sync.v b/src/ztex/fpga-sha256crypt/util/fifo_sync.v new file mode 100644 index 00000000000..6c62dc8a8c4 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/util/fifo_sync.v @@ -0,0 +1,227 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// +// Synchronous FIFO (DRAM) +// 1st Word Fall-Through +// Area Optimized +// +module fifo_sync_small #( + parameter D_WIDTH = -1, + parameter A_WIDTH = 5 + )( + input CLK, + input [D_WIDTH-1:0] din, + input wr_en, + output full, + + output [D_WIDTH-1:0] dout, + input rd_en, + output empty + ); + + (* RAM_STYLE="DISTRIBUTED" *) + reg [D_WIDTH-1:0] ram [2**A_WIDTH-1:0]; + reg [A_WIDTH-1:0] inptr = 0, outptr = 0; + + assign empty = inptr == outptr; + assign full = inptr + 1'b1 == outptr; + assign dout = ram[outptr]; + + always @(posedge CLK) begin + if (~full & wr_en) begin + ram[inptr] <= din; + inptr <= inptr + 1'b1; + end + if (~empty & rd_en) + outptr <= outptr + 1'b1; + end + +endmodule + +/* +module fifo_sync_fast #( + parameter D_WIDTH = -1, + parameter A_WIDTH = 5 + )( + input CLK, + input [D_WIDTH-1:0] din, + input wr_en, + output reg full = 0, + + output [D_WIDTH-1:0] dout, + input rd_en, + output reg empty = 1 + ); + + (* RAM_STYLE="DISTRIBUTED" *) + reg [D_WIDTH-1:0] ram [2**A_WIDTH-1:0]; + reg [A_WIDTH-1:0] inptr = 0, outptr = 0; + + assign dout = ram[outptr]; + + wire do_write = ~full & wr_en; + wire do_read = ~empty & rd_en; + + always @(posedge CLK) begin + if (do_write) begin + ram[inptr] <= din; + inptr <= inptr + 1'b1; + end + + if (do_read) + outptr <= outptr + 1'b1; + + full <= ~do_read & (inptr + 1'b1 == outptr + || inptr + 2'b10 == outptr & do_write); + + empty <= ~do_write & (inptr == outptr + || inptr == outptr + 1'b1 & do_read); + end + +endmodule + + +module fifo_sync_fast_af_ae #( + parameter D_WIDTH = -1, + parameter A_WIDTH = 5 + )( + input CLK, + input [D_WIDTH-1:0] din, + input wr_en, + output reg full = 0, + output reg almost_full = 0, + + output [D_WIDTH-1:0] dout, + input rd_en, + output reg empty = 1, + output reg almost_empty = 1 + ); + + (* RAM_STYLE="DISTRIBUTED" *) + reg [D_WIDTH-1:0] ram [2**A_WIDTH-1:0]; + reg [A_WIDTH-1:0] inptr = 0, outptr = 0; + + assign dout = ram[outptr]; + + wire do_write = ~full & wr_en; + wire do_read = ~empty & rd_en; + + always @(posedge CLK) begin + if (do_write) begin + ram[inptr] <= din; + inptr <= inptr + 1'b1; + end + + if (do_read) + outptr <= outptr + 1'b1; + + full <= ~do_read & (inptr + 1'b1 == outptr + || inptr + 2'b10 == outptr & do_write); + + almost_full <= full + || ~do_read & (inptr + 2'b10 == outptr + || inptr + 2'b11 == outptr & do_write); + + empty <= ~do_write & (inptr == outptr + || inptr == outptr + 1'b1 & do_read); + + almost_empty <= empty + || ~do_write & (inptr == outptr + 1'b1 + || inptr == outptr + 2'b10 & do_read); + end + +endmodule +*/ +/* +// +// Like fifo_sync_fast, output is equpped with extra register +// +module fifo_sync_very_fast #( + parameter D_WIDTH = -1, + parameter A_WIDTH = 5 + )( + input CLK, + input [D_WIDTH-1:0] din, + input wr_en, + output full, + + output reg [D_WIDTH-1:0] dout, + input rd_en, + output reg empty = 1 + ); + + wire [D_WIDTH-1:0] fifo_dout; + + fifo_sync_fast #( .A_WIDTH(A_WIDTH), .D_WIDTH(D_WIDTH) + ) fifo_sync_fast( + .CLK(CLK), + .din(din), + .wr_en(wr_en), .full(full), + + .dout(fifo_dout), + .rd_en(fifo_rd_en), .empty(fifo_empty) + ); + + assign fifo_rd_en = empty & ~fifo_empty + || ~empty & ~fifo_empty & rd_en; + + always @(posedge CLK) + if (fifo_rd_en) begin + dout <= fifo_dout; + empty <= 0; + end + else if (rd_en) + empty <= 1; + +endmodule + + +module fifo_sync_very_fast_af #( + parameter D_WIDTH = -1, + parameter A_WIDTH = 5 + )( + input CLK, + input [D_WIDTH-1:0] din, + input wr_en, + output full, almost_full, + + output reg [D_WIDTH-1:0] dout, + input rd_en, + output reg empty = 1 + ); + + wire [D_WIDTH-1:0] fifo_dout; + + fifo_sync_fast_af_ae #( .A_WIDTH(A_WIDTH), .D_WIDTH(D_WIDTH) + ) fifo_sync_fast( + .CLK(CLK), + .din(din), + .wr_en(wr_en), + .full(full), .almost_full(almost_full), + + .dout(fifo_dout), + .rd_en(fifo_rd_en), + .empty(fifo_empty), .almost_empty(fifo_almost_empty) + ); + + assign fifo_rd_en = empty & ~fifo_empty + || ~empty & ~fifo_empty & rd_en; + + always @(posedge CLK) + if (fifo_rd_en) begin + dout <= fifo_dout; + empty <= 0; + end + else if (rd_en) + empty <= 1; + +endmodule +*/ diff --git a/src/ztex/fpga-sha256crypt/util/log2.vh b/src/ztex/fpga-sha256crypt/util/log2.vh new file mode 100644 index 00000000000..a63760c478c --- /dev/null +++ b/src/ztex/fpga-sha256crypt/util/log2.vh @@ -0,0 +1,46 @@ +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ +`ifndef _LOG2_VH_ +`define _LOG2_VH_ + +`define MSB(x) ( \ + //x >= *65536 ?: \ + x >= 256 *65536 ? 24 : \ + x >= 128 *65536 ? 23 : \ + x >= 64 *65536 ? 22 : \ + x >= 32 *65536 ? 21 : \ + x >= 16 *65536 ? 20 : \ + x >= 8 *65536 ? 19 : \ + x >= 4 *65536 ? 18 : \ + x >= 2 *65536 ? 17 : \ + x >= 65536 ? 16 : \ + x >= 32768 ? 15 : \ + x >= 16384 ? 14 : \ + x >= 8192 ? 13 : \ + x >= 4096 ? 12 : \ + x >= 2048 ? 11 : \ + x >= 1024 ? 10 : \ + x >= 512 ? 9 : \ + x >= 256 ? 8 : \ + x >= 128 ? 7 : \ + x >= 64 ? 6 : \ + x >= 32 ? 5 : \ + x >= 16 ? 4 : \ + x >= 8 ? 3 : \ + x >= 4 ? 2 : \ + x >= 2 ? 1 : \ + x >= 1 ? 0 : \ + x == 0 ? 0 : \ + -1 ) + + +`define MAX(a,b) {(a) > (b) ? (a) : (b)} +`define MIN(a,b) {(a) < (b) ? (a) : (b)} + +`endif diff --git a/src/ztex/fpga-sha256crypt/util/regs2d.v b/src/ztex/fpga-sha256crypt/util/regs2d.v new file mode 100644 index 00000000000..5eed0bd090a --- /dev/null +++ b/src/ztex/fpga-sha256crypt/util/regs2d.v @@ -0,0 +1,61 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +module regs2d #( // 2-direction + parameter IN_WIDTH = -1, + parameter OUT_WIDTH = -1, + parameter STAGES = 0 // 0 stages - no registers + )( + input CLK, + //input en, + input [IN_WIDTH-1:0] enter_in, + output [OUT_WIDTH-1:0] enter_out, + output [IN_WIDTH-1:0] exit_in, + input [OUT_WIDTH-1:0] exit_out + ); + + + wire [IN_WIDTH-1:0] stage_in [STAGES:0]; + assign stage_in[0] = enter_in; + assign exit_in = stage_in [STAGES]; + + //wire [STAGES-1:0] stage_en; + //assign stage_en[0] = en; + + wire [OUT_WIDTH-1:0] stage_out [STAGES:0]; + assign enter_out = stage_out[0]; + assign stage_out [STAGES] = exit_out; + + + genvar k; + generate + // Stages are numbered 1..STAGES + for (k=1; k <= STAGES; k=k+1) begin:stage + + (* SHREG_EXTRACT="no" *) + //reg [1 + OUT_WIDTH + IN_WIDTH-1 :0] r = 0; + reg [OUT_WIDTH + IN_WIDTH-1 :0] r = 0; + + always @(posedge CLK) begin + //r[OUT_WIDTH + IN_WIDTH] <= stage_en[k-1]; + //if (stage_en[k-1]) begin + r[IN_WIDTH-1:0] <= stage_in[k-1]; + r[OUT_WIDTH + IN_WIDTH-1 :IN_WIDTH] <= stage_out[k]; + //end + end + + assign stage_in[k] = r[IN_WIDTH-1:0]; + //assign stage_en[k] = r[OUT_WIDTH + IN_WIDTH]; + assign stage_out[k-1] = r[OUT_WIDTH + IN_WIDTH-1 :IN_WIDTH]; + end + endgenerate + +endmodule diff --git a/src/ztex/fpga-sha256crypt/util/sync.v b/src/ztex/fpga-sha256crypt/util/sync.v new file mode 100644 index 00000000000..59f3cd5d257 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/util/sync.v @@ -0,0 +1,159 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +// 2-stage FF synchronizer +module sync_sig #( + parameter INIT = 0, + // if input signal is 1-2 clk cycles + // and CLK1 is set, result would be 1 cycle long + // * if input is longer than 2 cycles, it would produce extra result + // * if less than 1 cycle, there might be no result (consider usage of sync_short_sig) + parameter CLK1 = 0 + )( + input sig, + input clk, + //input en, + output out + ); + + (* SHREG_EXTRACT="NO" *) + reg [1:0] ff = {2{INIT[0]}}; + assign out = ff[1]; + + if (CLK1) begin + + always @(posedge clk) + if (ff[1] ^ INIT[0]) + ff[1:0] <= {2{INIT[0]}}; + else + ff[1:0] <= { ff[0], sig }; + + end else begin // ! CLK1 + + always @(posedge clk) + ff[1:0] <= { ff[0], sig }; + + end + +endmodule + +/* +// For synchronizing short-duration signals (less than clk cycle), +// 2-stage FF synchronizer is prepended with async register +module sync_short_sig #( + parameter INIT = 0, + parameter CLK1 = 0 + )( + input sig, + input clk, + output out + ); + + // There's no such registers in Spartan 6 architecture, + // with a warning tools produce an equvalent item from 3 parts + reg async_r = INIT[0]; + + always @(posedge clk or posedge sig) + if (sig) + async_r <= ~INIT[0]; + else + if (out) + async_r <= INIT[0]; + + sync_sig #(.INIT(INIT), .CLK1(CLK1)) sync(.sig(async_r), .clk(clk), .out(out)); + +endmodule +*/ + +// Any frequency relation between wr_clk and rd_clk +// 'out' duration is 1 clock cycle (repeats after 'busy' deasserts) +module sync_pulse ( + input wr_clk, + input sig, + output busy, + + input rd_clk, + // 'out' must be OK in terms of metastability + output out + ); + + reg flag_wr = 0; + always @(posedge wr_clk) flag_wr <= flag_wr ^ (sig & ~busy); + + (* SHREG_EXTRACT="NO" *) + reg [2:0] sync_rd = 3'b000; + always @(posedge rd_clk) sync_rd <= {sync_rd[1:0], flag_wr}; + + (* SHREG_EXTRACT="NO" *) + reg [1:0] sync_wr = 2'b00; + always @(posedge wr_clk) sync_wr <= {sync_wr[0], sync_rd[2]}; + + assign busy = flag_wr ^ sync_wr[1]; + assign out = sync_rd[2] ^ sync_rd[1]; + +endmodule + +/* +// Any frequency relation between wr_clk and rd_clk +module sync_ack( + input wr_clk, + input sig, + output busy, // asserts on the next cycle + + input rd_clk, + output out, + input done + ); + + reg flag_wr = 0; + always @(posedge wr_clk) flag_wr <= flag_wr ^ (sig & ~busy); + + (* SHREG_EXTRACT="NO" *) + reg [2:0] sync_rd = 3'b0; + always @(posedge rd_clk) + if (~out | done) + sync_rd <= {sync_rd[1:0], flag_wr}; + + (* SHREG_EXTRACT="NO" *) + reg [1:0] sync_wr = 2'b0; + always @(posedge wr_clk) + if (out | done | done_r) + sync_wr <= {sync_wr[0], sync_rd[2]}; + + assign out = sync_rd[2] ^ sync_rd[1]; + assign busy = flag_wr ^ sync_wr[1]; + + reg done_r = 0; + always @(posedge rd_clk) + if (out & done) + done_r <= 1; + else if (done_r) + done_r <= 0; + +endmodule +*/ +/* +// sig is active for no more than 1 cycle +module pulse1( + input CLK, + input sig, + output out + ); + + reg done = 0; + always @(posedge CLK) + done <= sig; + + assign out = sig & ~done; + +endmodule +*/ + diff --git a/src/ztex/fpga-sha256crypt/xpartition-mppr.pxml b/src/ztex/fpga-sha256crypt/xpartition-mppr.pxml new file mode 100644 index 00000000000..c2cfba56d9f --- /dev/null +++ b/src/ztex/fpga-sha256crypt/xpartition-mppr.pxml @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ztex/fpga-sha256crypt/xpartition.pxml b/src/ztex/fpga-sha256crypt/xpartition.pxml new file mode 100644 index 00000000000..6d2163949e4 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/xpartition.pxml @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/async2sync.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/async2sync.v new file mode 100644 index 00000000000..c57947d40ff --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/async2sync.v @@ -0,0 +1,48 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +//********************************************************** +// +// Provides active 'clk_en' for 1 'clk' cycle per 1 'async' pulse +// +//********************************************************** + +module async2sync( + input async, + input clk, + output reg clk_en = 0 + ); + + reg async_r; + always @(posedge clk or posedge async) + if (async) + async_r <= 1'b1; + else if (done || !init_done) + async_r <= 0; + + reg done = 0; + reg init_done = 0; + + always @(posedge clk) begin + if (!async && !init_done) + init_done <= 1; + + if (async_r && init_done) + if (!clk_en && !done) begin + clk_en <= 1; + done <= 1; + end + else + clk_en <= 0; + else + done <= 0; + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/chip_select.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/chip_select.v new file mode 100644 index 00000000000..eb9e3f942e1 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/chip_select.v @@ -0,0 +1,58 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// ********************************************** +// +// Proper handling of Chip Select (CS) input +// on a multi-FPGA board. +// +// On CS assertion: +// * cycle 1. CS input gets registered (CS) +// * cycle 2. Some outputs go T-state (out_z) +// * cycle 3. Some outputs go T-state (out_z_wait1) +// +// ********************************************** + +module chip_select( + // Asynchronous CS input + input CS_IN, + input CLK, + // Synchronous output + output CS, + //output out_z, + output out_z_wait1 + ); + + (* IOB="true" *) reg cs_in_r = 0; + always @(posedge CLK) + cs_in_r <= CS_IN; + assign CS = cs_in_r; + + //(* IOB="true" *) reg cs_out_inv_r = 0; + (* IOB="true" *) reg cs_out_inv_wait1_r = 0; + reg deselect_delay = 0; + + always @(posedge CLK) + if (~cs_in_r) begin + //cs_out_inv_r <= 1; + deselect_delay <= 1; + if (deselect_delay) + cs_out_inv_wait1_r <= 1; + end + else begin + //cs_out_inv_r <= 0; + deselect_delay <= 0; + cs_out_inv_wait1_r <= 0; + end + + //assign out_z = cs_out_inv_r; + assign out_z_wait1 = cs_out_inv_wait1_r; + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/clocks.ucf b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/clocks.ucf new file mode 100644 index 00000000000..0e23bff2dfe --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/clocks.ucf @@ -0,0 +1,51 @@ +# +# This software is Copyright (c) 2016-2018 Denis Burykin +# [denis_burykin yahoo com], [denis-burykin2014 yandex ru] +# and it is hereby released to the general public under the following terms: +# Redistribution and use in source and binary forms, with or without +# modification, are permitted. +# +# **************************** +# +# cmt2 - driven by IFCLK_IN +# cmt_special.v +# +# **************************** +# +INST "clocks/cmt2/DCM_0" LOC=DCM_X0Y4; +#INST "clocks/cmt2/DCM_CLKGEN_0" LOC=DCM_X0Y5; +#INST "clocks/cmt2/PLL_0" LOC=PLL_ADV_X0Y2; + +NET "IFCLK" TNM_NET = "IFCLK"; +TIMESPEC "TS_IFCLK" = PERIOD "IFCLK" 20.5 ns HIGH 50%; + +# CLK2X for PKT_COMM_CLK +NET "clocks/cmt2/dcm0_clk2x" TNM_NET = "PKT_COMM_CLK"; +TIMESPEC "TS_PKT_COMM_CLK" = PERIOD "PKT_COMM_CLK" 10.2 ns HIGH 50%; + +# CLK2 +#NET "clocks/cmt2/dcm0_clk90" TNM_NET = "cmt2_dcm0_clk90"; +#TIMESPEC "TS_cmt2_dcm0_clk90" = PERIOD "cmt2_dcm0_clk90" 20.833 ns HIGH 50%; +# PLL_CLK +#NET "clocks/cmt2/dcm0_clkdv" TNM_NET = "PKT_COMM_CLK"; +#TIMESPEC "TS_PKT_COMM_CLK" = PERIOD "PKT_COMM_CLK" 41.666 ns HIGH 50%; + +# **************************** +# +# Programmable clock #0 +# cmt_prog.v +# +# **************************** +# +INST "clocks/cmt3/DCM_CLKGEN_0" LOC=DCM_X0Y7; +INST "clocks/cmt3/PLL_0" LOC=PLL_ADV_X0Y3; + +NET "clocks/cmt3/pll0_clkout0" TNM_NET = "CORE_CLK"; +#TIMESPEC "TS_CORE_CLK" = PERIOD "CORE_CLK" 5.263 ns HIGH 50%; # 190 +#TIMESPEC "TS_CORE_CLK" = PERIOD "CORE_CLK" 5.405 ns HIGH 50%; # 185 +#TIMESPEC "TS_CORE_CLK" = PERIOD "CORE_CLK" 5.555 ns HIGH 50%; # 180 +#TIMESPEC "TS_CORE_CLK" = PERIOD "CORE_CLK" 5.714 ns HIGH 50%; # 175 +TIMESPEC "TS_CORE_CLK" = PERIOD "CORE_CLK" 5.882 ns HIGH 50%; # 170 +#TIMESPEC "TS_CORE_CLK" = PERIOD "CORE_CLK" 6.250 ns HIGH 50%; # 160 + + diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/clocks.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/clocks.v new file mode 100644 index 00000000000..ef2bceab98c --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/clocks.v @@ -0,0 +1,149 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// ********************************************************************** +// +// Input clocks: +// * IFCLK_IN 48 MHz. +// * FXCLK_IN 48 MHz. +// +// Output: +// * IFCLK - equal to IFCLK_IN, some phase backshift +// * other clocks +// +// ********************************************************************** + + +module clocks #( + // Using CLK2X + //parameter PKT_COMM_FREQ = 135, // adjust UCF + parameter CORE_FREQ = 135 // cmt3 - programmable (adjust UCF) + )( + input IFCLK_IN, + input FXCLK_IN, + + // Programmable clock + input [3:0] progen, + input progdata, progclk, + input pll_reset, + output progdone_inv, + + output IFCLK, + output PKT_COMM_CLK, + input core_clk_glbl_en, + output CORE_CLK + ); + + + // ******************************************************************************** + // + // Attention developer! + // + // * On ZTEX 1.15y board, clocks coming from USB device controller do bypass a CPLD. + // That's unknown why. To get Slave FIFO working, that requires clock phase backshift + // (DCM can do) or equal measure. That might be the placement of input registers deep + // into FPGA fabric or usage of IDELAY components. + // + // * If several DCMs and/or PLLs are used and their placement is not manually defined, + // tools (ISE 14.5) place them randomly without a respect to dedicated lines. + // That results in a usage of general routing for clocks, that in turn can + // result in an unroutable condition if it's full of wires. + // + // * When tools notice derived clocks, they mess up with timing at Place and Route stage. + // + // ******************************************************************************** + + + + // **************************************************************************** + // + // Spartan-6 Clocking Resources (Xilinx UG382) is anything but straightforward. + // + // **************************************************************************** + + // Tasks: + // - generate a number of clocks for various parts of application + // - don't use general routing for clocks + // - define frequencies in MHz, not in magic units + // - don't define derived clocks, 1 constraint should apply only to 1 clock. + + + // IFCLK_IN and FXCLK_IN are located near each other. + // There's some I/O clocking region there. + // Limited number of dedicated routes from that region to CMTs are available. + // + // Each input clock can go to up to 2 CMTs, one of them must be + // in the top half of fpga and other one must be in the bottom half. + // + // CMTs are numbered 0 to 5 from bottom to top. + + // Delay line waits 4 cycles after GSR deasserted + reg [3:0] delay_line = 0; + always @(posedge IFCLK) + delay_line[3:0] <= { delay_line[2:0], 1'b1 }; + wire CE = &delay_line[3:0]; + + + cmt2 #( + .PLL_FREQ(),//PKT_COMM_FREQ), + .PHASE_SHIFT(-15) + ) cmt2( + .I(IFCLK_IN), + .CLK0(IFCLK), + .CLK2X(PKT_COMM_CLK), + .PLL_CLK()//PKT_COMM_CLK) + ); + + + // Route FXCLK via BUFG to feed 2+ CMT's + BUFG FXCLK_BUFG_inst( + .I(FXCLK_IN), + .O(FXCLK) + ); +/* + // Programmable clock #1: + cmt_prog #( .F(CMP_FREQ) + ) cmt1( + .I(FXCLK), + .progen(progen[1]), .progdata(progdata), .progclk(progclk), + .pll_reset(pll_reset), + .CE(CE), + .progdone_inv(progdone_inv1), + .O(CMP_CLK) + ); +*/ + + // Programmable clock #0: + cmt_prog #( .F(CORE_FREQ) + ) cmt3( + .I(FXCLK), + .progen(progen[0]), .progdata(progdata), .progclk(progclk), + .pll_reset(pll_reset), + .CE(CE & core_clk_glbl_en), + .progdone_inv(progdone_inv0), + .O(CORE_CLK) + ); + + assign progdone_inv = progdone_inv0;// | progdone_inv1; + +/* + // Not-Programmable clock + cmt_prog #( .F(PKT_COMM_FREQ) + ) cmt5( + .I(FXCLK), + .progen(1'b0), .progdata(1'b0), .progclk(1'b0), + .pll_reset(pll_reset), + .CE(CE), + .progdone_inv(), + .O(PKT_COMM_CLK) + ); +*/ + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/cmt2.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/cmt2.v new file mode 100644 index 00000000000..168706a1dc4 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/cmt2.v @@ -0,0 +1,220 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +// ******************************************* +// +// Clock Management Tile #2 +// +// ******************************************* + +module cmt2 #( + parameter PHASE_SHIFT = 0, + parameter FREQ_IN = 48, + //parameter BUFIO2_DIVIDE = 1, + parameter CLK2_DIVIDE = 8, + parameter CLK2_FREQ = 210, + parameter PLL_FREQ = 0 + )( + input I, + output CLK0, + //output CLK2, + output CLK2X, + output PLL_CLK + ); + + assign PLL_CLK = 1'b0; + + + // ****************************************************** + // + // Available frequencies + // (*) - default value + // + // BUFIO2_DIVIDE = 1: + // + // CLK1_DIVIDE = 8: step 6 MHz, max. 192 MHz + // (*)CLK1_DIVIDE = 6: step 8 MHz, max. 256 MHz + // CLK1_DIVIDE = 4: step 12 MHz, max. 384 MHz + // + // (*)CLK2_DIVIDE = 8: step 6 MHz, max. ~260 MHz + // CLK2_DIVIDE = 6: step 8 MHz, max. ~320 MHz + // + // BUFIO2_DIVIDE = 2: + // + // (*)CLK1_DIVIDE = 6: step 4 MHz, max. 128 MHz + // CLK1_DIVIDE = 4: step 6 MHz, max. 192 MHz + // CLK1_DIVIDE = 3: step 8 MHz, max. 256 MHz + // CLK1_DIVIDE = 2: step 12 MHz, max. 384 MHz + // + // CLK2_DIVIDE = 16: step 1.5 MHz, max. ~380 MHz + // CLK2_DIVIDE = 12: step 2 MHz, max. >400 MHz + // (*)CLK2_DIVIDE = 8: step 3 MHz, max. >400 MHz + // CLK2_DIVIDE = 6: step 4 MHz, max. >400 MHz + // CLK2_DIVIDE = 4: step 6 MHz, max. >400 MHz + // + // ****************************************************** + + localparam BUFIO2_DIVIDE = 1; + localparam FREQ_IN_DIVIDED = FREQ_IN / BUFIO2_DIVIDE; + + localparam CLK2_MULTIPLY = CLK2_FREQ / (FREQ_IN_DIVIDED / CLK2_DIVIDE); + + localparam DCM0_DIVIDE = 2; + + /* + // + // Some problems with manual usage of BUFIO2. + // + BUFIO2 #( + .DIVIDE(BUFIO2_DIVIDE), // DIVCLK divider (1-8) + .DIVIDE_BYPASS(BUFIO2_DIVIDE == 1 ? "TRUE" : "FALSE"), // Bypass the divider circuitry (TRUE/FALSE) + .I_INVERT("FALSE"), // Invert clock (TRUE/FALSE) + .USE_DOUBLER("FALSE") // Use doubler circuitry (TRUE/FALSE) + ) + BUFIO2_inst ( + .DIVCLK(),//DIVCLK), // 1-bit output: Divided clock output + .IOCLK( CLK_IN ), // 1-bit output: I/O output clock + .SERDESSTROBE(),//SERDESSTROBE), // 1-bit output: Output SERDES strobe (connect to ISERDES2/OSERDES2) + .I( I ) // 1-bit input: Clock input (connect to IBUFG) + ); + */ + + + // ********************************************************************** + + + (* BUFFER_TYPE="NONE" *) wire dcm0_clk90, dcm0_clkdv; + (* KEEP="true" *) wire dcm0_clk2x; + + DCM_SP #(.CLKDV_DIVIDE ( DCM0_DIVIDE ), + .CLKFX_DIVIDE (), + .CLKFX_MULTIPLY (), + .CLKIN_DIVIDE_BY_2 ("FALSE"), + .CLKIN_PERIOD (), + .CLKOUT_PHASE_SHIFT ("FIXED"), + .CLK_FEEDBACK ("1X"), + .DESKEW_ADJUST ("SYSTEM_SYNCHRONOUS"),//("SOURCE_SYNCHRONOUS"), + .PHASE_SHIFT ( PHASE_SHIFT ), // -12: phase backshift 1 ns + .STARTUP_WAIT ("FALSE") + ) DCM_0 ( + // Input clock + .CLKIN ( I ), + .CLKFB (dcm0_clkfb), + // Output clocks + .CLK0 (dcm0_clk0), + .CLK90 (dcm0_clk90), + .CLK180 (),//dcm0_clk180), + .CLK270 (), + .CLK2X (dcm0_clk2x), + .CLK2X180 (), + .CLKFX (), + .CLKFX180 (), + .CLKDV (dcm0_clkdv), + // Ports for dynamic phase shift + .PSCLK(1'b0), .PSEN(1'b0), .PSINCDEC(1'b0), .PSDONE(), + .LOCKED(), .STATUS(), .RST(1'b0), .DSSEN(1'b0) + ); + + assign dcm0_clkfb = dcm0_clk0; // Adds BUFIO2FB + assign CLK0 = dcm0_clk0; + + assign CLK2X = dcm0_clk2x; + +/* + // ***************************************************** + // + // Usage of PLL: + // + // * Unless LOCated properly (in UCF), placer would probably place it in wrong place + // and that would result in routing problems + // * in UCF, uncomment dcm0_clkdv + // + if (PLL_FREQ) begin + + localparam PLL_DIVIDE = 4; // with FREQ_IN=48, DCM0_DIVIDE=2: step 6 MHz, max. ~270 MHz + + localparam PLL_MULT = PLL_FREQ / (FREQ_IN / DCM0_DIVIDE / PLL_DIVIDE); + + + // *********** Some black magic to avoid the error **************** + // + // Mapping design into LUTs... + // ERROR:LIT:664 - PLL_ADV symbol "clocks/cmt2/PLL_0/PLL_ADV" (output + // signal=clocks/cmt2/PLL_0/CLKOUT3) has pin CLKOUT2 driving a BUFPLL. Only + // CLKOUT0 and CLKOUT1 pins can drive a BUFPLL. Please modify your design to + // avoid this unroutable situation. + // Errors found during logical drc. + (* BUFFER_TYPE="NONE" *) wire [4:0] dummy; + (* KEEP="true" *) wire dummy1 = ^dummy; + + PLL_BASE #( + .BANDWIDTH("OPTIMIZED"), + .CLKFBOUT_MULT( PLL_MULT ), + .CLKOUT0_DIVIDE( PLL_DIVIDE ), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKIN_PERIOD(0.0), + .CLK_FEEDBACK("CLKFBOUT"), + .COMPENSATION("DCM2PLL"),//SYSTEM_SYNCHRONOUS"), + .DIVCLK_DIVIDE(1), + .REF_JITTER(0.10), + .RESET_ON_LOSS_OF_LOCK("FALSE") + ) PLL_0 ( + .CLKFBOUT(pll0_clkfb), + .CLKOUT0(pll0_clkout0), + .CLKOUT1(dummy[0]), + .CLKOUT2(dummy[1]), + .CLKOUT3(dummy[2]), + .CLKOUT4(dummy[3]), + .CLKOUT5(dummy[4]), + .LOCKED(), + .CLKFBIN(pll0_clkfb), + .CLKIN( dcm0_clkdv ), + .RST(1'b0) + ); + + BUFG BUFG_0( + .I(pll0_clkout0), + .O(PLL_CLK) + ); + + end else begin // PLL_FREQ + + assign PLL_CLK = 1'b0; + + end +*/ + // ***************************************************** + +/* + DCM_CLKGEN #( + .CLKFXDV_DIVIDE(2), // CLKFXDV divide value (2, 4, 8, 16, 32) + .CLKFX_DIVIDE( CLK2_DIVIDE ), // Divide value - D - (1-256) + .CLKFX_MD_MAX(0.0), // Specify maximum M/D ratio for timing anlysis + .CLKFX_MULTIPLY( CLK2_MULTIPLY ), // Multiply value - M - (2-256) + .CLKIN_PERIOD(), // Input clock period specified in nS + .SPREAD_SPECTRUM("NONE"), // Spread Spectrum mode "NONE", "CENTER_LOW_SPREAD", "CENTER_HIGH_SPREAD", + // "VIDEO_LINK_M0", "VIDEO_LINK_M1" or "VIDEO_LINK_M2" + .STARTUP_WAIT("FALSE") // Delay config DONE until DCM_CLKGEN LOCKED (TRUE/FALSE) + ) DCM_CLKGEN_0 ( + .CLKFX( CLK2 ), // 1-bit output: Generated clock output + .CLKFX180(),// dcm1_clkfx180 ), // 1-bit output: Generated clock output 180 degree out of phase from CLKFX. + .CLKFXDV(),// dcm1_clkfxdv ), // 1-bit output: Divided clock output + .LOCKED(), // 1-bit output: Locked output + .PROGDONE(), // 1-bit output: Active high output to indicate the successful re-programming + .STATUS(), // 2-bit output: DCM_CLKGEN status + .CLKIN( dcm0_clk90 ), // 1-bit input: Input clock + .FREEZEDCM(1'b0), // 1-bit input: Prevents frequency adjustments to input clock + .PROGCLK(1'b0), // 1-bit input: Clock input for M/D reconfiguration + .PROGDATA(1'b0), // 1-bit input: Serial data input for M/D reconfiguration + .PROGEN(1'b0), // 1-bit input: Active high program enable + .RST(1'b0) // 1-bit input: Reset input pin + ); +*/ +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/cmt_prog.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/cmt_prog.v new file mode 100644 index 00000000000..e16adceaf21 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/cmt_prog.v @@ -0,0 +1,129 @@ +`timescale 1ns / 1ps + +// +// * Programmable clock for internal parts of application +// * Wide range of possible frequencies 135..355 MHz +// * Programmable with step ~0.5-1 Mhz until ~300 Mhz +// * Everything calculated for FREQ_IN=48 +// +module cmt_prog #( + parameter FREQ_IN = 48, + parameter F = 225, // 1. Set startup frequency + // 2. Adjust timing constraint in UCF file! + parameter M = + F >=275 ? 38 : F >=270 ? 32 : F >=265 ? 34 : F >=260 ? 35 : + F >=255 ? 21 : F >=250 ? 37 : F >=245 ? 25 : F >=240 ? 30 : + F >=235 ? 34 : F >=230 ? 31 : F >=225 ? 20 : F >=220 ? 21 : + F >=215 ? 29 : F >=210 ? 38 : F >=205 ? 33 : F >=200 ? 27 : + F >=195 ? 25 : F >=190 ? 35 : F >=185 ? 31 : F >=180 ? 29 : + F >=175 ? 38 : F >=170 ? 33 : F >=165 ? 38 : F >=160 ? 30 : + F >=155 ? 25 : F >=150 ? 39 : F >=145 ? 31 : F >=140 ? 35 : + 36, // default:135 MHz + parameter D = + F >=275 ? 42 : F >=270 ? 36 : F >=265 ? 39 : F >=260 ? 41 : + F >=255 ? 25 : F >=250 ? 45 : F >=245 ? 31 : F >=240 ? 38 : + F >=235 ? 44 : F >=230 ? 41 : F >=225 ? 27 : F >=220 ? 29 : + F >=215 ? 41 : F >=210 ? 55 : F >=205 ? 49 : F >=200 ? 41 : + F >=195 ? 39 : F >=190 ? 56 : F >=185 ? 51 : F >=180 ? 49 : + F >=175 ? 66 : F >=170 ? 59 : F >=165 ? 70 : F >=160 ? 57 : + F >=155 ? 49 : F >=150 ? 79 : F >=145 ? 65 : F >=140 ? 76 : + 81, // default:135 MHz + parameter PLL_CLKIN_PERIOD = 1000.0 / ((FREQ_IN+0.0) * (M+0.0) / (D+0.0)) + )( + input I, + input progen, progdata, progclk, + input pll_reset, + input CE, + output progdone_inv, + output O + ); + + localparam DCM_CLKIN_PERIOD = 1000.0 / (FREQ_IN+0.0); + + wire [2:1] dcm_status; + + DCM_CLKGEN #( + .CLKFXDV_DIVIDE(2), // CLKFXDV divide value (2, 4, 8, 16, 32) + .CLKFX_DIVIDE( D ), // Divide value - D - (1-256) + .CLKFX_MD_MAX(0.0), // Specify maximum M/D ratio for timing anlysis + .CLKFX_MULTIPLY( M ), // Multiply value - M - (2-256) + .CLKIN_PERIOD(DCM_CLKIN_PERIOD), // Input clock period specified in nS + .SPREAD_SPECTRUM("NONE"), // Spread Spectrum mode "NONE", "CENTER_LOW_SPREAD", "CENTER_HIGH_SPREAD", + // "VIDEO_LINK_M0", "VIDEO_LINK_M1" or "VIDEO_LINK_M2" + .STARTUP_WAIT("FALSE") // Delay config DONE until DCM_CLKGEN LOCKED (TRUE/FALSE) + ) DCM_CLKGEN_0 ( + .CLKFX( dcm0_clkfx ), // 1-bit output: Generated clock output + .CLKFX180(), // 1-bit output: Generated clock output 180 degree out of phase from CLKFX. + .CLKFXDV(), // 1-bit output: Divided clock output + .LOCKED( dcm_locked ), // 1-bit output: Locked output + .PROGDONE( progdone ), // 1-bit output: Active high output to indicate the successful re-programming + .STATUS( dcm_status ), // 2-bit output: DCM_CLKGEN status + .CLKIN( I ), // 1-bit input: Input clock + .FREEZEDCM(1'b0), // 1-bit input: Prevents frequency adjustments to input clock + .PROGCLK( progclk ), // 1-bit input: Clock input for M/D reconfiguration + .PROGDATA( progdata ), // 1-bit input: Serial data input for M/D reconfiguration + .PROGEN( progen ), // 1-bit input: Active high program enable + .RST(~dcm_locked & dcm_status[2]) // 1-bit input: Reset input pin + ); + + reg unprog = 1; // unprogrammed (after reset) + always @(posedge progclk) + if (progen) + unprog <= 0; + assign progdone_inv = ~(progdone | unprog); + + + // After clock is generated with CLKGEN + // and arrives into PLL the frequency is multiplied. + // PLL allows input frequency no less than 19 MHz, + // after multiplied internally it should be in range 400 - 1,080 MHz + // + // Fixed M=19, D=3 allows input to PLL 21..56 MHz, produces 133..355 MHz. + localparam PLL_MULTIPLY = 19; + localparam PLL_DIVIDE = 3; + + + // *********** Some black magic to avoid the error **************** + // + // Mapping design into LUTs... + // ERROR:LIT:664 - PLL_ADV symbol "clocks/cmt2/PLL_0/PLL_ADV" (output + // signal=clocks/cmt2/PLL_0/CLKOUT3) has pin CLKOUT2 driving a BUFPLL. Only + // CLKOUT0 and CLKOUT1 pins can drive a BUFPLL. Please modify your design to + // avoid this unroutable situation. + // Errors found during logical drc. + (* BUFFER_TYPE="NONE" *) wire [4:0] dummy; + (* KEEP="true" *) wire dummy1 = ^dummy; + + PLL_BASE #( + .BANDWIDTH("OPTIMIZED"), + .CLKFBOUT_MULT( PLL_MULTIPLY ), + .CLKOUT0_DIVIDE( PLL_DIVIDE ), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKIN_PERIOD( PLL_CLKIN_PERIOD ), + .CLK_FEEDBACK("CLKFBOUT"), + .COMPENSATION("DCM2PLL"), + .DIVCLK_DIVIDE(1), + .REF_JITTER(0.10), + .RESET_ON_LOSS_OF_LOCK("FALSE") + ) PLL_0 ( + .CLKFBOUT( pll0_clkfb ), + .CLKOUT0( pll0_clkout0 ), + .CLKOUT1(dummy[0]), + .CLKOUT2(dummy[1]), + .CLKOUT3(dummy[2]), + .CLKOUT4(dummy[3]), + .CLKOUT5(dummy[4]), + .LOCKED( pll_locked ), + .CLKFBIN( pll0_clkfb ), + .CLKIN( dcm0_clkfx ), + .RST(pll_reset | ~dcm_locked) + ); + + BUFGCE BUFGCE_inst ( + .O(O), // 1-bit output: Clock buffer output + .CE(pll_locked & CE), // 1-bit input: Clock buffer select + .I(pll0_clkout0) // 1-bit input: Clock buffer input (S=0) + ); + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/hs_io_v2.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/hs_io_v2.v new file mode 100644 index 00000000000..f4d4f9314be --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/hs_io_v2.v @@ -0,0 +1,332 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +//***************************************************************************** +// +// High-Speed communtcation to USB device controller's Slave FIFO +// +// For Slave FIFO's signaling and timing diagram, see CY7C68013-56PVC-Datasheet +// +// Version 1 comment: +// +// It is implemented on a state machine with outputs dependent on both input +// and internal state. That's slow and is unable to operate at 48 MHz IFCLK. +// +// Version 2 improvements: +// +// 1. Removed asynchronous circuitry. That allows to operate at 48 MHz, +// removes synchronization to CPU issues. +// 2. I/O registers placed most close to pins - into ILOGIC/OLOGIC components. +// That removes the nesessity to manually allocate areas in UCF file. +// IFCLK appears to arrive too late, added some phase backshift. +// 3. One cycle delay when switching control outputs into Z-state on CS deassertion +// so controls for Slave FIFO (active low) always in a defined state. +// +//***************************************************************************** + +module hs_io_v2 #( + parameter USB_ENDPOINT_IN = 2, // from the point of view from the host + parameter USB_ENDPOINT_OUT = 6 + )( + input IFCLK, + // Low CS puts all outputs into Z-state, + // exactly as examples/intraffic is doing + input CS, + input out_z_wait1, + + // enable read/write + // Deasserted EN doesn't perform read/write, + // keeps signals for Slave FIFO in proper state. + input EN, + + // Attention: attempt to send data to FPGA not aligned to + // 2-byte word would result in a junk in upper byte + inout [15:0] FIFO_DATA, + output FIFOADR0, + output FIFOADR1, + // Following signals are active low. + output SLOE, // Slave output enable + output SLRD, + output SLWR, + output PKTEND, + // FLAGA/B/C are fixed (independent from FIFOADR) + input FLAGA, // PROG_FULL + input FLAGB, // FULL + input FLAGC, // EMPTY + + // write into some internal FIFO + output [15:0] dout, + output wr_en, + input almost_full, + + // read from some internal FIFO + input [15:0] din, + output rd_en, + input empty, + + // status information + output [7:0] io_timeout, // in ~1us intervals @30MHz IFCLK + output reg io_fsm_error = 0, // CS or EN deasserted while active I/O + output reg sfifo_not_empty = 0, + output reg io_err_write = 0 + ); + + reg rw_direction = 0; // 1: FPGA writes + + always @(posedge IFCLK) + if (CS & EN) + sfifo_not_empty <= FLAGC_R; + + // Timeout + localparam TIMEOUT_MSB = 12; + reg [TIMEOUT_MSB:0] timeout = {TIMEOUT_MSB+1{1'b1}}; + assign io_timeout = timeout[TIMEOUT_MSB : TIMEOUT_MSB-7]; + + + // FIFOADR (Address for USB endpoint buffer) + // - at 48 MHz, sometimes takes 2 cycles to propagate + localparam USB_EP_OUT_B = (USB_ENDPOINT_OUT-2) >> 1; + localparam USB_EP_IN_B = (USB_ENDPOINT_IN-2) >> 1; + assign {FIFOADR1, FIFOADR0} = + out_z_wait1 ? 2'bz : + rw_direction ? USB_EP_IN_B[1:0] : + USB_EP_OUT_B[1:0]; + + + // ************************* + // + // High-Speed Input + // + // ************************* + + // FPGA's Input register (data-out from hs_io) + (* IOB="true" *) reg [15:0] input_r; + assign dout = input_r; + always @(posedge IFCLK) + input_r <= FIFO_DATA; + + (* IOB="true" *) reg FLAGC_R = 0; + always @(posedge IFCLK) + FLAGC_R <= FLAGC; + + (* IOB="true" *) reg SLOE_R = 1; + assign SLOE = out_z_wait1 ? 1'bz : SLOE_R; + + (* IOB="true" *) reg SLRD_R = 1; + assign SLRD = out_z_wait1 ? 1'bz : SLRD_R; + + // input_r_ok indicates there was read last cycle (SLRD was active) + reg input_r_ok = 0; + always @(posedge IFCLK) + input_r_ok <= ~SLRD_R; + assign wr_en = input_r_ok & FLAGC_R; + + + // ************************* + // + // High-Speed Output + // + // ************************* + + // FLAGA(active low) is configured to be active when 0 bytes in buffer + (* IOB="true" *) reg FLAGA_R = 1; + always @(posedge IFCLK) + FLAGA_R <= FLAGA; + + (* IOB="true" *) reg FLAGB_R = 0; + always @(posedge IFCLK) + FLAGB_R <= FLAGB; + + (* IOB="true" *) reg SLWR_R = 1; + assign SLWR = out_z_wait1 ? 1'bz : SLWR_R; + + // FPGA's output register. + // valid data must be present on output 9.2 ns before write + (* IOB="true" *) reg [15:0] output_r = 0; + // Tristate-enable FF inside OLOGIC component + (* IOB="true" *) reg out_z = 1; + assign FIFO_DATA = out_z ? 16'bz : output_r; + always @(posedge IFCLK) + out_z <= ~(CS & EN & rw_direction); + + // Flag indicates valid data in output register. + // Could be better if output FIFO had almost_empty flag. + reg output_r_valid = 0; + assign rd_en = (~SLWR_R | io_state == IO_STATE_WR_SETUP1 & ~output_r_valid); + + (* IOB="true" *) reg PKTEND_R = 1; + assign PKTEND = out_z_wait1 ? 1'bz : PKTEND_R; + + + // It works as follows: + // 1. reads as long as possible; + // 2. writes up to USB_PKT_SIZE. + localparam USB_PKT_SIZE = 256; // in 16-bit words + reg [8:0] word_counter = 0; + + // Finally deal with PKTEND issue. + // - when output FIFO is in mode_limit, there's no problem: + // FIFO already has all the data, so it outputs every cycle + // until EMPTY. + // - when mode_limit is off, the data might arrive from FPGA's output FIFO + // in small pieces such as 2-8 bytes or so, with intervals like 2-4 cycles. + // That might result in partial reads by the host and overall performance degradation. + // + localparam PKTEND_WR_TIMEOUT = 5; + reg [2:0] wr_timeout = 0; + + + //localparam IO_STATE_RESET = 1; + localparam IO_STATE_READ_SETUP0 = 2; + localparam IO_STATE_READ_SETUP1 = 3; + localparam IO_STATE_READ_SETUP2 = 4; + localparam IO_STATE_READ = 6; + localparam IO_STATE_WR_SETUP0 = 7; + localparam IO_STATE_WR_SETUP1 = 8; + localparam IO_STATE_WR_SETUP2 = 9; + localparam IO_STATE_WR = 11; + localparam IO_STATE_DISABLED = 13; + localparam IO_STATE_WR_WAIT = 14; + localparam IO_STATE_PKT_COMMIT = 15; + + (* FSM_EXTRACT="YES" *) + reg [4:0] io_state = IO_STATE_DISABLED; + + always @(posedge IFCLK) + begin + if ( ! (&timeout[TIMEOUT_MSB : TIMEOUT_MSB-7]) + & io_state != IO_STATE_READ & io_state != IO_STATE_WR) + timeout <= timeout + 1'b1; + + // Disabled: EN is off, outputs in proper state + if (io_state == IO_STATE_DISABLED) begin + if (CS & EN) + io_state <= IO_STATE_READ_SETUP0; + end + + else if (~CS | ~EN) begin + // Expecting EZ-USB to disable hs_io before selecting other fpga + if (!io_timeout | (~CS & EN)) + io_fsm_error <= 1; + + SLOE_R <= 1; + SLRD_R <= 1; + SLWR_R <= 1; + output_r_valid <= 0; + PKTEND_R <= 1; + rw_direction <= 0; + io_state <= IO_STATE_DISABLED; + end + + else // CS & EN + (* FULL_CASE, PARALLEL_CASE *) case (io_state) + + IO_STATE_READ_SETUP0: begin + if (almost_full | ~FLAGC_R) + io_state <= IO_STATE_WR_SETUP0; + else begin + io_state <= IO_STATE_READ_SETUP1; + end + end + + IO_STATE_READ_SETUP1: begin + io_state <= IO_STATE_READ_SETUP2; + end + + IO_STATE_READ_SETUP2: begin + // must assert 18.7 ns before read + SLOE_R <= 0; + SLRD_R <= 0; + io_state <= IO_STATE_READ; + end + + IO_STATE_READ: begin + if (!almost_full & FLAGC_R) begin + timeout <= 0; + end + else begin + SLOE_R <= 1; + SLRD_R <= 1; + io_state <= IO_STATE_WR_SETUP0; + end + end + + IO_STATE_WR_SETUP0: begin + if ((empty & ~output_r_valid) | FLAGA_R) + io_state <= IO_STATE_READ_SETUP0; + // go on transmit + else begin + rw_direction <= 1; + word_counter <= 0; + io_state <= IO_STATE_WR_SETUP1; + end + end + + IO_STATE_WR_SETUP1: begin + if (~output_r_valid) begin + output_r <= din; + output_r_valid <= 1; + end + io_state <= IO_STATE_WR_SETUP2; + end + + IO_STATE_WR_SETUP2: begin + // must assert 18.1 ns before write + SLWR_R <= 0; + io_state <= IO_STATE_WR; + end + + IO_STATE_WR: begin + output_r <= din; + timeout <= 0; + wr_timeout <= 0; + word_counter <= word_counter + 1'b1; + if (empty) + output_r_valid <= 0; + + if (word_counter == USB_PKT_SIZE - 1) begin + SLWR_R <= 1; + rw_direction <= 0; + io_state <= IO_STATE_READ_SETUP0; + end + else if (empty) begin + SLWR_R <= 1; + io_state <= IO_STATE_WR_WAIT; + end + + if (~FLAGB_R) + io_err_write <= 1; + end + + IO_STATE_WR_WAIT: begin + wr_timeout <= wr_timeout + 1'b1; + + if (wr_timeout == PKTEND_WR_TIMEOUT) begin + PKTEND_R <= 0; + io_state <= IO_STATE_PKT_COMMIT; + end + else if (!empty) + io_state <= IO_STATE_WR_SETUP1; + end + + IO_STATE_PKT_COMMIT: begin + PKTEND_R <= 1; + rw_direction <= 0; + io_state <= IO_STATE_READ_SETUP0; + end + + endcase + // CS & EN + + end // IFCLK + + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/input_fifo.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/input_fifo.v new file mode 100644 index 00000000000..5e45cd5221d --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/input_fifo.v @@ -0,0 +1,75 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + + +module input_fifo( + input wr_clk, + input [15:0] din, + input wr_en, + output full, + output almost_full, + output prog_full, + + input rd_clk, + input rd_en, + output [7:0] dout, + //output almost_empty, + output empty + ); + + // fifo_16_sync_8kb + // FIFO Generator v9.3 + // * Common Clock - Block RAM + // * 1st word Fall-Through + // * write: width 16, depth 4096 (8 Kbytes) + // * Almost Full Flag + // * Single Programmable Full Threshold Constant: + // must assert when it has 7.5 kb free or more + // * Reset: off + wire [15:0] din_stage2; + + fifo_16_sync_8k fifo_input0( + .clk(wr_clk), + .din(din), + .wr_en(wr_en), + .full(full), + .almost_full(almost_full), + .prog_full(prog_full), + + //.rd_clk(wr_clk), + .dout(din_stage2), + .rd_en(tx_stage2), + .empty(empty_stage2) + ); + + assign tx_stage2 = ~empty_stage2 & ~full_stage2; + + + // FIFO Generator v9.3 + // * Independent Clocks - Block RAM + // * 1st word Fall-Through + // * Write width: 16 depth: 1024, Read width: 8 + // * Almost Empty Flag + // * Reset: off + //fifo_16in_8out_2k fifo_input1( + fifo_16in_8out_4k fifo_input1( + .wr_clk(wr_clk), + .din(din_stage2), + .wr_en(tx_stage2), + .full(full_stage2), + + .rd_clk(rd_clk), + .dout(dout), + .rd_en(rd_en), + //.almost_empty(almost_empty), + .empty(empty) + ); + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/output_fifo.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/output_fifo.v new file mode 100644 index 00000000000..8aa24f0311e --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/output_fifo.v @@ -0,0 +1,82 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +//********************************************************** +// +// Output FIFO (high-speed output). +// +//********************************************************** + +module output_fifo ( + input wr_clk, + input [15:0] din, + input wr_en, + output full, + + input rd_clk, + output [15:0] dout, + input rd_en, + output empty, + input mode_limit, + input reg_output_limit, + output [15:0] output_limit, + output output_limit_not_done + ); + + // + // output_limit_fifo (one is able to limit output) is unable for asynchronous operation. + // Because of that, a small asynchronous FIFO is prepend. + // + + // fifo_16x64: + // IP Coregen -> FIFO Generator + // Independent Clocks - Distributed RAM + // First Word Fall Through + // width 16, depth 64 + // Reset: off + // + wire [15:0] data_stage2; + fifo_16x64 fifo_output1( + .wr_clk(wr_clk), + .din(din), + .wr_en(wr_en), + .full(full), + + .rd_clk(rd_clk), + .dout(data_stage2), + .rd_en(rd_en_stage2), + .empty(empty_stage2) + ); + assign rd_en_stage2 = ~empty_stage2 & ~full_stage2; + assign wr_en_stage2 = rd_en_stage2; + + + output_limit_fifo #( + .ADDR_MSB(`MSB(`OUTPUT_FIFO_SIZE) - 2) + //.ADDR_MSB(13) // 32 Kbytes + ) fifo_output0( + .rst(1'b0), + .CLK(rd_clk), + + .din(data_stage2), + .wr_en(wr_en_stage2), + .full(full_stage2), + + .dout(dout), + .rd_en(rd_en), + .empty(empty), + + .mode_limit(mode_limit), + .reg_output_limit(reg_output_limit), + .output_limit(output_limit), + .output_limit_not_done(output_limit_not_done) + ); + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/output_limit_fifo.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/output_limit_fifo.v new file mode 100644 index 00000000000..2123ae33fb0 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/output_limit_fifo.v @@ -0,0 +1,132 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * + * Output Limit FIFO (high-speed output). + * + * Features: + * + * - Configurable width and depth + * - 1st word Fall-Through + * - Does not output on its own (reports EMPTY) when mode_limit == 1. + * + * - When reg_output_limit asserted: + * -- Reports amount ready for output (output_limit) in WIDTH-bit words + * -- Starts output of that amount, asserts output_limit_not_done + * -- Deasserts output_limit_not_done when finished + * + * - Does not require extra components from IP Coregen + * - The design is unable for asynchronous operation + * - Size equals to RAM size minus 1 word. + * + */ + +module output_limit_fifo #( + // ADDR_MSB==11 : 8 Kbytes + parameter ADDR_MSB = 11, + parameter WIDTH = 16 + )( + input rst, + input CLK, + + input [WIDTH-1:0] din, + input wr_en, + output full, + + output [WIDTH-1:0] dout, + input rd_en, + output empty, + + input mode_limit, // turn on output limit + input reg_output_limit, + output [15:0] output_limit, + output reg output_limit_not_done + ); + + reg [ADDR_MSB:0] addra = 0; + reg [ADDR_MSB:0] output_limit_addr = 0; + reg [ADDR_MSB:0] output_limit_r = 0; + reg [ADDR_MSB:0] addrb = 0; + + // 1st Word Fall-Through + reg wft = 0; + assign empty = rst || ~wft; + + assign output_limit = { {15-ADDR_MSB{1'b0}}, output_limit_r }; + + assign full = rst || (addra + 1'b1 == addrb); + wire ena = wr_en && !full; + + always @(posedge CLK) begin + if (rst) begin + addra <= 0; + output_limit_addr <= 0; + output_limit_r <= 0; + end + else begin + if (ena) begin + addra <= addra + 1'b1; + end + + if (!mode_limit || reg_output_limit) begin + output_limit_addr <= addra; + output_limit_r <= addra - output_limit_addr; + end + end // ~rst + end + + wire ram_empty_or_limit = (output_limit_addr == addrb); + + wire enb = (!ram_empty_or_limit && (empty || rd_en)); + reg enb_r = 0; + + wire [15:0] ram_out; + reg [15:0] dout_r; + assign dout = dout_r; + + always @(posedge CLK) begin + if (rst) begin + addrb <= 0; + wft <= 0; + enb_r <= 0; + end + else begin + if (empty || rd_en) + enb_r <= enb; + + if (enb) begin + addrb <= addrb + 1'b1; + end + + if (enb_r) begin + if (!wft || rd_en) begin + wft <= 1; + dout_r <= ram_out; + end + end // enb_r + else if (rd_en) + wft <= 0; + end // ~rst + + output_limit_not_done <= ~ram_empty_or_limit; + end + + + (* RAM_STYLE = "BLOCK" *) + reg [WIDTH-1:0] ram [2**(ADDR_MSB+1)-1:0]; + reg [WIDTH-1:0] ram_out_r; + assign ram_out = ram_out_r; + + always @(posedge CLK) begin + if (ena) + ram[addra] <= din; + if (enb) + ram_out_r <= ram[addrb]; + end + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/startup_spartan6.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/startup_spartan6.v new file mode 100644 index 00000000000..b840de1f9bd --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/startup_spartan6.v @@ -0,0 +1,26 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +module startup_spartan6 ( + input rst + ); + + STARTUP_SPARTAN6 STARTUP_SPARTAN6_inst ( + .CFGCLK(),//CFGCLK), // 1-bit output: Configuration logic main clock output. + .CFGMCLK(),//CFGMCLK), // 1-bit output: Configuration internal oscillator clock output. + .EOS(),//EOS), // 1-bit output: Active high output signal indicates the End Of Configuration. + .CLK(1'b0), // 1-bit input: User startup-clock input + .GSR(rst), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name) + .GTS(1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name) + .KEYCLEARB(1'b0) // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM) + ); + + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/vcr.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/vcr.v new file mode 100644 index 00000000000..97e4fbbd0a1 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/vcr.v @@ -0,0 +1,194 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + */ + +//*********************************************************** +// +// Vendor Command / Vendor Request feature +// Commands or requests are sent to EZ-USB via USB EP0 +// and handled by EZ-USB processor. +// +//*********************************************************** + +//*********************************************************** +// +// New feature: cmd 0x00 disables the interface, allows +// usage of raw I/O port PC[7:0]. A pulse on clk_vcr_addr returns from raw mode. +// +// There's up to 256 VCR addresses (subsystems) for read or(and) write. +// Sequential multi-byte read or/and write is possible. +// For some actions, there's no need to read or write, just select address. +// +// EZ-USB uses 11 lines to FPGA. Typical exchange is as follows: +// 1. set direction towards FPGA (vcr_dir=0). Assert CPU I/O controls accordingly. +// 2. assert address on [7:0] vcr_inout. +// 3. assert vcr_set_addr, then deassert vcr_set_addr. This selects address. +// Optionally write: +// 4. setup data byte on [7:0] vcr_inout. +// 5. assert vcr_set_data, then deassert vcr_set_data. This performs write of the byte from step 4. +// 6. go to step 4 if nesessary. +// Optionally read: +// 7. set direction for input from FPGA (vcr_dir=1). Assert CPU I/O controls accordingly. +// 8. read data byte from [7:0] vcr_inout. +// 9. assert vcr_set_data, then deassert vcr_set_data. This let next data byte appear on [7:0] vcr_inout. +// 10. go to step 7 if necessary. +// +//*********************************************************** + +module vcr( + input CS, + + input [7:0] vcr_in, // Vendor Command/Request (VCR) address/data + output [7:0] vcr_out, + input clk_vcr_addr, // on posedge, set (internal to FPGA) VCR IO address + input clk_vcr_data, // on posedge, perform write or synchronous read + + input IFCLK, + + input [2:0] FPGA_ID, + input [7:0] hs_io_timeout, + input hs_input_prog_full, + //input output_err_overflow, + input sfifo_not_empty, + input io_fsm_error, io_err_write, + input [15:0] output_limit, + input output_limit_not_done, + input progdone_inv, + input [7:0] app_status, + input [7:0] pkt_comm_status, debug2, debug3, + //input [255:0] debug, + + // + // Defaults for various controls; see also VCR_RESET + // + output reg inout_raw = 0, // use PC[7:0] in raw mode + output reg hs_en = 0, // enable high-speed i/o + output reg output_mode_limit = 1, // output_limit + output reg reg_output_limit = 0, // with respect to IFCLK + output reg [7:0] app_mode = 0 // default mode: 0 + ); + + wire ENABLE = CS; + + // VCR address definitions + localparam VCR_SET_HS_IO_ENABLE = 8'h80; + localparam VCR_SET_HS_IO_DISABLE = 8'h81; + localparam VCR_SET_APP_MODE = 8'h82; + localparam VCR_GET_IO_STATUS = 8'h84; + // registers output limit (in output_limit_fifo words); starts + // output of that many via high-speed interface + localparam VCR_REG_OUTPUT_LIMIT = 8'h85; + localparam VCR_SET_OUTPUT_LIMIT_ENABLE = 8'h86; + localparam VCR_SET_OUTPUT_LIMIT_DISABLE = 8'h87; + localparam VCR_ECHO_REQUEST = 8'h88; + localparam VCR_GET_FPGA_ID = 8'h8A; + localparam VCR_RESET = 8'h8B; + localparam VCR_GET_ID_DATA = 8'hA1; + //localparam VCR_ = 8'h; + + async2sync sync_addr_inst( .async(clk_vcr_addr), .clk(IFCLK), .clk_en(clk_addr_en) ); + async2sync sync_data_inst( .async(clk_vcr_data), .clk(IFCLK), .clk_en(clk_data_en) ); + + reg [7:0] vcr_addr; + reg [5:0] vcr_state = 0; + + ///////////////////////////////////////////////////////// + // + // declarations for Command / Request specific stuff + // + ///////////////////////////////////////////////////////// + localparam [15:0] BITSTREAM_TYPE = `BITSTREAM_TYPE; + + reg [7:0] echo_content [3:0]; + reg RESET_R = 0; + + // declarations for Command / Request specific stuff end + + + ///////////////////////////////////////////////////////// + // + // Input + // + ///////////////////////////////////////////////////////// + + always @(posedge IFCLK) begin + if (ENABLE && clk_addr_en) begin + vcr_addr <= vcr_in; + vcr_state <= 0; + + if (inout_raw) + inout_raw <= 0; + else if (vcr_in == 8'h00) + inout_raw <= 1; + else if (vcr_in == VCR_SET_HS_IO_ENABLE) + hs_en <= 1; + else if (vcr_in == VCR_SET_HS_IO_DISABLE) + hs_en <= 0; + else if (vcr_in == VCR_SET_OUTPUT_LIMIT_ENABLE) + output_mode_limit <= 1; + else if (vcr_in == VCR_SET_OUTPUT_LIMIT_DISABLE) + output_mode_limit <= 0; + else if (vcr_in == VCR_RESET) + RESET_R <= 1; + else if (vcr_in == VCR_REG_OUTPUT_LIMIT) + reg_output_limit <= 1; + + end // clk_addr_en + + else if (ENABLE && clk_data_en) begin + vcr_state <= vcr_state + 1'b1; + + if (vcr_addr == VCR_ECHO_REQUEST) + echo_content[ vcr_state[1:0] ] <= vcr_in; + else if (vcr_addr == VCR_SET_APP_MODE) + app_mode <= vcr_in; + end // clk_data_en + + else begin // !ENABLE + if (reg_output_limit) + reg_output_limit <= 0; + + end + end + + + + ///////////////////////////////////////////////////////// + // + // Output + // + ///////////////////////////////////////////////////////// + + assign vcr_out = + (vcr_addr == VCR_REG_OUTPUT_LIMIT && vcr_state == 0) ? output_limit[7:0] : + (vcr_addr == VCR_REG_OUTPUT_LIMIT && vcr_state == 1) ? output_limit[15:8] : + + (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 0) ? { + progdone_inv, 1'b0, io_err_write, io_fsm_error, + sfifo_not_empty, 1'b0, output_limit_not_done, hs_input_prog_full + } : + (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 1) ? hs_io_timeout : + (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 2) ? app_status : + (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 3) ? pkt_comm_status : + (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 4) ? debug2 : + (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 5) ? debug3 : + + (vcr_addr == VCR_ECHO_REQUEST) ? echo_content[ vcr_state[1:0] ] ^ 8'h5A : + + (vcr_addr == VCR_GET_ID_DATA && vcr_state == 0) ? BITSTREAM_TYPE[7:0] : + (vcr_addr == VCR_GET_ID_DATA && vcr_state == 1) ? BITSTREAM_TYPE[15:8] : + + (vcr_addr == VCR_GET_FPGA_ID) ? { {5{1'b0}}, FPGA_ID } : + //(vcr_addr == && vcr_state == ) ? : + 8'b0; + + + startup_spartan6 startup_spartan6(.rst(RESET_R)); + +endmodule diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/ztex_inouttraffic.ucf b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/ztex_inouttraffic.ucf new file mode 100644 index 00000000000..9a72609dd57 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/ztex_inouttraffic.ucf @@ -0,0 +1,65 @@ +# +# This software is Copyright (c) 2016 Denis Burykin +# [denis_burykin yahoo com], [denis-burykin2014 yandex ru] +# and it is hereby released to the general public under the following terms: +# Redistribution and use in source and binary forms, with or without +# modification, are permitted. +# +# TIMESPEC's moved to clocks.ucf +NET "IFCLK_IN" LOC = "K20" |IOSTANDARD = LVCMOS33 ; +NET "FXCLK_IN" LOC = "L22" | IOSTANDARD = LVCMOS33 ; + +NET "CS_IN" LOC = "AB11" |IOSTANDARD = LVCMOS33 ; + +NET "PA0" LOC = "AA22" |IOSTANDARD = LVCMOS33 ; +NET "PA1" LOC = "W17" |IOSTANDARD = LVCMOS33 ; +NET "PA7" LOC = "AB17" |IOSTANDARD = LVCMOS33 ; + +NET "SLOE" LOC = "U15" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ; # PA2 +NET "SLRD" LOC = "N22" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ; +NET "SLWR" LOC = "M22" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ; +NET "PKTEND" LOC = "AB5" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ; # PA6 +NET "FIFOADR0" LOC = "AB21" |IOSTANDARD = LVCMOS33 |DRIVE = 12 ; # PA4 +NET "FIFOADR1" LOC = "Y18" |IOSTANDARD = LVCMOS33 |DRIVE = 12 ; # PA5 +NET "FLAGA" LOC = "F20" |IOSTANDARD = LVCMOS33 ; +NET "FLAGB" LOC = "F19" |IOSTANDARD = LVCMOS33 ; +NET "FLAGC" LOC = "F18" |IOSTANDARD = LVCMOS33 ; + +NET "FIFO_DATA<0>" LOC = "Y17" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<1>" LOC = "V13" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<2>" LOC = "W13" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<3>" LOC = "AA8" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<4>" LOC = "AB8" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<5>" LOC = "W6" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<6>" LOC = "Y6" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<7>" LOC = "Y9" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<8>" LOC = "V21" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<9>" LOC = "V22" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<10>" LOC = "U20" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<11>" LOC = "U22" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<12>" LOC = "R20" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<13>" LOC = "R22" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<14>" LOC = "P18" |IOSTANDARD = LVCMOS33 ; +NET "FIFO_DATA<15>" LOC = "P19" |IOSTANDARD = LVCMOS33 ; + + +NET "PC<0>" LOC="G20" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "PC<1>" LOC="T20" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "PC<2>" LOC="Y5" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "PC<3>" LOC="AB9" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "PC<4>" LOC="G19" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "PC<5>" LOC="H20" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "PC<6>" LOC="H19" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "PC<7>" LOC="H18" |IOSTANDARD = LVCMOS33 |DRIVE = 12; + +NET "INT4" LOC = "C18" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +NET "INT5" LOC = "V17" |IOSTANDARD = LVCMOS33 |DRIVE = 12; +# NET "SCL" LOC = "F22" | IOSTANDARD = LVCMOS33 ; +# NET "SDA" LOC = "E22" | IOSTANDARD = LVCMOS33 ; +NET "FPGA_ID<0>" LOC="T12" |IOSTANDARD = LVCMOS33 ; +NET "FPGA_ID<1>" LOC="R13" |IOSTANDARD = LVCMOS33 ; +NET "FPGA_ID<2>" LOC="T14" |IOSTANDARD = LVCMOS33 ; + +NET "FPGA_ID*" TIG; + + diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic/ztex_inouttraffic.v b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/ztex_inouttraffic.v new file mode 100644 index 00000000000..6feea213ff7 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic/ztex_inouttraffic.v @@ -0,0 +1,219 @@ +`timescale 1ns / 1ps +/* + * This software is Copyright (c) 2016-2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * Used ISE version: 14.5 + * + * sha256crypt-ztex for John The Ripper password cracker - + * bitstream for ZTEX 1.15y USB-FPGA module (4x Spartan-6 LX150) + * + */ + +module ztex_inouttraffic( + input CS_IN, + input [2:0] FPGA_ID, + + // Both IFCLK_IN and FXCLK_IN are at 48 MHz. + input IFCLK_IN, + input FXCLK_IN, + + // Vendor Command/Request I/O + inout [7:0] PC, // Vendor Command/Request (VCR) address/data + input PA0, + input PA1, + input PA7, + + // High-Speed I/O Interface + inout [15:0] FIFO_DATA, + output FIFOADR0, + output FIFOADR1, + output SLOE, + output SLRD, + output SLWR, + output PKTEND, + input FLAGA, + input FLAGB, // FULL + input FLAGC, // EMPTY + + output INT4, + output INT5 + ); + + genvar i; + + + // PC_RAW is available when VCR interface is off with cmd 0x00 + wire [7:0] PC_RAW = CS & vcr_inout_raw ? PC : 8'b0; + + reg error_r = 0; // Global error. Stop operation until GSR. + + clocks clocks( + // Input clocks go to Clock Management Tile via dedicated routing + .IFCLK_IN(IFCLK_IN), + .FXCLK_IN(FXCLK_IN), + // Up to 4 Programmable clocks + .progen(PC_RAW[5:2]), .progdata(PC_RAW[1]), .progclk(PC_RAW[0]), + .pll_reset(error_r), // Stop application clocks on error + .progdone_inv(progdone_inv), + // Produced clocks + .IFCLK(IFCLK), // for operating I/O pins + .PKT_COMM_CLK(PKT_COMM_CLK), // for I/O packet processing + .core_clk_glbl_en(1'b1),//~cores_idle), + .CORE_CLK(CORE_CLK) // for operating computing units + ); + + chip_select chip_select( + .CS_IN(CS_IN), .CLK(IFCLK), .CS(CS), .out_z_wait1(out_z_wait1) + ); + + wire [255:0] debug; + wire [7:0] debug2, debug3; + + + // ******************************************************** + // + // Input buffer (via High Speed interface) + // + // ******************************************************** + wire [15:0] hs_input_din; + wire [7:0] hs_input_dout; + + input_fifo input_fifo( + .wr_clk(IFCLK), + .din( {hs_input_din[7:0],hs_input_din[15:8]} ), // to Cypress IO + .wr_en(hs_input_wr_en), // to Cypress IO + .full(), // to Cypress IO + .almost_full(hs_input_almost_full), // to Cypress IO + .prog_full(hs_input_prog_full), + + .rd_clk(PKT_COMM_CLK), + .dout(hs_input_dout), + .rd_en(hs_input_rd_en), + .empty(hs_input_empty) + ); + + + // ******************************************************** + // + // Some example application + // 16-bit input, 16-bit output + // + // ******************************************************** + wire [15:0] app_dout; + wire [7:0] app_mode; + wire [7:0] app_status, pkt_comm_status; + + sha256crypt pkt_comm( + .PKT_COMM_CLK(PKT_COMM_CLK), + .CORE_CLK(CORE_CLK), + // High-Speed FPGA input + .din(hs_input_dout), + .rd_en(hs_input_rd_en), + .empty(hs_input_empty), + // High-Speed FPGA output + .dout(app_dout), + .wr_en(app_wr_en), + .full(app_full), + // Application control (via VCR I/O). Set with fpga_set_app_mode() + .app_mode(app_mode), + // Application status. Available at fpga->wr.io_state.app_status + .cores_idle(cores_idle), + .app_status(app_status), .pkt_comm_status(pkt_comm_status), + .debug2(debug2), .debug3(debug3) + ); + + always @(posedge IFCLK) + error_r <= |pkt_comm_status | |app_status; + + + // ******************************************************** + // + // Output buffer (via High-Speed interface) + // + // ******************************************************** + wire [15:0] output_limit; + wire [15:0] output_dout; // output via High-Speed Interface + + output_fifo output_fifo( + .wr_clk(PKT_COMM_CLK), + .din(app_dout), + .wr_en(app_wr_en), + .full(app_full), + + .rd_clk(IFCLK), + .dout(output_dout), // to Cypress IO, + .rd_en(output_rd_en), // to Cypress IO, + .empty(output_empty), // to Cypress IO + .mode_limit(output_mode_limit), + .reg_output_limit(reg_output_limit), + .output_limit(output_limit), + .output_limit_not_done(output_limit_not_done) + ); + + + // ******************************************************** + // + // High-Speed I/O Interface (Slave FIFO) + // + // ******************************************************** + wire [7:0] hs_io_timeout; + + hs_io_v2 #( + .USB_ENDPOINT_IN(2), + .USB_ENDPOINT_OUT(6) + ) hs_io_inst( + .IFCLK(IFCLK), .CS(CS), .out_z_wait1(out_z_wait1), .EN(hs_en), + .FIFO_DATA(FIFO_DATA), .FIFOADR0(FIFOADR0), .FIFOADR1(FIFOADR1), + .SLOE(SLOE), .SLRD(SLRD), .SLWR(SLWR), .PKTEND(PKTEND), + .FLAGA(FLAGA), .FLAGB(FLAGB), .FLAGC(FLAGC), + // data output from Cypress IO, received by FPGA + .dout(hs_input_din), .wr_en(hs_input_wr_en), + .almost_full(hs_input_almost_full), + // to Cypress IO, out of FPGA + .din(output_dout), .rd_en(output_rd_en), .empty(output_empty), + .io_timeout(hs_io_timeout), .sfifo_not_empty(sfifo_not_empty), + .io_fsm_error(io_fsm_error), .io_err_write(io_err_write) + ); + + + // ******************************************************** + // + // Vendor Command/Request (VCR) I/O interface + // + // ******************************************************** + wire [7:0] vcr_out; + assign PC = CS && PA7 ? vcr_out : 8'bz; + + vcr vcr_inst( + .CS(CS), .vcr_in(PC), .vcr_out(vcr_out), + .clk_vcr_addr(PA0), .clk_vcr_data(PA1), + // i/o goes with respect to IFCLK + .IFCLK(IFCLK), + // various inputs to be read by CPU + .FPGA_ID(FPGA_ID), + .hs_io_timeout(hs_io_timeout), .hs_input_prog_full(hs_input_prog_full), + .sfifo_not_empty(sfifo_not_empty), .io_fsm_error(io_fsm_error), .io_err_write(io_err_write), + .output_limit(output_limit), .output_limit_not_done(output_limit_not_done), + .app_status(app_status), + .pkt_comm_status(pkt_comm_status), .debug2(debug2), .debug3(debug3), + //.debug(debug), + .progdone_inv(progdone_inv), // Programmable clock + // various control wires + .inout_raw(vcr_inout_raw), + .hs_en(hs_en), + .output_mode_limit(output_mode_limit), + .reg_output_limit(reg_output_limit), + .app_mode(app_mode) + ); + + + // External interrupts for USB controller - put into defined state + assign INT4 = 1'b0; + assign INT5 = 1'b1; + +endmodule + diff --git a/src/ztex/fpga-sha256crypt/ztex_inouttraffic_summary.html b/src/ztex/fpga-sha256crypt/ztex_inouttraffic_summary.html new file mode 100644 index 00000000000..7efb7f69d31 --- /dev/null +++ b/src/ztex/fpga-sha256crypt/ztex_inouttraffic_summary.html @@ -0,0 +1,557 @@ +Xilinx Design Summary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ztex_inouttraffic Project Status (08/18/2018 - 10:47:51)
Project File:fpga-sha256crypt.xiseParser Errors: No Errors
Module Name:ztex_inouttrafficImplementation State:Programming File Generated
Target Device:xc6slx150-3csg484
  • Errors:
+No Errors
Product Version:ISE 14.7
  • Warnings:
3199 Warnings (3199 new)
Design Goal:Balanced
  • Routing Results:
+All Signals Completely Routed
Design Strategy:sha256crypt
  • Timing Constraints:
+X +1 Failing Constraint
Environment: + +System Settings +
  • Final Timing Score:
1792  (Timing Report)
+ + + + 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Device Utilization Summary [-]
Slice Logic UtilizationUsedAvailableUtilizationNote(s)
Number of Slice Registers72,023184,30439% 
    Number used as Flip Flops66,798   
    Number used as Latches0   
    Number used as Latch-thrus0   
    Number used as AND/OR logics5,225   
Number of Slice LUTs62,88892,15268% 
    Number used as logic49,33192,15253% 
        Number using O6 output only27,323   
        Number using O5 output only1,154   
        Number using O5 and O620,854   
        Number used as ROM0   
    Number used as Memory4,41521,68020% 
        Number used as Dual Port RAM3,999   
            Number using O6 output only1,238   
            Number using O5 output only53   
            Number using O5 and O62,708   
        Number used as Single Port RAM165   
            Number using O6 output only129   
            Number using O5 output only10   
            Number using O5 and O626   
        Number used as Shift Register251   
            Number using O6 output only126   
            Number using O5 output only0   
            Number using O5 and O6125   
    Number used exclusively as route-thrus9,142   
        Number with same-slice register load9,034   
        Number with same-slice carry load108   
        Number with other load0   
Number of occupied Slices20,43923,03888% 
Number of MUXCYs used17,93246,07638% 
Number of LUT Flip Flop pairs used67,233   
    Number with an unused Flip Flop13,36567,23319% 
    Number with an unused LUT4,34567,2336% 
    Number of fully used LUT-FF pairs49,52367,23373% 
    Number of unique control sets3,080   
    Number of slice register sites lost
        to control set restrictions
7,824184,3044% 
Number of bonded IOBs4433813% 
    Number of LOCed IOBs4444100% 
    IOB Flip Flops62   
Number of RAMB16BWERs92683% 
Number of RAMB8BWERs32653660% 
Number of BUFIO2/BUFIO2_2CLKs1323% 
    Number used as BUFIO2s1   
    Number used as BUFIO2_2CLKs0   
Number of BUFIO2FB/BUFIO2FB_2CLKs1323% 
    Number used as BUFIO2FBs1   
    Number used as BUFIO2FB_2CLKs0   
Number of BUFG/BUFGMUXs41625% 
    Number used as BUFGs3   
    Number used as BUFGMUX1   
Number of DCM/DCM_CLKGENs21216% 
    Number used as DCMs1   
    Number used as DCM_CLKGENs1   
Number of ILOGIC2/ISERDES2s205863% 
    Number used as ILOGIC2s20   
    Number used as ISERDES2s0   
Number of IODELAY2/IODRP2/IODRP2_MCBs05860% 
Number of OLOGIC2/OSERDES2s225863% 
    Number used as OLOGIC2s22   
    Number used as OSERDES2s0   
Number of BSCANs040% 
Number of BUFHs03840% 
Number of BUFPLLs080% 
Number of BUFPLL_MCBs040% 
Number of DSP48A1s01800% 
Number of ICAPs010% 
Number of MCBs040% 
Number of PCILOGICSEs020% 
Number of PLL_ADVs1616% 
    Number of LOCed PLL_ADVs11100% 
Number of PMVs010% 
Number of STARTUPs11100% 
Number of SUSPEND_SYNCs010% 
Average Fanout of Non-Clock Nets2.90   
+ + + + 
+ + + + + + + + + + + + + + + + + +
Performance Summary [-]
Final Timing Score:1792 (Setup: 1792, Hold: 0, Component Switching Limit: 0)Pinout Data:Pinout Report
Routing Results: +All Signals Completely RoutedClock Data:Clock Report
Timing Constraints: +X +1 Failing Constraint  
+ + + + 
+ + + + + + + + + + +
Detailed Reports [-]
Report NameStatusGeneratedErrorsWarningsInfos
Synthesis ReportCurrentбс 18. рту 09:45:27 20180170 Warnings (170 new)42 Infos (42 new)
Translation ReportCurrentбс 18. рту 09:47:11 2018000
Map ReportCurrentбс 18. рту 10:14:14 201801202 Warnings (1202 new)545 Infos (545 new)
Place and Route ReportCurrentбс 18. рту 10:31:21 20180914 Warnings (914 new)2 Infos (2 new)
Power Report     
Post-PAR Static Timing ReportCurrentбс 18. рту 10:47:43 201801 Warning (1 new)3 Infos (3 new)
Bitgen ReportCurrentбс 18. рту 10:39:54 20180912 Warnings (912 new)1 Info (1 new)

+ + + + +
Secondary Reports [-]
Report NameStatusGenerated
ISIM Simulator LogOut of Dateбс 18. рту 07:29:45 2018
WebTalk Log FileCurrentбс 18. рту 10:40:02 2018
+ + +
Date Generated: 08/18/2018 - 10:47:51
+ \ No newline at end of file diff --git a/src/ztex_sha256crypt.c b/src/ztex_sha256crypt.c new file mode 100644 index 00000000000..5250ebcded2 --- /dev/null +++ b/src/ztex_sha256crypt.c @@ -0,0 +1,434 @@ +/* + * This software is Copyright (c) 2018 Denis Burykin + * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] + * and it is hereby released to the general public under the following terms: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * This file is part of John the Ripper password cracker, + * Copyright (c) 1996-2001,2008,2010-2013,2015 by Solar Designer + * + * This file is part of John the Ripper password cracker, + * Copyright (c) 2012 magnum / JimF + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + */ +#include +#include + +#include "arch.h" +#include "common.h" +#include "formats.h" +#include "memory.h" +#include "config.h" +#include "options.h" + +#include "ztex/device_bitstream.h" +#include "ztex/device_format.h" +#include "ztex/task.h" +#include "ztex/pkt_comm/cmp_config.h" + + +#define FORMAT_LABEL "sha256crypt-ztex" +#define ALGORITHM_NAME "sha256crypt ZTEX" + +#define FORMAT_NAME "crypt(3) $5$" +#define FORMAT_TAG "$5$" +#define FORMAT_TAG_LEN (sizeof(FORMAT_TAG)-1) + +#define BENCHMARK_COMMENT " (rounds=5000)" +#define BENCHMARK_LENGTH -1 + +#define CIPHERTEXT_LENGTH 43 + +// Data structures differ from ones from CPU implementation: +// - Only partial hash in the database (BINARY_SIZE=4) +// - The hardware allows candidate length no more than 32 +// +#define PLAINTEXT_LENGTH 32 +#define BINARY_SIZE 4 +#define BINARY_ALIGN 4 +#define SALT_SIZE sizeof(sha256crypt_salt_t) +#define SALT_ALIGN 4 + +#define ROUNDS_PREFIX "rounds=" +#define ROUNDS_DEFAULT 5000 +#define ROUNDS_MIN 1 +#define ROUNDS_MAX 999999999 + +#define SALT_LENGTH 16 + +// unable to use sha256crypt_common.h +//#include "sha256crypt_common.h" + + +static struct device_bitstream bitstream = { + // bitstream ID (check is performed by querying operating bitstream) + 0x256c, + "$JOHN/ztex/ztex115y_sha256crypt.bit", + // parameters for high-speed packet communication (pkt_comm) + { 2, 7422, 4094 }, + // computing performance estimation (in candidates per interval) + // (keys * mask_num_cand)/crypt_all_interval per jtr_device. + 1, // set by init() base on john.conf setting + 2048, // 2K keys/fpga for self-test + 1536 * 1024, // Would be 48 MB of USB traffic on 32-byte keys + 512, // Max. number of entries in onboard comparator. + 150, // Min. number of keys for effective device utilization + 1, { 135 }, // Programmable clocks + "sha256crypt", // label for configuration file + NULL, 0 // Initialization data +}; + + +static struct fmt_tests tests[] = { + // from CPU/GPU implementations + {"$5$LKO/Ute40T3FNF95$U0prpBQd4PloSGU0pnpM4z9wKn4vZ1.jsrzQfPqxph9", + "U*U*U*U*"}, + {"$5$LKO/Ute40T3FNF95$fdgfoJEBoMajNxCv3Ru9LyQ0xZgv0OBMQoq80LQ/Qd.", + "U*U***U"}, + {"$5$LKO/Ute40T3FNF95$8Ry82xGnnPI/6HtFYnvPBTYgOL23sdMXn8C29aO.x/A", + "U*U***U*"}, + {"$5$XSLWLBSQUCNOWXOB$i7Ho5wUAIjsH2e2zA.WarqYLWir5nmZbUEcjK//Or7.", + "hgnirgayjnhvi"}, + {"$5$VDCTRFOIDQXRQVHR$uolqT0wEwU.pvI9jq5xU457JQpiwTTKX3PB/9RS4/h4", + "o"}, + {"$5$EKt.VLXiPjwyv.xe$52wdOp9ixFXMsHDI1JcCw8KJ83IakDP6J7MIEV2OUk0", + "1234567"}, + + // salt_len < 16 + {"$5$rounds=5019$0.2345.789.bede$MkvvIivtYEIOJcDzMEvma3ParB" + "1/s9Ht02poIWA1RK7", "salt15,key=13"}, + {"$5$rounds=5023$bQEwn2FVUb6ATd$qVlYFRnSpOg64SPaVY/1CBTrbCY" + "5Kv6Y.Km/Um7jg61", "test #2: salt_len=14,key_len=31"}, + {"$5$TGf3jSp.tVaZB$WD6RH0Gzk5pb5Vt1Zq8e0hUWoRu3aq5iDPMl9kXdZRA", + "s13_k6"}, + {"$5$rounds=4995$gjBVWL7tGHdK$Iwj/2BP.b1rrg6/B.fC4HIDhmhLZB" + "uw8SrCeAXoSpH5", "salt11_key12"}, + {"$5$rounds=5022$bQ7rLwn$aUIOwEgSRRrpGlLV5Jt5DtRNzSmyv54dMn" + "uCCaD7CtC", "salt7key9"}, + {"$5$GH0itE$i1kIs5UMcM.Qomz3.2L2INxGYlaKRBDArZ6TNmh9ed7", + "salt=6key=12"}, + {"$5$HfD3B$bVW9AObAFBZZ7KopQxRwaTs.X2/aVrYt55mW6f6EXl7", + "s5k4"}, + {"$5$=$Qh125aRhMbwg8Phe/jIjQwos/v9I.vR/e7R1rjiYfBC", + "salt1,key11"}, + + // from the reference implementation + {"$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5", + "Hello world!"}, + + // slows down --test + //{"$5$rounds=66000$FghyT5KLjHQW4sCG$80SFA7YemhfPH0OlnLa5fDjd" + // "T4XXOrW/l3i7O9h5XF4", "testing CPU's SUBB instruction"}, + //{"$5$rounds=1024000$fg80uTCVDKPeTbnB$N8bF/pNbfCoI1ImDdG8rKV" + // "OBvrbHzXtElv0QivEyvi4", "heavier_thing"}, + // times out in 5s (increase the default) + //{"$5$rounds=4096000$AFhfg9h8z.GEwvcB$tNR5A1CALj4bsC41VTisok" + // "zcn9Cc26Tr.oi2dJ.ZLl2", "device_format.c:TASK_TIMEOUT"}, + + {"$5$rounds=4972$0/2345.789//edef$DDPKQRM7xJkpe4pdf13My8qCJ" + "PeFmXn6nNiwYk.R.wB", "abc"}, + {"$5$rounds=4970$0.234.6789.bc/ef$7NDazjArUHJs988r5ovAyd5tI" + "kJybwD9JOibJfzgWuD", "12345678"}, + {"$5$012/45.7/9ab/def$wz2Bni8S/YVASQHPTNWPiUd17QwYow5qLbmSUvgZhd1", + "test #3: salt_len=16, key_len=32"}, + {"$5$RFGhdnBMk0PYdQAN$GMIdTVp3gVpcOP2G4F7d74Vp3RbjSv7Z1aWA7kBkYiC", + "salt_len=16,key_len=23."}, + {"$5$R.BGHLcxaqOIU1Fd$v56KjRPkbT6HoXm4G.YVYXGBH.D7alOUbsS2ybx8or2", + "8-bit-chars\195\195\195"}, + {NULL} +}; + + +typedef struct { + unsigned int len; + unsigned int rounds; + unsigned char salt[16]; +} sha256crypt_salt_t; + + +static int valid(char * ciphertext, struct fmt_main * self) { + char *pos, *start; + + if (strncmp(ciphertext, FORMAT_TAG, FORMAT_TAG_LEN)) + return 0; + + ciphertext += FORMAT_TAG_LEN; + + if (!strncmp(ciphertext, ROUNDS_PREFIX, + sizeof(ROUNDS_PREFIX) - 1)) { + const char *num = ciphertext + sizeof(ROUNDS_PREFIX) - 1; + char *endp; + if (!strtoul(num, &endp, 10)) + return 0; + if (*endp == '$') + ciphertext = endp + 1; + } + for (pos = ciphertext; *pos && *pos != '$'; pos++); + if (!*pos || pos < ciphertext) return 0; + + start = ++pos; + while (atoi64[ARCH_INDEX(*pos)] != 0x7F) pos++; + if (*pos || pos - start != CIPHERTEXT_LENGTH) return 0; + return 1; +} + + +/* ------- To binary functions ------- */ +#define TO_BINARY(b1, b2, b3) \ + value = (uint32_t)atoi64[ARCH_INDEX(pos[0])] | \ + ((uint32_t)atoi64[ARCH_INDEX(pos[1])] << 6) | \ + ((uint32_t)atoi64[ARCH_INDEX(pos[2])] << 12) | \ + ((uint32_t)atoi64[ARCH_INDEX(pos[3])] << 18); \ + pos += 4; \ + out[b1] = value >> 16; \ + out[b2] = value >> 8; \ + out[b3] = value; + +static void * get_binary(char * ciphertext) { + static uint32_t outbuf[BINARY_SIZE/4]; + uint32_t value; + char *pos = strrchr(ciphertext, '$') + 1; + unsigned char *out = (unsigned char*)outbuf; + int i=0; + + do { + TO_BINARY(i, (i+10)%30, (i+20)%30); + i = (i+21)%30; + } while (i != 0); + value = (uint32_t)atoi64[ARCH_INDEX(pos[0])] | + ((uint32_t)atoi64[ARCH_INDEX(pos[1])] << 6) | + ((uint32_t)atoi64[ARCH_INDEX(pos[2])] << 12); + out[31] = value >> 8; + out[30] = value; + return (void *)out; +} + + +static void *get_salt(char *ciphertext) +{ + static sha256crypt_salt_t out; + int len; + + memset(&out, 0, sizeof(out)); + out.rounds = ROUNDS_DEFAULT; + ciphertext += FORMAT_TAG_LEN; + if (!strncmp(ciphertext, ROUNDS_PREFIX, + sizeof(ROUNDS_PREFIX) - 1)) { + const char *num = ciphertext + sizeof(ROUNDS_PREFIX) - 1; + char *endp; + unsigned long int srounds = strtoul(num, &endp, 10); + if (*endp == '$') + { + ciphertext = endp + 1; + srounds = srounds < ROUNDS_MIN ? + ROUNDS_MIN : srounds; + out.rounds = srounds > ROUNDS_MAX ? + ROUNDS_MAX : srounds; + } + } + + for (len = 0; ciphertext[len] != '$'; len++); + + if (len > SALT_LENGTH) + len = SALT_LENGTH; + + memcpy(out.salt, ciphertext, len); + out.len = len; + return &out; +} + + +static unsigned int iteration_count(void *salt) +{ + sha256crypt_salt_t *sha256crypt_salt; + + sha256crypt_salt = salt; + return sha256crypt_salt->rounds; +} + + +static int target_rounds; + +static void init(struct fmt_main *fmt_main) +{ +//printf("verbosity (init):%d\n", options.verbosity); + // It uses performance estimation (bitstream.candidates_per_crypt) + // to calculate keys_per_crypt. Performance depends on count of rounds. + // Count is not available in init() and can change at runtime. + // In crypt_all(), count is available but keys_per_crypt can't change. + // + // It gets TargetRounds from john.conf and adjust + // bitstream.candidates_per_crypt. + + // Starting from TARGET_ROUNDS_1KPC, it sets keys_per_crypt + // equal to bitstream.min_keys + // + const int TARGET_ROUNDS_1KPC = 512*1024; + + target_rounds = cfg_get_int("ZTEX:", bitstream.label, + "TargetRounds"); + if (target_rounds <= 0) + target_rounds = 5000; + + if (target_rounds < 1000) + fprintf(stderr, "Warning: invalid TargetRounds=%d in john.conf." + " Valid values are 1000-999999999\n", target_rounds); + + if (target_rounds < 1000) + target_rounds = 1000; + + if (target_rounds >= TARGET_ROUNDS_1KPC) + bitstream.candidates_per_crypt = bitstream.min_keys; + else + bitstream.candidates_per_crypt = bitstream.min_keys + * (2 * TARGET_ROUNDS_1KPC / target_rounds); + + //fprintf(stderr, "bitstream.candidates_per_crypt=%d\n", + // bitstream.candidates_per_crypt); + + device_format_init(fmt_main, &bitstream, options.acc_devices);//, + //options.verbosity); +} + + +/* + * There's an existing CPU implementation. It stores salt in the database. + * 1) Salt data structure db_salt->salt is specific to algorithm + * 2) db_salt->salt depends on host system (e.g. different on 32 and 64-bit) + * 3) This salt internally has tunable costs and is used to + * populate db_salt->cost[FMT_TUNABLE_COSTS]. + * + * Salt is sent to devices in some uniform way in CMP_CONFIG packet: + * - first it goes binary salt in network byte order + * - then it sends 4-byte tunable cost(s) if any + * - then it sends 2 bytes - number of hashes + * - then partial hashes ("binaries") sorted in ascending order. + * (It accepts up to 512 32-bit hashes, order doesn't matter). + */ + + +extern volatile int bench_running; + +static int crypt_all(int *pcount, struct db_salt *salt) +{ + static int warning_target_rounds = 0; + int curr_rounds = salt->cost[0]; + + int result; + sha256crypt_salt_t *sha256crypt_salt = salt->salt; + unsigned char salt_buf[18]; // salt to send to device + + if (!warning_target_rounds && !bench_running + && (curr_rounds >= target_rounds * 4 + || curr_rounds <= target_rounds / 4) + ) { + fprintf(stderr, "Warning: TargetRounds=%d, processing" + " hash with rounds=%d, expecting suboptimal performance or" + " timeout, consider to adjust TargetRounds in john.conf\n", + target_rounds, curr_rounds); + warning_target_rounds = 1; + } + + // 1 byte unused, 1 byte salt_len, 16 bytes salt in network byte order + salt_buf[0] = 0; + salt_buf[1] = sha256crypt_salt->len; + memcpy(salt_buf + 2, sha256crypt_salt->salt, 16); + + cmp_config_new(salt, salt_buf, 18); + + result = device_format_crypt_all(pcount, salt); + return result; +} + + +extern struct task_list *task_list; + +static int cmp_exact(char *source, int index) +{ + struct task_result *result = task_result_by_index(task_list, index); +/* + fprintf(stderr,"cmp_exact index %d, key '%s'\n",index,result->key); + int i; + for (i=0; i < 32; i++) + fprintf(stderr,"%02x ", result->binary[i]); + fprintf(stderr,"\n"); + for (i=0; i < 32; i++) + fprintf(stderr,"%02x ", (((char *)get_binary(source)) + i)[0] & 0xFF); + fprintf(stderr,"\n"); +*/ + return !memcmp(result->binary, get_binary(source), 32); +} + + +struct fmt_main fmt_ztex_sha256crypt = { + { + FORMAT_LABEL, + FORMAT_NAME, + ALGORITHM_NAME, + BENCHMARK_COMMENT, + BENCHMARK_LENGTH, + 0, + PLAINTEXT_LENGTH, + BINARY_SIZE, + BINARY_ALIGN, + SALT_SIZE, + SALT_ALIGN, + 1, // set by device_format_reset() + 1, + FMT_CASE | FMT_8_BIT | FMT_MASK, + { + "iteration count", + }, + { + FORMAT_TAG + }, + tests + }, { + init, + device_format_done, + device_format_reset, + fmt_default_prepare, + valid, + fmt_default_split, + get_binary, + get_salt, + { + iteration_count, + }, + fmt_default_source, + { + fmt_default_binary_hash_0, + fmt_default_binary_hash_1, + fmt_default_binary_hash_2, + fmt_default_binary_hash_3, + fmt_default_binary_hash_4, + fmt_default_binary_hash_5, + fmt_default_binary_hash_6 + }, + fmt_default_salt_hash, + NULL, + device_format_set_salt, + device_format_set_key, + device_format_get_key, + fmt_default_clear_keys, + crypt_all, + { + device_format_get_hash_0, + device_format_get_hash_1, + device_format_get_hash_2, + device_format_get_hash_3, + device_format_get_hash_4, + device_format_get_hash_5, + device_format_get_hash_6 + }, + device_format_cmp_all, + device_format_cmp_one, + cmp_exact + } +};