├── Makefile
├── README.md
├── fpga
├── application.v
├── async2sync.v
├── chip_select.v
├── clocks.ucf
├── definitions.vh
├── descrypt
│ ├── arbiter.v
│ ├── cmp_config.v
│ ├── descrypt.ucf
│ ├── descrypt_core
│ │ ├── Eblock.v
│ │ ├── IP1.v
│ │ ├── SP_v2.v
│ │ ├── crypt3_ascii2bin.v
│ │ ├── des_loop.v
│ │ ├── descrypt.vh
│ │ ├── descrypt16.v
│ │ ├── descrypt_core_v5.v
│ │ ├── descrypt_round.v
│ │ ├── pc1.v
│ │ └── rotate_1or2_pc2.v
│ └── wrapper_v2.v
├── hs_io.v
├── hs_io_v2.v
├── inouttraffic.bit
├── inouttraffic.v
├── inouttraffic.xds
├── input_fifo.v
├── main.ucf
├── output_fifo.v
├── output_limit_fifo.v
├── packet_aware_fifo.v
├── packet_aware_fifo_test.v
├── pkt_comm
│ ├── inpkt_header.v
│ ├── outpkt_checksum.v
│ ├── outpkt_v2.v
│ ├── outpkt_word.v
│ ├── pkt_comm.ucf
│ ├── pkt_comm.v
│ ├── pkt_comm_arbiter.v
│ ├── pkt_comm_test.v
│ ├── word_gen.ucf
│ ├── word_gen.v
│ ├── word_gen.vh
│ ├── word_gen_char_range.v
│ ├── word_insert.v
│ ├── word_list.v
│ └── word_shift.v
├── util
│ ├── cdc_reg.v
│ ├── clocks.v
│ ├── cmt2.v
│ ├── cmt_common.v
│ ├── startup_spartan6.v
│ └── sync.v
└── vcr.v
├── host
├── compile.sh
├── descrypt_test.c
├── fw_upload.c
├── inouttraffic.c
├── inouttraffic.h
├── pkt_comm
│ ├── cmp_config.c
│ ├── cmp_config.h
│ ├── compile.sh
│ ├── outpkt.c
│ ├── outpkt.h
│ ├── pkt_comm.c
│ ├── pkt_comm.h
│ ├── word_gen.c
│ ├── word_gen.h
│ ├── word_list.c
│ └── word_list.h
├── pkt_test.c
├── simple_test.c
├── test.c
├── ztex.c
├── ztex.h
├── ztex_scan.c
└── ztex_scan.h
├── inouttraffic.c
└── inouttraffic.ihx
/Makefile:
--------------------------------------------------------------------------------
1 | #########################
2 | # configuration section #
3 | #########################
4 |
5 | # Defines the location of the EZ-USB SDK
6 | ZTEXPREFIX=../../..
7 |
8 | # The name of the jar archive
9 | JARTARGET=InTraffic.jar
10 | # Java Classes that have to be build
11 | CLASSTARGETS=InTraffic.class
12 | # Extra dependencies for Java Classes
13 | CLASSEXTRADEPS=
14 |
15 | # ihx files (firmware ROM files) that have to be build
16 | IHXTARGETS=intraffic.ihx
17 | # Extra Dependencies for ihx files
18 | IHXEXTRADEPS=
19 |
20 | # Extra files that should be included into th jar archive
21 | EXTRAJARFILES=intraffic.ihx fpga/intraffic.bit
22 |
23 | ################################
24 | # DO NOT CHANAGE THE FOLLOWING #
25 | ################################
26 | # includes the main Makefile
27 | include $(ZTEXPREFIX)/Makefile.mk
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | crypt(3) Standard DES password auditing tool for Ztex 1.15y FPGA board.
3 |
4 | Includes Verilog code, bitstream and example host software. To operate boards, you have to:
5 | - compile-in configuration for onboard comparator (salt and hashed passwords);
6 | - compile-in configurations for onboard candidate password generator;
7 | - read and understand output in hexadecimal.
8 |
9 | Compiles and runs on Linux and Windows. Supports operation of several connected boards (you have to improve host software yourself to distribute candidates among fpgas and boards). Performs at approximately 700 MH/s.
10 |
11 | Uses Ztex USB Multi-FPGA board communication framework https://github.com/Apingis/ztex_inouttraffic
12 |
13 | Project discontinued 10.2016 in favor of integration with John the Ripper.
14 |
15 | "John the Ripper" password cracker
16 | Home: http://openwall.com/john
17 | Development version: https://github.com/magnumripper/JohnTheRipper
18 |
--------------------------------------------------------------------------------
/fpga/application.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | module application(
4 | input CLK,
5 | //input RESET,
6 |
7 | // read from some internal FIFO (recieved via high-speed interface)
8 | //input [63:0] din,
9 | input [7:0] din,
10 | output rd_en,
11 | input empty,
12 |
13 | // write into some internal FIFO (to be send via high-speed interface)
14 | //output [63:0] dout,
15 | output [15:0] dout,
16 | output wr_en,
17 | input full,
18 | //output pkt_end,
19 |
20 | // control input (VCR interface)
21 | input [7:0] app_mode,
22 |
23 | // status output (VCR interface)
24 | output [7:0] pkt_comm_status,
25 | output [7:0] debug2,
26 | output [7:0] app_status
27 | );
28 |
29 | assign pkt_comm_status = 8'h00;
30 | assign debug2 = 8'h55;
31 | assign app_status = 8'h00;
32 |
33 | // convert 8-bit to 16-bit
34 | reg [15:0] dout_mode01;
35 | reg dout_mode01_ready = 0;
36 | reg counter = 0;
37 |
38 | // Application: send what received
39 | assign dout = dout_mode01;
40 | assign rd_en = ~empty & ~full;
41 | assign wr_en = dout_mode01_ready;
42 |
43 |
44 | always @(posedge CLK) begin
45 | if (counter == 0) begin
46 | dout_mode01_ready <= 0;
47 | end
48 | if (rd_en && (app_mode == 8'h00 || app_mode == 8'h01) ) begin
49 | if (counter == 0) begin
50 | dout_mode01[7:0] <= din;
51 | end
52 | else if (counter == 1) begin
53 | dout_mode01[15:8] <= din;
54 | dout_mode01_ready <= 1;
55 | end
56 | counter <= counter + 1'b1;
57 | end
58 | end
59 |
60 | endmodule
61 |
--------------------------------------------------------------------------------
/fpga/async2sync.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //**********************************************************
4 | //
5 | // Provides active 'clk_en' for 1 'clk' cycle per 1 'async' pulse
6 | //
7 | //**********************************************************
8 |
9 | module async2sync(
10 | input async,
11 | input clk,
12 | output reg clk_en = 0
13 | );
14 |
15 | reg async_r;
16 | always @(posedge clk or posedge async)
17 | if (async)
18 | async_r <= 1'b1;
19 | else if (done || !init_done)
20 | async_r <= 0;
21 |
22 | reg done = 0;
23 | reg init_done = 0;
24 |
25 | always @(posedge clk) begin
26 | if (!async && !init_done)
27 | init_done <= 1;
28 |
29 | if (async_r && init_done)
30 | if (!clk_en && !done) begin
31 | clk_en <= 1;
32 | done <= 1;
33 | end
34 | else
35 | clk_en <= 0;
36 | else
37 | done <= 0;
38 | end
39 |
40 | endmodule
41 |
--------------------------------------------------------------------------------
/fpga/chip_select.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // **********************************************
4 | //
5 | // Proper handling of Chip Select (CS) input
6 | // on a multi-FPGA board.
7 | //
8 | // On CS assertion:
9 | // * cycle 1. CS input gets registered (CS)
10 | // * cycle 2. Some outputs go T-state (out_z)
11 | // * cycle 3. Some outputs go T-state (out_z_wait1)
12 | //
13 | // **********************************************
14 |
15 | module chip_select(
16 | // Asynchronous CS input
17 | input CS_IN,
18 | input CLK,
19 | // Synchronous output
20 | output CS,
21 | //output out_z,
22 | output out_z_wait1
23 | );
24 |
25 | (* IOB="true" *) reg cs_in_r = 0;
26 | always @(posedge CLK)
27 | cs_in_r <= CS_IN;
28 | assign CS = cs_in_r;
29 |
30 | //(* IOB="true" *) reg cs_out_inv_r = 0;
31 | (* IOB="true" *) reg cs_out_inv_wait1_r = 0;
32 | reg deselect_delay = 0;
33 |
34 | always @(posedge CLK)
35 | if (~cs_in_r) begin
36 | //cs_out_inv_r <= 1;
37 | deselect_delay <= 1;
38 | if (deselect_delay)
39 | cs_out_inv_wait1_r <= 1;
40 | end
41 | else begin
42 | //cs_out_inv_r <= 0;
43 | deselect_delay <= 0;
44 | cs_out_inv_wait1_r <= 0;
45 | end
46 |
47 | //assign out_z = cs_out_inv_r;
48 | assign out_z_wait1 = cs_out_inv_wait1_r;
49 |
50 | endmodule
51 |
--------------------------------------------------------------------------------
/fpga/clocks.ucf:
--------------------------------------------------------------------------------
1 | # ****************************
2 | #
3 | # cmt2 - driven by IFCLK_IN
4 | # cmt_special.v
5 | #
6 | # ****************************
7 | #
8 | #INST "clocks/cmt2/BUFIO2_inst" LOC=BUFIO2_X3Y13;
9 | INST "clocks/cmt2/DCM_0" LOC=DCM_X0Y4;
10 | #INST "clocks/cmt2/DCM_CLKGEN_0" LOC=DCM_X0Y5;
11 | INST "clocks/cmt2/PLL_0" LOC=PLL_ADV_X0Y2;
12 |
13 | NET "IFCLK" TNM_NET = "IFCLK";
14 | TIMESPEC "TS_IFCLK" = PERIOD "IFCLK" 20.833 ns HIGH 50%;
15 | # CLK2
16 | #NET "clocks/cmt2/dcm0_clk90" TNM_NET = "cmt2_dcm0_clk90";
17 | #TIMESPEC "TS_cmt2_dcm0_clk90" = PERIOD "cmt2_dcm0_clk90" 20.833 ns HIGH 50%;
18 | # PLL_CLK
19 | NET "clocks/cmt2/dcm0_clkdv" TNM_NET = "cmt2_dcm0_clkdv";
20 | TIMESPEC "TS_cmt2_dcm0_clkdv" = PERIOD "cmt2_dcm0_clkdv" 41.666 ns HIGH 50%;
21 |
22 | # ****************************
23 | #
24 | # cmt1 - driven by FXCLK_IN
25 | # cmt_common.v
26 | #
27 | # ****************************
28 | #
29 | #INST "clocks/cmt1/BUFIO2_inst" LOC=BUFIO2_X3Y11;
30 | INST "clocks/cmt1/DCM_0" LOC=DCM_X0Y2;
31 | #INST "clocks/cmt1/DCM_CLKGEN_0" LOC=DCM_X0Y3;
32 | INST "clocks/cmt1/PLL_0" LOC=PLL_ADV_X0Y1;
33 |
34 | # CLK2
35 | #NET "clocks/cmt1/dcm0_clk90" TNM_NET = "cmt1_dcm0_clk90";
36 | #TIMESPEC "TS_cmt1_dcm0_clk90" = PERIOD "cmt1_dcm0_clk90" 20.833 ns HIGH 50%;
37 | # PLL_CLK
38 | NET "clocks/cmt1/dcm0_clkdv" TNM_NET = "cmt1_dcm0_clkdv";
39 | TIMESPEC "TS_cmt1_dcm0_clkdv" = PERIOD "cmt1_dcm0_clkdv" 41.666 ns HIGH 50%;
40 |
41 | # ****************************
42 | #
43 | # cmt3 - driven by FXCLK_IN
44 | # cmt_common.v
45 | #
46 | # ****************************
47 | #
48 | #INST "clocks/cmt3/BUFIO2_inst" LOC=BUFIO2_X4Y19;
49 | INST "clocks/cmt3/DCM_0" LOC=DCM_X0Y6;
50 | INST "clocks/cmt3/DCM_CLKGEN_0" LOC=DCM_X0Y7;
51 | INST "clocks/cmt3/PLL_0" LOC=PLL_ADV_X0Y3;
52 |
53 | # CLK2
54 | #NET "clocks/cmt3/dcm0_clk90" TNM_NET = "cmt3_dcm0_clk90";
55 | #TIMESPEC "TS_cmt3_dcm0_clk90" = PERIOD "cmt3_dcm0_clk90" 20.833 ns HIGH 50%;
56 | # PLL_CLK
57 | NET "clocks/cmt3/dcm0_clkdv" TNM_NET = "cmt3_dcm0_clkdv";
58 | TIMESPEC "TS_cmt3_dcm0_clkdv" = PERIOD "cmt3_dcm0_clkdv" 41.666 ns HIGH 50%;
59 |
60 | # ****************************
61 | #
62 | # cmt_bufg0 (random location) - driven from BUFG
63 | # cmt_common.v
64 | #
65 | # ****************************
66 | #
67 | NET "clocks/cmt_bufg0/dcm0_clkdv" TNM_NET = "cmt_bufg0_dcm0_clkdv";
68 | TIMESPEC "TS_cmt_bufg0_dcm0_clkdv" = PERIOD "cmt_bufg0_dcm0_clkdv" 41.666 ns HIGH 50%;
69 |
--------------------------------------------------------------------------------
/fpga/definitions.vh:
--------------------------------------------------------------------------------
1 | `ifndef _DEFINITIONS_VH_
2 |
3 |
4 | `define MSB(x) ( \
5 | //x >= *65536 ?: \
6 | x >= 256 *65536 ? 24 : \
7 | x >= 128 *65536 ? 23 : \
8 | x >= 64 *65536 ? 22 : \
9 | x >= 32 *65536 ? 21 : \
10 | x >= 16 *65536 ? 20 : \
11 | x >= 8 *65536 ? 19 : \
12 | x >= 4 *65536 ? 18 : \
13 | x >= 2 *65536 ? 17 : \
14 | x >= 65536 ? 16 : \
15 | x >= 32768 ? 15 : \
16 | x >= 16384 ? 14 : \
17 | x >= 8192 ? 13 : \
18 | x >= 4096 ? 12 : \
19 | x >= 2048 ? 11 : \
20 | x >= 1024 ? 10 : \
21 | x >= 512 ? 9 : \
22 | x >= 256 ? 8 : \
23 | x >= 128 ? 7 : \
24 | x >= 64 ? 6 : \
25 | x >= 32 ? 5 : \
26 | x >= 16 ? 4 : \
27 | x >= 8 ? 3 : \
28 | x >= 4 ? 2 : \
29 | x >= 2 ? 1 : \
30 | x >= 1 ? 0 : \
31 | x == 0 ? 0 : \
32 | -1 )
33 |
34 |
35 |
36 | `define _DEFINITIONS_VH_
37 |
38 | `endif
39 |
--------------------------------------------------------------------------------
/fpga/descrypt/cmp_config.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | `include "descrypt_core/descrypt.vh"
4 |
5 | module cmp_config(
6 | input wr_clk,
7 | input [7:0] din,
8 | input wr_en,
9 | output full,
10 |
11 | // Assumes frequency of rd_clk is greater than or equal to wr_clk
12 | input rd_clk,
13 | output reg [`SALT_MSB:0] salt_out,
14 | output reg [`RAM_ADDR_MSB-1:0] read_addr_start = {`RAM_ADDR_MSB{1'b1}},
15 | output reg [`RAM_ADDR_MSB-1:0] addr_diff_start = { 1'b1, {`RAM_ADDR_MSB-1{1'b0}} },
16 | output hash_valid, hash_end,
17 | output [`HASH_MSB:0] hash_out,
18 | output [`RAM_ADDR_MSB:0] hash_addr_out,
19 | input rd_en,
20 | output empty,
21 | output new_cmp_config, // asserts when incoming comparator config is going
22 | input config_applied, // configuration is taken into processing,
23 | // let pkt_comm handle next packet
24 | output error
25 | );
26 |
27 | assign full = full_r | state == STATE_ERROR | state == STATE_EMPTY_HASHES;
28 |
29 | localparam BYTE_COUNT_INT = ((`HASH_MSB + 1) / 8);
30 | localparam BYTE_COUNT_MAX = BYTE_COUNT_INT + |(`HASH_MSB + 1 - BYTE_COUNT_INT * 8);
31 |
32 | reg full_r = 0;
33 | reg [`HASH_MSB:0] hash_r;
34 | reg hash_valid_r, hash_end_r;
35 | reg new_cmp_config_r = 0;
36 | reg [`RAM_ADDR_MSB:0] num_hashes = 0, prev_num_hashes = 0, hash_addr_r = 0, hash_count = 0;
37 | reg [`MSB(BYTE_COUNT_MAX-1):0] byte_count = 0;
38 |
39 | sync_short_sig sync_config_applied(.sig(config_applied), .clk(wr_clk), .out(config_applied_sync));
40 | reg config_applied_r = 0;
41 |
42 | reg cmp_configured = 0;
43 |
44 | localparam STATE_SALT0 = 0,
45 | STATE_SALT1 = 1,
46 | STATE_NUM_HASHES0 = 2,
47 | STATE_NUM_HASHES1 = 3,
48 | STATE_HASH = 4,
49 | STATE_EMPTY_HASHES = 5,
50 | STATE_MAGIC = 6,
51 | STATE_ERROR = 7;
52 |
53 | (* FSM_EXTRACT="true", FSM_ENCODING="one-hot" *)
54 | reg [2:0] state = STATE_SALT0;
55 |
56 | always @(posedge wr_clk) begin
57 | if (config_applied_sync) begin
58 | config_applied_r <= 1;
59 | new_cmp_config_r <= 0;
60 | end
61 |
62 | if (state == STATE_ERROR) begin
63 | end
64 |
65 | // Comparator's hash table has 2**(`RAM_ADDR_MSB+1)-1 rows (uppermost row is unused).
66 | // Hashes must be sorted in ascending order.
67 | // MSB of each row in table is hash_valid bit.
68 | // It requires to fill all empty rows with hash_valid=0.
69 | //
70 | // On startup all rows are 0. After reset, 1st configuration fills all rows.
71 | // If a new configuration has less rows than previous one, remaining rows filled with 0.
72 | //
73 | else if (~full_r & state == STATE_EMPTY_HASHES) begin
74 | // write at least 1 hash with hash_valid=0
75 | // to satisfy a requirement to produce an output with hash_end_r=1.
76 | if (~hash_end_r) begin
77 | hash_valid_r <= 0;
78 | full_r <= 1;
79 | hash_addr_r <= hash_count;
80 | hash_count <= hash_count + 1'b1;
81 | end
82 | if (hash_count >= prev_num_hashes || ~cmp_configured & &hash_count) begin
83 | hash_end_r <= 1;
84 | // if config_applied is not set - wait here
85 | if (config_applied_r) begin
86 | config_applied_r <= 0;
87 | state <= STATE_MAGIC;
88 | end
89 | end
90 | end
91 |
92 | else if (~full_r & wr_en) begin
93 | case(state)
94 | STATE_SALT0: begin
95 | salt_out[7:0] <= din;
96 | prev_num_hashes <= num_hashes;
97 | hash_count <= 0;
98 | state <= STATE_SALT1;
99 | end
100 |
101 | STATE_SALT1: begin
102 | salt_out[`SALT_MSB:8] <= din[`SALT_MSB-8:0];
103 | if (din[7:`SALT_MSB-7])
104 | // salt must be (`SALT_MSB+1) bits.
105 | state <= STATE_ERROR;
106 | else
107 | state <= STATE_NUM_HASHES0;
108 | end
109 |
110 | STATE_NUM_HASHES0: begin
111 | num_hashes[7:0] <= din;
112 | state <= STATE_NUM_HASHES1;
113 | end
114 |
115 | STATE_NUM_HASHES1: begin
116 | new_cmp_config_r <= 1;
117 | read_addr_start <= read_addr_start_out;
118 | addr_diff_start <= addr_diff_start_out;
119 |
120 | num_hashes[`RAM_ADDR_MSB:8] <= din[`RAM_ADDR_MSB-8:0];
121 | if (din[7:`RAM_ADDR_MSB-7] || !din[`RAM_ADDR_MSB-8:0] & !num_hashes[7:0])
122 | // num_hashes exceeds maximum value or zero num_hashes
123 | state <= STATE_ERROR;
124 | else
125 | state <= STATE_HASH;
126 | end
127 |
128 | STATE_HASH: begin
129 | hash_r[(byte_count + 1)*8-1 -:8] <= din;
130 | hash_valid_r <= 1;
131 | hash_end_r <= 0;
132 | if (byte_count == BYTE_COUNT_MAX - 1) begin
133 | byte_count <= 0;
134 | full_r <= 1;
135 | hash_addr_r <= hash_count;
136 | hash_count <= hash_count + 1'b1;
137 | if (hash_count + 1'b1 == num_hashes) begin
138 | state <= STATE_EMPTY_HASHES;
139 | end
140 | end
141 | else
142 | byte_count <= byte_count + 1'b1;
143 | end
144 |
145 | // It doesn't read last byte ("magic") of comparator configuration
146 | // until configuration is applied. That blocks pkt_comm from
147 | // reading further packets.
148 | //
149 | // Well, the application might need some common mechanism for
150 | // arranging input packet flow.
151 | STATE_MAGIC: begin
152 | if (din != 8'hCC)
153 | state <= STATE_ERROR;
154 | else begin
155 | state <= STATE_SALT0;
156 | cmp_configured <= 1;
157 | end
158 | end
159 | endcase
160 | end // ~full_r & wr_en
161 |
162 | else if (output_reg_wr_en)
163 | full_r <= 0;
164 | end
165 |
166 | wire [`RAM_ADDR_MSB-1:0] read_addr_start_out, addr_diff_start_out;
167 |
168 | // STATE_NUM_HASHES1
169 | get_read_addr_start get_read_addr_start(
170 | .in({ din[`RAM_ADDR_MSB-8:0], num_hashes[7:0] }),
171 | .read_addr_start(read_addr_start_out),
172 | .addr_diff_start(addr_diff_start_out)
173 | );
174 |
175 | sync_sig sync_new_cmp_config(.sig(new_cmp_config_r), .clk(rd_clk), .out(new_cmp_config));
176 |
177 | assign error = state == STATE_ERROR;
178 |
179 | assign output_reg_wr_en = ~output_reg_full & full_r;
180 |
181 | cdc_reg #(.WIDTH(2 + `HASH_MSB+1 + `RAM_ADDR_MSB+1)) output_reg (
182 | .wr_clk(wr_clk),
183 | .din({ hash_end_r, hash_valid_r, hash_r, hash_addr_r }),
184 | .wr_en(output_reg_wr_en), .full(output_reg_full),
185 |
186 | .rd_clk(rd_clk),
187 | .dout({ hash_end, hash_valid, hash_out, hash_addr_out }),
188 | .rd_en(rd_en), .empty(empty)
189 | );
190 |
191 | endmodule
192 |
193 |
194 | module get_read_addr_start #(
195 | parameter MSB = `RAM_ADDR_MSB
196 | )(
197 | input [MSB:0] in, // total number of hashes (>0)
198 | output [MSB-1:0] read_addr_start,
199 | output [MSB-1:0] addr_diff_start
200 | );
201 |
202 | wire [MSB-1:0] in_shr = in[MSB:1];
203 |
204 | genvar i;
205 | generate
206 | for (i=0; i < MSB; i=i+1)
207 | begin: gen_read_addr
208 |
209 | assign read_addr_start[i] = (i == MSB-1) ? in_shr[i] : in_shr[i] | read_addr_start[i+1];
210 |
211 | end
212 | endgenerate
213 |
214 | wire [MSB-2:0] read_addr_shr = read_addr_start[MSB-1:1];
215 |
216 | assign addr_diff_start = read_addr_start ^ { 1'b0, read_addr_shr };
217 |
218 | endmodule
219 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt.ucf:
--------------------------------------------------------------------------------
1 | #
2 | # cmp_config
3 | #
4 | INST "pkt_comm/cmp_config/*" AREA_GROUP = "arbiter";
5 | NET "pkt_comm/cmp_config/salt_out*" TIG;
6 | NET "pkt_comm/cmp_config/read_addr_start*" TIG;
7 | NET "pkt_comm/cmp_config/addr_diff_start*" TIG;
8 | #
9 | # arbiter, I/O fifo's
10 | #
11 | #AREA_GROUP "arbiter" RANGE=SLICE_X88Y80:SLICE_X103Y95; # 1024 LUTs
12 | #AREA_GROUP "arbiter" RANGE=SLICE_X64Y80:SLICE_X103Y95;
13 | AREA_GROUP "arbiter" RANGE=SLICE_X48Y80:SLICE_X103Y95;
14 | AREA_GROUP "arbiter" RANGE=RAMB16_X3Y38:RAMB16_X3Y48,RAMB8_X4Y40:RAMB8_X4Y47; # 6 x 16Kbit, 8 x 8Kbit
15 | INST "pkt_comm/arbiter/*" AREA_GROUP = "arbiter";
16 | #AREA_GROUP "arbiter_input_fifo" RANGE=RAMB8_X4Y40:RAMB8_X4Y43;
17 | #INST "pkt_comm/arbiter/arbiter_input_fifo/*" AREA_GROUP = "arbiter_input_fifo";
18 | INST "input_fifo/fifo_bram_8x1024_fwft/*" AREA_GROUP="arbiter";
19 | INST "output_fifo/fifo_dram_async_16/*" AREA_GROUP="arbiter";
20 |
21 |
22 | AREA_GROUP "wrapper0" RANGE=SLICE_X8Y109:SLICE_X60Y120;
23 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/*" AREA_GROUP="wrapper0";
24 | AREA_GROUP "wrapper0_2" RANGE=SLICE_X8Y130:SLICE_X60Y141;
25 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/*r2*" AREA_GROUP="wrapper0_2";
26 |
27 | AREA_GROUP "core0_0" RANGE=SLICE_X0Y139:SLICE_X31Y158;
28 | AREA_GROUP "core0_0" RANGE=RAMB16_X0Y70:RAMB16_X1Y78;
29 | AREA_GROUP "core0_1" RANGE=SLICE_X32Y139:SLICE_X63Y158;
30 | AREA_GROUP "core0_1" RANGE=RAMB16_X2Y70:RAMB16_X2Y78;
31 | AREA_GROUP "core0_2" RANGE=SLICE_X0Y118:SLICE_X31Y137;
32 | AREA_GROUP "core0_2" RANGE=RAMB16_X0Y60:RAMB16_X1Y68;
33 | AREA_GROUP "core0_3" RANGE=SLICE_X32Y118:SLICE_X63Y137;
34 | AREA_GROUP "core0_3" RANGE=RAMB16_X2Y60:RAMB16_X2Y68;
35 | AREA_GROUP "core0_4" RANGE=SLICE_X0Y97:SLICE_X29Y116;
36 | AREA_GROUP "core0_4" RANGE=RAMB16_X0Y50:RAMB16_X1Y58;
37 | AREA_GROUP "core0_5" RANGE=SLICE_X32Y97:SLICE_X63Y116;
38 | AREA_GROUP "core0_5" RANGE=RAMB16_X2Y50:RAMB16_X2Y58;
39 |
40 |
41 | AREA_GROUP "wrapper1" RANGE=SLICE_X66Y109:SLICE_X112Y120;
42 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/*" AREA_GROUP="wrapper1";
43 | AREA_GROUP "wrapper1_2" RANGE=SLICE_X66Y130:SLICE_X112Y141;
44 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/*r2*" AREA_GROUP="wrapper1_2";
45 |
46 | AREA_GROUP "core1_0" RANGE=SLICE_X64Y139:SLICE_X95Y158;
47 | AREA_GROUP "core1_0" RANGE=RAMB16_X3Y70:RAMB16_X3Y78;
48 | AREA_GROUP "core1_1" RANGE=SLICE_X96Y139:SLICE_X127Y158;
49 | AREA_GROUP "core1_1" RANGE=RAMB16_X4Y70:RAMB16_X5Y78;
50 | AREA_GROUP "core1_2" RANGE=SLICE_X64Y118:SLICE_X95Y137;
51 | AREA_GROUP "core1_2" RANGE=RAMB16_X3Y60:RAMB16_X3Y68;
52 | AREA_GROUP "core1_3" RANGE=SLICE_X96Y118:SLICE_X127Y137;
53 | AREA_GROUP "core1_3" RANGE=RAMB16_X4Y60:RAMB16_X5Y68;
54 | AREA_GROUP "core1_4" RANGE=SLICE_X64Y97:SLICE_X95Y116;
55 | AREA_GROUP "core1_4" RANGE=RAMB16_X3Y50:RAMB16_X3Y58;
56 | AREA_GROUP "core1_5" RANGE=SLICE_X96Y97:SLICE_X127Y116;
57 | AREA_GROUP "core1_5" RANGE=RAMB16_X4Y50:RAMB16_X5Y58;
58 |
59 |
60 | AREA_GROUP "wrapper2" RANGE=SLICE_X8Y54:SLICE_X60Y62;
61 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/*" AREA_GROUP="wrapper2";
62 | AREA_GROUP "wrapper2_2" RANGE=SLICE_X8Y34:SLICE_X60Y42;
63 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/*r2*" AREA_GROUP="wrapper2_2";
64 |
65 | AREA_GROUP "core2_0" RANGE=SLICE_X0Y59:SLICE_X31Y78;
66 | AREA_GROUP "core2_0" RANGE=RAMB16_X0Y32:RAMB16_X1Y38;
67 | AREA_GROUP "core2_1" RANGE=SLICE_X32Y59:SLICE_X63Y78;
68 | AREA_GROUP "core2_1" RANGE=RAMB16_X2Y32:RAMB16_X2Y38;
69 | AREA_GROUP "core2_2" RANGE=SLICE_X0Y38:SLICE_X31Y57;
70 | AREA_GROUP "core2_2" RANGE=RAMB16_X0Y20:RAMB16_X1Y28;
71 | AREA_GROUP "core2_3" RANGE=SLICE_X32Y38:SLICE_X63Y57;
72 | AREA_GROUP "core2_3" RANGE=RAMB16_X2Y20:RAMB16_X2Y28;
73 | AREA_GROUP "core2_4" RANGE=SLICE_X0Y17:SLICE_X31Y36;
74 | AREA_GROUP "core2_4" RANGE=RAMB16_X0Y10:RAMB16_X1Y18;
75 | AREA_GROUP "core2_5" RANGE=SLICE_X32Y17:SLICE_X63Y36;
76 | AREA_GROUP "core2_5" RANGE=RAMB16_X2Y10:RAMB16_X2Y18;
77 |
78 |
79 | AREA_GROUP "wrapper3" RANGE=SLICE_X66Y54:SLICE_X112Y62;
80 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/*" AREA_GROUP="wrapper3";
81 | AREA_GROUP "wrapper3_2" RANGE=SLICE_X66Y34:SLICE_X112Y42;
82 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/*r2*" AREA_GROUP="wrapper3_2";
83 |
84 | AREA_GROUP "core3_0" RANGE=SLICE_X64Y59:SLICE_X95Y78;
85 | AREA_GROUP "core3_0" RANGE=RAMB16_X3Y32:RAMB16_X3Y38;
86 | AREA_GROUP "core3_1" RANGE=SLICE_X96Y59:SLICE_X127Y78;
87 | AREA_GROUP "core3_1" RANGE=RAMB16_X4Y32:RAMB16_X5Y38;
88 | AREA_GROUP "core3_2" RANGE=SLICE_X64Y38:SLICE_X95Y57;
89 | AREA_GROUP "core3_2" RANGE=RAMB16_X3Y20:RAMB16_X3Y28;
90 | AREA_GROUP "core3_3" RANGE=SLICE_X96Y38:SLICE_X127Y57;
91 | AREA_GROUP "core3_3" RANGE=RAMB16_X4Y20:RAMB16_X5Y28;
92 | AREA_GROUP "core3_4" RANGE=SLICE_X64Y17:SLICE_X95Y36;
93 | AREA_GROUP "core3_4" RANGE=RAMB16_X3Y10:RAMB16_X3Y18;
94 | AREA_GROUP "core3_5" RANGE=SLICE_X96Y17:SLICE_X127Y36;
95 | AREA_GROUP "core3_5" RANGE=RAMB16_X4Y10:RAMB16_X5Y18;
96 |
97 |
98 | #RANGE=SLICE_X98Y170:SLICE_X127Y189;
99 |
100 |
101 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/core_gen[0].core/*" AREA_GROUP="core0_0";
102 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/core_gen[1].core/*" AREA_GROUP="core0_1";
103 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/core_gen[2].core/*" AREA_GROUP="core0_2";
104 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/core_gen[3].core/*" AREA_GROUP="core0_3";
105 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/core_gen[4].core/*" AREA_GROUP="core0_4";
106 | INST "pkt_comm/arbiter/wrapper_gen[0].wrapper/core_gen[5].core/*" AREA_GROUP="core0_5";
107 |
108 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/core_gen[0].core/*" AREA_GROUP="core1_0";
109 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/core_gen[1].core/*" AREA_GROUP="core1_1";
110 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/core_gen[2].core/*" AREA_GROUP="core1_2";
111 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/core_gen[3].core/*" AREA_GROUP="core1_3";
112 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/core_gen[4].core/*" AREA_GROUP="core1_4";
113 | INST "pkt_comm/arbiter/wrapper_gen[1].wrapper/core_gen[5].core/*" AREA_GROUP="core1_5";
114 |
115 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/core_gen[0].core/*" AREA_GROUP="core2_0";
116 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/core_gen[1].core/*" AREA_GROUP="core2_1";
117 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/core_gen[2].core/*" AREA_GROUP="core2_2";
118 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/core_gen[3].core/*" AREA_GROUP="core2_3";
119 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/core_gen[4].core/*" AREA_GROUP="core2_4";
120 | INST "pkt_comm/arbiter/wrapper_gen[2].wrapper/core_gen[5].core/*" AREA_GROUP="core2_5";
121 |
122 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/core_gen[0].core/*" AREA_GROUP="core3_0";
123 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/core_gen[1].core/*" AREA_GROUP="core3_1";
124 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/core_gen[2].core/*" AREA_GROUP="core3_2";
125 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/core_gen[3].core/*" AREA_GROUP="core3_3";
126 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/core_gen[4].core/*" AREA_GROUP="core3_4";
127 | INST "pkt_comm/arbiter/wrapper_gen[3].wrapper/core_gen[5].core/*" AREA_GROUP="core3_5";
128 |
129 |
130 | NET "pkt_comm/arbiter/wrapper_gen[*].wrapper/core_gen[*].core/salt*" TIG;
131 | NET "pkt_comm/arbiter/wrapper_gen[*].wrapper/core_gen[*].core/read_addr_start*" TIG;
132 | NET "pkt_comm/arbiter/wrapper_gen[*].wrapper/core_gen[*].core/addr_diff_start*" TIG;
133 | NET "pkt_comm/arbiter/wrapper_gen[*].wrapper/core_gen[*].core/pkt_num*" TIG;
134 | NET "pkt_comm/arbiter/wrapper_gen[*].wrapper/core_gen[*].core/batch_num*" TIG;
135 |
136 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/Eblock.v:
--------------------------------------------------------------------------------
1 |
2 | `include "descrypt.vh"
3 |
4 |
5 | module Eblock(
6 | input [`SALT_MSB:0] salt,
7 | input [31:0] R,
8 | output [47:0] result
9 | );
10 |
11 | assign result = {
12 |
13 | R[0], R[31], R[30], R[29], R[28], R[27], R[28], R[27], R[26], R[25], R[24], R[23],
14 |
15 | salt[11]? R[8] : R[24],
16 | salt[10]? R[7] : R[23],
17 | salt[9] ? R[6] : R[22],
18 | salt[8] ? R[5] : R[21],
19 | salt[7] ? R[4] : R[20],
20 | salt[6] ? R[3] : R[19],
21 | salt[5] ? R[4] : R[20],
22 | salt[4] ? R[3] : R[19],
23 | salt[3] ? R[2] : R[18],
24 | salt[2] ? R[1] : R[17],
25 | salt[1] ? R[0] : R[16],
26 | salt[0] ? R[31] : R[15],
27 |
28 | R[16], R[15], R[14], R[13], R[12], R[11], R[12], R[11], R[10], R[9], R[8], R[7],
29 |
30 | !salt[11]? R[8] : R[24],
31 | !salt[10]? R[7] : R[23],
32 | !salt[9] ? R[6] : R[22],
33 | !salt[8] ? R[5] : R[21],
34 | !salt[7] ? R[4] : R[20],
35 | !salt[6] ? R[3] : R[19],
36 | !salt[5] ? R[4] : R[20],
37 | !salt[4] ? R[3] : R[19],
38 | !salt[3] ? R[2] : R[18],
39 | !salt[2] ? R[1] : R[17],
40 | !salt[1] ? R[0] : R[16],
41 | !salt[0] ? R[31] : R[15]
42 |
43 | };
44 |
45 |
46 | endmodule
47 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/IP1.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ns
2 |
3 | // Final permutation, FP = IP^(-1)
4 | module IP1(
5 | input [63:0] din,
6 | output [63:0] dout
7 | );
8 |
9 | assign dout = {
10 | din[24], din[56], din[16], din[48], din[8], din[40], din[0], din[32],
11 | din[25], din[57], din[17], din[49], din[9], din[41], din[1], din[33],
12 | din[26], din[58], din[18], din[50], din[10], din[42], din[2], din[34],
13 | din[27], din[59], din[19], din[51], din[11], din[43], din[3], din[35],
14 | din[28], din[60], din[20], din[52], din[12], din[44], din[4], din[36],
15 | din[29], din[61], din[21], din[53], din[13], din[45], din[5], din[37],
16 | din[30], din[62], din[22], din[54], din[14], din[46], din[6], din[38],
17 | din[31], din[63], din[23], din[55], din[15], din[47], din[7], din[39]
18 | };
19 |
20 | endmodule
21 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/crypt3_ascii2bin.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // Converts 8 ASCII characters (7 bit each) into 64-bit
4 | // exactly like crypt(3) is doing
5 | // for further use in PC1
6 |
7 | module crypt3_ascii2bin(
8 | input [55:0] din,
9 | output [63:0] dout
10 | );
11 |
12 | assign dout = {
13 | 1'b0, din[49], din[50], din[51], din[52], din[53], din[54], din[55],
14 | 1'b0, din[42], din[43], din[44], din[45], din[46], din[47], din[48],
15 | 1'b0, din[35], din[36], din[37], din[38], din[39], din[40], din[41],
16 | 1'b0, din[28], din[29], din[30], din[31], din[32], din[33], din[34],
17 |
18 | 1'b0, din[21], din[22], din[23], din[24], din[25], din[26], din[27],
19 | 1'b0, din[14], din[15], din[16], din[17], din[18], din[19], din[20],
20 | 1'b0, din[7], din[8], din[9], din[10], din[11], din[12], din[13],
21 | 1'b0, din[0], din[1], din[2], din[3], din[4], din[5], din[6]
22 | };
23 |
24 | endmodule
25 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/des_loop.v:
--------------------------------------------------------------------------------
1 | //
2 |
3 | `include "descrypt.vh"
4 |
5 |
6 | ////////////////////////////////////////////////////////////////////////
7 | //
8 | // body of inner loop (1 of 16)
9 | //
10 |
11 | module des_loop (
12 | input [63:0] Ti_in,
13 | input [47:0] Ki,
14 | input [`SALT_MSB:0] salt_in,
15 | output [63:0] Ti_out
16 | );
17 |
18 | wire [31:0] Li = Ti_in[63:32];
19 | wire [31:0] Ri = Ti_in[31:0];
20 |
21 | // E,xor,S,P
22 | wire [47:0] E_result;
23 | Eblock Eblock_instance( salt_in, Ri, E_result );
24 |
25 | wire [47:0] xor_result;
26 | assign xor_result = E_result ^ Ki;
27 |
28 | wire [31:0] P_result;
29 | //des_SP des_SP_instance(xor_result, P_result);
30 | SP_v2 SP(xor_result, P_result);
31 |
32 | assign Ti_out [31:0] = Li ^ P_result;
33 | assign Ti_out [63:32] = Ri;
34 |
35 | endmodule
36 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/descrypt.vh:
--------------------------------------------------------------------------------
1 | `ifndef _DESCRYPT_VH_
2 |
3 |
4 | `define SALT_NBITS 12
5 | `define SALT_MSB `SALT_NBITS - 1
6 |
7 | `define CRYPT_COUNT 25
8 | `define CRYPT_COUNTER_NBITS 5
9 |
10 | // Hash storage. MSB=9: 1023 hashes
11 | `define RAM_ADDR_MSB 9
12 |
13 | // Each core has up to NUM_BATCHES in flight, each batch
14 | // contain NUM_CRYPT_INSTANSES items.
15 | // * 1 batch in descrypt instances
16 | // * 1 batch in comparator
17 | // * 1-2 batches in core's output registers
18 | `define NUM_BATCHES 4
19 | `define NUM_BATCHES_MSB `MSB(`NUM_BATCHES-1)
20 |
21 | // Arbiter processes that many pkt_id's at once.
22 | `define NUM_PKTS 2
23 | `define NUM_PKTS_MSB `MSB(`NUM_PKTS-1)
24 |
25 | // Max. number of batches in packet
26 | `define PKT_BATCHES_MSB 31
27 |
28 | //`define COMPARE_35_BIT // compare only first 35 bits - not implemented
29 | `ifdef COMPARE_35_BIT
30 | `define DIN_MSB 56
31 | `define HASH_MSB 34
32 | `else
33 | `define DIN_MSB 64
34 | `define HASH_MSB 63
35 | `endif
36 |
37 |
38 |
39 | `define _DESCRYPT_VH_
40 |
41 | `endif
42 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/descrypt16.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ns
2 |
3 | `include "descrypt.vh"
4 |
5 |
6 | module descrypt16(
7 | input CLK,
8 |
9 | input [`SALT_MSB:0] salt_in,
10 | input [55:0] key56_in,
11 | input valid_in,
12 |
13 | input ENABLE_CRYPT,
14 | input START_CRYPT,
15 |
16 | output [`HASH_MSB:0] hash_out,
17 | output valid_out
18 | );
19 |
20 | genvar i;
21 |
22 | wire [55:0] CiDi [15:0];
23 | wire [63:0] Ti [15:0];
24 | wire [15:0] valid;
25 |
26 | wire [63:0] Ti_out = Ti[15];
27 | wire [63:0] Ti_in = {Ti_out[31:0], Ti_out[63:32]};
28 |
29 | wire [55:0] CiDi_in = START_CRYPT ? key56_in : CiDi[15];
30 | wire valid0_in = START_CRYPT ? valid_in : valid[15];
31 |
32 | //(* KEEP_HIERARCHY="true" *)
33 | descrypt_round0 descrypt_round0(
34 | .CLK(CLK), .ENABLE_CRYPT(ENABLE_CRYPT), .START_CRYPT(START_CRYPT), .salt_in(salt_in),
35 | .CiDi_in(CiDi_in), .Ti_in(Ti_in), .valid_in(valid0_in),
36 | .CiDi_out(CiDi[0]), .Ti_out(Ti[0]), .valid_out(valid[0])
37 | );
38 |
39 | generate
40 | for (i=1; i < 16; i=i+1) begin: rounds
41 |
42 | localparam ROTATE2 = i==1 || i==8 || i==15 ? 1'b0 : 1'b1;
43 |
44 | //(* KEEP_HIERARCHY="true" *)
45 | descrypt_round #(.ROTATE2(ROTATE2)) descrypt_round(
46 | .CLK(CLK), .salt_in(salt_in),
47 | .CiDi_in(CiDi[i-1]), .Ti_in(Ti[i-1]), .valid_in(valid[i-1]),
48 | .CiDi_out(CiDi[i]), .Ti_out(Ti[i]), .valid_out(valid[i])
49 | );
50 |
51 | end
52 | endgenerate
53 |
54 | wire [63:0] IP1_out;
55 | IP1 IP1_instance(Ti_out, IP1_out);
56 |
57 | assign hash_out = IP1_out[63:63-`HASH_MSB];
58 | assign valid_out = valid[15];
59 |
60 | endmodule
61 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/descrypt_core_v5.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | `include "descrypt.vh"
4 |
5 | // Features:
6 | // * Input register
7 | // * CiDi circles over pipeline
8 | //
9 | module descrypt_core_v5 #(
10 | parameter NUM_CRYPT_INSTANCES = 16
11 | )(
12 | input CORE_CLK,
13 | input CMP_CLK,
14 | input [`DIN_MSB:0] din,
15 | // addr_in:
16 | // ***1 - write hash into RAM
17 | // ***010 - write salt, read_addr_start, addr_diff_start
18 | // ***100 - write 56-bit key
19 | // ***110 - start computation, write batch_num & pkt_num
20 | input [`RAM_ADDR_MSB+1:0] addr_in,
21 | input wr_en,
22 |
23 | output crypt_ready, // asserted when it's ready for new data
24 | output cmp_ready_sync, // cmp_ready synchronized to CLK
25 |
26 | input dout_full,
27 | output reg [`RAM_ADDR_MSB:0] dout,
28 | output reg [`MSB(NUM_CRYPT_INSTANCES-1):0] dout_instance,
29 | output reg dout_equal,
30 | output reg dout_key_valid,
31 | output reg [`NUM_BATCHES_MSB:0] dout_batch_num,
32 | output reg [`NUM_PKTS_MSB:0] dout_pkt_num,
33 | output reg dout_batch_complete,
34 | output reg dout_wr_en = 0,
35 | output reg core_error = 0,
36 | output reg cmp_error = 0
37 | );
38 |
39 | genvar i;
40 | integer k;
41 |
42 | //
43 | // Input register.
44 | //
45 | reg [`DIN_MSB:0] din_r;
46 | reg [`RAM_ADDR_MSB+1:0] addr_r;
47 | reg wr_en_r = 0;
48 |
49 | always @(posedge CORE_CLK) begin
50 | if (wr_en) begin
51 | din_r <= din;
52 | addr_r <= addr_in;
53 | end
54 | wr_en_r <= wr_en;
55 | end
56 |
57 | reg [`SALT_MSB:0] salt = 0;
58 |
59 | always @(posedge CORE_CLK)
60 | if (wr_en_r) begin
61 | if (addr_r[2:0] == 3'b010)
62 | { addr_diff_start,
63 | read_addr_start,
64 | salt
65 | } <= din_r[`RAM_ADDR_MSB + `RAM_ADDR_MSB + `SALT_MSB:0];
66 | end
67 |
68 | wire [55:0] key56_in = din_r[55:0];
69 | wire valid_in = din_r[56];
70 |
71 | wire write_key_r = wr_en_r & addr_r[2:0] == 3'b100;
72 |
73 | wire [`HASH_MSB:0] hash_out;
74 |
75 | reg enable_crypt_r = 0;
76 | always @(posedge CORE_CLK)
77 | enable_crypt_r <= wr_en & addr_in[2:0] == 3'b100 | ~crypt_ready_r;
78 |
79 | // Only round0 affected by ENABLE
80 | wire ENABLE_CRYPT = enable_crypt_r;
81 |
82 | //(* KEEP_HIERARCHY="true" *)
83 | descrypt16 descrypt16(
84 | .CLK(CORE_CLK), .salt_in(salt), .key56_in(key56_in), .valid_in(valid_in),
85 | .ENABLE_CRYPT(ENABLE_CRYPT),
86 | .START_CRYPT(write_key_r),
87 |
88 | .hash_out(hash_out), .valid_out(valid_out)
89 | );
90 |
91 | reg [3:0] loop_counter = 0;
92 | reg [`CRYPT_COUNTER_NBITS-1:0] crypt_counter = 0;
93 | reg crypt_cnt24 = 0;
94 | reg loop14_crypt24 = 0;
95 |
96 | reg crypt_ready_r = 1; // it goes 400 cycles when crypt_ready_r deasserted
97 | assign crypt_ready = crypt_ready_r & ~cmp_wait;
98 |
99 | // Writer writes a batch of 16 keys in sequence
100 | always @(posedge CORE_CLK) begin
101 | if (write_key_r & crypt_ready_r) begin
102 | if (~crypt_ready)
103 | core_error <= 1;
104 | crypt_ready_r <= 0;
105 | loop_counter <= 0; //?
106 | crypt_counter <= 0;
107 | crypt_cnt24 <= 0;
108 | loop14_crypt24 <= 0;
109 | end
110 | else if (~crypt_ready_r) begin
111 | loop_counter <= loop_counter + 1'b1;
112 | loop14_crypt24 <= loop_counter == 13 & crypt_cnt24;
113 |
114 | if (loop_counter == 15) begin
115 | if (crypt_cnt24)
116 | crypt_ready_r <= 1; // assuming no extra register stages between arbiter and core
117 | else begin
118 | crypt_counter <= crypt_counter + 1'b1;
119 | crypt_cnt24 <= crypt_counter == `CRYPT_COUNT - 2;
120 | end
121 | end
122 | end
123 | end
124 |
125 |
126 | // Issue. Pipeline rounds except for round0 don't have clock enable.
127 | // Destination memory bank must be empty at the start of the crypt.
128 | //
129 | (* RAM_STYLE="DISTRIBUTED" *)
130 | reg [1+`HASH_MSB:0] result [2 * NUM_CRYPT_INSTANCES - 1 :0];
131 | reg [3:0] result_cnt = 0;
132 | reg result_bank_wr = 0, result_bank_rd = 0;
133 | reg write_result = 0; // results are being written from the end of the pipeline into memory
134 |
135 | // extra register stage is not required at 216 MHz.
136 | /*
137 | reg [1+`HASH_MSB:0] result_r;
138 | reg [3:0] result_cnt_wr;
139 | reg result_wr = 0;
140 |
141 | always @(posedge CORE_CLK)
142 | if (write_result) begin
143 | result_r <= { valid_out, hash_out };
144 | result_cnt_wr <= result_cnt;
145 | result_wr <= 1;
146 | end
147 | else
148 | result_wr <= 0;
149 |
150 | always @(posedge CORE_CLK)
151 | if (result_wr)
152 | result [result_cnt_wr] <= result_r;
153 | */
154 | always @(posedge CORE_CLK)
155 | if (write_result)
156 | result [ {result_bank_wr, result_cnt} ] <= { valid_out, hash_out };
157 |
158 | always @(posedge CORE_CLK)
159 | if (write_result) begin
160 | result_cnt <= result_cnt + 1'b1;
161 | if (result_cnt == 15) begin
162 | write_result <= 0;
163 | result_bank_wr <= ~result_bank_wr;
164 | end
165 | end
166 | else if (loop14_crypt24)
167 | write_result <= 1;
168 |
169 | reg cmp_start = 0; // flag for comparator
170 | reg cmp_wait = 0; // asserted when waiting for comparator to finish
171 |
172 | always @(posedge CORE_CLK)
173 | if (cmp_start)
174 | cmp_start <= 0;
175 |
176 | else if (loop14_crypt24)
177 | if (cmp_ready_sync)
178 | cmp_start <= 1;
179 | else
180 | cmp_wait <= 1;
181 |
182 | else if (cmp_wait & cmp_ready_sync) begin
183 | cmp_wait <= 0;
184 | cmp_start <= 1;
185 | end
186 |
187 |
188 | // batch_num & pkt_num written on the next cycle after keys
189 | reg [`NUM_BATCHES_MSB:0] batch_num;
190 | reg [`NUM_BATCHES_MSB:0] cmp_batch_num [1:0];
191 | reg [`NUM_PKTS_MSB:0] pkt_num;
192 | reg [`NUM_PKTS_MSB:0] cmp_pkt_num [1:0];
193 |
194 | always @(posedge CORE_CLK) begin
195 | if (wr_en_r & addr_r[2:0] == 3'b110) begin
196 | batch_num <= addr_r[`NUM_BATCHES_MSB+3:3];
197 | pkt_num <= addr_r[`NUM_PKTS_MSB + `NUM_BATCHES_MSB+4 : `NUM_BATCHES_MSB+4];
198 | end
199 |
200 | if (write_result) begin
201 | cmp_batch_num[result_bank_wr] <= batch_num;
202 | cmp_pkt_num[result_bank_wr] <= pkt_num;
203 | end
204 | end
205 |
206 |
207 | // *********************************************************
208 | //
209 | // Comparator
210 | //
211 | // *********************************************************
212 |
213 | reg cmp_ready = 1; // asserted when it's ready for comparsion
214 |
215 | sync_sig sync_cmp_ready(.sig(cmp_ready), .clk(CORE_CLK), .out(cmp_ready_sync));
216 |
217 | // Assuming CMP_CLK frequency is less than CORE_CLK
218 | sync_short_sig sync_cmp_start(.sig(cmp_start), .clk(CMP_CLK), .out(cmp_start_sync));
219 |
220 | // Comparator configuration.
221 | localparam [`RAM_ADDR_MSB-1:0] READ_ADDR_INIT = {`RAM_ADDR_MSB{1'b1}};
222 | reg [`RAM_ADDR_MSB-1:0] read_addr_start = READ_ADDR_INIT;
223 | localparam [`RAM_ADDR_MSB-1:0] ADDR_DIFF_INIT = { 1'b1, {`RAM_ADDR_MSB-1{1'b0}} };
224 | reg [`RAM_ADDR_MSB-1:0] addr_diff_start = ADDR_DIFF_INIT;
225 |
226 |
227 | reg [`MSB(NUM_CRYPT_INSTANCES-1):0] cmp_instance = 0;
228 | reg [`HASH_MSB:0] cmp_hash;
229 | reg current_key_valid = 0;
230 |
231 | wire [`RAM_ADDR_MSB:0] ram_read_addr;
232 | reg [`RAM_ADDR_MSB:0] ram_read_addr_r;
233 | reg [`RAM_ADDR_MSB-1:0] read_addr_diff;
234 |
235 |
236 | // MSB in RAM indicates hash is valid
237 | (* RAM_STYLE = "BLOCK" *)
238 | reg [1+`HASH_MSB:0] ram [2**(`RAM_ADDR_MSB+1)-1:0];
239 | initial
240 | for (k=0; k < 2**(`RAM_ADDR_MSB+1); k=k+1)
241 | ram[k] = {1+`HASH_MSB+1{1'b0}};
242 |
243 |
244 | reg [`HASH_MSB:0] ram_out = 0, ram_out_r = 0;
245 | reg hash_valid = 0, hash_valid_r = 0;
246 | reg ram_rd_en = 0;
247 |
248 | always @(posedge CORE_CLK)
249 | if (wr_en_r & addr_r[0])
250 | ram[ addr_r[`RAM_ADDR_MSB+1:1] ] <= din_r[1+`HASH_MSB:0];
251 |
252 | always @(posedge CMP_CLK)
253 | if (ram_rd_en)
254 | {hash_valid, ram_out} <= ram[ram_read_addr];
255 |
256 | wire EQUAL = current_key_valid & hash_valid_r & cmp_hash == ram_out_r;
257 |
258 | // Bsearch-type comparator. Expecting hashes in RAM are in ascending order.
259 | // On the 1st read from memory on a new search, 'ram_read_start' is asserted.
260 | wire ram_read_start =
261 | cmp_state == CMP_STATE_START || EQUAL || !read_addr_diff || ~current_key_valid;
262 |
263 | assign ram_read_addr =
264 | ram_read_start ? { 1'b0, read_addr_start } :
265 | !hash_valid_r || cmp_hash < ram_out_r ? ram_read_addr_r - read_addr_diff :
266 | ram_read_addr_r + read_addr_diff;
267 |
268 |
269 | localparam CMP_STATE_IDLE = 0,
270 | CMP_STATE_START = 1,
271 | CMP_STATE_READ = 2,
272 | CMP_STATE_COMPARE = 3;
273 |
274 | (* FSM_EXTRACT="true" *)
275 | reg [1:0] cmp_state = CMP_STATE_IDLE;
276 |
277 | always @(posedge CMP_CLK) begin
278 | case (cmp_state)
279 | CMP_STATE_IDLE: begin
280 | dout_wr_en <= 0;
281 | if (cmp_start_sync) begin
282 | if (!cmp_ready)
283 | cmp_error <= 1;
284 | cmp_ready <= 0;
285 |
286 | ram_read_addr_r <= { 1'b0, read_addr_start };
287 | read_addr_diff <= addr_diff_start;
288 |
289 | ram_rd_en <= 1;
290 | cmp_state <= CMP_STATE_START;
291 | end
292 | end
293 |
294 | CMP_STATE_START: begin // 1st read from ram
295 | ram_rd_en <= 0;
296 | cmp_state <= CMP_STATE_READ;
297 | end
298 |
299 | CMP_STATE_READ: begin // hash_valid, ram_out signals valid
300 | dout_wr_en <= 0;
301 |
302 | hash_valid_r <= hash_valid;
303 | ram_out_r <= ram_out;
304 | {current_key_valid, cmp_hash} <= result [ {result_bank_rd, cmp_instance} ];
305 |
306 | ram_rd_en <= 1;
307 | cmp_state <= CMP_STATE_COMPARE;
308 | end
309 |
310 | CMP_STATE_COMPARE: begin
311 | ram_rd_en <= 0;
312 |
313 | if (EQUAL || !read_addr_diff || ~current_key_valid) begin // search for current hash ends
314 | // can't write.
315 | if (dout_full) begin
316 | end
317 | // write result, proceed with next comparsion
318 | else begin
319 | dout <= ram_read_addr_r;
320 | dout_instance <= cmp_instance;
321 | dout_equal <= EQUAL;
322 | dout_key_valid <= current_key_valid;
323 | dout_batch_num <= cmp_batch_num[result_bank_rd];
324 | dout_pkt_num <= cmp_pkt_num[result_bank_rd];
325 | // Output equality or(and) batch_complete
326 | if (EQUAL || cmp_instance == NUM_CRYPT_INSTANCES - 1)
327 | dout_wr_en <= 1;
328 |
329 | ram_read_addr_r <= { 1'b0, read_addr_start };
330 | read_addr_diff <= addr_diff_start;
331 | if (cmp_instance == NUM_CRYPT_INSTANCES - 1) begin // comparsion of all instances ends
332 | cmp_ready <= 1;
333 | dout_batch_complete <= 1;
334 | cmp_instance <= 0;
335 | result_bank_rd <= ~result_bank_rd;
336 | cmp_state <= CMP_STATE_IDLE;
337 | end
338 | else begin // comparsion of next hash
339 | dout_batch_complete <= 0;
340 | cmp_instance <= cmp_instance + 1'b1;
341 | cmp_state <= CMP_STATE_READ;
342 | end
343 | end // ~dout_full
344 | end
345 |
346 | else begin
347 | ram_read_addr_r <= ram_read_addr;
348 | read_addr_diff <= read_addr_diff >> 1;
349 | cmp_state <= CMP_STATE_READ;
350 | end
351 | end
352 |
353 | endcase
354 | end
355 |
356 |
357 | endmodule
358 |
359 |
360 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/descrypt_round.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ns
2 |
3 | `include "descrypt.vh"
4 |
5 | // rounds 1-15 don't have ENABLE_CRYPT
6 | module descrypt_round #(
7 | parameter [0:0] ROTATE2 = 1
8 | )(
9 | input CLK,
10 |
11 | input [`SALT_MSB:0] salt_in,
12 | input [55:0] CiDi_in,
13 | input [63:0] Ti_in,
14 | input valid_in,
15 |
16 | output [55:0] CiDi_out,
17 | output [63:0] Ti_out,
18 | output reg valid_out = 0
19 | );
20 |
21 | //(* SHREG_EXTRACT="NO" *)
22 | reg [55:0] CiDi;
23 | wire [47:0] Ki;
24 | rotate_1or2_pc2 rotate_1or2_pc2_instance(ROTATE2[0], CiDi, CiDi_out, Ki);
25 |
26 | always @(posedge CLK)
27 | CiDi <= CiDi_in;
28 |
29 |
30 | reg [63:0] Ti = 0;
31 |
32 | des_loop des_loop_instance(
33 | .Ti_in(Ti),
34 | .Ki(Ki),
35 | .salt_in(salt_in),
36 | .Ti_out(Ti_out)
37 | );
38 |
39 | always @(posedge CLK)
40 | Ti <= Ti_in;
41 |
42 | always @(posedge CLK)
43 | valid_out <= valid_in;
44 |
45 | endmodule
46 |
47 |
48 | module descrypt_round0(
49 | input CLK,
50 | input ENABLE_CRYPT,
51 | input START_CRYPT,
52 |
53 | input [`SALT_MSB:0] salt_in,
54 | input [55:0] CiDi_in,
55 | input [63:0] Ti_in,
56 | input valid_in,
57 |
58 | output [55:0] CiDi_out,
59 | output [63:0] Ti_out,
60 | reg valid_out = 0
61 | );
62 |
63 | //(* SHREG_EXTRACT="NO" *)
64 | reg [55:0] CiDi;
65 | wire [47:0] Ki;
66 | rotate_1or2_pc2 rotate_1or2_pc2_instance(1'b0, CiDi, CiDi_out, Ki);
67 |
68 | always @(posedge CLK)
69 | if (ENABLE_CRYPT)
70 | CiDi <= CiDi_in;
71 |
72 |
73 | reg [63:0] Ti = 0;
74 |
75 | des_loop des_loop_instance(
76 | .Ti_in(Ti),
77 | .Ki(Ki),
78 | .salt_in(salt_in),
79 | .Ti_out(Ti_out)
80 | );
81 |
82 | always @(posedge CLK)
83 | if (START_CRYPT)
84 | Ti <= 0;
85 | else if (ENABLE_CRYPT)
86 | Ti <= Ti_in;
87 |
88 | always @(posedge CLK)
89 | if (ENABLE_CRYPT)
90 | valid_out <= valid_in;
91 |
92 | endmodule
93 |
94 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/pc1.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // ******************************************************************
4 | // * Permuted-choice 1 from the key bits to yield C and D.
5 | // * Note that bits 8,16... are left out:
6 | // * They are intended for a parity check.
7 | // ******************************************************************
8 |
9 | module pc1(
10 | input [64:1] din,
11 | output [55:0] dout
12 | );
13 |
14 | assign dout = {
15 | din[4], din[12], din[20], din[28], din[5], din[13], din[21],
16 | din[29], din[37], din[45], din[53], din[61], din[6], din[14],
17 | din[22], din[30], din[38], din[46], din[54], din[62], din[7],
18 | din[15], din[23], din[31], din[39], din[47], din[55], din[63],
19 |
20 | din[36], din[44], din[52], din[60], din[3], din[11], din[19],
21 | din[27], din[35], din[43], din[51], din[59], din[2], din[10],
22 | din[18], din[26], din[34], din[42], din[50], din[58], din[1],
23 | din[9], din[17], din[25], din[33], din[41], din[49], din[57]
24 | };
25 |
26 | endmodule
27 |
--------------------------------------------------------------------------------
/fpga/descrypt/descrypt_core/rotate_1or2_pc2.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ns
2 |
3 |
4 | module rotate_1or2_pc2(
5 | input rotate2,
6 | input [55:0] CiDi_in,
7 | output [55:0] CiDi_out,
8 | output [47:0] k
9 | );
10 |
11 | wire [27:0] Ci = CiDi_in[27:0];
12 | wire [27:0] Di = CiDi_in[55:28];
13 | wire [55:0] cd;
14 | assign cd = rotate2 ?
15 | { Di[1], Di[0], Di[27:2], Ci[1], Ci[0], Ci[27:2] } :
16 | { Di[0], Di[27:1], Ci[0], Ci[27:1] };
17 |
18 | assign CiDi_out = cd;
19 |
20 | assign k = {
21 | cd[31], cd[28], cd[35], cd[49], cd[41], cd[45], cd[52], cd[33], cd[55], cd[38], cd[48], cd[43],
22 | cd[47], cd[32], cd[44], cd[50], cd[39], cd[29], cd[54], cd[46], cd[36], cd[30], cd[51], cd[40],
23 |
24 | cd[1], cd[12], cd[19], cd[26], cd[6], cd[15], cd[7], cd[25], cd[3], cd[11], cd[18], cd[22],
25 | cd[9], cd[20], cd[5], cd[14], cd[27], cd[2], cd[4], cd[0], cd[23], cd[10], cd[16], cd[13]
26 | };
27 |
28 | endmodule
29 |
--------------------------------------------------------------------------------
/fpga/descrypt/wrapper_v2.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | `include "descrypt_core/descrypt.vh"
4 |
5 | module wrapper_v2 #(
6 | parameter N_CORES = -1,
7 | parameter [N_CORES*16+15 : 0] CORES_CONF = 0,
8 | parameter NUM_CRYPT_INSTANCES = 16
9 | )(
10 | input CORE_CLK,
11 | input [`DIN_MSB:0] din,
12 | input [`RAM_ADDR_MSB+1:0] addr_in,
13 |
14 | input [N_CORES-1 :0] wr_en,
15 | output [N_CORES-1 :0] crypt_ready,
16 | output [N_CORES-1 :0] core_idle,
17 | output [N_CORES-1 :0] err_core,
18 |
19 | input CMP_CLK,
20 | output reg [N_CORES * (`RAM_ADDR_MSB+1) - 1 :0] dout,
21 | output reg [N_CORES * (`MSB(NUM_CRYPT_INSTANCES-1)+1) - 1 :0] dout_instance,
22 | output reg [N_CORES-1 :0] dout_equal,
23 | output reg [N_CORES-1 :0] dout_key_valid,
24 | output reg [N_CORES * (`NUM_BATCHES_MSB+1) - 1 :0] dout_batch_num,
25 | output reg [N_CORES * (`NUM_PKTS_MSB+1) - 1 :0] dout_pkt_num,
26 | output reg [N_CORES-1 :0] dout_batch_complete,
27 | output reg [N_CORES-1 :0] err_cmp = 0,
28 |
29 | input [N_CORES-1 :0] rd_en,
30 | output [N_CORES-1 :0] empty
31 | );
32 |
33 | // Input register stages (broadcast)
34 | (* SHREG_EXTRACT="NO", EQUIVALENT_REGISTER_REMOVAL="NO" *)
35 | reg [`DIN_MSB:0] din_r1, din_r2;
36 | (* SHREG_EXTRACT="NO", EQUIVALENT_REGISTER_REMOVAL="NO" *)
37 | reg [`RAM_ADDR_MSB+1:0] addr_in_r1, addr_in_r2;
38 |
39 | always @(posedge CORE_CLK) begin
40 | din_r1 <= din;
41 | addr_in_r1 <= addr_in;
42 |
43 | din_r2 <= din_r1;
44 | addr_in_r2 <= addr_in_r1;
45 | end
46 |
47 |
48 |
49 | genvar i;
50 | generate
51 | for (i=0; i < N_CORES; i=i+1) begin:core_gen
52 |
53 | localparam INPUT_R_STAGES = CORES_CONF[i*16+3 : i*16+2];
54 | localparam OUTPUT_R_STAGES = CORES_CONF[i*16+1 : i*16+0];
55 |
56 | // Input register stages
57 | (* SHREG_EXTRACT="NO" *) reg wr_en_r1 = 0, wr_en_r2 = 0;
58 |
59 | // Status signals from the core @ CORE_CLK
60 | (* SHREG_EXTRACT="NO" *) reg crypt_ready_r1, crypt_ready_r2;
61 | (* SHREG_EXTRACT="NO" *) reg core_idle_r1, core_idle_r2;
62 | (* SHREG_EXTRACT="NO" *) reg err_core_r1 = 0, err_core_r2 = 0;
63 |
64 | always @(posedge CORE_CLK) begin
65 | wr_en_r1 <= wr_en[i];
66 | crypt_ready_r1 <= crypt_ready_in; // ready to get a batch keys
67 | err_core_r1 <= core_error;
68 | // no data in descrypt instances and in the comparator;
69 | // there still might be valid data in output register.
70 | core_idle_r1 <= crypt_ready_in & cmp_ready;
71 |
72 | wr_en_r2 <= wr_en_r1;
73 | crypt_ready_r2 <= crypt_ready_r1;
74 | core_idle_r2 <= core_idle_r1;
75 | err_core_r2 <= err_core_r1;
76 | end
77 |
78 | assign crypt_ready[i] = INPUT_R_STAGES==1 ? crypt_ready_r1 : crypt_ready_r2;
79 | assign core_idle[i] = INPUT_R_STAGES==1 ? core_idle_r1 : core_idle_r2;
80 | assign err_core[i] = INPUT_R_STAGES==1 ? err_core_r1 : err_core_r2;
81 |
82 |
83 | // Output from the core @ CMP_CLK
84 | reg dout_full_r1 = 0, dout_full_r2 = 0; // Output register is full.
85 |
86 | wire [`RAM_ADDR_MSB:0] core_dout;
87 | wire [`NUM_BATCHES_MSB:0] core_dout_batch_num;
88 | wire [`MSB(NUM_CRYPT_INSTANCES-1):0] core_dout_instance;
89 | wire [`NUM_PKTS_MSB:0] core_dout_pkt_num;
90 |
91 | (* KEEP_HIERARCHY="true" *)
92 | descrypt_core_v5 core(
93 | .CORE_CLK(CORE_CLK),
94 | .din(INPUT_R_STAGES==1 ? din_r1 : din_r2),
95 | .addr_in(INPUT_R_STAGES==1 ? addr_in_r1 : addr_in_r2),
96 | .wr_en(INPUT_R_STAGES==1 ? wr_en_r1 : wr_en_r2),
97 | .crypt_ready(crypt_ready_in), .cmp_ready_sync(cmp_ready),
98 |
99 | .CMP_CLK(CMP_CLK),
100 | .dout_full(INPUT_R_STAGES==1 ? dout_full_r1 : dout_full_r2),
101 | .dout(core_dout),
102 | .dout_instance(core_dout_instance),
103 | .dout_equal(core_dout_equal),
104 | .dout_key_valid(core_dout_key_valid),
105 | .dout_batch_num(core_dout_batch_num),
106 | .dout_pkt_num(core_dout_pkt_num),
107 | .dout_batch_complete(core_dout_batch_complete),
108 | .dout_wr_en(core_dout_wr_en),
109 | .core_error(core_error),
110 | .cmp_error(cmp_error)
111 | );
112 |
113 | //
114 | // Extra register stage for output (CMP_CLK)
115 | //
116 | (* SHREG_EXTRACT="NO" *) reg [`RAM_ADDR_MSB:0] dout_r2;
117 | (* SHREG_EXTRACT="NO" *) reg [`MSB(NUM_CRYPT_INSTANCES-1):0] dout_instance_r2;
118 | (* SHREG_EXTRACT="NO" *) reg dout_equal_r2;
119 | (* SHREG_EXTRACT="NO" *) reg dout_key_valid_r2;
120 | (* SHREG_EXTRACT="NO" *) reg [`NUM_BATCHES_MSB:0] dout_batch_num_r2;
121 | (* SHREG_EXTRACT="NO" *) reg [`NUM_PKTS_MSB:0] dout_pkt_num_r2;
122 | (* SHREG_EXTRACT="NO" *) reg dout_batch_complete_r2;
123 | (* SHREG_EXTRACT="NO" *) reg err_cmp_r2 = 0;
124 |
125 | always @(posedge CMP_CLK) begin
126 | if (INPUT_R_STAGES == 2 & core_dout_wr_en) begin
127 | dout_full_r2 <= 1;
128 | dout_r2 <= core_dout;
129 | dout_instance_r2 <= core_dout_instance;
130 | dout_equal_r2 <= core_dout_equal;
131 | dout_key_valid_r2 <= core_dout_key_valid;
132 | dout_batch_num_r2 <= core_dout_batch_num;
133 | dout_pkt_num_r2 <= core_dout_pkt_num;
134 | dout_batch_complete_r2 <= core_dout_batch_complete;
135 | err_cmp_r2 <= cmp_error;
136 | end
137 | else if (INPUT_R_STAGES == 2 & rd_en_internal) begin
138 | dout_full_r2 <= 0;
139 | end
140 | end
141 |
142 | wire rd_en_internal = ~dout_full_r1 & dout_full_r2;
143 |
144 | always @(posedge CMP_CLK) begin
145 | if (INPUT_R_STAGES == 1 & core_dout_wr_en | INPUT_R_STAGES == 2 & rd_en_internal) begin
146 | dout_full_r1 <= 1;
147 | dout[(i+1) * (`RAM_ADDR_MSB+1)-1 -:`RAM_ADDR_MSB+1]
148 | <= INPUT_R_STAGES == 1 ? core_dout : dout_r2;
149 |
150 | dout_instance[(i+1) * (`MSB(NUM_CRYPT_INSTANCES-1)+1)-1 -:`MSB(NUM_CRYPT_INSTANCES-1)+1]
151 | <= INPUT_R_STAGES == 1 ? core_dout_instance : dout_instance_r2;
152 |
153 | dout_equal[i] <= INPUT_R_STAGES == 1 ? core_dout_equal : dout_equal_r2;
154 | dout_key_valid[i] <= INPUT_R_STAGES == 1 ? core_dout_key_valid : dout_key_valid_r2;
155 | dout_batch_num[(i+1) * (`NUM_BATCHES_MSB+1)-1 -:`NUM_BATCHES_MSB+1]
156 | <= INPUT_R_STAGES == 1 ? core_dout_batch_num : dout_batch_num_r2;
157 |
158 | dout_pkt_num [(i+1) * (`NUM_PKTS_MSB+1)-1 -:`NUM_PKTS_MSB+1]
159 | <= INPUT_R_STAGES == 1 ? core_dout_pkt_num : dout_pkt_num_r2;
160 |
161 | dout_batch_complete[i] <= INPUT_R_STAGES == 1 ? core_dout_batch_complete : dout_batch_complete_r2;
162 | err_cmp[i] <= INPUT_R_STAGES == 1 ? cmp_error : err_cmp_r2;
163 | end
164 | else if (rd_en[i]) begin
165 | dout_full_r1 <= 0;
166 | end
167 | end
168 |
169 | assign empty[i] = ~dout_full_r1;
170 |
171 | end
172 | endgenerate
173 |
174 |
175 | endmodule
176 |
177 | /*
178 | // It removes equivalent instances.
179 | module in_r(
180 | input CLK,
181 | input [`DIN_MSB:0] din,
182 | input [`RAM_ADDR_MSB+1:0] addr_in,
183 | (* SHREG_EXTRACT="NO", EQUIVALENT_REGISTER_REMOVAL="NO" *)
184 | output reg [`DIN_MSB:0] dout,
185 | (* SHREG_EXTRACT="NO", EQUIVALENT_REGISTER_REMOVAL="NO" *)
186 | output reg [`RAM_ADDR_MSB+1:0] addr_out
187 | );
188 |
189 | always @(posedge CLK) begin
190 | dout <= din;
191 | addr_out <= addr_in;
192 | end
193 |
194 | endmodule
195 | */
--------------------------------------------------------------------------------
/fpga/hs_io.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //*****************************************************************************
4 | //
5 | // High-Speed communtcation to USB device controller's Slave FIFO
6 | //
7 | // It is implemented on a state machine with outputs dependent on both input
8 | // and internal state. That's slow and is unable to operate at 48 MHz IFCLK.
9 | //
10 | //*****************************************************************************
11 |
12 | module hs_io #(
13 | parameter USB_ENDPOINT_IN = 2, // from the point of view from the host
14 | parameter USB_ENDPOINT_OUT = 6
15 | )(
16 | input IFCLK,
17 | // Low CS puts all outputs into Z-state,
18 | // exactly as examples/intraffic is doing
19 | input CS,
20 |
21 | // enable read/write
22 | input EN,
23 |
24 | // Attention: attempt to send data to FPGA not aligned to
25 | // 2-byte word would result in a junk in upper byte
26 | input [15:0] FIFO_DATA_IN,
27 | output FIFOADR0,
28 | output FIFOADR1,
29 | // Following signals are active low.
30 | output SLOE, // Slave output enable
31 | output SLRD,
32 | output SLWR,
33 | output PKTEND,
34 | input FLAGB, // FULL
35 | input FLAGC, // EMPTY
36 |
37 | output rw_direction,
38 |
39 | // write into some internal FIFO
40 | output [15:0] dout,
41 | output wr_en,
42 | //input full,
43 | input almost_full,
44 |
45 | // read from some internal FIFO
46 | //input [15:0] din,
47 | output rd_en,
48 | input empty,
49 |
50 | // status information
51 | output [7:0] io_timeout, // in ~1us intervals @30MHz IFCLK
52 | output sfifo_not_empty,
53 | output io_fsm_error
54 | );
55 |
56 | wire ENABLE = EN && CS;
57 |
58 | assign sfifo_not_empty = FLAGC;
59 | assign io_fsm_error = 1'b0;
60 |
61 | // Input register (data-out from hs_io)
62 | (* KEEP="true" *) reg [15:0] input_r;
63 | assign dout = input_r;
64 | always @(posedge IFCLK)
65 | input_r <= FIFO_DATA_IN;
66 |
67 | (* KEEP_HIERARCHY="true" *) hs_io_logic hs_io_logic_inst(
68 | .IFCLK(IFCLK), .ENABLE(ENABLE),
69 | .FLAGB(FLAGB), .FLAGC(FLAGC),
70 | .rw_direction(rw_direction), .input_r_ok(input_r_ok),
71 | .IO_WRITE_OK(IO_WRITE_OK), .IO_READ_OK(IO_READ_OK),
72 | .IO_SLOE_OK(IO_SLOE_OK), .IO_PKTEND_OK(IO_PKTEND_OK),
73 | .full(almost_full), .empty(empty),
74 | .io_timeout(io_timeout)
75 | );
76 |
77 | assign SLOE = ~CS ? 1'bz : EN ? ~IO_SLOE_OK : 1'b1;
78 | assign SLRD = ~CS ? 1'bz : EN ? ~IO_READ_OK : 1'b1;
79 | assign wr_en = input_r_ok;
80 |
81 | assign SLWR = ~CS ? 1'bz : EN ? ~IO_WRITE_OK : 1'b1;
82 | assign rd_en = IO_WRITE_OK;
83 | assign PKTEND = ~CS ? 1'bz : EN ? ~IO_PKTEND_OK : 1'b1;
84 |
85 | localparam USB_EP_OUT_B = (USB_ENDPOINT_OUT-2) >> 1;
86 | localparam USB_EP_IN_B = (USB_ENDPOINT_IN-2) >> 1;
87 | assign {FIFOADR1, FIFOADR0} =
88 | ~CS ? 2'bz :
89 | EN && rw_direction ? USB_EP_IN_B[1:0] :
90 | USB_EP_OUT_B[1:0];
91 |
92 | endmodule
93 |
94 |
95 | /////////////////////////////////////////////////////////////////////
96 | //
97 | // Gather the stuff in some place near FLAG{B,C}, SL{WR/RD}
98 | // SLICE_X124Y120:SLICE_X127Y127
99 | //
100 | /////////////////////////////////////////////////////////////////////
101 | module hs_io_logic (
102 | input IFCLK,
103 | input ENABLE,
104 | output reg rw_direction = 0,
105 | output reg input_r_ok = 0,
106 | output IO_WRITE_OK,
107 | output IO_READ_OK,
108 | output IO_SLOE_OK,
109 | output IO_PKTEND_OK,
110 | input FLAGB, // FULL
111 | input FLAGC, // EMPTY
112 | input full,
113 | input empty,
114 | output [7:0] io_timeout // in ~1us intervals @30MHz IFCLK
115 | );
116 |
117 | // It works as follows:
118 | // 1. reads as long as possible; //up to USB_PKT_SIZE,
119 | // 2. writes up to USB_PKT_SIZE.
120 | localparam USB_PKT_SIZE = 256; // in 16-bit words
121 | reg [8:0] word_counter = 0;
122 |
123 | localparam TIMEOUT_MSB = 12;
124 | reg [TIMEOUT_MSB:0] timeout = 0;//{TIMEOUT_MSB+1{1'b1}};
125 | assign io_timeout = timeout[TIMEOUT_MSB : TIMEOUT_MSB-7];
126 |
127 | // Finally deal with PKTEND issue.
128 | // - when output FIFO is in mode_limit, there's no problem:
129 | // FIFO already has all the data, so it outputs every cycle
130 | // until EMPTY.
131 | // - when mode_limit is off, the data might arrive from FPGA's output FIFO
132 | // in small pieces such as 2-8 bytes or so, with intervals like 2-4 cycles.
133 | // That might result in partial reads by the host and overall performance degradation.
134 | //
135 | localparam PKTEND_WR_TIMEOUT = 5;
136 | reg [2:0] rw_timeout = 0;
137 |
138 | wire READ_OK = (!full && FLAGC && ENABLE);// && word_counter < USB_PKT_SIZE);
139 | wire WRITE_OK = (!empty && FLAGB && ENABLE && word_counter != USB_PKT_SIZE);
140 | //wire PKTEND_OK = (empty && FLAGB && ENABLE && word_counter > 0 && word_counter < USB_PKT_SIZE);
141 |
142 | localparam IO_STATE_RESET = 1;
143 | localparam IO_STATE_READ_SETUP0 = 2;
144 | localparam IO_STATE_READ_SETUP1 = 3;
145 | localparam IO_STATE_READ_SETUP2 = 4;
146 | localparam IO_STATE_READ = 6;
147 | localparam IO_STATE_WR_SETUP0 = 7;
148 | localparam IO_STATE_WR_SETUP1 = 8;
149 | localparam IO_STATE_WR_SETUP2 = 9;
150 | localparam IO_STATE_WR = 11;
151 | localparam IO_STATE_DISABLED = 13;
152 | localparam IO_STATE_WR_WAIT = 14;
153 |
154 | (* FSM_EXTRACT="YES" *)//,FSM_ENCODING="auto" *)
155 | reg [3:0] io_state = IO_STATE_RESET;
156 |
157 | always @(posedge IFCLK)
158 | begin
159 | if (!ENABLE && io_state != IO_STATE_DISABLED)
160 | io_state <= IO_STATE_DISABLED;
161 |
162 | if ( ! (&timeout[TIMEOUT_MSB : TIMEOUT_MSB-7]) )
163 | timeout <= timeout + 1'b1;
164 |
165 | (* FULL_CASE, PARALLEL_CASE *) case (io_state)
166 | IO_STATE_RESET: begin
167 | //timeout <= {TIMEOUT_MSB+1{1'b1}};
168 | io_state <= IO_STATE_READ_SETUP0;
169 | end
170 |
171 | IO_STATE_READ_SETUP0: begin
172 | rw_direction <= 0;
173 | //word_counter <= 0;
174 | io_state <= IO_STATE_READ_SETUP1;
175 | end
176 |
177 | IO_STATE_READ_SETUP1:
178 | io_state <= IO_STATE_READ_SETUP2;
179 |
180 | IO_STATE_READ_SETUP2:
181 | io_state <= IO_STATE_READ;
182 |
183 | IO_STATE_READ: begin
184 | if (READ_OK) begin
185 | input_r_ok <= 1;
186 | //word_counter <= word_counter + 1'b1;
187 | timeout <= 0;
188 | end
189 | else begin
190 | input_r_ok <= 0;
191 | io_state <= IO_STATE_WR_SETUP0;
192 | end
193 |
194 | end
195 |
196 | IO_STATE_WR_SETUP0: begin
197 | rw_direction <= 1;
198 | word_counter <= 0;
199 | io_state <= IO_STATE_WR_SETUP1;
200 | end
201 |
202 | IO_STATE_WR_SETUP1:
203 | io_state <= IO_STATE_WR_SETUP2;
204 |
205 | IO_STATE_WR_SETUP2:
206 | io_state <= IO_STATE_WR;
207 |
208 | IO_STATE_WR: begin
209 | if (WRITE_OK) begin
210 | word_counter <= word_counter + 1'b1;
211 | timeout <= 0;
212 | rw_timeout <= 0;
213 | end
214 | else begin
215 | if (!FLAGB || word_counter == USB_PKT_SIZE || word_counter == 0)
216 | io_state <= IO_STATE_READ_SETUP0;
217 |
218 | else if (rw_timeout == PKTEND_WR_TIMEOUT)
219 | io_state <= IO_STATE_WR_WAIT;
220 |
221 | rw_timeout <= rw_timeout + 1'b1;
222 | end
223 | end
224 |
225 | IO_STATE_WR_WAIT: begin
226 | io_state <= IO_STATE_READ_SETUP0;
227 | end
228 |
229 | IO_STATE_DISABLED: begin
230 | rw_direction <= 0;
231 | if (ENABLE)
232 | io_state <= IO_STATE_READ_SETUP0;
233 | end
234 | endcase
235 | end // IFCLK
236 |
237 | assign IO_READ_OK = io_state == IO_STATE_READ && READ_OK;
238 | assign IO_WRITE_OK = io_state == IO_STATE_WR && WRITE_OK;
239 |
240 | assign IO_SLOE_OK = (io_state == IO_STATE_READ_SETUP2 || io_state == IO_STATE_READ);
241 | assign IO_PKTEND_OK = io_state == IO_STATE_WR_WAIT;//IO_STATE_WR && PKTEND_OK;
242 |
243 | endmodule
244 |
245 |
--------------------------------------------------------------------------------
/fpga/hs_io_v2.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //*****************************************************************************
4 | //
5 | // High-Speed communtcation to USB device controller's Slave FIFO
6 | //
7 | // For Slave FIFO's signaling and timing diagram, see CY7C68013-56PVC-Datasheet
8 | //
9 | // Version 1 comment:
10 | //
11 | // It is implemented on a state machine with outputs dependent on both input
12 | // and internal state. That's slow and is unable to operate at 48 MHz IFCLK.
13 | //
14 | // Version 2 improvements:
15 | //
16 | // 1. Removed asynchronous circuitry. That allows to operate at 48 MHz,
17 | // removes synchronization to CPU issues.
18 | // 2. I/O registers placed most close to pins - into ILOGIC/OLOGIC components.
19 | // That removes the nesessity to manually allocate areas in UCF file.
20 | // IFCLK appears to arrive too late, added some phase backshift.
21 | // 3. One cycle delay when switching control outputs into Z-state on CS deassertion
22 | // so controls for Slave FIFO (active low) always in a defined state.
23 | //
24 | //*****************************************************************************
25 |
26 | module hs_io_v2 #(
27 | parameter USB_ENDPOINT_IN = 2, // from the point of view from the host
28 | parameter USB_ENDPOINT_OUT = 6
29 | )(
30 | input IFCLK,
31 | // Low CS puts all outputs into Z-state,
32 | // exactly as examples/intraffic is doing
33 | input CS,
34 | input out_z_wait1,
35 |
36 | // enable read/write
37 | // Deasserted EN doesn't perform read/write,
38 | // keeps signals for Slave FIFO in proper state.
39 | input EN,
40 |
41 | // Attention: attempt to send data to FPGA not aligned to
42 | // 2-byte word would result in a junk in upper byte
43 | inout [15:0] FIFO_DATA,
44 | output FIFOADR0,
45 | output FIFOADR1,
46 | // Following signals are active low.
47 | output SLOE, // Slave output enable
48 | output SLRD,
49 | output SLWR,
50 | output PKTEND,
51 | // FLAGA/B/C are fixed (independent from FIFOADR)
52 | input FLAGA, // PROG_FULL
53 | input FLAGB, // FULL
54 | input FLAGC, // EMPTY
55 |
56 | // write into some internal FIFO
57 | output [15:0] dout,
58 | output wr_en,
59 | //input full,
60 | input almost_full,
61 |
62 | // read from some internal FIFO
63 | input [15:0] din,
64 | output rd_en,
65 | input empty,
66 |
67 | // status information
68 | output [7:0] io_timeout, // in ~1us intervals @30MHz IFCLK
69 | output reg io_fsm_error = 0, // CS or EN deasserted while active I/O
70 | output reg sfifo_not_empty = 0,
71 | output reg io_err_write = 0
72 | );
73 |
74 | reg rw_direction = 0; // 1: FPGA writes
75 |
76 | always @(posedge IFCLK)
77 | if (CS & EN)
78 | sfifo_not_empty <= FLAGC_R;
79 |
80 | // Timeout
81 | localparam TIMEOUT_MSB = 12;
82 | reg [TIMEOUT_MSB:0] timeout = {TIMEOUT_MSB+1{1'b1}};
83 | assign io_timeout = timeout[TIMEOUT_MSB : TIMEOUT_MSB-7];
84 |
85 |
86 | // FIFOADR (Address for USB endpoint buffer)
87 | // - at 48 MHz, sometimes takes 2 cycles to propagate
88 | localparam USB_EP_OUT_B = (USB_ENDPOINT_OUT-2) >> 1;
89 | localparam USB_EP_IN_B = (USB_ENDPOINT_IN-2) >> 1;
90 | assign {FIFOADR1, FIFOADR0} =
91 | out_z_wait1 ? 2'bz :
92 | rw_direction ? USB_EP_IN_B[1:0] :
93 | USB_EP_OUT_B[1:0];
94 |
95 |
96 | // *************************
97 | //
98 | // High-Speed Input
99 | //
100 | // *************************
101 |
102 | // FPGA's Input register (data-out from hs_io)
103 | (* IOB="true" *) reg [15:0] input_r;
104 | assign dout = input_r;
105 | always @(posedge IFCLK)
106 | input_r <= FIFO_DATA;
107 |
108 | (* IOB="true" *) reg FLAGC_R = 0;
109 | always @(posedge IFCLK)
110 | FLAGC_R <= FLAGC;
111 |
112 | (* IOB="true" *) reg SLOE_R = 1;
113 | assign SLOE = out_z_wait1 ? 1'bz : SLOE_R;
114 |
115 | (* IOB="true" *) reg SLRD_R = 1;
116 | assign SLRD = out_z_wait1 ? 1'bz : SLRD_R;
117 |
118 | // input_r_ok indicates there was read last cycle (SLRD was active)
119 | reg input_r_ok = 0;
120 | always @(posedge IFCLK)
121 | input_r_ok <= ~SLRD_R;
122 | assign wr_en = input_r_ok & FLAGC_R;
123 |
124 |
125 | // *************************
126 | //
127 | // High-Speed Output
128 | //
129 | // *************************
130 |
131 | // FLAGA(active low) is configured to be active when 0 bytes in buffer
132 | (* IOB="true" *) reg FLAGA_R = 1;
133 | always @(posedge IFCLK)
134 | FLAGA_R <= FLAGA;
135 |
136 | (* IOB="true" *) reg FLAGB_R = 0;
137 | always @(posedge IFCLK)
138 | FLAGB_R <= FLAGB;
139 |
140 | (* IOB="true" *) reg SLWR_R = 1;
141 | assign SLWR = out_z_wait1 ? 1'bz : SLWR_R;
142 |
143 | // FPGA's output register.
144 | // valid data must be present on output 9.2 ns before write
145 | (* IOB="true" *) reg [15:0] output_r;
146 | // Tristate-enable FF inside OLOGIC component
147 | (* IOB="true" *) reg out_z = 1;
148 | assign FIFO_DATA = out_z ? 16'bz : output_r;
149 | always @(posedge IFCLK)
150 | out_z <= ~(CS & EN & rw_direction);
151 |
152 | // Flag indicates valid data in output register.
153 | // Could be better if output FIFO had almost_empty flag.
154 | reg output_r_valid = 0;
155 | assign rd_en = (~SLWR_R | io_state == IO_STATE_WR_SETUP1 & ~output_r_valid);
156 |
157 | (* IOB="true" *) reg PKTEND_R = 1;
158 | assign PKTEND = out_z_wait1 ? 1'bz : PKTEND_R;
159 |
160 |
161 | // It works as follows:
162 | // 1. reads as long as possible;
163 | // 2. writes up to USB_PKT_SIZE.
164 | localparam USB_PKT_SIZE = 256; // in 16-bit words
165 | reg [8:0] word_counter = 0;
166 |
167 | // Finally deal with PKTEND issue.
168 | // - when output FIFO is in mode_limit, there's no problem:
169 | // FIFO already has all the data, so it outputs every cycle
170 | // until EMPTY.
171 | // - when mode_limit is off, the data might arrive from FPGA's output FIFO
172 | // in small pieces such as 2-8 bytes or so, with intervals like 2-4 cycles.
173 | // That might result in partial reads by the host and overall performance degradation.
174 | //
175 | localparam PKTEND_WR_TIMEOUT = 5;
176 | reg [2:0] wr_timeout = 0;
177 |
178 |
179 | //localparam IO_STATE_RESET = 1;
180 | localparam IO_STATE_READ_SETUP0 = 2;
181 | localparam IO_STATE_READ_SETUP1 = 3;
182 | localparam IO_STATE_READ_SETUP2 = 4;
183 | localparam IO_STATE_READ = 6;
184 | localparam IO_STATE_WR_SETUP0 = 7;
185 | localparam IO_STATE_WR_SETUP1 = 8;
186 | localparam IO_STATE_WR_SETUP2 = 9;
187 | localparam IO_STATE_WR = 11;
188 | localparam IO_STATE_DISABLED = 13;
189 | localparam IO_STATE_WR_WAIT = 14;
190 | localparam IO_STATE_PKT_COMMIT = 15;
191 |
192 | (* FSM_EXTRACT="YES" *)
193 | reg [4:0] io_state = IO_STATE_DISABLED;
194 |
195 | always @(posedge IFCLK)
196 | begin
197 | if ( ! (&timeout[TIMEOUT_MSB : TIMEOUT_MSB-7])
198 | & io_state != IO_STATE_READ & io_state != IO_STATE_WR)
199 | timeout <= timeout + 1'b1;
200 |
201 | // Disabled: EN is off, outputs in proper state
202 | if (io_state == IO_STATE_DISABLED) begin
203 | if (CS & EN)
204 | io_state <= IO_STATE_READ_SETUP0;
205 | end
206 |
207 | else if (~CS | ~EN) begin
208 | if (!io_timeout | (~CS & EN))
209 | io_fsm_error <= 1;
210 |
211 | SLOE_R <= 1;
212 | SLRD_R <= 1;
213 | SLWR_R <= 1;
214 | output_r_valid <= 0;
215 | PKTEND_R <= 1;
216 | rw_direction <= 0;
217 | io_state <= IO_STATE_DISABLED;
218 | end
219 |
220 | else // CS & EN
221 | (* FULL_CASE, PARALLEL_CASE *) case (io_state)
222 |
223 | IO_STATE_READ_SETUP0: begin
224 | if (almost_full | ~FLAGC_R)
225 | io_state <= IO_STATE_WR_SETUP0;
226 | else begin
227 | io_state <= IO_STATE_READ_SETUP1;
228 | end
229 | end
230 |
231 | IO_STATE_READ_SETUP1: begin
232 | io_state <= IO_STATE_READ_SETUP2;
233 | end
234 |
235 | IO_STATE_READ_SETUP2: begin
236 | // must assert 18.7 ns before read
237 | SLOE_R <= 0;
238 | SLRD_R <= 0;
239 | io_state <= IO_STATE_READ;
240 | end
241 |
242 | IO_STATE_READ: begin
243 | if (!almost_full & FLAGC_R) begin
244 | timeout <= 0;
245 | end
246 | else begin
247 | SLOE_R <= 1;
248 | SLRD_R <= 1;
249 | io_state <= IO_STATE_WR_SETUP0;
250 | end
251 | end
252 |
253 | IO_STATE_WR_SETUP0: begin
254 | //if (empty | ~FLAGB_R)
255 | if ((empty & ~output_r_valid) | FLAGA_R)
256 | io_state <= IO_STATE_READ_SETUP0;
257 | // go on transmit
258 | else begin
259 | rw_direction <= 1;
260 | word_counter <= 0;
261 | io_state <= IO_STATE_WR_SETUP1;
262 | end
263 | end
264 |
265 | IO_STATE_WR_SETUP1: begin
266 | if (~output_r_valid) begin
267 | output_r <= din;
268 | output_r_valid <= 1;
269 | end
270 | io_state <= IO_STATE_WR_SETUP2;
271 | end
272 |
273 | IO_STATE_WR_SETUP2: begin
274 | // must assert 18.1 ns before write
275 | SLWR_R <= 0;
276 | io_state <= IO_STATE_WR;
277 | end
278 |
279 | IO_STATE_WR: begin
280 | output_r <= din;
281 | timeout <= 0;
282 | wr_timeout <= 0;
283 | word_counter <= word_counter + 1'b1;
284 | if (empty)
285 | output_r_valid <= 0;
286 |
287 | if (word_counter == USB_PKT_SIZE - 1) begin
288 | SLWR_R <= 1;
289 | rw_direction <= 0;
290 | io_state <= IO_STATE_READ_SETUP0;
291 | end
292 | else if (empty) begin
293 | SLWR_R <= 1;
294 | io_state <= IO_STATE_WR_WAIT;
295 | end
296 |
297 | if (~FLAGB_R)
298 | io_err_write <= 1;
299 | end
300 |
301 | IO_STATE_WR_WAIT: begin
302 | wr_timeout <= wr_timeout + 1'b1;
303 |
304 | if (wr_timeout == PKTEND_WR_TIMEOUT) begin
305 | PKTEND_R <= 0;
306 | io_state <= IO_STATE_PKT_COMMIT;
307 | end
308 | else if (!empty)
309 | io_state <= IO_STATE_WR_SETUP1;
310 | end
311 |
312 | IO_STATE_PKT_COMMIT: begin
313 | PKTEND_R <= 1;
314 | rw_direction <= 0;
315 | io_state <= IO_STATE_READ_SETUP0;
316 | end
317 |
318 | endcase
319 | // CS & EN
320 |
321 | end // IFCLK
322 |
323 |
324 | endmodule
325 |
326 |
--------------------------------------------------------------------------------
/fpga/inouttraffic.bit:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apingis/ztex-descrypt/ca90b7ce30fadac1ae52de1b335cc68c4a01d673/fpga/inouttraffic.bit
--------------------------------------------------------------------------------
/fpga/inouttraffic.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // *************************************************************
4 | //
5 | // Improved version: 30.07.2016
6 | //
7 | // Original release: 20.03.2016
8 | //
9 | // ISE version: 14.5
10 | // Design Goals & Strategies:
11 | //
12 | // definitions.vh -> "Source Properties" -> "Include as Global File in Compile List"
13 | //
14 | // * http://github.com/Apingis
15 | //
16 | // *************************************************************
17 |
18 | module inouttraffic(
19 | input CS_IN,
20 | input [2:0] FPGA_ID,
21 |
22 | // Both IFCLK_IN and FXCLK_IN are at 48 MHz.
23 | input IFCLK_IN,
24 | input FXCLK_IN,
25 |
26 | // Vendor Command/Request I/O
27 | inout [7:0] PC, // Vendor Command/Request (VCR) address/data
28 | input PA0, // set (internal to FPGA) VCR IO address
29 | input PA1, // write or synchronous read
30 | input PA7, // PC direction: 0 = write to FPGA, 1 = read from FPGA
31 |
32 | // High-Speed I/O Interface
33 | inout [15:0] FIFO_DATA,
34 | output FIFOADR0,
35 | output FIFOADR1,
36 | output SLOE,
37 | output SLRD,
38 | output SLWR,
39 | output PKTEND,
40 | input FLAGA,
41 | input FLAGB, // FULL
42 | input FLAGC, // EMPTY
43 |
44 | output INT4,
45 | output INT5
46 | );
47 |
48 |
49 | clocks clocks(
50 | // Input clocks go to Clock Management Tile via dedicated routing
51 | .IFCLK_IN(IFCLK_IN),
52 | .FXCLK_IN(FXCLK_IN),
53 | // Produced clocks
54 | .IFCLK(IFCLK), // for operating I/O pins
55 | .PKT_COMM_CLK(PKT_COMM_CLK), // for processing data packets
56 | .WORD_GEN_CLK(WORD_GEN_CLK), // word generator (generation part)
57 | .CORE_CLK(CORE_CLK), // for running application core
58 | .CMP_CLK(CMP_CLK) // for running comparators
59 | );
60 |
61 | chip_select chip_select(
62 | .CS_IN(CS_IN), .CLK(IFCLK), .CS(CS), .out_z_wait1(out_z_wait1)//, .out_z(out_z)
63 | );
64 |
65 | wire [7:0] debug2, debug3;
66 | assign debug3 = 8'hd3;
67 |
68 |
69 | // ********************************************************
70 | //
71 | // Input buffer (via High Speed interface)
72 | //
73 | // ********************************************************
74 | wire [15:0] hs_input_din;
75 | wire [7:0] hs_input_dout;
76 |
77 | input_fifo input_fifo(
78 | .wr_clk(IFCLK),
79 | .din( {hs_input_din[7:0],hs_input_din[15:8]} ), // to Cypress IO
80 | .wr_en(hs_input_wr_en), // to Cypress IO
81 | .full(), // to Cypress IO
82 | .almost_full(hs_input_almost_full), // to Cypress IO
83 | .prog_full(hs_input_prog_full),
84 |
85 | .rd_clk(PKT_COMM_CLK),
86 | .dout(hs_input_dout),
87 | .rd_en(hs_input_rd_en),
88 | .empty(hs_input_empty)
89 | );
90 |
91 |
92 | // ********************************************************
93 | //
94 | // Some example application
95 | // 8-bit input, 16-bit output
96 | //
97 | // ********************************************************
98 | //wire [63:0] app_dout;
99 | wire [15:0] app_dout;
100 | wire [7:0] app_mode;
101 | wire [7:0] app_status, pkt_comm_status;
102 |
103 | pkt_comm_arbiter pkt_comm(
104 | //pkt_comm pkt_comm(
105 | //application application(
106 | .CLK(PKT_COMM_CLK),
107 | .WORD_GEN_CLK(WORD_GEN_CLK),
108 | .CORE_CLK(CORE_CLK),
109 | .CMP_CLK(CMP_CLK),
110 | // High-Speed FPGA input
111 | .din(hs_input_dout),
112 | .rd_en(hs_input_rd_en),
113 | .empty(hs_input_empty),
114 | // High-Speed FPGA output
115 | .dout(app_dout),
116 | .wr_en(app_wr_en),
117 | .full(app_full),
118 | // Application control (via VCR I/O). Set with fpga_set_app_mode()
119 | .app_mode(app_mode),
120 | // Application status (via VCR I/O). Available at fpga->wr.io_state.app_status
121 | .pkt_comm_status(pkt_comm_status),
122 | .debug2(debug2),
123 | .app_status(app_status)
124 | );
125 |
126 |
127 | // ********************************************************
128 | //
129 | // Output buffer (via High-Speed interface)
130 | //
131 | // ********************************************************
132 | wire [15:0] output_limit;
133 | wire [15:0] output_dout; // output via High-Speed Interface
134 |
135 | output_fifo output_fifo(
136 | //.wr_clk(PKT_COMM_CLK),
137 | .wr_clk(CMP_CLK),
138 | .din(app_dout),
139 | .wr_en(app_wr_en),
140 | .full(app_full),
141 |
142 | .rd_clk(IFCLK),
143 | .dout(output_dout), // to Cypress IO,
144 | .rd_en(output_rd_en), // to Cypress IO,
145 | .empty(output_empty), // to Cypress IO
146 | .mode_limit(output_mode_limit),
147 | .reg_output_limit(reg_output_limit),
148 | .output_limit(output_limit),
149 | .output_limit_not_done(output_limit_not_done)
150 | );
151 |
152 |
153 | // ********************************************************
154 | //
155 | // High-Speed I/O Interface (Slave FIFO)
156 | //
157 | // ********************************************************
158 | wire [7:0] hs_io_timeout;
159 |
160 | hs_io_v2 #(
161 | .USB_ENDPOINT_IN(2),
162 | .USB_ENDPOINT_OUT(6)
163 | ) hs_io_inst(
164 | .IFCLK(IFCLK), .CS(CS), .out_z_wait1(out_z_wait1), .EN(hs_en),
165 | .FIFO_DATA(FIFO_DATA), .FIFOADR0(FIFOADR0), .FIFOADR1(FIFOADR1),
166 | .SLOE(SLOE), .SLRD(SLRD), .SLWR(SLWR), .PKTEND(PKTEND), .FLAGA(FLAGA), .FLAGB(FLAGB), .FLAGC(FLAGC),
167 | // data output from Cypress IO, received by FPGA
168 | .dout(hs_input_din), .wr_en(hs_input_wr_en), .almost_full(hs_input_almost_full),
169 | .din(output_dout), .rd_en(output_rd_en), .empty(output_empty), // to Cypress IO, out of FPGA
170 | .io_timeout(hs_io_timeout), .sfifo_not_empty(sfifo_not_empty),
171 | .io_fsm_error(io_fsm_error), .io_err_write(io_err_write)
172 | );
173 |
174 |
175 | // ********************************************************
176 | //
177 | // Vendor Command/Request (VCR) I/O interface
178 | //
179 | // ********************************************************
180 | wire [7:0] vcr_in = PC;
181 | wire [7:0] vcr_out;
182 | assign PC = CS && PA7 ? vcr_out : 8'bz;
183 |
184 | (* KEEP_HIERARCHY="true" *) vcr vcr_inst(
185 | .CS(CS), .vcr_in(vcr_in), .vcr_out(vcr_out), .clk_vcr_addr(PA0), .clk_vcr_data(PA1),
186 | // i/o goes with respect to IFCLK
187 | .IFCLK(IFCLK),
188 | // various inputs to be read by CPU
189 | .FPGA_ID(FPGA_ID),
190 | .hs_io_timeout(hs_io_timeout), .hs_input_prog_full(hs_input_prog_full),
191 | .sfifo_not_empty(sfifo_not_empty), .io_fsm_error(io_fsm_error), .io_err_write(io_err_write),
192 | .output_limit(output_limit), .output_limit_not_done(output_limit_not_done),
193 | .app_status(app_status),
194 | .pkt_comm_status(pkt_comm_status), .debug2(debug2), .debug3(debug3),
195 | // various control wires
196 | .hs_en(hs_en),
197 | .output_mode_limit(output_mode_limit),
198 | .reg_output_limit(reg_output_limit),
199 | .app_mode(app_mode),
200 | .RESET_OUT()
201 | );
202 |
203 |
204 | // External interrupts for USB controller - put into defined state
205 | assign INT4 = 1'b0;
206 | assign INT5 = 1'b1;
207 |
208 | endmodule
209 |
--------------------------------------------------------------------------------
/fpga/inouttraffic.xds:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 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.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/fpga/input_fifo.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 |
4 | module input_fifo(
5 | input wr_clk,
6 | input [15:0] din,
7 | input wr_en,
8 | output full,
9 | output almost_full,
10 | output prog_full,
11 |
12 | input rd_clk,
13 | input rd_en,
14 | output [7:0] dout,
15 | output empty
16 | );
17 |
18 | // FIFO Generator v9.3
19 | // * Independent Clocks - Block RAM
20 | // * 1st word Fall-Through
21 | // * write: width 16, depth 16384 (32 Kbytes), read width 8
22 | // * Almost Full Flag
23 | // * Single Programmable Full Threshold Constant: Assert Value 8192
24 | // * Reset: off
25 | wire [7:0] din_stage2;
26 |
27 | fifo_16in_8out fifo_16in_8out(
28 | .wr_clk(wr_clk),
29 | .din(din),
30 | .wr_en(wr_en),
31 | .full(full),
32 | .almost_full(almost_full),
33 | .prog_full(prog_full),
34 |
35 | .rd_clk(wr_clk),
36 | //.dout(dout),
37 | //.rd_en(rd_en),
38 | //.empty(empty)
39 | .dout(din_stage2),
40 | .rd_en(tx_stage2),
41 | .empty(empty_stage2)
42 | );
43 |
44 | assign tx_stage2 = ~empty_stage2 & ~full_stage2;
45 |
46 | //
47 | // fifo_16in_8out is large in size and its memory blocks are scattered over large area.
48 | // That's unable to operate at high frequency such as 200 MHz because of routing delay.
49 | // An additional small FIFO is append.
50 | //
51 |
52 | // FIFO Generator v9.3
53 | // * Independent Clocks
54 | // * 1st word Fall-Through
55 | // * Reset: off
56 | fifo_bram_8x1024_fwft fifo_bram_8x1024_fwft(
57 | .wr_clk(wr_clk),
58 | .din(din_stage2),
59 | .wr_en(tx_stage2),
60 | .full(full_stage2),
61 |
62 | .rd_clk(rd_clk),
63 | .dout(dout),
64 | .rd_en(rd_en),
65 | .empty(empty)
66 | );
67 |
68 | endmodule
69 |
--------------------------------------------------------------------------------
/fpga/main.ucf:
--------------------------------------------------------------------------------
1 | # TIMESPEC's moved to clocks.ucf
2 | NET "IFCLK_IN" LOC = "K20" |IOSTANDARD = LVCMOS33 ;
3 | NET "FXCLK_IN" LOC = "L22" | IOSTANDARD = LVCMOS33 ;
4 |
5 | NET "CS_IN" LOC = "AB11" |IOSTANDARD = LVCMOS33 ;
6 |
7 | NET "PA0" LOC = "AA22" |IOSTANDARD = LVCMOS33 ;
8 | NET "PA1" LOC = "W17" |IOSTANDARD = LVCMOS33 ;
9 | NET "PA7" LOC = "AB17" |IOSTANDARD = LVCMOS33 ;
10 |
11 | NET "SLOE" LOC = "U15" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ; # PA2
12 | NET "SLRD" LOC = "N22" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
13 | NET "SLWR" LOC = "M22" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
14 | NET "PKTEND" LOC = "AB5" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ; # PA6
15 | NET "FIFOADR0" LOC = "AB21" |IOSTANDARD = LVCMOS33 |DRIVE = 12 ; # PA4
16 | NET "FIFOADR1" LOC = "Y18" |IOSTANDARD = LVCMOS33 |DRIVE = 12 ; # PA5
17 | NET "FLAGA" LOC = "F20" |IOSTANDARD = LVCMOS33 ;
18 | NET "FLAGB" LOC = "F19" |IOSTANDARD = LVCMOS33 ;
19 | NET "FLAGC" LOC = "F18" |IOSTANDARD = LVCMOS33 ;
20 |
21 | NET "FIFO_DATA<0>" LOC = "Y17" |IOSTANDARD = LVCMOS33 ;
22 | NET "FIFO_DATA<1>" LOC = "V13" |IOSTANDARD = LVCMOS33 ;
23 | NET "FIFO_DATA<2>" LOC = "W13" |IOSTANDARD = LVCMOS33 ;
24 | NET "FIFO_DATA<3>" LOC = "AA8" |IOSTANDARD = LVCMOS33 ;
25 | NET "FIFO_DATA<4>" LOC = "AB8" |IOSTANDARD = LVCMOS33 ;
26 | NET "FIFO_DATA<5>" LOC = "W6" |IOSTANDARD = LVCMOS33 ;
27 | NET "FIFO_DATA<6>" LOC = "Y6" |IOSTANDARD = LVCMOS33 ;
28 | NET "FIFO_DATA<7>" LOC = "Y9" |IOSTANDARD = LVCMOS33 ;
29 | NET "FIFO_DATA<8>" LOC = "V21" |IOSTANDARD = LVCMOS33 ;
30 | NET "FIFO_DATA<9>" LOC = "V22" |IOSTANDARD = LVCMOS33 ;
31 | NET "FIFO_DATA<10>" LOC = "U20" |IOSTANDARD = LVCMOS33 ;
32 | NET "FIFO_DATA<11>" LOC = "U22" |IOSTANDARD = LVCMOS33 ;
33 | NET "FIFO_DATA<12>" LOC = "R20" |IOSTANDARD = LVCMOS33 ;
34 | NET "FIFO_DATA<13>" LOC = "R22" |IOSTANDARD = LVCMOS33 ;
35 | NET "FIFO_DATA<14>" LOC = "P18" |IOSTANDARD = LVCMOS33 ;
36 | NET "FIFO_DATA<15>" LOC = "P19" |IOSTANDARD = LVCMOS33 ;
37 |
38 |
39 | NET "PC<0>" LOC="G20" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
40 | NET "PC<1>" LOC="T20" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
41 | NET "PC<2>" LOC="Y5" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
42 | NET "PC<3>" LOC="AB9" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
43 | NET "PC<4>" LOC="G19" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
44 | NET "PC<5>" LOC="H20" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
45 | NET "PC<6>" LOC="H19" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
46 | NET "PC<7>" LOC="H18" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
47 |
48 | NET "INT4" LOC = "C18" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
49 | NET "INT5" LOC = "V17" |IOSTANDARD = LVCMOS33 |DRIVE = 12;
50 | # NET "SCL" LOC = "F22" | IOSTANDARD = LVCMOS33 ;
51 | # NET "SDA" LOC = "E22" | IOSTANDARD = LVCMOS33 ;
52 | NET "FPGA_ID<0>" LOC="T12" |IOSTANDARD = LVCMOS33 ;
53 | NET "FPGA_ID<1>" LOC="R13" |IOSTANDARD = LVCMOS33 ;
54 | NET "FPGA_ID<2>" LOC="T14" |IOSTANDARD = LVCMOS33 ;
55 |
56 | NET "FPGA_ID*" TIG;
57 |
58 |
59 | # VCR
60 | AREA_GROUP "pblock_io3" RANGE=SLICE_X64Y80:SLICE_X67Y95;
61 | #AREA_GROUP "pblock_io3" RANGE=SLICE_X88Y80:SLICE_X103Y95;
62 | INST "vcr_inst" AREA_GROUP="pblock_io3";
63 | #INST "" AREA_GROUP "pblock_io3";
64 |
65 |
--------------------------------------------------------------------------------
/fpga/output_fifo.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //**********************************************************
4 | //
5 | // Output FIFO (high-speed output).
6 | //
7 | //**********************************************************
8 |
9 | module output_fifo (
10 | input wr_clk,
11 | //input [63:0] din,
12 | input [15:0] din,
13 | input wr_en,
14 | output full,
15 |
16 | input rd_clk,
17 | output [15:0] dout,
18 | input rd_en,
19 | output empty,
20 | //input pkt_end,
21 | //output err_overflow,
22 | input mode_limit,
23 | input reg_output_limit,
24 | //input [15:0] output_limit_min,
25 | output [15:0] output_limit,
26 | output output_limit_not_done
27 | );
28 |
29 | // Frontend 16-deep asynchronous FIFO:
30 | // Required for Clock Domain Crossing
31 | // IP Coregen: DRAM - Independent clocks, width 64, 1st Word Fall-Through
32 | //
33 | // TODO: replace with some 1-deep design
34 |
35 | /* wire [63:0] data_stage2;
36 | fifo_dram_async fifo_dram_async(
37 | .rst(rst),
38 | .wr_clk(wr_clk),
39 | .rd_clk(rd_clk),
40 | .din(din),
41 | .wr_en(wr_en),
42 | .rd_en(rd_en_stage2),
43 | .dout(data_stage2),
44 | .full(full),
45 | .empty(empty_stage2)
46 | );
47 | */
48 |
49 | wire [15:0] data_stage2;
50 | fifo_dram_async_16 fifo_dram_async_16(
51 | .wr_clk(wr_clk),
52 | .din(din),
53 | .wr_en(wr_en),
54 | .full(full),
55 |
56 | .rd_clk(rd_clk),
57 | .dout(data_stage2),
58 | .rd_en(rd_en_stage2),
59 | .empty(empty_stage2)
60 | );
61 | assign rd_en_stage2 = ~empty_stage2 & ~full_stage2;
62 | assign wr_en_stage2 = rd_en_stage2;
63 |
64 | /*
65 | // Output FIFO reconsidered:
66 | //
67 | // * Task for handling application's data packets
68 | // removed from link layer
69 | //
70 | packet_aware_fifo packet_aware_fifo_inst(
71 | .rst(1'b0),
72 | .CLK(rd_clk),
73 | .din(data_stage2),
74 | .wr_en(wr_en_stage2),
75 | .rd_en(rd_en),
76 | .dout(dout),
77 | .full(full_stage2),
78 | .empty(empty),
79 |
80 | .pkt_end(1'b1),//pkt_end),
81 | .err_overflow(),//err_overflow),
82 | .mode_limit(mode_limit),
83 | .reg_output_limit(reg_output_limit),
84 | .output_limit_min(16'b0),//output_limit_min),
85 | .output_limit(output_limit),
86 | .output_limit_done(output_limit_done)
87 | );
88 | */
89 |
90 | output_limit_fifo #(
91 | //.ADDR_MSB(12)
92 | .ADDR_MSB(13) // 32 Kbytes
93 | ) output_limit_fifo(
94 | .rst(1'b0),
95 | .CLK(rd_clk),
96 |
97 | .din(data_stage2),
98 | .wr_en(wr_en_stage2),
99 | .full(full_stage2),
100 |
101 | .dout(dout),
102 | .rd_en(rd_en),
103 | .empty(empty),
104 |
105 | .mode_limit(mode_limit),
106 | .reg_output_limit(reg_output_limit),
107 | .output_limit(output_limit),
108 | .output_limit_not_done(output_limit_not_done)
109 | );
110 |
111 | endmodule
112 |
--------------------------------------------------------------------------------
/fpga/output_limit_fifo.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //**********************************************************
4 | //
5 | // Output Limit FIFO (high-speed output).
6 | //
7 | // Features:
8 | //
9 | // * Configurable width and depth
10 | //
11 | // * 1st word Fall-Through
12 | //
13 | // * Does not output on its own (reports EMPTY) when mode_limit == 1.
14 | // When reg_output_limit asserted:
15 | // - Reports amount ready for output (output_limit) in WIDTH-bit words
16 | // - Starts output of that amount, asserts output_limit_not_done
17 | // - Deasserts output_limit_not_done when finished
18 | //
19 | // * Does not require extra components from IP Coregen
20 | //
21 | // * The design is unable for asynchronous operation
22 | //
23 | // * Size equals to RAM size minus 1 word.
24 | //
25 | // * http://github.com/Apingis
26 | //
27 | //**********************************************************
28 |
29 | module output_limit_fifo #(
30 | // ADDR_MSB==11 : 8 Kbytes
31 | parameter ADDR_MSB = 11,
32 | parameter WIDTH = 16
33 | )(
34 | input rst,
35 | input CLK,
36 |
37 | input [WIDTH-1:0] din,
38 | input wr_en,
39 | output full,
40 |
41 | output [WIDTH-1:0] dout,
42 | input rd_en,
43 | output empty,
44 |
45 | input mode_limit, // turn on output limit
46 | input reg_output_limit,
47 | output [15:0] output_limit,
48 | output reg output_limit_not_done
49 | );
50 |
51 | reg [ADDR_MSB:0] addra = 0;
52 | reg [ADDR_MSB:0] output_limit_addr = 0;
53 | reg [ADDR_MSB:0] output_limit_r = 0;
54 | reg [ADDR_MSB:0] addrb = 0;
55 |
56 | // 1st Word Fall-Through
57 | reg wft = 0;
58 | assign empty = rst || ~wft;
59 |
60 | assign output_limit = { {15-ADDR_MSB{1'b0}}, output_limit_r };
61 |
62 | assign full = rst || (addra + 1'b1 == addrb);
63 | wire ena = wr_en && !full;
64 |
65 | always @(posedge CLK) begin
66 | if (rst) begin
67 | addra <= 0;
68 | output_limit_addr <= 0;
69 | output_limit_r <= 0;
70 | end
71 | else begin
72 | if (ena) begin
73 | addra <= addra + 1'b1;
74 | end
75 |
76 | if (!mode_limit || reg_output_limit) begin
77 | output_limit_addr <= addra;
78 | output_limit_r <= addra - output_limit_addr;
79 | end
80 | end // ~rst
81 | end
82 |
83 | wire ram_empty_or_limit = (output_limit_addr == addrb);
84 |
85 | wire enb = (!ram_empty_or_limit && (empty || rd_en));
86 | reg enb_r = 0;
87 |
88 | wire [15:0] ram_out;
89 | reg [15:0] dout_r;
90 | assign dout = dout_r;
91 |
92 | always @(posedge CLK) begin
93 | if (rst) begin
94 | addrb <= 0;
95 | wft <= 0;
96 | enb_r <= 0;
97 | end
98 | else begin
99 | if (empty || rd_en)
100 | enb_r <= enb;
101 |
102 | if (enb) begin
103 | addrb <= addrb + 1'b1;
104 | end
105 |
106 | if (enb_r) begin
107 | if (!wft || rd_en) begin
108 | wft <= 1;
109 | dout_r <= ram_out;
110 | end
111 | end // enb_r
112 | else if (rd_en)
113 | wft <= 0;
114 | end // ~rst
115 |
116 | output_limit_not_done <= ~ram_empty_or_limit;
117 | end
118 |
119 |
120 | (* RAM_STYLE = "BLOCK" *)
121 | reg [WIDTH-1:0] ram [2**(ADDR_MSB+1)-1:0];
122 | reg [WIDTH-1:0] ram_out_r;
123 | assign ram_out = ram_out_r;
124 |
125 | always @(posedge CLK) begin
126 | if (ena)
127 | ram[addra] <= din;
128 | if (enb)
129 | ram_out_r <= ram[addrb];
130 | end
131 | /*
132 | // IP Coregen -> Block RAM
133 | // Simple Dual-Port mode
134 | // Port A: write width 16 (8K = depth 4096, ADDR_MSB 11)
135 | // Port B: width 16
136 | // Use pins: ena, enb
137 | bram_sdp16_output_fifo bram0(
138 | .clka(CLK),
139 | .ena(ena),
140 | .wea(1'b1),
141 | .addra(addra),
142 | .dina(din),
143 | .clkb(CLK),
144 | .enb(enb),
145 | .addrb(addrb),
146 | .doutb(ram_out)
147 | );
148 | */
149 | endmodule
150 |
--------------------------------------------------------------------------------
/fpga/packet_aware_fifo.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //**********************************************************
4 | //
5 | // Packet Aware FIFO (high-speed output).
6 | //
7 | // Features:
8 | //
9 | // * 64-bit input, 16-bit output
10 | // * 1st word Fall-Through
11 | //
12 | // * Does not output on its own (reports EMPTY) when mode_limit == 1.
13 | // When reg_output_limit asserted:
14 | // - Reports amount ready for output (output_limit)
15 | // -- if that's no less than output_limit_min
16 | // -- incomplete packets don't count
17 | // - Starts output of that amount
18 | // - Asserts output_limit_done when finished
19 | //
20 | // * The design is unable for asynchronous operation
21 | //
22 | //**********************************************************
23 |
24 | module packet_aware_fifo (
25 | input rst,
26 | input CLK,
27 | //input wr_clk,
28 | //input rd_clk,
29 | input [63:0] din,
30 | input wr_en,
31 | input rd_en,
32 | output [15:0] dout,
33 | output full,
34 | output empty,
35 | input pkt_end,
36 | output err_overflow, // overflow with unpacketed data
37 | input mode_limit, // turn on output limit
38 | input reg_output_limit,
39 | input [15:0] output_limit_min, // don't register output limit if no such amount
40 | output [15:0] output_limit,
41 | output output_limit_done
42 | );
43 |
44 | // ADDR_MSB == 8: 4Kbytes; 9: 8KB; 10: 16KB
45 | localparam ADDR_MSB = 9;
46 |
47 | reg [ADDR_MSB:0] addra = 0;
48 | reg [ADDR_MSB:0] last_pkt_end = 0;
49 | reg [ADDR_MSB:0] output_limit_addr = 0;
50 | reg [ADDR_MSB:0] output_limit_r = 0;
51 | reg [ADDR_MSB+2:0] addrb = 0;
52 | // 1st Word Fall-Through
53 | reg wft = 0;
54 | assign empty = rst || ~wft;
55 |
56 | assign output_limit = { {15-ADDR_MSB{1'b0}}, output_limit_r };
57 |
58 | assign full = rst || (addra + 1'b1 == addrb[ADDR_MSB+2:2]);
59 | assign err_overflow = full && last_pkt_end == addrb[ADDR_MSB+2:2];
60 | wire ena = wr_en && !full;
61 |
62 | wire [ADDR_MSB:0] output_limit_min_cmp =
63 | (|output_limit_min[15:ADDR_MSB+1]) ?
64 | {ADDR_MSB+1{1'b1}} : output_limit_min[ADDR_MSB:0];
65 |
66 | always @(posedge CLK) begin
67 | if (rst) begin
68 | addra <= 0;
69 | last_pkt_end <= 0;
70 | output_limit_addr <= 0;
71 | output_limit_r <= 0;
72 | end
73 | else begin
74 | if (ena) begin
75 | addra <= addra + 1'b1;
76 | if (pkt_end)
77 | last_pkt_end <= addra + 1'b1;
78 | end
79 |
80 | if (!mode_limit || reg_output_limit) begin
81 | if (!mode_limit || last_pkt_end - output_limit_addr >= output_limit_min_cmp) begin
82 | output_limit_addr <= last_pkt_end;
83 | output_limit_r <= last_pkt_end - output_limit_addr;
84 | end
85 | else
86 | output_limit_r <= 0;
87 | end
88 | end // !RESET
89 | end
90 |
91 | wire ram_empty_or_limit = (output_limit_addr == addrb[ADDR_MSB+2:2]);
92 | assign output_limit_done = ram_empty_or_limit;
93 |
94 | wire enb = (!ram_empty_or_limit && (empty || rd_en));
95 | reg enb_r = 0;
96 |
97 | wire [15:0] ram_out;
98 | reg [15:0] dout_r;
99 | assign dout = dout_r;
100 |
101 | always @(posedge CLK) begin
102 | if (rst) begin
103 | addrb <= 0;
104 | wft <= 0;
105 | enb_r <= 0;
106 | end
107 | else begin
108 | if (empty || rd_en)
109 | enb_r <= enb;
110 |
111 | if (enb) begin
112 | addrb <= addrb + 1'b1;
113 | end
114 |
115 | if (enb_r) begin
116 | if (!wft || rd_en) begin
117 | wft <= 1;
118 | dout_r <= ram_out;
119 | end
120 | end // enb_r
121 | else if (rd_en)
122 | wft <= 0;
123 | end // !RESET
124 | end
125 |
126 | // IP Coregen -> Block RAM
127 | // True Dual-Port mode
128 | // Port A: write width 64, depth: 512=4K, 1024=8K, 2048=16K (adjust localparam ADDR_MSB)
129 | // Port B: width 16
130 | // Use pins: ena, enb
131 | bram_tdp_64in_output_fifo bram0(
132 | .clka(CLK),
133 | .ena(ena),
134 | .wea(1'b1),
135 | .addra(addra),
136 | .dina(din),
137 | .douta(), // unused
138 | .clkb(CLK),
139 | .enb(enb),
140 | .web(1'b0),
141 | .addrb(addrb),
142 | .dinb({16{1'b0}}), // unused
143 | .doutb(ram_out)
144 | );
145 |
146 | endmodule
147 |
--------------------------------------------------------------------------------
/fpga/packet_aware_fifo_test.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | module packet_aware_fifo_test();
4 | reg [63:0] din;
5 | reg wr_en;
6 | reg wr_clk;
7 | wire full;
8 | reg pkt_end;
9 |
10 | wire [15:0] dout;
11 | wire empty;
12 | reg rd_clk;
13 | reg rd_en;
14 |
15 | wire [15:0] output_size,debug1;
16 |
17 | packet_aware_fifo uut(
18 | .rst(1'b0),
19 | .wr_clk(wr_clk),
20 | .rd_clk(rd_clk),
21 | .din(din),
22 | .wr_en(wr_en),
23 | .rd_en(rd_en), // wired to Cypress IO,
24 | .dout(dout), // wired to Cypress IO,
25 | .full(full),
26 | .empty(empty), // wired to Cypress IO
27 | .pkt_end(1'b1),
28 | .output_size(output_size),
29 | .debug1(debug1)
30 | );
31 |
32 | initial begin
33 | pkt_end <= 1;
34 | #40;
35 | wr_en <= 1;
36 |
37 | din <= 64'h0001_0002_0003_0004;
38 | #20;
39 | din <= 64'h000a_000b_000c_000d;
40 | #20;
41 | wr_en <= 0;
42 | end
43 |
44 | initial begin
45 | rd_en <= 0;
46 | #200;
47 | rd_en <= 1;
48 | end
49 |
50 |
51 | initial begin
52 | wr_clk <= 0;
53 | #5;
54 | while (1) begin
55 | wr_clk <= ~wr_clk; #10;
56 | end
57 | end
58 |
59 | initial begin
60 | rd_clk <= 0;
61 | #5;
62 | while (1) begin
63 | rd_clk <= ~rd_clk; #10;
64 | end
65 | end
66 |
67 | endmodule
68 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/inpkt_header.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // processes input (from the point of view from FPGA) headers
4 | // version 1.
5 | // packet header is 10 bytes.
6 | //
7 | // struct pkt {
8 | // unsigned char version; // version 1
9 | // unsigned char type;
10 | // unsigned short reserved0;
11 | // unsigned char data_len0;
12 | // unsigned char data_len1;
13 | // unsigned char data_len2; // doesn't count header
14 | // unsigned char reserved1;
15 | // unsigned short id;
16 | // unsigned char data[pkt_data_len];
17 | // };
18 | //
19 | // assumes PKT_MAX_LEN is no less than 65536
20 | // packets not aligned to 2-byte word can be padded with 0
21 | //
22 | // Checksum is PKT_CHECKSUM_LEN bytes long. Words added and inverted.
23 | // Checksum is not included in data length.
24 | // - inserted after packet header
25 | // - after each PKT_CHECKSUM_INTERVAL bytes <-- not implemented
26 | // - after the end of packet
27 | //
28 | // TODO: some improved CRC check
29 | //
30 |
31 | module inpkt_header #(
32 | parameter VERSION = 1,
33 | parameter PKT_MAX_LEN = 65536,
34 | parameter PKT_MAX_TYPE = -1,
35 | parameter PKT_TYPE_MSB = `MSB(PKT_MAX_TYPE),
36 | parameter DISABLE_CHECKSUM = 0
37 | )(
38 | input CLK,
39 | input [7:0] din,
40 | input wr_en,
41 |
42 | output reg [PKT_TYPE_MSB:0] pkt_type = 0,
43 | output reg [15:0] pkt_id,
44 | output pkt_data, // asserts when it goes packet data
45 | output pkt_end, // asserts when it goes the last byte of data
46 | output pkt_err,
47 | output reg err_pkt_version = 0, err_pkt_type = 0, err_pkt_len = 0, err_pkt_checksum = 0
48 | );
49 |
50 |
51 | localparam PKT_LEN_MSB = `MSB(PKT_MAX_LEN);
52 |
53 | reg [31:0] checksum = 0;
54 | reg [31:0] checksum_tmp = 0;
55 | reg [1:0] checksum_byte_count = 0;
56 |
57 | // flag is set when checksum_tmp contains checksum value from data-in
58 | reg checksum_check_flag = 0;
59 |
60 | reg [PKT_LEN_MSB:0] pkt_byte_count_max;
61 | reg [PKT_LEN_MSB:0] pkt_byte_count;
62 |
63 | localparam PKT_STATE_VERSION = 1,
64 | PKT_STATE_TYPE = 2,
65 | PKT_STATE_RESERVED0_0 = 3,
66 | PKT_STATE_RESERVED0_1 = 4,
67 | PKT_STATE_LEN0 = 5,
68 | PKT_STATE_LEN1 = 6,
69 | PKT_STATE_LEN2 = 7,
70 | PKT_STATE_RESERVED1 = 8,
71 | PKT_STATE_ID0 = 9,
72 | PKT_STATE_ID1 = 10,
73 | PKT_STATE_DATA = 11,
74 | PKT_STATE_ERROR = 12,
75 | PKT_STATE_CHECKSUM = 13;
76 |
77 | (* FSM_EXTRACT = "true", FSM_ENCODING = "auto" *)
78 | reg [3:0] pkt_state = PKT_STATE_VERSION;
79 |
80 | // Verify checksum regardless of wr_en
81 | always @(posedge CLK)
82 | if (checksum_check_flag) begin
83 | if (~checksum != checksum_tmp & ~DISABLE_CHECKSUM[0])
84 | err_pkt_checksum <= 1;
85 | end
86 |
87 | always @(posedge CLK) begin
88 | if (err_pkt_checksum)
89 | pkt_state <= PKT_STATE_ERROR;
90 |
91 | if (wr_en) begin
92 | if (pkt_state != PKT_STATE_CHECKSUM & ~(pkt_state == PKT_STATE_VERSION & !din)) begin
93 |
94 | checksum_check_flag <= 0;
95 |
96 | if (checksum_byte_count == 0) begin
97 | checksum_tmp[31:8] <= 0;
98 | if (~checksum_check_flag)
99 | checksum <= checksum + checksum_tmp;
100 | else
101 | checksum <= 0;
102 | end
103 |
104 | checksum_tmp[8*(checksum_byte_count+1)-1 -:8] <= din;
105 | checksum_byte_count <= checksum_byte_count + 1'b1;
106 | end
107 |
108 | case (pkt_state)
109 | PKT_STATE_VERSION: begin
110 | if (!din) begin
111 | // input 0 - skip
112 | end
113 | else begin
114 | if (din != VERSION) begin
115 | // wrong packet version
116 | err_pkt_version <= 1;
117 | pkt_state <= PKT_STATE_ERROR;
118 | end
119 | else
120 | pkt_state <= PKT_STATE_TYPE;
121 | end
122 | end
123 |
124 | PKT_STATE_TYPE: begin
125 | if (!din || din[PKT_TYPE_MSB:0] > PKT_MAX_TYPE || din[7:PKT_TYPE_MSB+1]) begin
126 | // wrong packet type
127 | err_pkt_type <= 1;
128 | pkt_state <= PKT_STATE_ERROR;
129 | end
130 | else begin
131 | pkt_byte_count <= 0;
132 | pkt_type <= din[PKT_TYPE_MSB:0];
133 | pkt_state <= PKT_STATE_RESERVED0_0;
134 | end
135 | end
136 |
137 | PKT_STATE_RESERVED0_0: begin
138 | pkt_state <= PKT_STATE_RESERVED0_1;
139 | end
140 |
141 | PKT_STATE_RESERVED0_1: begin
142 | pkt_state <= PKT_STATE_LEN0;
143 | end
144 |
145 | PKT_STATE_LEN0: begin
146 | pkt_byte_count_max[7:0] <= din;
147 | pkt_state <= PKT_STATE_LEN1;
148 | end
149 |
150 | PKT_STATE_LEN1: begin
151 | pkt_byte_count_max[15:8] <= din;
152 | pkt_state <= PKT_STATE_LEN2;
153 | end
154 |
155 | PKT_STATE_LEN2: begin
156 | pkt_byte_count_max <= { din[PKT_LEN_MSB-16:0], pkt_byte_count_max[15:0] } - 1'b1;
157 |
158 | if ( din[7:PKT_LEN_MSB-16+1] || !(din[PKT_LEN_MSB-16:0] || pkt_byte_count_max[15:0]) ) begin
159 | // wrong packet length
160 | err_pkt_len <= 1;
161 | pkt_state <= PKT_STATE_ERROR;
162 | end
163 | else begin
164 | pkt_state <= PKT_STATE_RESERVED1;
165 | end
166 | end
167 |
168 | PKT_STATE_RESERVED1: begin
169 | pkt_state <= PKT_STATE_ID0;
170 | end
171 |
172 | PKT_STATE_ID0: begin
173 | pkt_id[7:0] <= din;
174 | pkt_state <= PKT_STATE_ID1;
175 | end
176 |
177 | PKT_STATE_ID1: begin
178 | pkt_id[15:8] <= din;
179 | checksum_byte_count <= 0;
180 | pkt_state <= PKT_STATE_CHECKSUM;
181 | end
182 |
183 | PKT_STATE_DATA: begin
184 | if (pkt_byte_count == pkt_byte_count_max) begin
185 | checksum_byte_count <= 0;
186 | pkt_state <= PKT_STATE_CHECKSUM;
187 | end
188 | else
189 | pkt_byte_count <= pkt_byte_count + 1'b1;
190 | end
191 |
192 | PKT_STATE_CHECKSUM: begin
193 | checksum_tmp[8*(checksum_byte_count+1)-1 -:8] <= din;
194 | checksum_byte_count <= checksum_byte_count + 1'b1;
195 |
196 | if (checksum_byte_count == 0) begin
197 | checksum <= checksum + checksum_tmp;
198 | end
199 | else if (checksum_byte_count == 3) begin
200 | checksum_check_flag <= 1;
201 | // Suppose checksum_byte_count is a power of 2
202 | //checksum_byte_count <= 0;
203 | if (pkt_byte_count == pkt_byte_count_max)
204 | pkt_state <= PKT_STATE_VERSION;
205 | else
206 | pkt_state <= PKT_STATE_DATA;
207 | end
208 | end
209 | endcase
210 |
211 | end // wr_en
212 | end
213 |
214 | assign pkt_data = pkt_state == PKT_STATE_DATA;
215 |
216 | assign pkt_end = pkt_data && pkt_byte_count == pkt_byte_count_max;
217 |
218 | assign pkt_err = pkt_state == PKT_STATE_ERROR;
219 |
220 |
221 | endmodule
222 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/outpkt_checksum.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | module outpkt_checksum(
4 | input CLK,
5 | input [15:0] din,
6 | input pkt_new, // asserted on 1st word of packet header
7 | input pkt_end, // asserted on last word of packet data
8 | input wr_en,
9 | output full,
10 | output [15:0] dout,
11 | input rd_en,
12 | output empty
13 | );
14 |
15 | localparam PKT_HEADER_LEN = 10;
16 |
17 | // 4-byte checksum:
18 | //
19 | // after packet header
20 | // after each PKT_CHECKSUM_INTERVAL bytes <-- not implemented
21 | // after the end of packet
22 | localparam PKT_CHECKSUM_INTERVAL = 448;
23 |
24 | // Input register.
25 | reg [15:0] input_r;
26 | reg full_r = 0, pkt_new_r = 0, pkt_end_r = 0;
27 | assign full = full_r;
28 |
29 | always @(posedge CLK) begin
30 | if (wr_en & (~full_r | input_rd_en)) begin
31 | input_r <= din;
32 | pkt_new_r <= pkt_new;
33 | pkt_end_r <= pkt_end;
34 | full_r <= 1;
35 | end
36 | else if (input_rd_en)
37 | full_r <= 0;
38 | end
39 |
40 | // Output register.
41 | reg [15:0] output_r;
42 | assign dout = output_r;
43 | reg empty_r = 1;
44 | assign empty = empty_r;
45 |
46 | always @(posedge CLK)
47 | if (rd_en & ~output_wr_en)
48 | empty_r <= 1;
49 | else if (output_wr_en & ~rd_en)
50 | empty_r <= 0;
51 |
52 |
53 | (* USE_DSP48="true" *)
54 | reg [31:0] checksum = 0;
55 | reg [15:0] checksum_tmp = 0;
56 | reg checksum_counter = 0;
57 | //reg [`MSB(PKT_CHECKSUM_INTERVAL/2):0] word_counter = 0;
58 | reg [`MSB(PKT_HEADER_LEN/2):0] word_counter = 0;
59 |
60 | localparam STATE_PKT_INPUT = 0,
61 | STATE_CHECKSUM0 = 1,
62 | STATE_CHECKSUM1 = 2,
63 | STATE_CHECKSUM2 = 3;
64 |
65 | (* FSM_EXTRACT="true" *)
66 | reg [1:0] state = STATE_PKT_INPUT;
67 |
68 | reg pkt_state = 0; // 0: packet header, 1: packet data
69 |
70 | // Read from input register.
71 | assign input_rd_en =
72 | full_r & (state == STATE_PKT_INPUT)
73 | & (empty_r | ~empty_r & rd_en);
74 |
75 | // Write into output register.
76 | assign output_wr_en =
77 | (full_r & (state == STATE_PKT_INPUT)
78 | | (state == STATE_CHECKSUM1 | state == STATE_CHECKSUM2))
79 | & (empty_r | ~empty_r & rd_en);
80 |
81 | always @(posedge CLK) begin
82 | if (state == STATE_PKT_INPUT) begin
83 | if (output_wr_en) begin
84 |
85 | output_r <= input_r;
86 |
87 | if (pkt_new_r | ~checksum_counter) begin
88 | checksum_tmp <= input_r;
89 | checksum_counter <= 1;
90 | end
91 | else if (checksum_counter) begin
92 | checksum <= checksum + {input_r, checksum_tmp};
93 | checksum_counter <= 0;
94 | end
95 |
96 | if (~pkt_state & word_counter == PKT_HEADER_LEN/2 - 1
97 | //| word_counter == PKT_CHECKSUM_INTERVAL/2 - 1
98 | | pkt_end_r
99 | ) begin
100 | if (~checksum_counter)
101 | state <= STATE_CHECKSUM0;
102 | else
103 | state <= STATE_CHECKSUM1;
104 | end
105 | else
106 | word_counter <= word_counter + 1'b1;
107 | end // input_rd_en
108 | end
109 |
110 | else if (state == STATE_CHECKSUM0) begin
111 | checksum <= checksum + checksum_tmp;
112 | state <= STATE_CHECKSUM1;
113 | end
114 |
115 | else if (state == STATE_CHECKSUM1) begin
116 | if (output_wr_en) begin
117 | output_r <= ~checksum[15:0];
118 | state <= STATE_CHECKSUM2;
119 | end
120 | end
121 |
122 | else if (state == STATE_CHECKSUM2) begin
123 | if (output_wr_en) begin
124 | output_r <= ~checksum[31:16];
125 | checksum_counter <= 0;
126 | checksum <= 0;
127 |
128 | pkt_state <= ~pkt_state;
129 | word_counter <= 0;
130 | state <= STATE_PKT_INPUT;
131 | end
132 | end
133 | end
134 |
135 |
136 | endmodule
137 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/outpkt_v2.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | `include "../descrypt/descrypt_core/descrypt.vh"
4 |
5 | // ******************************************************
6 | //
7 | // * Read units of various data (all the packet data in parallel)
8 | // * Create output application packets (pkt_comm.h)
9 | // * Expect read from 16-bit output FIFO
10 | //
11 | // ******************************************************
12 |
13 | module outpkt_v2 #(
14 | parameter [7:0] VERSION = 1,
15 | parameter PKT_TYPE_MSB = 1
16 | )(
17 | input CLK,
18 |
19 | output full,
20 | input wr_en,
21 | input [PKT_TYPE_MSB:0] pkt_type,
22 | // data depends on packet type
23 | input [15:0] pkt_id, word_id, // this pkt_id is for inclusion into packet body for reference
24 | input [31:0] gen_id, num_processed,
25 | input [`RAM_ADDR_MSB:0] hash_num_eq,
26 |
27 | //input rd_clk,
28 | output [15:0] dout,
29 | input rd_en,
30 | output empty
31 | );
32 |
33 | localparam HEADER_LEN = 10; // in bytes
34 |
35 | localparam OUTPKT_TYPE_CMP_EQUAL = 8'hD1;
36 | localparam OUTPKT_TYPE_PACKET_DONE = 8'hD2;
37 |
38 | reg [PKT_TYPE_MSB:0] outpkt_type_r;
39 |
40 | wire [7:0] outpkt_type =
41 | outpkt_type_r == 'b01 ? OUTPKT_TYPE_CMP_EQUAL :
42 | outpkt_type_r == 'b10 ? OUTPKT_TYPE_PACKET_DONE :
43 | 0;
44 |
45 | wire [15:0] outpkt_len = // in bytes, must be even number
46 | outpkt_type_r == 'b01 ? 10 :
47 | outpkt_type_r == 'b10 ? 6 :
48 | 0;
49 |
50 |
51 | // Register everything then go.
52 | reg [15:0] pkt_id_r, word_id_r;
53 | reg [31:0] gen_id_r, num_processed_r;
54 | reg [`RAM_ADDR_MSB:0] hash_num_eq_r;
55 |
56 | // *************************************
57 | //
58 | // pkt_id for output packets.
59 | //
60 | // *************************************
61 | reg [15:0] outpkt_id = 0;
62 |
63 |
64 | reg full_r = 0;
65 | assign full = full_r;
66 |
67 | reg [7:0] count = 0;
68 |
69 | always @(posedge CLK) begin
70 | if (~full & wr_en) begin
71 | gen_id_r <= gen_id;
72 | pkt_id_r <= pkt_id;
73 | word_id_r <= word_id;
74 | num_processed_r <= num_processed;
75 | hash_num_eq_r <= hash_num_eq;
76 | outpkt_type_r <= pkt_type;
77 | full_r <= 1;
78 | end
79 |
80 | if (full_r & rd_en_pkt) begin
81 | if (count == outpkt_len[8:1] + HEADER_LEN/2 - 1) begin
82 | count <= 0;
83 | full_r <= 0;
84 | end
85 | else
86 | count <= count + 1'b1;
87 | end
88 | end
89 |
90 | wire pkt_new = count == 0;
91 |
92 | wire pkt_end = count == outpkt_len[8:1] + HEADER_LEN/2 - 1;
93 |
94 | wire [15:0] pkt_dout =
95 | // version, type
96 | count == 0 ? { outpkt_type, VERSION } :
97 | // reserved
98 | count == 1 ? 16'h0 :
99 | // data length
100 | count == 2 ? outpkt_len :
101 | count == 3 ? 16'h0 :
102 | // packet id
103 | count == 4 ? outpkt_id :
104 | // packet header ends
105 |
106 | count == 5 ? (
107 | outpkt_type == OUTPKT_TYPE_CMP_EQUAL ? pkt_id_r :
108 | outpkt_type == OUTPKT_TYPE_PACKET_DONE ? pkt_id_r :
109 | {16{1'b0}}
110 | ) :
111 | count == 6 ? (
112 | outpkt_type == OUTPKT_TYPE_CMP_EQUAL ? word_id_r :
113 | outpkt_type == OUTPKT_TYPE_PACKET_DONE ? num_processed_r[15:0] :
114 | {16{1'b0}}
115 | ) :
116 | count == 7 ? (
117 | outpkt_type == OUTPKT_TYPE_CMP_EQUAL ? gen_id_r[15:0] :
118 | outpkt_type == OUTPKT_TYPE_PACKET_DONE ? num_processed_r[31:16] :
119 | {16{1'b0}}
120 | ) :
121 | count == 8 ? (
122 | outpkt_type == OUTPKT_TYPE_CMP_EQUAL ? { gen_id_r[31:16] } :
123 | {16{1'b0}}
124 | ) :
125 | count == 9 ? (
126 | outpkt_type == OUTPKT_TYPE_CMP_EQUAL ? { {16-(`RAM_ADDR_MSB+1){1'b0}}, hash_num_eq_r } :
127 | {16{1'b0}}
128 | ) :
129 | {16{1'b0}};
130 |
131 |
132 | assign rd_en_pkt = full_r & ~full_checksum;
133 | assign wr_en_checksum = rd_en_pkt;
134 |
135 | outpkt_checksum outpkt_checksum(
136 | .CLK(CLK), .din(pkt_dout), .pkt_new(pkt_new), .pkt_end(pkt_end),
137 | .wr_en(wr_en_checksum), .full(full_checksum),
138 |
139 | .dout(dout), .rd_en(rd_en), .empty(empty)
140 | );
141 |
142 | endmodule
143 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/outpkt_word.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //
4 | // 1. Read words from wide bus
5 | // (FWFT style read)
6 | // 2. Create headers (packet type 0x81)
7 | // 3. Write packets into 16-bit wide fifo
8 | //
9 | module outpkt_word(
10 | input CLK,
11 |
12 | input [32+16+ 55:0] din,
13 | input [15:0] pkt_id,
14 | input wr_en,
15 | output full,
16 |
17 | output [15:0] dout,
18 | output pkt_new, pkt_end,
19 | input rd_en,
20 | output empty
21 | );
22 |
23 | reg full_r = 0;
24 | assign full = full_r;
25 | assign empty = ~full_r;
26 |
27 | reg [32+16+ 55:0] din_r;
28 | reg [15:0] pkt_id_r;
29 |
30 | localparam HEADER_LEN = 10; // in bytes
31 | localparam [15:0] DATA_LEN = 14; // in bytes
32 | localparam NUM_WRITES = (HEADER_LEN + DATA_LEN) / 2;
33 |
34 | reg [`MSB(NUM_WRITES-1):0] count = 0;
35 |
36 | always @(posedge CLK) begin
37 | if (~full & wr_en) begin
38 | din_r <= din;
39 | pkt_id_r <= pkt_id;
40 | full_r <= 1;
41 | end
42 |
43 | if (~empty & rd_en) begin
44 | if (count == NUM_WRITES - 1) begin
45 | count <= 0;
46 | full_r <= 0;
47 | end
48 | else
49 | count <= count + 1'b1;
50 | end
51 | end
52 |
53 | assign pkt_new = count == 0;
54 |
55 | assign pkt_end = count == NUM_WRITES - 1;
56 |
57 | assign dout =
58 | // version, type
59 | count == 0 ? { 8'h81, 8'h01 } :
60 | // no checksum for now
61 | count == 1 ? { {16{1'b0}} } :
62 | // data length
63 | count == 2 ? DATA_LEN :
64 | count == 3 ? 16'h0 :
65 | // packet id
66 | count == 4 ? pkt_id_r :
67 | // packet header ends
68 |
69 | // data
70 | count == 5 ? { 1'b0, din_r[13:7], 1'b0, din_r[6:0] } :
71 | count == 6 ? { 1'b0, din_r[27:21], 1'b0, din_r[20:14] } :
72 | count == 7 ? { 1'b0, din_r[41:35], 1'b0, din_r[34:28] } :
73 | count == 8 ? { 1'b0, din_r[55:49], 1'b0, din_r[48:42] } :
74 | // IDs - word_id
75 | count == 9 ? { din_r[71:56] } :
76 | // IDs - gen_id
77 | count == 10 ? { din_r[87:72] } :
78 | { din_r[103:88] };
79 |
80 |
81 | endmodule
82 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/pkt_comm.ucf:
--------------------------------------------------------------------------------
1 | #
2 | # pkt_comm
3 | #
4 | #AREA_GROUP "pkt_comm" RANGE=SLICE_X104Y80:SLICE_X115Y95; # 768 LUTs
5 | AREA_GROUP "pkt_comm" RANGE=SLICE_X100Y80:SLICE_X109Y95;
6 | #AREA_GROUP "pkt_comm" RANGE=SLICE_XY80:SLICE_X109Y95;
7 | INST "pkt_comm/inpkt_header/*" AREA_GROUP = "pkt_comm";
8 | INST "pkt_comm/word_list/*" AREA_GROUP = "pkt_comm";
9 | INST "pkt_comm/outpkt/*" AREA_GROUP = "pkt_comm";
10 |
11 | INST "pkt_comm/extra_reg_empty*" AREA_GROUP = "pkt_comm";
12 | #
13 | #
14 | #
15 | #AREA_GROUP "io2" RANGE=SLICE_X84Y80:SLICE_X97Y99;
16 | #INST "input_fifo/fifo_bram_8x1024_fwft/*" AREA_GROUP = "io2";
17 | #INST "output_fifo/fifo_dram_async_16/*" AREA_GROUP = "io2";
18 | #INST "pkt_comm/fifo_dram_async_120/*" AREA_GROUP = "io2";
19 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/pkt_comm.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // *********************************************************
4 | //
5 | // Packet-Based Communication for FPGA Application
6 | //
7 | // Host Software sends data:
8 | // * to different subsystems of FPGA application
9 | // * in sequential packets
10 | //
11 | // see pkt_comm.h for packet format
12 | //
13 | // Naming: in*, out* from the point of view from FPGA application
14 | //
15 | // *********************************************************
16 |
17 | module pkt_comm #(
18 | parameter VERSION = 1,
19 | parameter PKT_MAX_LEN = 16*65536,
20 | parameter PKT_LEN_MSB = `MSB(PKT_MAX_LEN)
21 | )(
22 | input CLK,
23 | input WORD_GEN_CLK,
24 | input CORE_CLK,
25 | input CMP_CLK,
26 |
27 | // read from some internal FIFO (recieved via high-speed interface)
28 | input [7:0] din,
29 | output rd_en,
30 | input empty,
31 |
32 | // write into some internal FIFO (to be send via high-speed interface)
33 | //output [63:0] dout,
34 | output [15:0] dout,
35 | output wr_en,
36 | input full,
37 |
38 | // control input (VCR interface)
39 | input [7:0] app_mode,
40 | // status output (VCR interface)
41 | output [7:0] app_status,
42 | output [7:0] pkt_comm_status,
43 | output [7:0] debug2
44 | );
45 |
46 |
47 | assign debug2 = 8'hd2;
48 | assign app_status = app_mode;
49 |
50 |
51 | localparam DISABLE_TEST_MODES_0_AND_1 = 0;
52 |
53 | //assign rd_en = inpkt_rd_en;
54 | //assign wr_en = output_fifo_wr_en;
55 | //assign dout = dout_mode2;
56 |
57 | // **************************************************
58 | //
59 | // Application modes 0 & 1: send back what received
60 | // used by simple_test.c and test.c
61 | //
62 | // **************************************************
63 | //assign dout = din;
64 |
65 | // convert 8-bit to 16-bit
66 | reg [15:0] dout_app_mode01;
67 | reg dout_app_mode01_ready = 0;
68 | reg counter = 0;
69 |
70 | assign rd_en =
71 | DISABLE_TEST_MODES_0_AND_1 | app_mode==2 || app_mode==3 ? inpkt_rd_en :
72 | app_mode==0 || app_mode==1 ? ~empty & ~full :
73 | 1'b0;
74 |
75 | assign wr_en =
76 | DISABLE_TEST_MODES_0_AND_1 | app_mode==2 ? output_fifo_wr_en :
77 | app_mode==0 || app_mode==1 ? dout_app_mode01_ready :
78 | //app_mode==3 ?
79 | 1'b0;
80 |
81 | assign dout =
82 | DISABLE_TEST_MODES_0_AND_1 | app_mode==2 ? dout_app_mode2 :
83 | app_mode==0 || app_mode==1 ? dout_app_mode01 :
84 | //app_mode==3 ?
85 | 16'b0;//64'b0;
86 |
87 | if (!DISABLE_TEST_MODES_0_AND_1) begin
88 |
89 | always @(posedge CLK) begin
90 | if (counter == 0) begin
91 | dout_app_mode01_ready <= 0;
92 | end
93 | if (rd_en && (app_mode == 8'h00 || app_mode == 8'h01) ) begin
94 | if (counter == 0) begin
95 | dout_app_mode01[7:0] <= din;
96 | end
97 | else if (counter == 1) begin
98 | dout_app_mode01[15:8] <= din;
99 | dout_app_mode01_ready <= 1;
100 | end
101 | counter <= counter + 1'b1;
102 | end
103 | end // CLK
104 |
105 | end // !DISABLE_TEST_MODES_0_AND_1
106 |
107 |
108 | assign pkt_comm_status = {
109 | 1'b0, err_word_gen_conf, err_word_list_len, err_word_list_count,
110 | err_pkt_version, err_inpkt_type, err_inpkt_len, err_inpkt_checksum
111 | };
112 |
113 |
114 | // **************************************************
115 | //
116 | // Application mode 2 & 3: read packets
117 | // process data base on packet type
118 | //
119 | // **************************************************
120 |
121 | localparam PKT_TYPE_WORD_LIST = 1;
122 | localparam PKT_TYPE_WORD_GEN = 2;
123 | localparam PKT_TYPE_CONFIG = 3;
124 |
125 | localparam PKT_MAX_TYPE = 3;
126 |
127 | reg error = 0;
128 | always @(posedge CLK)
129 | error <= inpkt_err | err_word_gen_conf | err_word_list_len | err_word_list_count;
130 |
131 |
132 | wire [`MSB(PKT_MAX_TYPE):0] inpkt_type;
133 | wire [15:0] inpkt_id;
134 |
135 | inpkt_header #(
136 | .VERSION(VERSION),
137 | .PKT_MAX_LEN(PKT_MAX_LEN),
138 | .PKT_MAX_TYPE(PKT_MAX_TYPE)
139 | ) inpkt_header(
140 | .CLK(CLK),
141 | .din(din),
142 | .wr_en(inpkt_rd_en),
143 | .pkt_type(inpkt_type), .pkt_id(inpkt_id), .pkt_data(inpkt_data),
144 | .pkt_end(inpkt_end), .pkt_err(inpkt_err),
145 | .err_pkt_version(err_pkt_version), .err_pkt_type(err_inpkt_type),
146 | .err_pkt_len(err_inpkt_len), .err_pkt_checksum(err_inpkt_checksum)
147 | );
148 |
149 | // input packet processing: read enable
150 | assign inpkt_rd_en = ~empty & ~error
151 | & (~inpkt_data | word_gen_conf_en | word_list_wr_en);
152 |
153 |
154 | localparam WORD_MAX_LEN = 8;
155 | localparam CHAR_BITS = 7;
156 | localparam RANGES_MAX = 8;
157 |
158 |
159 | // **************************************************
160 | //
161 | // input packet type WORD_LIST (0x01)
162 | //
163 | // **************************************************
164 | wire word_list_wr_en = ~empty & ~error
165 | & inpkt_type == PKT_TYPE_WORD_LIST & inpkt_data & ~word_list_full;
166 |
167 | wire [WORD_MAX_LEN * CHAR_BITS - 1:0] word_list_dout;
168 | wire [`MSB(WORD_MAX_LEN):0] word_len;
169 | wire [15:0] word_id;
170 |
171 | word_list #(
172 | .CHAR_BITS(CHAR_BITS), .WORD_MAX_LEN(WORD_MAX_LEN)
173 | ) word_list(
174 | .wr_clk(CLK), .din(din),
175 | .wr_en(word_list_wr_en), .full(word_list_full), .inpkt_end(inpkt_end),
176 |
177 | .rd_clk(WORD_GEN_CLK),
178 | .dout(word_list_dout), .word_len(word_len), .word_id(word_id), .word_list_end(word_list_end),
179 | .rd_en(word_list_rd_en), .empty(word_list_empty),
180 |
181 | .err_word_list_len(err_word_list_len), .err_word_list_count(err_word_list_count)
182 | );
183 |
184 |
185 | // **************************************************
186 | //
187 | // input packet type WORD_GEN (0x02)
188 | //
189 | // **************************************************
190 | wire word_gen_conf_en = ~empty & ~error
191 | & inpkt_type == PKT_TYPE_WORD_GEN & inpkt_data & ~word_gen_conf_full;
192 |
193 | wire word_wr_en = ~word_list_empty & ~word_full;
194 | assign word_list_rd_en = word_wr_en;
195 |
196 | wire [WORD_MAX_LEN * CHAR_BITS - 1:0] word_gen_dout;
197 | wire [15:0] pkt_id, word_id_out;
198 | wire [31:0] gen_id;
199 |
200 | word_gen #(
201 | .CHAR_BITS(CHAR_BITS), .RANGES_MAX(RANGES_MAX), .WORD_MAX_LEN(WORD_MAX_LEN)
202 | ) word_gen(
203 | .CLK(CLK), .din(din),
204 | .inpkt_id(inpkt_id), .wr_conf_en(word_gen_conf_en), .conf_full(word_gen_conf_full),
205 |
206 | .word_in(word_list_dout), .word_len(word_len), .word_id(word_id), .word_list_end(word_list_end),
207 | .word_wr_en(word_wr_en), .word_full(word_full),
208 |
209 | .WORD_GEN_CLK(WORD_GEN_CLK),
210 | .rd_en(word_gen_rd_en), .empty(word_gen_empty),
211 | .dout(word_gen_dout), .pkt_id(pkt_id), .word_id_out(word_id_out), .gen_id(gen_id), .gen_end(gen_end),
212 |
213 | .err_word_gen_conf(err_word_gen_conf)
214 | );
215 | //
216 | // OK. Got words with ID's.
217 | //
218 | //wire [32 + 16 + WORD_MAX_LEN * CHAR_BITS -1 :0] word_gen_out =
219 | // { gen_id, word_id_out, word_gen_dout };
220 | //
221 | // also [15:0] pkt_id from incoming packet.
222 |
223 |
224 | assign word_gen_rd_en = ~word_gen_empty & ~fifo120_almost_full_r;
225 |
226 | wire extra_reg_wr_en = word_gen_rd_en;
227 |
228 | //
229 | // Words are written into intermediate FIFO at generation speed.
230 | // Extra register stage is required.
231 | //
232 | reg fifo120_almost_full_r = 0;
233 | always @(posedge WORD_GEN_CLK)
234 | fifo120_almost_full_r <= fifo120_almost_full;
235 |
236 | reg [WORD_MAX_LEN * CHAR_BITS - 1:0] word_gen_dout_r;
237 | reg [15:0] pkt_id_r, word_id_out_r;
238 | reg [31:0] gen_id_r;
239 | reg gen_end_r;
240 | reg extra_reg_empty = 1;
241 |
242 | always @(posedge WORD_GEN_CLK)
243 | if (extra_reg_wr_en) begin
244 | extra_reg_empty <= 0;
245 | word_gen_dout_r <= word_gen_dout;
246 | pkt_id_r <= pkt_id; word_id_out_r <= word_id_out;
247 | gen_id_r <= gen_id; gen_end_r <= gen_end;
248 | end
249 | else if (fifo120_wr_en)
250 | extra_reg_empty <= 1;
251 |
252 | wire fifo120_wr_en = ~extra_reg_empty & ~fifo120_full;
253 |
254 | wire [119:0] fifo120_dout;
255 |
256 | //
257 | // IP Coregen: FIFO, DRAM, Independent Clocks, 1st Word Fall-Through
258 | // Almost Full Flag
259 | //
260 | fifo_dram_async_112 fifo_dram_async_120 (
261 | .wr_clk(WORD_GEN_CLK),
262 | .din({ gen_id_r, word_id_out_r, word_gen_dout_r, pkt_id_r }),
263 | //.din({ gen_id, word_id_out, word_gen_dout, pkt_id }),
264 | .wr_en(fifo120_wr_en),//word_gen_rd_en),
265 | .full(fifo120_full),
266 | .almost_full(fifo120_almost_full),
267 |
268 | .rd_clk(CLK),
269 | .dout(fifo120_dout),
270 | .rd_en(wr_en_outpkt),
271 | .empty(fifo120_empty)
272 | );
273 |
274 | assign wr_en_outpkt = ~fifo120_empty & ~full_outpkt;
275 |
276 |
277 | // **************************************************
278 | //
279 | // Application mode 2.
280 | //
281 | // each word (wire [WORD_MAX_LEN * CHAR_BITS -1:0] word_gen_dout)
282 | // converted to 8-bit ascii
283 | // and sent in a separate packet along with
284 | // word_id, gen_id.
285 | // pkt_id (that comes from input packet_id) goes into packet_id.
286 | //
287 | // **************************************************
288 |
289 | // **************************************************
290 | //
291 | // output packet type 0x81
292 | // header is 10 bytes
293 | // contains 1 word (8 bytes) + IDs (6 bytes)
294 | //
295 | // **************************************************
296 | wire [15:0] outpkt_dout;
297 |
298 | // read from word_list
299 | //assign word_list_rd_en = ~word_list_empty & ~full_outpkt;
300 | //wire wr_en_outpkt = word_list_rd_en;
301 |
302 | // read from word_gen
303 | //assign word_gen_rd_en = ~word_gen_empty & ~full_outpkt;
304 | //wire wr_en_outpkt = word_gen_rd_en;
305 |
306 |
307 | outpkt_word outpkt(
308 | .CLK(CLK),
309 | //.din({ 32'b0, word_id, word_list_dout }), .pkt_id(inpkt_id),
310 | //.din({ gen_id, word_id_out, word_gen_dout }), .pkt_id(pkt_id),
311 | .din(fifo120_dout[119:16]), .pkt_id(fifo120_dout[15:0]),
312 | .wr_en(wr_en_outpkt), .full(full_outpkt),
313 |
314 | .dout(outpkt_dout), .pkt_new(outpkt_new), .pkt_end(outpkt_end),
315 | .rd_en(rd_en_outpkt), .empty(empty_outpkt)
316 | );
317 |
318 | //assign rd_en_outpkt = ~empty_outpkt & ~full;
319 | //assign output_fifo_wr_en = rd_en_outpkt;
320 | wire [15:0] dout_app_mode2;
321 |
322 | assign rd_en_outpkt = ~empty_outpkt & ~full_outpkt_checksum;
323 | wire wr_en_outpkt_checksum = rd_en_outpkt;
324 |
325 | outpkt_checksum outpkt_checksum(
326 | .CLK(CLK), .din(outpkt_dout), .pkt_new(outpkt_new), .pkt_end(outpkt_end),
327 | .wr_en(wr_en_outpkt_checksum), .full(full_outpkt_checksum),
328 | .dout(dout_app_mode2), .rd_en(rd_en_outpkt_checksum), .empty(empty_outpkt_checksum)
329 | );
330 |
331 | assign rd_en_outpkt_checksum = ~empty_outpkt_checksum & ~full;
332 | assign output_fifo_wr_en = rd_en_outpkt_checksum;
333 |
334 | endmodule
335 |
336 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/pkt_comm_test.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 |
4 | module pkt_comm_test();
5 |
6 | integer i;
7 | integer k;
8 |
9 | reg CLK = 0, CMP_CLK = 0, CORE_CLK = 0, IFCLK = 0, WORD_GEN_CLK = 0;
10 |
11 | reg [7:0] din;
12 |
13 | wire [15:0] app_dout;
14 | reg [7:0] app_mode = 8'd02;
15 | wire [7:0] app_status, pkt_comm_status, debug2;
16 |
17 | wire [7:0] hs_input_dout;
18 | reg wr_en = 0;
19 |
20 | fifo_bram_8x1024_fwft fifo_bram_8x1024_fwft(
21 | .wr_clk(CLK),
22 | .din(din),
23 | .wr_en(wr_en),
24 | .full(),
25 |
26 | .rd_clk(CLK),
27 | .dout(hs_input_dout),
28 | .rd_en(hs_input_rd_en),
29 | .empty(hs_input_empty)
30 | );
31 |
32 | pkt_comm_arbiter #(.DISABLE_CHECKSUM(1)) pkt_comm(
33 | .CLK(CLK),
34 | .WORD_GEN_CLK(WORD_GEN_CLK),
35 | .CORE_CLK(CORE_CLK),
36 | .CMP_CLK(CMP_CLK),
37 | // High-Speed FPGA input
38 | .din(hs_input_dout),
39 | .rd_en(hs_input_rd_en),
40 | .empty(hs_input_empty),
41 | // High-Speed FPGA output
42 | .dout(app_dout),
43 | .wr_en(app_wr_en),
44 | .full(app_full),
45 | // Application control (via VCR I/O). Set with fpga_set_app_mode()
46 | .app_mode(app_mode),
47 | // Application status (via VCR I/O). Available at fpga->wr.io_state.app_status
48 | .pkt_comm_status(pkt_comm_status),
49 | .debug2(debug2),
50 | .app_status(app_status)
51 | );
52 |
53 | output_fifo output_fifo(
54 | .wr_clk(CMP_CLK),
55 | .din(app_dout),
56 | .wr_en(app_wr_en),
57 | .full(app_full),
58 |
59 | .rd_clk(IFCLK),
60 | .dout(), // wired to Cypress IO,
61 | .rd_en(1'b0), // wired to Cypress IO,
62 | .empty(), // wired to Cypress IO
63 | .mode_limit(1'b1),
64 | .reg_output_limit(1'b0),
65 | .output_limit(),
66 | .output_limit_not_done()
67 | );
68 |
69 | /*
70 | reg [15:0] r [127:0];
71 | initial
72 | for (i=0; i < 128; i=i+1)
73 | r[i] = 0;
74 |
75 | reg [15:0] cnt = 0;
76 | always @(posedge CMP_CLK)
77 | if (app_wr_en) begin
78 | r[cnt] <= app_dout;
79 | cnt <= cnt + 1'b1;
80 | end
81 | */
82 | initial begin
83 | #1000;
84 | wr_en <= 1;
85 | // write cmp_config packet
86 | din <= 1; #20; // ver
87 | din <= 3; #20; // type
88 | din <= 0; #40; // reserved0
89 | din <= 13 + 9*8; #20; // len[7:0]
90 | din <= 0; #40; // len[23:0]
91 | din <= 0; #20; // reserved1
92 | din <= 8'hAB; #20; // id0
93 | din <= 8'hCD; #20; // id1;
94 | din <= 0; #80; // checksum
95 |
96 | // 10 hashes
97 | din <= 8'hC7; #20;
98 | din <= 8'h01; #20;
99 | din <= 8'd10; #20;
100 | din <= 8'h00; #20;
101 | din <= 8'hbb; #1600;
102 | din <= 8'hCC; #20;
103 |
104 | din <= 0; #80; // checksum
105 | wr_en <= 0;
106 | end
107 |
108 | initial begin
109 | #50000;
110 | wr_en <= 1;
111 | // write cmp_config packet
112 | din <= 1; #20; // ver
113 | din <= 3; #20; // type
114 | din <= 0; #40; // reserved0
115 | din <= 5+2*8; #20; // len[7:0]
116 | din <= 0; #40; // len[23:0]
117 | din <= 0; #20; // reserved1
118 | din <= 8'hAB; #20; // id0
119 | din <= 8'hCD; #20; // id1;
120 | din <= 0; #80; // checksum
121 |
122 | din <= 8'hC7; #20; // salt "55"
123 | din <= 8'h01; #20;
124 | din <= 8'h02; #20; // 2 hashes
125 | din <= 8'h00; #20;
126 | // hash for "mypwd123"
127 | din <= 8'had; #20; din <= 8'h31; #20; din <= 8'h87; #20; din <= 8'hcc; #20;
128 | din <= 8'he3; #20; din <= 8'hf4; #20; din <= 8'h51; #20; din <= 8'hac; #20;
129 | // "mypwd999"
130 | din <= 8'hcb; #20; din <= 8'h68; #20; din <= 8'h00; #20; din <= 8'h08; #20;
131 | din <= 8'h8f; #20; din <= 8'h7a; #20; din <= 8'h7d; #20; din <= 8'he4; #20;
132 | din <= 8'hCC; #20;
133 |
134 | din <= 0; #80; // checksum
135 | wr_en <= 0;
136 | end
137 |
138 | initial begin
139 | #100000;
140 |
141 | for (k=0; k < 2; k=k+1) begin
142 |
143 | wr_en <= 1;
144 | // word_gen packet
145 | din <= 1; #20; din <= 2; #20; din <= 0; #40;
146 | din <= 35; #20; // len[7:0]
147 | din <= 0; #60; din <= 8'h07; #40; din <= 0; #80;
148 | // body
149 | din <= 8; #20; // num_ranges
150 | din <= 1; #20; din <= 0; #20; din <= "m"; #20;
151 | din <= 1; #20; din <= 0; #20; din <= "y"; #20;
152 | din <= 1; #20; din <= 0; #20; din <= "p"; #20;
153 | din <= 1; #20; din <= 0; #20; din <= "w"; #20;
154 | din <= 1; #20; din <= 0; #20; din <= "d"; #20;
155 | din <= 1; #20; din <= 0; #20; din <= "9"; #20; //din <= "1"; #20;
156 | din <= 1; #20; din <= 0; #20; din <= "9"; #20; //din <= "2"; #20;
157 | din <= 5; #20; din <= 0; #20; din <= "9"; #100; //din <= "0"; #20; din <= "3"; #20;
158 |
159 | din <= 0; #20; // num_words
160 | din <= 0; #80; din <= 8'hbb; #20;
161 | din <= 0; #80; // checksum
162 | wr_en <= 0;
163 |
164 | end
165 |
166 | end
167 |
168 | initial begin
169 | #5;
170 | while (1) begin
171 | CLK <= ~CLK; #10;
172 | end
173 | end
174 |
175 | initial begin
176 | #4;
177 | while (1) begin
178 | CORE_CLK <= ~CORE_CLK; #8;
179 | end
180 | end
181 |
182 | initial begin
183 | #7;
184 | while (1) begin
185 | CMP_CLK <= ~CMP_CLK; #14;
186 | end
187 | end
188 |
189 | initial begin
190 | #35;
191 | while (1) begin
192 | IFCLK <= ~IFCLK; #70;
193 | end
194 | end
195 |
196 | initial begin
197 | #3;
198 | while (1) begin
199 | WORD_GEN_CLK <= ~WORD_GEN_CLK; #6;
200 | end
201 | end
202 |
203 | endmodule
204 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/word_gen.ucf:
--------------------------------------------------------------------------------
1 | AREA_GROUP "word_gen" RANGE=SLICE_X110Y80:SLICE_X119Y95,SLICE_X120Y86:SLICE_X123Y89;
2 | INST "pkt_comm/word_gen/*" AREA_GROUP = "word_gen";
3 |
4 | AREA_GROUP "word_gen_ranges" RANGE=RAMB8_X5Y40:RAMB8_X5Y47;
5 | AREA_GROUP "word_gen_ranges" RANGE=SLICE_X120Y80:SLICE_X123Y95;
6 | INST "pkt_comm/word_gen/char_ranges[*].word_gen_char_range/*" AREA_GROUP="word_gen_ranges";
7 |
8 | AREA_GROUP "word_gen_backyard" RANGE=SLICE_X124Y80:SLICE_X127Y95;
9 | INST "pkt_comm/word_gen/char_ranges[*].word_gen_char_range/start_idx*" AREA_GROUP="word_gen_backyard";
10 | INST "pkt_comm/word_gen/char_ranges[*].word_gen_char_range/num_chars_*_r" AREA_GROUP="word_gen_backyard";
11 |
12 | NET "pkt_comm/word_gen/char_ranges[*].word_gen_char_range/start_idx*" TIG;
13 | NET "pkt_comm/word_gen/char_ranges[*].word_gen_char_range/num_chars_*_r" TIG;
14 |
15 | AREA_GROUP "word_gen_side" RANGE=SLICE_X118Y80:SLICE_X119Y85,SLICE_X118Y90:SLICE_X119Y95;
16 | INST "pkt_comm/word_gen/char_ranges[*].word_gen_char_range/dout_r2*" AREA_GROUP="word_gen_side";
17 |
18 | INST "pkt_comm/word_gen/word_full" LOC=SLICE_X120Y87;
19 | INST "pkt_comm/word_gen/op_state_FSM_FFd5" LOC=SLICE_X121Y88;
20 | INST "pkt_comm/word_gen/op_state_FSM_FFd9" LOC=SLICE_X120Y89;
21 |
22 |
23 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/word_gen.vh:
--------------------------------------------------------------------------------
1 | //`ifndef WORD_GEN_VH
2 |
3 | // Extra stage suggested if BRAM is used.
4 | localparam EXTRA_REGISTER_STAGE = 1;
5 |
6 | localparam OP_STATE_READY = 0,
7 | OP_STATE_START = 1,
8 | OP_STATE_EXTRA_STAGE = 2,
9 | OP_STATE_NEXT_CHAR = 3,
10 | OP_STATE_NEXT_WORD = 4,
11 | OP_STATE_DONE = 5;
12 |
13 |
14 | //`define WORD_GEN_VH
15 | //`endif
16 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/word_gen_char_range.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | module word_gen_char_range #(
4 | parameter CHAR_BITS = 7, // valid values: 7 8
5 | parameter CHARS_NUMBER_MAX = CHAR_BITS == 7 ? 96 : 224,
6 | parameter NUM_CHARS_MSB = `MSB(CHARS_NUMBER_MAX)
7 | )(
8 | input CONF_CLK, // configuration clock
9 | input [CHAR_BITS-1:0] din,
10 |
11 | input conf_en_num_chars,
12 | input num_chars_eq0, // number of chars in the range equals to 0
13 | input num_chars_lt2, // less than 2 chars in the range
14 |
15 | input conf_en_start_idx,
16 |
17 | input conf_en_chars,
18 | input [NUM_CHARS_MSB:0] conf_char_addr,
19 | input pre_end_char, // asserted on char before last char in the range (conf_en_chars)
20 |
21 | input OP_CLK, // generation clock
22 | input op_en,
23 | input [2:0] op_state,
24 | input op_done_sync,
25 |
26 | input carry_in,
27 | output carry,
28 | output [CHAR_BITS-1:0] dout
29 | );
30 |
31 | `include "word_gen.vh"
32 |
33 | reg num_chars_eq0_r = 1;
34 | reg num_chars_lt2_r = 1;
35 | reg [NUM_CHARS_MSB:0] current_idx = 0;
36 | reg [NUM_CHARS_MSB:0] start_idx;
37 |
38 | wire do_next;
39 |
40 | wire [1+ CHAR_BITS-1:0] dina = { pre_end_char, din[NUM_CHARS_MSB:0]};
41 | wire pre_end_char_out;
42 | wire [CHAR_BITS-1:0] char_out;
43 |
44 | word_gen_range_ram #( .ADDR_MSB(CHAR_BITS-1), .WIDTH(1+ CHAR_BITS)
45 | ) ram(
46 | .wr_clk(CONF_CLK), .addra(conf_char_addr), .ena(conf_en_chars),
47 | .dina(dina),
48 |
49 | .rd_clk(OP_CLK),
50 | .addrb(current_idx), .enb(do_next), .rstb(num_chars_eq0_r),
51 | .doutb({pre_end_char_out, char_out})
52 | );
53 |
54 | always @(posedge OP_CLK) begin
55 | if (op_state == OP_STATE_READY | op_state == OP_STATE_NEXT_WORD)
56 | current_idx <= start_idx;
57 |
58 | else if ((do_next & pre_end_char_out) | num_chars_lt2_r)
59 | current_idx <= 0;
60 |
61 | else if (do_next)
62 | current_idx <= current_idx + 1'b1;
63 |
64 | end
65 |
66 | reg carry_r;
67 | always @(posedge OP_CLK)
68 | if (do_next)
69 | carry_r <= pre_end_char_out | num_chars_lt2_r;
70 |
71 |
72 | // Extra register stage
73 | if (EXTRA_REGISTER_STAGE) begin
74 |
75 | assign do_next =
76 | op_state == OP_STATE_START | op_state == OP_STATE_EXTRA_STAGE
77 | | op_state == OP_STATE_NEXT_CHAR & op_en & carry_in;
78 |
79 | reg carry_r2;
80 | reg [CHAR_BITS-1:0] dout_r2;
81 | always @(posedge OP_CLK)
82 | if (do_next) begin
83 | carry_r2 <= carry_r;
84 | dout_r2 <= char_out;
85 | end
86 |
87 | assign carry = carry_r2;
88 | assign dout = dout_r2;
89 |
90 | end else begin
91 |
92 | assign do_next =
93 | op_state == OP_STATE_START
94 | | op_state == OP_STATE_NEXT_CHAR & op_en & carry_in;
95 |
96 | assign carry = carry_r;
97 | assign dout = char_out;
98 |
99 | end // EXTRA_REGISTER_STAGE
100 |
101 |
102 | // Range configuration
103 | always @(posedge CONF_CLK) begin
104 | if (op_done_sync) begin
105 | num_chars_eq0_r <= 1;
106 | num_chars_lt2_r <= 1;
107 | end
108 | else if (conf_en_num_chars) begin
109 | num_chars_eq0_r <= num_chars_eq0;
110 | num_chars_lt2_r <= num_chars_lt2;
111 | end
112 | end
113 |
114 | always @(posedge CONF_CLK)
115 | if (conf_en_start_idx)
116 | start_idx <= din[NUM_CHARS_MSB:0];
117 |
118 | endmodule
119 |
120 |
121 | module word_gen_range_ram #(
122 | parameter ADDR_MSB = 0,
123 | parameter WIDTH = 18
124 | )(
125 | input wr_clk,
126 | input [ADDR_MSB:0] addra,
127 | input [WIDTH-1:0] dina,
128 | input ena,
129 |
130 | input rd_clk,
131 | input [ADDR_MSB:0] addrb,
132 | input rstb, enb,
133 | output [WIDTH-1:0] doutb
134 | );
135 |
136 | (* RAM_STYLE = "BLOCK" *)
137 | //(* RAM_STYLE = "DISTRIBUTED" *)
138 | reg [WIDTH-1:0] ram [2**(ADDR_MSB+1)-1:0];
139 | reg [WIDTH-1:0] ram_out_r;
140 | assign doutb = ram_out_r;
141 |
142 | always @(posedge wr_clk)
143 | // Port A write
144 | if (ena)
145 | ram[addra] <= dina;
146 |
147 | always @(posedge rd_clk) begin
148 | //
149 | // UG383 Spartan-6 Block RAM User Guide pg.21
150 | // "... the set/reset function is active only
151 | // when the enable pin of the port is active."
152 | //
153 | // Port B reset (RSTBRST)
154 | if (rstb)
155 | ram_out_r <= 0;
156 |
157 | // Port B read enable (ENBRDEN)
158 | else if (enb)
159 | ram_out_r <= ram[addrb];
160 | end
161 |
162 | endmodule
163 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/word_insert.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // There's a result from word generator in 'range_dout'
4 | // 1. insert word (length='word_len') at position 'word_pos'
5 | // - if !word_len, pass-by input from word generator
6 | // 2. pad empty chars with 0's up to WORD_MAX_LEN
7 | //
8 | module word_insert #(
9 | parameter CHAR_BITS = 7,
10 | parameter RANGES_MAX = 8,
11 | parameter WORD_MAX_LEN = RANGES_MAX,
12 | parameter WORDS_INSERT_MAX = 1,
13 | parameter WORD_LEN_MSB = `MSB(WORD_MAX_LEN)
14 | )(
15 | input [RANGES_MAX * CHAR_BITS - 1 :0] range_dout,
16 | input [WORD_MAX_LEN * CHAR_BITS - 1 :0] word_in,
17 | input [WORD_LEN_MSB:0] word_len,
18 | input [`MSB(WORD_MAX_LEN-1):0] word_pos,
19 | output [WORD_MAX_LEN * CHAR_BITS - 1 :0] dout
20 | );
21 |
22 | localparam WORD_LEN_NBITS = WORD_LEN_MSB + 1;
23 |
24 |
25 | wire [WORD_MAX_LEN * CHAR_BITS - 1 :0] shifts [WORD_MAX_LEN-1:0];
26 |
27 | genvar i;
28 |
29 | generate
30 | for (i=0; i < WORD_MAX_LEN; i=i+1)
31 | begin: shifts_gen
32 |
33 | assign shifts[i] =
34 | { range_dout[(WORD_MAX_LEN-i) * CHAR_BITS - 1 :0], {i*CHAR_BITS{1'b0}} };
35 |
36 | end
37 | endgenerate
38 |
39 | // if result char to be taken from some range
40 | //wire [WORD_MAX_LEN-1:0] if_range;
41 | wire [WORD_MAX_LEN-1:0] if_range_pass_by;
42 | wire [WORD_MAX_LEN-1:0] if_range_shift;
43 |
44 | // if result char to be taken from inserted word
45 | wire [WORD_MAX_LEN-1:0] if_word;
46 |
47 | generate
48 | for (i=0; i < WORD_MAX_LEN; i=i+1)
49 | begin: if_range_gen
50 |
51 | //assign if_range[i] = word_pos > i || word_pos + word_len <= i;
52 | assign if_range_pass_by[i] = !word_len || word_pos > i;
53 | assign if_range_shift[i] = word_pos + word_len <= i;
54 |
55 | assign if_word[i] = word_pos <= i && word_pos + word_len > i;
56 |
57 | end
58 | endgenerate
59 |
60 |
61 | generate
62 | for (i=0; i < WORD_MAX_LEN; i=i+1)
63 | begin: dout_gen
64 |
65 | assign dout [(i+1)*CHAR_BITS-1 -:CHAR_BITS] =
66 |
67 | if_range_pass_by[i] ? range_dout[(i+1)*CHAR_BITS-1 -:CHAR_BITS] :
68 | //if_word[i] ? word_in[(i+1)*CHAR_BITS-1 -:CHAR_BITS] :
69 |
70 | if_range_shift[i] ? shifts[word_len][(i+1)*CHAR_BITS-1 -:CHAR_BITS] :
71 |
72 | //range_dout[(i+1)*CHAR_BITS-1 -:CHAR_BITS];
73 | word_in[(i+1)*CHAR_BITS-1 -:CHAR_BITS];
74 |
75 | end
76 | endgenerate
77 |
78 |
79 | endmodule
80 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/word_list.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //
4 | // Process incoming ASCII words (\0 terminated) char by char.
5 | //
6 | module word_list #(
7 | parameter CHAR_BITS = 7,
8 | parameter WORD_MAX_LEN = 8
9 | )(
10 | input wr_clk,
11 | input [7:0] din,
12 | input wr_en,
13 | output full,
14 | input inpkt_end,
15 |
16 | input rd_clk,
17 | output [WORD_MAX_LEN*CHAR_BITS-1:0] dout,
18 | output [`MSB(WORD_MAX_LEN):0] word_len, // 4 bits if max.len==8
19 | output [15:0] word_id,
20 | output word_list_end,
21 | input rd_en,
22 | output empty,
23 |
24 | output reg err_word_list_len = 0, err_word_list_count = 0
25 | );
26 |
27 | reg full_r = 0;
28 | assign full = full_r;
29 |
30 | reg [WORD_MAX_LEN*CHAR_BITS-1:0] dout_r = { WORD_MAX_LEN*CHAR_BITS {1'b0}};
31 |
32 | reg [15:0] word_id_r = 0;
33 |
34 | reg word_list_end_r = 0;
35 |
36 | reg [`MSB(WORD_MAX_LEN):0] char_count = 0;
37 |
38 |
39 | always @(posedge wr_clk) begin
40 | if (~full_r & wr_en) begin
41 | if ( !din && !char_count ) begin
42 | // extra \0 or empty word - skip
43 | end
44 | else if (!din) begin
45 | // word ends
46 | full_r <= 1;
47 | end
48 | else begin
49 | if (char_count == WORD_MAX_LEN) begin
50 | // word exceeds max.length; extra chars skipped
51 | err_word_list_len <= 1;
52 | end
53 | else begin
54 | dout_r[(char_count + 1'b1)*CHAR_BITS-1 -:CHAR_BITS] <= din[CHAR_BITS-1:0];
55 | char_count <= char_count + 1'b1;
56 | end
57 | end
58 |
59 | if (inpkt_end) begin
60 | word_list_end_r <= 1;
61 | // packet ends and last word not terminated with '\0' - let it go
62 | full_r <= 1;
63 | end
64 | end // ~full & wr_en
65 |
66 | else if (full_r & rd_en_internal) begin
67 | full_r <= 0;
68 | dout_r <= { WORD_MAX_LEN*CHAR_BITS {1'b0}};
69 | char_count <= 0;
70 | word_list_end_r <= 0;
71 | if (word_list_end_r)
72 | word_id_r <= 0;
73 | else
74 | word_id_r <= word_id_r + 1'b1;
75 |
76 | if ( ~|(word_id_r + 1'b1) )
77 | // word_id_r overflows
78 | err_word_list_count <= 1;
79 | end
80 | end
81 |
82 | assign rd_en_internal = full_r & ~output_reg_full;
83 |
84 | cdc_reg #( .WIDTH(WORD_MAX_LEN*CHAR_BITS + `MSB(WORD_MAX_LEN)+1 + 16 + 1)
85 | ) output_reg (
86 | .wr_clk(wr_clk),
87 | .din({ dout_r, char_count, word_id_r, word_list_end_r }),
88 | .wr_en(rd_en_internal), .full(output_reg_full),
89 |
90 | .rd_clk(rd_clk),
91 | .dout({ dout, word_len, word_id, word_list_end }),
92 | .rd_en(rd_en), .empty(empty)
93 | );
94 |
95 | endmodule
96 |
97 |
--------------------------------------------------------------------------------
/fpga/pkt_comm/word_shift.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | module word_shift #(
4 | parameter CHAR_BITS = 7,
5 | parameter WORD_MAX_LEN = 8
6 | )(
7 | input [WORD_MAX_LEN * CHAR_BITS - 1 :0] din,
8 | input [`MSB(WORD_MAX_LEN-1):0] pos,
9 | output [WORD_MAX_LEN * CHAR_BITS - 1 :0] dout
10 | );
11 |
12 |
13 | wire [WORD_MAX_LEN * CHAR_BITS - 1 :0] shifts [WORD_MAX_LEN-1:0];
14 |
15 | genvar i;
16 |
17 | generate
18 | for (i=0; i < WORD_MAX_LEN; i=i+1)
19 | begin: shifts_gen
20 |
21 | assign shifts[i] = { din[(WORD_MAX_LEN-i) * CHAR_BITS - 1 :0], {i*CHAR_BITS{1'b0}} };
22 |
23 | end
24 | endgenerate
25 |
26 | assign dout = shifts[pos];
27 |
28 | endmodule
29 |
--------------------------------------------------------------------------------
/fpga/util/cdc_reg.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // *********************************************************
4 | //
5 | // Clock Domain Crossing Register
6 | //
7 | // * assumes frequency relation: wr_clk <= rd_clk <= wr_clk X 2
8 | //
9 | // *********************************************************
10 |
11 | module cdc_reg #(
12 | parameter WIDTH = 128
13 | )(
14 | input wr_clk,
15 | input [WIDTH-1:0] din,
16 | input wr_en,
17 | output reg full = 0,
18 |
19 | input rd_clk,
20 | output reg [WIDTH-1:0] dout = {WIDTH{1'b0}},
21 | input rd_en,
22 | output empty
23 | );
24 |
25 | always @(posedge wr_clk) begin
26 | if (~full) begin
27 | if (wr_en) begin
28 | dout <= din;
29 | full <= 1;
30 | end
31 | end
32 | else if (rd_en_sync)
33 | full <= 0;
34 | end
35 |
36 | sync_sig sync_full(.sig(full), .clk(rd_clk), .out(full_sync));
37 |
38 | sync_short_sig #(.CLK1(1)) sync_rd_en(.sig(rd_en), .clk(wr_clk), .out(rd_en_sync));
39 |
40 | // EMPTY considerations.
41 | // must react on rd_en in 1 cycle - requires to run on rd_clk clock
42 | // after read, consider FULL flag synchronization
43 | localparam EMPTY_STATE_INIT = 0,
44 | EMPTY_STATE_CAN_READ = 1,
45 | EMPTY_STATE_READ_COMPLETE = 2;
46 |
47 | (* FSM_EXTRACT="true" *)
48 | reg [1:0] empty_state = EMPTY_STATE_INIT;
49 |
50 | always @(posedge rd_clk)
51 | case (empty_state)
52 | EMPTY_STATE_INIT:
53 | if (full_sync)
54 | empty_state <= EMPTY_STATE_CAN_READ;
55 |
56 | EMPTY_STATE_CAN_READ:
57 | if (rd_en)
58 | empty_state <= EMPTY_STATE_READ_COMPLETE;
59 |
60 | EMPTY_STATE_READ_COMPLETE:
61 | if (~full_sync)
62 | empty_state <= EMPTY_STATE_INIT;
63 |
64 | endcase
65 |
66 | assign empty = empty_state == EMPTY_STATE_CAN_READ ? 1'b0 : 1'b1;
67 |
68 |
69 | endmodule
70 |
71 |
--------------------------------------------------------------------------------
/fpga/util/clocks.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // **********************************************************************
4 | //
5 | // Input clocks:
6 | // * IFCLK_IN 48 MHz.
7 | // * FXCLK_IN 48 MHz.
8 | //
9 | // Output:
10 | // * IFCLK - equal to IFCLK_IN, some phase backshift
11 | // * other clocks
12 | //
13 | // **********************************************************************
14 |
15 |
16 | module clocks #(
17 | parameter WORD_GEN_FREQ = 234,
18 | parameter PKT_COMM_FREQ = 174,
19 | parameter CORE_FREQ = 216,
20 | parameter CMP_FREQ = 156
21 | )(
22 | input IFCLK_IN,
23 | input FXCLK_IN,
24 |
25 | output IFCLK,
26 | output WORD_GEN_CLK,
27 | output PKT_COMM_CLK,
28 | output CORE_CLK,
29 | output CMP_CLK
30 | );
31 |
32 |
33 | // ********************************************************************************
34 | //
35 | // Attention developer!
36 | //
37 | // * On ZTEX 1.15y board, clocks coming from USB device controller do bypass a CPLD.
38 | // That's unknown why. To get Slave FIFO working, that requires clock phase backshift
39 | // (DCM can do) or equal measure. That might be the placement of input registers deep
40 | // into FPGA fabric or usage of IDELAY components.
41 | //
42 | // * If several DCMs and/or PLLs are used and their placement is not manually defined,
43 | // tools (ISE 14.5) place them randomly without a respect to dedicated lines.
44 | // That results in a usage of general routing for clocks, that in turn can
45 | // result in an unroutable condition if it's full of wires.
46 | //
47 | // * When tools notice derived clocks, they mess up with timing at Place and Route stage.
48 | //
49 | // ********************************************************************************
50 |
51 |
52 |
53 | // ****************************************************************************
54 | //
55 | // Spartan-6 Clocking Resources (Xilinx UG382) is anything but straightforward.
56 | //
57 | // ****************************************************************************
58 |
59 | // Tasks:
60 | // - generate a number of clocks for various parts of application
61 | // - don't use general routing for clocks
62 | // - define frequencies in MHz, not in magic units
63 | // - don't define derived clocks, 1 constraint should apply only to 1 clock.
64 |
65 |
66 | // IFCLK_IN and FXCLK_IN are located near each other.
67 | // There's some I/O clocking region there.
68 | // Limited number of dedicated routes from that region to CMTs are available.
69 | //
70 | // Each input clock can go to up to 2 CMTs, one of them must be
71 | // in the top half of fpga and other one must be in the bottom half.
72 | //
73 | // CMTs are numbered 0 to 5 from bottom to top.
74 |
75 | cmt2 #(
76 | .PLL_FREQ(WORD_GEN_FREQ),
77 | .PHASE_SHIFT(-15)
78 | ) cmt2(
79 | .I(IFCLK_IN),
80 | .CLK0(IFCLK),
81 | .PLL_CLK(WORD_GEN_CLK),
82 | .IFCLK1_BUFG(IFCLK1_BUFG)
83 | );
84 |
85 |
86 | cmt_common #(
87 | //.CLK2_FREQ(),
88 | .PLL_FREQ(CMP_FREQ)
89 | ) cmt1(
90 | .I(FXCLK_IN),
91 | .CLK2(),
92 | .PLL_CLK(CMP_CLK)
93 | );
94 |
95 | cmt_common #(
96 | //.CLK2_FREQ(),
97 | .PLL_FREQ(CORE_FREQ)
98 | ) cmt3(
99 | .I(FXCLK_IN),
100 | .CLK2(),
101 | .PLL_CLK(CORE_CLK)
102 | );
103 |
104 |
105 |
106 | // ********************************************************************
107 | //
108 | // If more PLLs are used, they can source input clock signal from BUFG.
109 | //
110 | // ********************************************************************
111 |
112 | cmt_common #(
113 | //.CLK2_FREQ(),
114 | .PLL_FREQ(PKT_COMM_FREQ)
115 | ) cmt_bufg0(
116 | .I(IFCLK1_BUFG),
117 | .CLK2(),
118 | .PLL_CLK(PKT_COMM_CLK)
119 | );
120 |
121 | endmodule
122 |
--------------------------------------------------------------------------------
/fpga/util/cmt2.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // *******************************************
4 | //
5 | // Clock Management Tile #2
6 | //
7 | // *******************************************
8 |
9 | module cmt2 #(
10 | parameter PHASE_SHIFT = 0,
11 | parameter FREQ_IN = 48,
12 | //parameter BUFIO2_DIVIDE = 1,
13 | parameter CLK2_DIVIDE = 8,
14 | parameter CLK2_FREQ = 210,
15 | parameter PLL_FREQ = 0
16 | )(
17 | input I,
18 | output CLK0,
19 | //output CLK2,
20 | output PLL_CLK,
21 | output IFCLK1_BUFG
22 | );
23 |
24 | // ******************************************************
25 | //
26 | // Available frequencies
27 | // (*) - default value
28 | //
29 | // BUFIO2_DIVIDE = 1:
30 | //
31 | // CLK1_DIVIDE = 8: step 6 MHz, max. 192 MHz
32 | // (*)CLK1_DIVIDE = 6: step 8 MHz, max. 256 MHz
33 | // CLK1_DIVIDE = 4: step 12 MHz, max. 384 MHz
34 | //
35 | // (*)CLK2_DIVIDE = 8: step 6 MHz, max. ~260 MHz
36 | // CLK2_DIVIDE = 6: step 8 MHz, max. ~320 MHz
37 | //
38 | // BUFIO2_DIVIDE = 2:
39 | //
40 | // (*)CLK1_DIVIDE = 6: step 4 MHz, max. 128 MHz
41 | // CLK1_DIVIDE = 4: step 6 MHz, max. 192 MHz
42 | // CLK1_DIVIDE = 3: step 8 MHz, max. 256 MHz
43 | // CLK1_DIVIDE = 2: step 12 MHz, max. 384 MHz
44 | //
45 | // CLK2_DIVIDE = 16: step 1.5 MHz, max. ~380 MHz
46 | // CLK2_DIVIDE = 12: step 2 MHz, max. >400 MHz
47 | // (*)CLK2_DIVIDE = 8: step 3 MHz, max. >400 MHz
48 | // CLK2_DIVIDE = 6: step 4 MHz, max. >400 MHz
49 | // CLK2_DIVIDE = 4: step 6 MHz, max. >400 MHz
50 | //
51 | // ******************************************************
52 |
53 | localparam BUFIO2_DIVIDE = 1;
54 | localparam FREQ_IN_DIVIDED = FREQ_IN / BUFIO2_DIVIDE;
55 |
56 | localparam CLK2_MULTIPLY = CLK2_FREQ / (FREQ_IN_DIVIDED / CLK2_DIVIDE);
57 |
58 | localparam DCM0_DIVIDE = 2;
59 |
60 | /*
61 | //
62 | // Some problems with manual usage of BUFIO2.
63 | //
64 | BUFIO2 #(
65 | .DIVIDE(BUFIO2_DIVIDE), // DIVCLK divider (1-8)
66 | .DIVIDE_BYPASS(BUFIO2_DIVIDE == 1 ? "TRUE" : "FALSE"), // Bypass the divider circuitry (TRUE/FALSE)
67 | .I_INVERT("FALSE"), // Invert clock (TRUE/FALSE)
68 | .USE_DOUBLER("FALSE") // Use doubler circuitry (TRUE/FALSE)
69 | )
70 | BUFIO2_inst (
71 | .DIVCLK(),//DIVCLK), // 1-bit output: Divided clock output
72 | .IOCLK( CLK_IN ), // 1-bit output: I/O output clock
73 | .SERDESSTROBE(),//SERDESSTROBE), // 1-bit output: Output SERDES strobe (connect to ISERDES2/OSERDES2)
74 | .I( I ) // 1-bit input: Clock input (connect to IBUFG)
75 | );
76 | */
77 |
78 |
79 | // **********************************************************************
80 |
81 |
82 | (* BUFFER_TYPE="NONE" *) wire dcm0_clk90, dcm0_clkdv;
83 |
84 | DCM_SP #(.CLKDV_DIVIDE ( DCM0_DIVIDE ),
85 | .CLKFX_DIVIDE (),
86 | .CLKFX_MULTIPLY (),
87 | .CLKIN_DIVIDE_BY_2 ("FALSE"),
88 | .CLKIN_PERIOD (),
89 | .CLKOUT_PHASE_SHIFT ("FIXED"),
90 | .CLK_FEEDBACK ("1X"),
91 | .DESKEW_ADJUST ("SYSTEM_SYNCHRONOUS"),//("SOURCE_SYNCHRONOUS"),
92 | .PHASE_SHIFT ( PHASE_SHIFT ), // -12: phase backshift 1 ns
93 | .STARTUP_WAIT ("FALSE")
94 | ) DCM_0 (
95 | // Input clock
96 | .CLKIN ( I ),
97 | .CLKFB (dcm0_clkfb),
98 | // Output clocks
99 | .CLK0 (dcm0_clk0),
100 | .CLK90 (dcm0_clk90),
101 | .CLK180 (dcm0_clk180),
102 | .CLK270 (),
103 | .CLK2X (),
104 | .CLK2X180 (),
105 | .CLKFX (),
106 | .CLKFX180 (),
107 | .CLKDV (dcm0_clkdv),
108 | // Ports for dynamic phase shift
109 | .PSCLK(1'b0), .PSEN(1'b0), .PSINCDEC(1'b0), .PSDONE(),
110 | .LOCKED(), .STATUS(), .RST(1'b0), .DSSEN(1'b0)
111 | );
112 |
113 | assign dcm0_clkfb = dcm0_clk0; // Adds BUFIO2FB
114 | assign CLK0 = dcm0_clk0;
115 |
116 |
117 | BUFG BUFG_1(
118 | .I(dcm0_clk180),
119 | .O(IFCLK1_BUFG)
120 | );
121 |
122 | // *****************************************************
123 | //
124 | // Usage of PLL:
125 | //
126 | // * Unless LOCated properly (in UCF), placer would probably place it in wrong place
127 | // and that would result in routing problems
128 | // * in UCF, uncomment dcm0_clkdv
129 | //
130 | if (PLL_FREQ) begin
131 |
132 | localparam PLL_DIVIDE = 4; // with FREQ_IN=48, DCM0_DIVIDE=2: step 6 MHz, max. ~270 MHz
133 |
134 | localparam PLL_MULT = PLL_FREQ / (FREQ_IN / DCM0_DIVIDE / PLL_DIVIDE);
135 |
136 | PLL_BASE #(
137 | .BANDWIDTH("OPTIMIZED"),
138 | .CLKFBOUT_MULT( PLL_MULT ),
139 | .CLKOUT0_DIVIDE( PLL_DIVIDE ),
140 | .CLKOUT0_DUTY_CYCLE(0.5),
141 | .CLKIN_PERIOD(0.0),
142 | .CLK_FEEDBACK("CLKFBOUT"),
143 | .COMPENSATION("DCM2PLL"),//SYSTEM_SYNCHRONOUS"),
144 | .DIVCLK_DIVIDE(1),
145 | .REF_JITTER(0.10),
146 | .RESET_ON_LOSS_OF_LOCK("FALSE")
147 | ) PLL_0 (
148 | .CLKFBOUT(pll0_clkfb),
149 | .CLKOUT0(pll0_clkout0),
150 | .CLKOUT1(),
151 | .CLKOUT2(),
152 | .CLKOUT3(),
153 | .CLKOUT4(),
154 | .CLKOUT5(),
155 | .LOCKED(),
156 | .CLKFBIN(pll0_clkfb),
157 | .CLKIN( dcm0_clkdv ),
158 | .RST(1'b0)
159 | );
160 |
161 | BUFG BUFG_0(
162 | .I(pll0_clkout0),
163 | .O(PLL_CLK)
164 | );
165 |
166 | end else begin // PLL_FREQ
167 |
168 | assign PLL_CLK = 1'b0;
169 |
170 | end
171 |
172 | // *****************************************************
173 |
174 | /*
175 | DCM_CLKGEN #(
176 | .CLKFXDV_DIVIDE(2), // CLKFXDV divide value (2, 4, 8, 16, 32)
177 | .CLKFX_DIVIDE( CLK2_DIVIDE ), // Divide value - D - (1-256)
178 | .CLKFX_MD_MAX(0.0), // Specify maximum M/D ratio for timing anlysis
179 | .CLKFX_MULTIPLY( CLK2_MULTIPLY ), // Multiply value - M - (2-256)
180 | .CLKIN_PERIOD(), // Input clock period specified in nS
181 | .SPREAD_SPECTRUM("NONE"), // Spread Spectrum mode "NONE", "CENTER_LOW_SPREAD", "CENTER_HIGH_SPREAD",
182 | // "VIDEO_LINK_M0", "VIDEO_LINK_M1" or "VIDEO_LINK_M2"
183 | .STARTUP_WAIT("FALSE") // Delay config DONE until DCM_CLKGEN LOCKED (TRUE/FALSE)
184 | ) DCM_CLKGEN_0 (
185 | .CLKFX( CLK2 ), // 1-bit output: Generated clock output
186 | .CLKFX180(),// dcm1_clkfx180 ), // 1-bit output: Generated clock output 180 degree out of phase from CLKFX.
187 | .CLKFXDV(),// dcm1_clkfxdv ), // 1-bit output: Divided clock output
188 | .LOCKED(), // 1-bit output: Locked output
189 | .PROGDONE(), // 1-bit output: Active high output to indicate the successful re-programming
190 | .STATUS(), // 2-bit output: DCM_CLKGEN status
191 | .CLKIN( dcm0_clk90 ), // 1-bit input: Input clock
192 | .FREEZEDCM(1'b0), // 1-bit input: Prevents frequency adjustments to input clock
193 | .PROGCLK(1'b0), // 1-bit input: Clock input for M/D reconfiguration
194 | .PROGDATA(1'b0), // 1-bit input: Serial data input for M/D reconfiguration
195 | .PROGEN(1'b0), // 1-bit input: Active high program enable
196 | .RST(1'b0) // 1-bit input: Reset input pin
197 | );
198 | */
199 | endmodule
200 |
--------------------------------------------------------------------------------
/fpga/util/cmt_common.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // *******************************************
4 | //
5 | // Spartan-6 Clock Management Tile.
6 | //
7 | // *******************************************
8 |
9 | module cmt_common #(
10 | parameter FREQ_IN = 48,
11 | parameter CLK2_DIVIDE = 8,
12 | parameter CLK2_FREQ = 192,
13 | parameter PLL_FREQ = 0
14 | )(
15 | input I,
16 | output CLK2,
17 | output PLL_CLK
18 | );
19 |
20 | // ******************************************************
21 | //
22 | // Available frequencies from CLK2 (FREQ_IN=48)
23 | // (*) - default value
24 | //
25 | // (*)CLK2_DIVIDE = 8: step 6 MHz, max. ~260 MHz
26 | // CLK2_DIVIDE = 6: step 8 MHz, max. ~320 MHz
27 | //
28 | // ******************************************************
29 |
30 | localparam CLK2_MULTIPLY = CLK2_FREQ / (FREQ_IN / CLK2_DIVIDE);
31 |
32 | localparam DCM0_DIVIDE = 2;
33 |
34 |
35 |
36 | (* BUFFER_TYPE="NONE" *) wire dcm0_clk0, dcm0_clk90, dcm0_clkdv;
37 |
38 | DCM_SP #(.CLKDV_DIVIDE ( DCM0_DIVIDE ),
39 | .CLKFX_DIVIDE (),
40 | .CLKFX_MULTIPLY (),
41 | .CLKIN_DIVIDE_BY_2 ("FALSE"),
42 | .CLKIN_PERIOD (),
43 | .CLKOUT_PHASE_SHIFT ("FIXED"),
44 | .CLK_FEEDBACK ("1X"),
45 | .DESKEW_ADJUST ("SYSTEM_SYNCHRONOUS"),
46 | .PHASE_SHIFT (0),
47 | .STARTUP_WAIT ("FALSE")
48 | ) DCM_0 (
49 | // Input clock
50 | .CLKIN ( I ),
51 | .CLKFB (dcm0_clkfb),
52 | // Output clocks
53 | .CLK0 (dcm0_clk0),
54 | .CLK90 (dcm0_clk90),
55 | .CLK180 (),
56 | .CLK270 (),
57 | .CLK2X (),
58 | .CLK2X180 (),
59 | .CLKFX (),
60 | .CLKFX180 (),
61 | .CLKDV (dcm0_clkdv),
62 | // Ports for dynamic phase shift
63 | .PSCLK(1'b0), .PSEN(1'b0), .PSINCDEC(1'b0), .PSDONE(),
64 | .LOCKED(), .STATUS(), .RST(1'b0), .DSSEN(1'b0)
65 | );
66 |
67 | assign dcm0_clkfb = dcm0_clk0;
68 |
69 |
70 |
71 | if (PLL_FREQ) begin
72 |
73 | localparam PLL_DIVIDE = 4; // with FREQ_IN=48, DCM0_DIVIDE=2: step 6 MHz, max. ~270 MHz
74 |
75 | localparam PLL_MULT = PLL_FREQ / (FREQ_IN / DCM0_DIVIDE / PLL_DIVIDE);
76 |
77 | PLL_BASE #(
78 | .BANDWIDTH("OPTIMIZED"),
79 | .CLKFBOUT_MULT( PLL_MULT ),
80 | .CLKOUT0_DIVIDE( PLL_DIVIDE ),
81 | .CLKOUT0_DUTY_CYCLE(0.5),
82 | .CLKIN_PERIOD(0.0),
83 | .CLK_FEEDBACK("CLKFBOUT"),
84 | .COMPENSATION("DCM2PLL"),
85 | .DIVCLK_DIVIDE(1),
86 | .REF_JITTER(0.10),
87 | .RESET_ON_LOSS_OF_LOCK("FALSE")
88 | ) PLL_0 (
89 | .CLKFBOUT(pll0_clkfb),
90 | .CLKOUT0(pll0_clkout0),
91 | .CLKOUT1(),
92 | .CLKOUT2(),
93 | .CLKOUT3(),
94 | .CLKOUT4(),
95 | .CLKOUT5(),
96 | .LOCKED(),
97 | .CLKFBIN(pll0_clkfb),
98 | .CLKIN( dcm0_clkdv ),
99 | .RST(1'b0)
100 | );
101 |
102 | BUFG BUFG_0(
103 | .I(pll0_clkout0),
104 | .O(PLL_CLK)
105 | );
106 |
107 | end else begin // PLL_FREQ
108 |
109 | assign PLL_CLK = 1'b0;
110 |
111 | end
112 |
113 | // *****************************************************
114 |
115 |
116 | DCM_CLKGEN #(
117 | .CLKFXDV_DIVIDE(2), // CLKFXDV divide value (2, 4, 8, 16, 32)
118 | .CLKFX_DIVIDE( CLK2_DIVIDE ), // Divide value - D - (1-256)
119 | .CLKFX_MD_MAX(0.0), // Specify maximum M/D ratio for timing anlysis
120 | .CLKFX_MULTIPLY( CLK2_MULTIPLY ), // Multiply value - M - (2-256)
121 | .CLKIN_PERIOD(), // Input clock period specified in nS
122 | .SPREAD_SPECTRUM("NONE"), // Spread Spectrum mode "NONE", "CENTER_LOW_SPREAD", "CENTER_HIGH_SPREAD",
123 | // "VIDEO_LINK_M0", "VIDEO_LINK_M1" or "VIDEO_LINK_M2"
124 | .STARTUP_WAIT("FALSE") // Delay config DONE until DCM_CLKGEN LOCKED (TRUE/FALSE)
125 | ) DCM_CLKGEN_0 (
126 | .CLKFX( CLK2 ), // 1-bit output: Generated clock output
127 | .CLKFX180(), // 1-bit output: Generated clock output 180 degree out of phase from CLKFX.
128 | .CLKFXDV(), // 1-bit output: Divided clock output
129 | .LOCKED(), // 1-bit output: Locked output
130 | .PROGDONE(), // 1-bit output: Active high output to indicate the successful re-programming
131 | .STATUS(), // 2-bit output: DCM_CLKGEN status
132 | .CLKIN( dcm0_clk90 ), // 1-bit input: Input clock
133 | .FREEZEDCM(1'b0), // 1-bit input: Prevents frequency adjustments to input clock
134 | .PROGCLK(1'b0), // 1-bit input: Clock input for M/D reconfiguration
135 | .PROGDATA(1'b0), // 1-bit input: Serial data input for M/D reconfiguration
136 | .PROGEN(1'b0), // 1-bit input: Active high program enable
137 | .RST(1'b0) // 1-bit input: Reset input pin
138 | );
139 |
140 | endmodule
141 |
--------------------------------------------------------------------------------
/fpga/util/startup_spartan6.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 |
4 | module startup_spartan6 (
5 | input rst
6 | );
7 |
8 | STARTUP_SPARTAN6 STARTUP_SPARTAN6_inst (
9 | .CFGCLK(),//CFGCLK), // 1-bit output: Configuration logic main clock output.
10 | .CFGMCLK(),//CFGMCLK), // 1-bit output: Configuration internal oscillator clock output.
11 | .EOS(),//EOS), // 1-bit output: Active high output signal indicates the End Of Configuration.
12 | .CLK(1'b0), // 1-bit input: User startup-clock input
13 | .GSR(rst), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name)
14 | .GTS(1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name)
15 | .KEYCLEARB(1'b0) // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM)
16 | );
17 |
18 |
19 | endmodule
20 |
--------------------------------------------------------------------------------
/fpga/util/sync.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | // 2-stage FF synchronizer
4 | module sync_sig #(
5 | parameter INIT = 0,
6 | // if input signal is 1-2 clk cycles
7 | // and CLK1 is set, result would be 1 cycle long
8 | // * if input is longer than 2 cycles, it would produce extra result
9 | // * if less than 1 cycle, there might be no result (consider usage of sync_short_sig)
10 | parameter CLK1 = 0
11 | )(
12 | input sig,
13 | input clk,
14 | //input en,
15 | output out
16 | );
17 |
18 | (* SHREG_EXTRACT="NO" *)
19 | reg [1:0] ff = {2{INIT[0]}};
20 | assign out = ff[1];
21 |
22 | if (CLK1) begin
23 |
24 | always @(posedge clk)
25 | if (ff[1] ^ INIT[0])
26 | ff[1:0] <= {2{INIT[0]}};
27 | else
28 | ff[1:0] <= { ff[0], sig };
29 |
30 | end else begin // ! CLK1
31 |
32 | always @(posedge clk)
33 | ff[1:0] <= { ff[0], sig };
34 |
35 | end
36 |
37 | endmodule
38 |
39 |
40 | // For synchronizing short-duration signals (less than clk cycle),
41 | // 2-stage FF synchronizer is prepended with async register
42 | module sync_short_sig #(
43 | parameter INIT = 0,
44 | parameter CLK1 = 0
45 | )(
46 | input sig,
47 | input clk,
48 | output out
49 | );
50 |
51 | // There's no such registers in Spartan 6 architecture,
52 | // with a warning tools produce an equvalent item from 3 parts
53 | reg async_r = INIT[0];
54 |
55 | always @(posedge clk or posedge sig)
56 | if (sig)
57 | async_r <= ~INIT[0];
58 | else
59 | if (out)
60 | async_r <= INIT[0];
61 |
62 | sync_sig #(.INIT(INIT), .CLK1(CLK1)) sync(.sig(async_r), .clk(clk), .out(out));
63 |
64 | endmodule
65 |
66 | /*
67 | // Any frequency relation between wr_clk and rd_clk
68 | // 'out' duration is 1 clock cycle
69 | module sync_pulse(
70 | input wr_clk,
71 | input sig,
72 | output busy,
73 |
74 | input rd_clk,
75 | output out
76 | );
77 |
78 | reg flag_wr = 0;
79 | always @(posedge wr_clk) flag_wr <= flag_wr ^ (sig & ~busy);
80 |
81 | (* SHREG_EXTRACT="NO" *)
82 | reg [2:0] sync_rd = 3'b0;
83 | always @(posedge rd_clk) sync_rd <= {sync_rd[1:0], flag_wr};
84 |
85 | (* SHREG_EXTRACT="NO" *)
86 | reg [1:0] sync_wr = 2'b0;
87 | always @(posedge wr_clk) sync_wr <= {sync_wr[0], sync_rd[2]};
88 |
89 | assign out = (sync_rd[2] ^ sync_rd[1]);
90 | assign busy = flag_wr ^ sync_wr[1];
91 |
92 | endmodule
93 | */
94 |
95 | // Any frequency relation between wr_clk and rd_clk
96 | module sync_ack(
97 | input wr_clk,
98 | input sig,
99 | output busy,
100 |
101 | input rd_clk,
102 | output out,
103 | input done
104 | );
105 |
106 | reg flag_wr = 0;
107 | always @(posedge wr_clk) flag_wr <= flag_wr ^ (sig & ~busy);
108 |
109 | (* SHREG_EXTRACT="NO" *)
110 | reg [2:0] sync_rd = 3'b0;
111 | always @(posedge rd_clk)
112 | if (~out | done)
113 | sync_rd <= {sync_rd[1:0], flag_wr};
114 |
115 | (* SHREG_EXTRACT="NO" *)
116 | reg [1:0] sync_wr = 2'b0;
117 | always @(posedge wr_clk)
118 | if (out | done | done_r)
119 | sync_wr <= {sync_wr[0], sync_rd[2]};
120 |
121 | assign out = sync_rd[2] ^ sync_rd[1];
122 | assign busy = flag_wr ^ sync_wr[1];
123 |
124 | reg done_r = 0;
125 | always @(posedge rd_clk)
126 | if (out & done)
127 | done_r <= 1;
128 | else if (done_r)
129 | done_r <= 0;
130 |
131 | endmodule
132 |
--------------------------------------------------------------------------------
/fpga/vcr.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //***********************************************************
4 | //
5 | // Vendor Command / Vendor Request feature
6 | // Commands or requests are sent to EZ-USB via USB EP0
7 | // and handled by EZ-USB processor.
8 | //
9 | //***********************************************************
10 |
11 | module vcr(
12 | input CS,
13 |
14 | input [7:0] vcr_in, // Vendor Command/Request (VCR) address/data
15 | output [7:0] vcr_out,
16 | input clk_vcr_addr, // on posedge, set (internal to FPGA) VCR IO address
17 | input clk_vcr_data, // on posedge, perform write or synchronous read
18 | //input vcr_dir, // VCR direction: 0 = write to FPGA, 1 = read from FPGA
19 |
20 | input IFCLK,
21 |
22 | input [2:0] FPGA_ID,
23 | input [7:0] hs_io_timeout,
24 | input hs_input_prog_full,
25 | //input output_err_overflow,
26 | input sfifo_not_empty,
27 | input io_fsm_error, io_err_write,
28 | input [15:0] output_limit,
29 | input output_limit_not_done,
30 | input [7:0] app_status,
31 | input [7:0] pkt_comm_status, debug2, debug3,
32 |
33 | //
34 | // Defaults for various controls; see also VCR_RESET
35 | //
36 | output reg hs_en = 0, // high-speed i/o
37 | output reg output_mode_limit = 1, // output_limit
38 | //output reg [15:0] output_limit_min = 0,
39 | output reg reg_output_limit = 0, // with respect to IFCLK
40 | output reg [7:0] app_mode = 0, // default mode: 0
41 | output RESET_OUT // with respect to IFCLK
42 | );
43 |
44 | wire ENABLE = CS;
45 |
46 | // VCR address definitions
47 | localparam VCR_SET_HS_IO_ENABLE = 8'h80;
48 | localparam VCR_SET_HS_IO_DISABLE = 8'h81;
49 | localparam VCR_SET_APP_MODE = 8'h82;
50 | localparam VCR_GET_IO_STATUS = 8'h84;
51 | // registers output limit (in output_limit_fifo words); starts
52 | // output of that many via high-speed interface
53 | localparam VCR_REG_OUTPUT_LIMIT = 8'h85;
54 | localparam VCR_SET_OUTPUT_LIMIT_MIN = 8'h83;
55 | localparam VCR_SET_OUTPUT_LIMIT_ENABLE = 8'h86;
56 | localparam VCR_SET_OUTPUT_LIMIT_DISABLE = 8'h87;
57 | localparam VCR_ECHO_REQUEST = 8'h88;
58 | localparam VCR_GET_FPGA_ID = 8'h8A;
59 | localparam VCR_RESET = 8'h8B;
60 | localparam VCR_GET_ID_DATA = 8'hA1;
61 | //localparam VCR_ = 8'h;
62 |
63 | async2sync sync_addr_inst( .async(clk_vcr_addr), .clk(IFCLK), .clk_en(clk_addr_en) );
64 | async2sync sync_data_inst( .async(clk_vcr_data), .clk(IFCLK), .clk_en(clk_data_en) );
65 |
66 | reg [7:0] vcr_addr;
67 | reg [5:0] vcr_state = 0;
68 |
69 | /////////////////////////////////////////////////////////
70 | //
71 | // declarations for Command / Request specific stuff
72 | //
73 | /////////////////////////////////////////////////////////
74 | localparam [15:0] BITSTREAM_TYPE = 1;
75 | //reg [3:0] io_state_r;
76 | //reg [7:0] io_timeout_r;
77 | reg [7:0] echo_content [3:0];
78 | //localparam RESET_TIMER_MSB = 3;
79 | //reg [RESET_TIMER_MSB:0] reset_timer = 0;
80 | reg RESET_R = 0;
81 |
82 | // declarations for Command / Request specific stuff end
83 |
84 |
85 | /////////////////////////////////////////////////////////
86 | //
87 | // Input
88 | //
89 | /////////////////////////////////////////////////////////
90 |
91 | always @(posedge IFCLK) begin
92 | if (ENABLE && clk_addr_en) begin
93 | vcr_addr <= vcr_in;
94 | vcr_state <= 0;
95 |
96 | if (vcr_in == VCR_SET_HS_IO_ENABLE)
97 | hs_en <= 1;
98 | else if (vcr_in == VCR_SET_HS_IO_DISABLE)
99 | hs_en <= 0;
100 | else if (vcr_in == VCR_SET_OUTPUT_LIMIT_ENABLE)
101 | output_mode_limit <= 1;
102 | else if (vcr_in == VCR_SET_OUTPUT_LIMIT_DISABLE)
103 | output_mode_limit <= 0;
104 | else if (vcr_in == VCR_RESET) begin
105 | //reset_timer <= 0;
106 | RESET_R <= 1;
107 | //output_mode_limit <= 1;
108 | //output_limit_min <= 0;
109 | //app_mode <= 0;
110 | end
111 | else if (vcr_in == VCR_REG_OUTPUT_LIMIT)
112 | reg_output_limit <= 1;
113 |
114 | end // clk_addr_en
115 |
116 | else if (ENABLE && clk_data_en) begin
117 | vcr_state <= vcr_state + 1'b1;
118 |
119 | if (vcr_addr == VCR_ECHO_REQUEST)
120 | echo_content[ vcr_state[1:0] ] <= vcr_in;
121 | //else if (vcr_addr == VCR_SET_OUTPUT_LIMIT_MIN && vcr_state == 0)
122 | // output_limit_min[7:0] <= vcr_in;
123 | //else if (vcr_addr == VCR_SET_OUTPUT_LIMIT_MIN && vcr_state == 1)
124 | // output_limit_min[15:8] <= vcr_in;
125 | else if (vcr_addr == VCR_SET_APP_MODE)
126 | app_mode <= vcr_in;
127 | end // clk_data_en
128 |
129 | else begin // !ENABLE
130 | if (reg_output_limit)
131 | reg_output_limit <= 0;
132 |
133 | //if ( !(&reset_timer) )
134 | // reset_timer <= reset_timer + 1'b1;
135 | end
136 | end
137 |
138 | //assign RESET_OUT = !(&reset_timer);
139 | assign RESET_OUT = RESET_R;
140 |
141 |
142 | /////////////////////////////////////////////////////////
143 | //
144 | // Output
145 | //
146 | /////////////////////////////////////////////////////////
147 |
148 | assign vcr_out =
149 | (vcr_addr == VCR_REG_OUTPUT_LIMIT && vcr_state == 0) ? output_limit[7:0] :
150 | (vcr_addr == VCR_REG_OUTPUT_LIMIT && vcr_state == 1) ? output_limit[15:8] :
151 |
152 | (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 0) ? {
153 | {2{1'b0}}, io_err_write, io_fsm_error,
154 | sfifo_not_empty, 1'b0, output_limit_not_done, hs_input_prog_full
155 | } :
156 | (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 1) ? hs_io_timeout :
157 | (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 2) ? app_status :
158 | (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 3) ? pkt_comm_status :
159 | (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 4) ? debug2 :
160 | (vcr_addr == VCR_GET_IO_STATUS && vcr_state == 5) ? debug3 :
161 |
162 | (vcr_addr == VCR_ECHO_REQUEST) ? echo_content[ vcr_state[1:0] ] ^ 8'h5A :
163 |
164 | (vcr_addr == VCR_GET_ID_DATA && vcr_state == 0) ? BITSTREAM_TYPE[7:0] :
165 | (vcr_addr == VCR_GET_ID_DATA && vcr_state == 1) ? BITSTREAM_TYPE[15:8] :
166 | //(vcr_addr == VCR_GET_ID_DATA) ? id_data[ vcr_state[4:0] ] :
167 |
168 | (vcr_addr == VCR_GET_FPGA_ID) ? { {5{1'b0}}, FPGA_ID } :
169 | //(vcr_addr == && vcr_state == ) ? :
170 | 8'b0;
171 |
172 | always @(posedge IFCLK) begin
173 | //io_state_r <= { sfifo_not_empty, output_err_overflow, output_limit_done, hs_input_prog_full };
174 | //io_timeout_r <= hs_io_timeout;
175 | end
176 |
177 | startup_spartan6 startup_spartan6(.rst(RESET_R));
178 |
179 | endmodule
180 |
--------------------------------------------------------------------------------
/host/compile.sh:
--------------------------------------------------------------------------------
1 | #gcc ztex.c inouttraffic.c pkt_comm/pkt_comm.c simple_test.c -osimple_test -lusb-1.0
2 | #gcc ztex.c inouttraffic.c ztex_scan.c pkt_comm/pkt_comm.c test.c -otest -lusb-1.0
3 | #gcc ztex.c inouttraffic.c ztex_scan.c pkt_comm/*.o pkt_test.c -opkt_test -lusb-1.0
4 | gcc ztex.c inouttraffic.c ztex_scan.c pkt_comm/*.o descrypt_test.c -odescrypt_test -lusb-1.0
5 |
--------------------------------------------------------------------------------
/host/fw_upload.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "ztex.h"
11 |
12 | // ***************************************************************
13 | //
14 | // Task: upload firmware onto a board with no default firmware
15 | //
16 | // Usage: ./fw_upload [filename]
17 | //
18 | // If filename is not specified, prints a list of devices with no firmware
19 | //
20 | // ***************************************************************
21 |
22 | libusb_device_handle *device_open(libusb_device *usb_dev)
23 | {
24 | struct libusb_device_handle *handle;
25 |
26 | int result = libusb_open(usb_dev, &handle);
27 | if (result < 0) {
28 | fprintf(stderr, "libusb_open returns %d (%s)\n",
29 | result, libusb_strerror(result));
30 | return NULL;
31 | }
32 | return handle;
33 | }
34 |
35 | void cypress_scan(char *filename)
36 | {
37 | libusb_device **usb_devs;
38 | int result;
39 | int count = 0;
40 | ssize_t cnt;
41 |
42 | cnt = libusb_get_device_list(NULL, &usb_devs);
43 | if (cnt < 0) {
44 | fprintf(stderr, "libusb_get_device_list: %s\n",
45 | libusb_strerror((int)cnt));
46 | return;
47 | }
48 |
49 | int i;
50 | for (i = 0; usb_devs[i]; i++) {
51 | libusb_device *usb_dev = usb_devs[i];
52 |
53 | struct libusb_device_descriptor desc;
54 | result = libusb_get_device_descriptor(usb_dev, &desc);
55 | if (result < 0) {
56 | fprintf(stderr, "libusb_get_device_descriptor: %s\n",
57 | libusb_strerror(result));
58 | continue;
59 | }
60 |
61 | if (desc.idVendor != 0x04b4 || desc.idProduct != 0x8613)
62 | continue;
63 |
64 | int busnum = libusb_get_bus_number(usb_dev);
65 | int devnum = libusb_get_device_address(usb_dev);
66 | printf("Found Cypress device: busnum %d, devnum %d\n", busnum, devnum);
67 |
68 | libusb_device_handle *handle = device_open(usb_dev);
69 | if (!handle)
70 | continue;
71 |
72 | if (!filename)
73 | continue;
74 |
75 | struct ztex_device *dev = malloc(sizeof(struct ztex_device));
76 | dev->handle = handle;
77 | //sprintf("%d %d", dev->snString, busnum, devnum);
78 |
79 | ZTEX_DEBUG = 1;
80 | ztex_firmware_upload(dev, filename);
81 | }
82 | }
83 |
84 | int main(int argc, char **argv)
85 | {
86 | int result = libusb_init(NULL);
87 | if (result < 0) {
88 | fprintf(stderr, "libusb_init(): %s\n", libusb_strerror(result));
89 | exit(EXIT_FAILURE);
90 | }
91 |
92 | //libusb_device *usb_dev;
93 | //struct libusb_device_handle *handle;
94 |
95 | if (argc == 2)
96 | cypress_scan(argv[1]);
97 | else
98 | cypress_scan(NULL);
99 |
100 | libusb_exit(NULL);
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/host/inouttraffic.h:
--------------------------------------------------------------------------------
1 |
2 | #define ERR_IO_STATE_TIMEOUT -3001
3 | #define ERR_IO_STATE_OVERFLOW -3002
4 | #define ERR_IO_STATE_LIMIT_NOT_DONE -3003
5 | #define ERR_IO_STATE_SFIFO_NOT_EMPTY -3004
6 |
7 | #define ERR_WR_PARTIAL -3101
8 |
9 | #define ERR_RD_ZEROREAD -3201
10 |
11 | #define DEVICE_FPGAS_MAX 4
12 |
13 | #define OUTPUT_WORD_WIDTH 2
14 |
15 | extern int DEBUG;
16 |
17 | // used by VR 0x84, fpga_get_io_state()
18 | // the most important thing here is io_state.IO_STATE_INPUT_PROG_FULL
19 | // When not asserted FPGA's input buffer has space for data
20 | struct fpga_io_state {
21 | unsigned char io_state;
22 | unsigned char timeout;
23 | unsigned char app_status;
24 | unsigned char pkt_comm_status;
25 | unsigned char debug2;
26 | unsigned char debug3;
27 | };
28 |
29 | // fpga_io_state.io_state
30 | #define IO_STATE_INPUT_PROG_FULL 0x01
31 | #define IO_STATE_LIMIT_NOT_DONE 0x02
32 | #define IO_STATE_OUTPUT_ERR_OVERFLOW 0x04
33 | #define IO_STATE_SFIFO_NOT_EMPTY 0x08
34 |
35 | // used by VR 0x88, fpga_test_get_id()
36 | struct fpga_echo_request {
37 | unsigned short out[2];
38 | struct {
39 | unsigned short data[2];
40 | unsigned char fpga_id;
41 | unsigned char reserved;
42 | unsigned short bitstream_type;
43 | } reply;
44 | };
45 |
46 | // Requests 'struct fpga_io_state' fro currently selected FPGA
47 | int fpga_get_io_state(struct libusb_device_handle *handle, struct fpga_io_state *io_state);
48 |
49 | // FPGA would not send data until fpga_setup_output().
50 | // Returns number of bytes FPGA is going to transmit.
51 | int fpga_setup_output(struct libusb_device_handle *handle);
52 |
53 | // soft reset (VC 0x8B)
54 | // It resets FPGA to its post-configuration state with Global Set Reset (GSR).
55 | // Inouttraffic bitstreams have High-Speed interface disabled by default.
56 | // After reset, fpga_reset() enables High-Speed interface.
57 | // consider device_fpga_reset() to reset all FPGA's on device
58 | int fpga_reset(struct libusb_device_handle *handle);
59 |
60 | // enable/disable high-speed output.
61 | // FPGA comes with High-Speed I/O (hs_io) disabled.
62 | // Application usually would not need this:
63 | // hs_io status changes internally by e.g. fpga_select() and fpga_reset().
64 | int fpga_hs_io_enable(struct libusb_device_handle *handle, int enable);
65 |
66 | // enabled by default; disable for raw I/O tests
67 | int fpga_output_limit_enable(struct libusb_device_handle *handle, int enable);
68 |
69 |
70 | // used by VR 0x8C, fpga_select_setup_io()
71 | struct fpga_status {
72 | struct fpga_io_state io_state;
73 | unsigned short read_limit;
74 | };
75 |
76 | struct fpga_wr {
77 | struct fpga_io_state io_state;
78 | int io_state_valid; // io_state was taken from other source
79 | //struct timeval io_state_tv;
80 | int io_state_timeout_count;
81 | int wr_done;
82 | uint64_t wr_count;
83 | unsigned char *buf;
84 | int len;
85 | };
86 |
87 | struct fpga_rd {
88 | unsigned short read_limit;
89 | int read_limit_valid; // read_limit previously set
90 | int rd_done;
91 | uint64_t read_count;
92 | uint64_t partial_read_count;
93 | unsigned char *buf;
94 | int len;
95 | };
96 |
97 | struct fpga {
98 | struct device *device;
99 | //struct fpga_id fpga_id;
100 | unsigned short bitstream_type;
101 | int num;
102 | int valid; // actually not used; on a valid device all FPGA's are OK
103 | struct fpga_wr wr;
104 | struct fpga_rd rd;
105 | uint64_t cmd_count;
106 | uint64_t data_out,data_in; // specific for advanced_test.c
107 |
108 | struct pkt_comm *comm;
109 | };
110 |
111 | struct device {
112 | struct ztex_device *ztex_device;
113 | struct device *next;
114 | int valid;
115 | struct libusb_device_handle *handle;
116 | struct fpga fpga[DEVICE_FPGAS_MAX];
117 | int num_of_valid_fpgas; // actually not used; on a valid device all FPGA's are OK
118 | int num_of_fpgas;
119 | int selected_fpga;
120 | };
121 |
122 | struct device_list {
123 | struct device *device;
124 | struct ztex_dev_list *ztex_dev_list;
125 | };
126 |
127 | // Creates 'struct device' on top of 'struct ztex_device'
128 | // claims USB interface 1
129 | struct device *device_new(struct ztex_device *ztex_device);
130 |
131 | void device_delete(struct device *device);
132 |
133 | // device usually invalidated if there's some error
134 | // underlying ztex_device also invalidated
135 | void device_invalidate(struct device *device);
136 |
137 | // check if device has valid state
138 | int device_valid(struct device *device);
139 |
140 |
141 | struct device_list *device_list_new(struct ztex_dev_list *ztex_dev_list);
142 |
143 | void device_list_add(struct device_list *device_list, struct device *device);
144 |
145 | int device_list_count(struct device_list *device_list);
146 |
147 | // After merge, added device list deleted.
148 | // Underlying ztex_dev_list's also merged.
149 | int device_list_merge(struct device_list *device_list, struct device_list *added_list);
150 |
151 | // Performs fpga_reset() on all FPGA's
152 | // It resets FPGAs to its post-configuration state with Global Set Reset (GSR).
153 | //
154 | // Return values:
155 | // < 0 error; would require heavier reset
156 | //
157 | // Issue. What if only 1 of onboard FPGAs has error.
158 | // Currently following approarch used (heavy_test.c):
159 | // Initialization functions (soft_reset, check_bitstream) initialize all onboard FPGAs.
160 | // On any error, entire device is put into invalid state.
161 | int device_fpga_reset(struct device *device);
162 |
163 | // Bitstream type is hardcoded into bitstream (vcr.v/BITSTREAM_TYPE)
164 | // Return value:
165 | // > 0 all FPGA's has bitstream of specified type
166 | // 0 at least 1 FPGA has no bitstream or bitstream of other type
167 | // < 0 error
168 | int device_check_bitstream_type(struct device *device, unsigned short bitstream_type);
169 |
170 | // Checks if bitstreams on devices are loaded and of specified type.
171 | // if (filename != NULL) performs upload in case of wrong or no bitstream
172 | // Returns: number of devices with bitstreams uploaded
173 | int device_list_check_bitstreams(struct device_list *device_list, unsigned short BITSTREAM_TYPE, const char *filename);
174 |
175 | // tests if bitstream from currently selected FPGA is operational and gets bitstream_type
176 | // Returns:
177 | // < 0 on I/O error
178 | // 0 bitstream isn't operational or unable to get bitstream_type
179 | // > 0 bitstream OK
180 | // consider use of device_check_bitstream_type()
181 | int fpga_test_get_id(struct fpga *fpga);
182 |
183 | // some application mode, does not directly affect I/O
184 | int fpga_set_app_mode(struct fpga *fpga, int app_mode);
185 |
186 | // set app_mode on every FPGA on every device in the list
187 | // Returns number of affected devices
188 | // On error, invalidates device and continues
189 | int device_list_set_app_mode(struct device_list *device_list, int app_mode);
190 |
191 | // Performs device_fpga_reset() on each device in the list
192 | int device_list_fpga_reset(struct device_list *device_list);
193 |
194 | // unlike ztex_select_fpga(), it waits for I/O timeout
195 | int fpga_select(struct fpga *fpga);
196 |
197 | // combines fpga_select(), fpga_get_io_state(), fpga_setup_output() in 1 USB request
198 | int fpga_select_setup_io(struct fpga *fpga);
199 |
200 | // in OUTPUT_WORD_WIDTH words, default 0.
201 | // fpga_setup_output() would return 0 if amount in output buffer is less than limit_min.
202 | // if limit_min is greater than output buffer size, limit_min equal to buffer size is used.
203 | //int fpga_set_output_limit_min(struct fpga *fpga, unsigned short limit_min);
204 |
205 |
206 | // checks io_state (unless previously checked with fpga_select_setup_io)
207 | // if input buffer isn't full - performs write
208 | int fpga_write(struct fpga *fpga);
209 |
210 | // requests read_limit (unless previously requested with fpga_select_setup_io) and performs read
211 | int fpga_read(struct fpga *fpga);
212 |
213 | // Synchronous write with pkt_comm
214 | int fpga_pkt_write(struct fpga *fpga);
215 |
216 | // Synchronous read with pkt_comm
217 | int fpga_pkt_read(struct fpga *fpga);
218 |
--------------------------------------------------------------------------------
/host/pkt_comm/cmp_config.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "pkt_comm.h"
8 | #include "cmp_config.h"
9 |
10 |
11 | struct pkt *pkt_cmp_config_new(struct cmp_config *cmp_config)
12 | {
13 |
14 | char *data = malloc(CMP_CONFIG_MAX_SIZE);
15 | if (!data) {
16 | pkt_error("pkt_cmp_config_new(): unable to allocate %d bytes\n",
17 | CMP_CONFIG_MAX_SIZE);
18 | return NULL;
19 | }
20 |
21 | int offset = 0;
22 |
23 | int i;
24 |
25 | if (cmp_config->salt & 0xf000) {
26 | pkt_error("pkt_cmp_config_new(): bad salt 0x%04x\n", cmp_config->salt);
27 | return NULL;
28 | }
29 | data[offset++] = cmp_config->salt;
30 | data[offset++] = cmp_config->salt >> 8;
31 |
32 | if (!cmp_config->num_hashes || cmp_config->num_hashes > CMP_CONFIG_NUM_HASHES_MAX) {
33 | pkt_error("pkt_cmp_config_new(): bad num_hashes %d\n", cmp_config->num_hashes);
34 | return NULL;
35 | }
36 | data[offset++] = cmp_config->num_hashes;
37 | data[offset++] = cmp_config->num_hashes >> 8;
38 |
39 | for (i = 0; i < cmp_config->num_hashes; i++) {
40 | int j;
41 | for (j = 0; j < CMP_CONFIG_HASH_LEN; j++)
42 | data[offset++] = cmp_config->cmp_hash[i].b[j];
43 | }
44 |
45 | data[offset++] = 0xCC;
46 |
47 | struct pkt *pkt = pkt_new(PKT_TYPE_CMP_CONFIG, data, offset);
48 | //for (i=0; i < offset; i++)
49 | // printf("0x%02x ", data[i] & 0xff);
50 | //printf("\nlen: %d\n", offset);
51 | return pkt;
52 | }
53 |
--------------------------------------------------------------------------------
/host/pkt_comm/cmp_config.h:
--------------------------------------------------------------------------------
1 |
2 | #define PKT_TYPE_CMP_CONFIG 3
3 |
4 | // ***************************************************************
5 | //
6 | // Comparator Configuration
7 | //
8 | // ***************************************************************
9 |
10 | #define CMP_CONFIG_NUM_HASHES_MAX 1023
11 | #define CMP_CONFIG_HASH_LEN 8
12 |
13 | #define CMP_CONFIG_MAX_SIZE ( 5 + \
14 | CMP_CONFIG_NUM_HASHES_MAX * CMP_CONFIG_HASH_LEN )
15 |
16 | struct cmp_hash {
17 | unsigned char b[CMP_CONFIG_HASH_LEN];
18 | };
19 |
20 | struct cmp_config {
21 | unsigned short salt; // 12 LSB's used
22 | unsigned short num_hashes;
23 | // Excess hashes are not transmitted
24 | struct cmp_hash cmp_hash[CMP_CONFIG_NUM_HASHES_MAX];
25 | unsigned char magic; // 0xCC
26 | };
27 |
28 | struct pkt *pkt_cmp_config_new(struct cmp_config *cmp_config);
29 |
30 |
--------------------------------------------------------------------------------
/host/pkt_comm/compile.sh:
--------------------------------------------------------------------------------
1 | gcc -O -c *.c
2 |
--------------------------------------------------------------------------------
/host/pkt_comm/outpkt.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "outpkt.h"
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/host/pkt_comm/outpkt.h:
--------------------------------------------------------------------------------
1 | #include "pkt_comm.h"
2 |
3 | #define PKT_TYPE_CMP_EQUAL 0xd1
4 | #define PKT_TYPE_PROCESSING_DONE 0xd2
5 |
6 | // ***************************************************************
7 | //
8 | // output packets (from remote device)
9 | //
10 | // ***************************************************************
11 |
12 | struct outpkt_cmp_equal {
13 | int pkt_id;
14 | int word_id;
15 | unsigned long gen_id;
16 | int hash_num_eq;
17 | };
18 |
19 | struct outpkt_done {
20 | int pkt_id;
21 | unsigned long num_processed;
22 | };
23 |
24 |
--------------------------------------------------------------------------------
/host/pkt_comm/pkt_comm.h:
--------------------------------------------------------------------------------
1 |
2 | // ***************************************************************
3 | //
4 | // Communication to a remote system
5 | //
6 | // * communication goes in sequential packets
7 | // * API is independent from hardware and link layer
8 | //
9 | // ***************************************************************
10 |
11 | #ifndef _PKT_COMM_H_
12 |
13 | // *****************************************************************
14 | //
15 | // That's how packet looks when transmitted
16 | // over link layer
17 | //
18 | // struct pkt {
19 | // unsigned char version; // version 1
20 | // unsigned char type;
21 | // unsigned short reserved0;
22 | // unsigned char data_len0;
23 | // unsigned char data_len1;
24 | // unsigned char data_len2; // doesn't count header and checksum
25 | // unsigned char reserved1;
26 | // unsigned short id;
27 | // unsigned char data[pkt_data_len];
28 | // };
29 | //
30 | // Checksum is PKT_CHECKSUM_LEN bytes long. Words added and inverted.
31 | // Checksum is not included in data length.
32 | // - inserted after packet header
33 | // - after the end of packet
34 | //
35 | // *****************************************************************
36 |
37 | #define PKT_COMM_VERSION 1
38 |
39 | #define PKT_HEADER_LEN 10
40 |
41 | // packet can be split when transmitted over link layer
42 | #define PKT_MAX_LEN (4 * 65536) // 256K
43 |
44 | #define PKT_CHECKSUM_LEN 4
45 | // PKT_CHECKSUM_TYPE must be unsigned type
46 | #define PKT_CHECKSUM_TYPE unsigned long
47 | //#define PKT_CHECKSUM_INTERVAL 448
48 |
49 | struct pkt {
50 | unsigned char version;
51 | unsigned char type; // type must be > 0
52 | int data_len; // data length
53 | unsigned short id;
54 | unsigned char *data;
55 | int header_ok;
56 | // partially received packet
57 | int partial_header_len;
58 | int partial_data_len;
59 | // variable usage for output and input
60 | unsigned char *header;
61 | };
62 |
63 | // Currently error messages are printed to stderr
64 | void pkt_error(const char *s, ...);
65 |
66 | // Total number of packets created with pkt_new() and not yet deleted
67 | int get_pkt_count(void);
68 |
69 | // Creates new packet. Does not allocate memory for data
70 | struct pkt *pkt_new(int type, char *data, int data_len);
71 |
72 | // Deletes packet, also frees pkt->data
73 | void pkt_delete(struct pkt *pkt);
74 |
75 |
76 | // *****************************************************************
77 | //
78 | // packet queue
79 | //
80 | // *****************************************************************
81 |
82 | #define PKT_QUEUE_MAX 2000
83 |
84 | struct pkt_queue {
85 | int count; // number of packets currently in queue
86 | int empty_slot_idx; // index of 1st empty slot
87 | int first_pkt_idx; // index of first packet
88 | struct pkt *pkt[PKT_QUEUE_MAX];
89 | };
90 |
91 | struct pkt_queue *pkt_queue_new();
92 |
93 | void pkt_queue_delete(struct pkt_queue *queue);
94 |
95 | // returns false if queue has space for 'num' more packets
96 | int pkt_queue_full(struct pkt_queue *queue, int num);
97 |
98 | // returns -1 if queue is full
99 | int pkt_queue_push(struct pkt_queue *queue, struct pkt *pkt);
100 |
101 | // returns NULL if queue is empty
102 | struct pkt *pkt_queue_fetch(struct pkt_queue *queue);
103 |
104 |
105 | // *****************************************************************
106 | //
107 | // struct pkt_comm
108 | //
109 | // Represents a communication to some independently communicating
110 | // device (part of device)
111 | // * Queue for output packets
112 | // * Queue for input packets
113 | //
114 | // *****************************************************************
115 |
116 | // Parameters for link layer
117 | struct pkt_comm_params {
118 | int alignment;
119 | int output_max_len; // link layer max. transmit length
120 | int input_max_len; // link layer max. receive length
121 | };
122 |
123 | struct pkt_comm {
124 | struct pkt_comm_params *params;
125 |
126 | struct pkt_queue *output_queue;
127 | unsigned char *output_buf;
128 | int output_buf_size;
129 | int output_buf_offset;
130 |
131 | struct pkt_queue *input_queue;
132 | unsigned char *input_buf;
133 | int input_buf_len;
134 | int input_buf_offset;
135 | struct pkt *input_pkt;
136 |
137 | int error;
138 | };
139 |
140 | struct pkt_comm *pkt_comm_new(struct pkt_comm_params *params);
141 |
142 | void pkt_comm_delete(struct pkt_comm *comm);
143 |
144 |
145 | // *****************************************************************
146 | //
147 | // Following functions are for I/O over link layer
148 | //
149 | // *****************************************************************
150 |
151 | // Get data for output over link layer
152 | // Return NULL if there's no data for output
153 | unsigned char *pkt_comm_get_output_data(struct pkt_comm *comm, int *len);
154 |
155 | // Called after the transmission of data requested with pkt_comm_output_get_data()
156 | // 'len' is length of actually transmitted data
157 | // < 0 on error
158 | void pkt_comm_output_completed(struct pkt_comm *comm, int len, int error);
159 |
160 | // Get buffer for link layer input
161 | // Return NULL if input is full
162 | unsigned char *pkt_comm_input_get_buf(struct pkt_comm *comm);
163 |
164 | // Called after data was received into buffer requested with pkt_comm_input_get_buf()
165 | // 'len' is length of actually received data
166 | // < 0 on error
167 | int pkt_comm_input_completed(struct pkt_comm *comm, int len, int error);
168 |
169 |
170 | #define _PKT_COMM_H_
171 | #endif
172 |
--------------------------------------------------------------------------------
/host/pkt_comm/word_gen.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "pkt_comm.h"
6 | #include "word_gen.h"
7 |
8 |
9 | struct word_gen word_gen_words_pass_by = {
10 | 0, { }, // ranges
11 | 1, 0 // insert 1 word at position 0
12 | };
13 |
14 |
15 | struct pkt *pkt_word_gen_new(struct word_gen *word_gen)
16 | {
17 |
18 | char *data = malloc(WORD_GEN_MAX_SIZE);
19 | if (!data) {
20 | pkt_error("pkt_word_gen_new(): unable to allocate %d bytes\n",
21 | WORD_GEN_MAX_SIZE);
22 | return NULL;
23 | }
24 |
25 | int offset = 0;
26 |
27 | int i;
28 |
29 | data[offset++] = word_gen->num_ranges;
30 | for (i = 0; i < word_gen->num_ranges; i++) {
31 | struct word_gen_char_range *range = &word_gen->ranges[i];
32 | data[offset++] = range->num_chars;
33 | data[offset++] = range->start_idx;
34 | int j;
35 | for (j = 0; j < range->num_chars; j++)
36 | data[offset++] = range->chars[j];
37 | }
38 |
39 | data[offset++] = word_gen->num_words;
40 | for (i = 0; i < word_gen->num_words; i++) {
41 | data[offset++] = word_gen->word_insert_pos[i];
42 | }
43 |
44 | data[offset++] = word_gen->num_generate;
45 | data[offset++] = word_gen->num_generate >> 8;
46 | data[offset++] = word_gen->num_generate >> 16;
47 | data[offset++] = word_gen->num_generate >> 24;
48 |
49 | data[offset++] = 0xBB;
50 |
51 | struct pkt *pkt = pkt_new(PKT_TYPE_WORD_GEN, data, offset);
52 | //printf("pkt_word_gen_new: data_len %d\n", offset);
53 | return pkt;
54 | }
55 |
--------------------------------------------------------------------------------
/host/pkt_comm/word_gen.h:
--------------------------------------------------------------------------------
1 |
2 | #define PKT_TYPE_WORD_GEN 2
3 |
4 | // ***************************************************************
5 | //
6 | // Word Generator
7 | //
8 | // ***************************************************************
9 |
10 | #define CHAR_BITS 7 // 7 or 8
11 | #define RANGES_MAX 8
12 | #define WORD_MAX_LEN RANGES_MAX
13 | #define WORDS_INSERT_MAX 1
14 |
15 | #define WORD_GEN_MAX_SIZE ( 7 \
16 | + RANGES_MAX * (2+(CHAR_BITS==7 ? 96 : 224)) \
17 | + WORDS_INSERT_MAX )
18 |
19 |
20 | struct word_gen_char_range {
21 | unsigned char num_chars; // number of chars in range
22 | unsigned char start_idx; // index of char to start iteration
23 | unsigned char chars[CHAR_BITS==7 ? 96 : 224];
24 | };
25 | // range must have at least 1 char
26 |
27 | struct word_gen {
28 | unsigned char num_ranges;
29 | struct word_gen_char_range ranges[RANGES_MAX];
30 | unsigned char num_words;
31 | unsigned char word_insert_pos[WORDS_INSERT_MAX];
32 | unsigned long num_generate;
33 | unsigned char magic; // 0xBB
34 | };
35 |
36 | struct word_gen word_gen_words_pass_by;
37 |
38 | struct pkt *pkt_word_gen_new(struct word_gen *word_gen);
39 |
40 |
--------------------------------------------------------------------------------
/host/pkt_comm/word_list.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "pkt_comm.h"
6 | #include "word_list.h"
7 |
8 | struct pkt *pkt_word_list_new(char **words)
9 | {
10 | int len = 0;
11 | int i;
12 | for (i = 0; words[i]; i++) {
13 | len += strlen(words[i]) + 1;
14 | }
15 |
16 | char *data = malloc(len);
17 | if (!data) {
18 | pkt_error("pkt_wordlist_new(): unable to allocate %d bytes\n", len);
19 | return NULL;
20 | }
21 |
22 | int offset = 0;
23 | for (i = 0; words[i]; i++) {
24 | strcpy(data + offset, words[i]);
25 | offset += strlen(words[i]) + 1;
26 | }
27 |
28 | struct pkt *pkt = pkt_new(PKT_TYPE_WORD_LIST, data, len);
29 | return pkt;
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/host/pkt_comm/word_list.h:
--------------------------------------------------------------------------------
1 |
2 | #define PKT_TYPE_WORD_LIST 1
3 |
4 | // ***************************************************************
5 | //
6 | // Word List
7 | //
8 | // ***************************************************************
9 |
10 | struct pkt *pkt_word_list_new(char **words);
11 |
--------------------------------------------------------------------------------
/host/simple_test.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "ztex.h"
9 | #include "inouttraffic.h"
10 |
11 |
12 | #define IGNORE_BAD_DATA 0
13 | int test_factor = 8;
14 | int test_num = 0;
15 |
16 | const int BUF_SIZE_MAX = 65536;
17 |
18 | //============================================================================================
19 |
20 | void test_select_fpga(struct ztex_device *dev, int count)
21 | {
22 | printf("Test #%d. Performing %d K ztex_select_fpga() commands\n", test_num++, count/1024);
23 |
24 | int i;
25 | int result;
26 | int num = 0;
27 | struct timeval tv0, tv1;
28 |
29 | gettimeofday(&tv0, NULL);
30 | for (i = 0; i < count; i++) {
31 |
32 | result = ztex_select_fpga(dev, num);
33 | if (result < 0) {
34 | fprintf(stderr,"ztex_select_fpga(%d) returned %d, usb_strerror: %s\n", num, result, libusb_strerror(result));
35 | break;
36 | }
37 | if (++num >= dev->num_of_fpgas)
38 | num = 0;
39 | if (!(i%1024)) {
40 | printf(".");
41 | fflush(stdout);
42 | }
43 | }
44 | gettimeofday(&tv1, NULL);
45 | unsigned long usec = (tv1.tv_sec - tv0.tv_sec)*1000000 + tv1.tv_usec - tv0.tv_usec;
46 | printf("rate: %.1f K cmd/s\n", (float)count*1000000/usec /1024 );
47 | }
48 |
49 | //============================================================================================
50 | unsigned long long buf_set(unsigned char *buf, int buf_size, unsigned long long data)
51 | {
52 | int i;
53 | for (i = 0; i < buf_size; i+=8, data++) {
54 | buf[i] = data & 0xff; buf[i+1] = (data >> 8) & 0xff;
55 | buf[i+2] = (data >> 16) & 0xff; buf[i+3] = (data >> 24) & 0xff;
56 | buf[i+4] = (data >> 32) & 0xff; buf[i+5] = (data >> 40) & 0xff;
57 | buf[i+6] = (data >> 48) & 0xff; buf[i+7] = (data >> 56) & 0xff;
58 | //printf("%08x\n",data);
59 | }
60 | return data;
61 | }
62 |
63 | void test_hs_inout(struct libusb_device_handle *handle, int buf_size, int pkt_count_max)
64 | {
65 | int mbytes_total = pkt_count_max/1024*buf_size/1024;
66 | printf("Test #%d. Sending %d MB via high-speed interface and reading it back (%d-byte r/w)\n",
67 | test_num++, mbytes_total, buf_size);
68 |
69 | int i;
70 | int result;
71 | unsigned long long data_out, data_in, final_data;
72 | unsigned char buf_out[BUF_SIZE_MAX];
73 | unsigned char buf_in[BUF_SIZE_MAX];
74 | int pkt_count = 0;
75 | int write_ok = 0;
76 | int read_ok = 0;
77 | struct timeval tv0, tv1;
78 |
79 | data_in = data_out = 0x4000300020001000;//0x12345678;//0xABC00DEF;
80 | final_data = data_in + pkt_count_max/8*buf_size;
81 | gettimeofday(&tv0, NULL);
82 |
83 | for ( ; ; ) {
84 | if (pkt_count < pkt_count_max) {
85 | if (!pkt_count || write_ok)
86 | data_out = buf_set(buf_out, buf_size, data_out);
87 |
88 | int transferred = 0;
89 | result = libusb_bulk_transfer(handle, 0x06, buf_out, buf_size, &transferred, 200);
90 | if (result < 0) {
91 | fprintf(stderr, "usb_bulk_write returned %d, usb_strerror: %s\n", result, libusb_strerror(result));
92 | break;
93 | }
94 | else if (transferred != buf_size) {
95 | fprintf(stderr, "usb_bulk_transfer: write %d of %d\n", transferred, result);
96 | break;
97 | }
98 | else {
99 | write_ok = 1;
100 | pkt_count++;
101 | if ( (uint64_t)(pkt_count*buf_size/1024/1024)
102 | != (uint64_t)( (pkt_count+1)*buf_size/1024/1024) ) {
103 | printf(".");
104 | fflush(stdout);
105 | }
106 | }
107 | } // pkt_count < pkt_count_max
108 |
109 | int transferred = 0;
110 | result = libusb_bulk_transfer(handle, 0x82, buf_in, buf_size, &transferred, 200);
111 | if (result < 0) {
112 | fprintf(stderr, "usb_bulk_read returned %d, usb_strerror: %s\n", result, libusb_strerror(result));
113 | break;
114 | }
115 | else if (transferred != buf_size) {
116 | fprintf(stderr, "partial read: transferred %d of %d\n", transferred, buf_size);
117 | break;
118 | }
119 | else {
120 | //if (DEBUG) fprintf(stderr,"usb_bulk_read: transferred %d, res %d\n", transferred, result);
121 | read_ok = 1;
122 | for (i = 0; i < transferred; i+=8, data_in++) {
123 | unsigned long long tmp = buf_in[i] | (buf_in[i+1] << 8) | (buf_in[i+2] << 16) | (buf_in[i+3] << 24);
124 | unsigned long long tmp1 = buf_in[i+4] | (buf_in[i+5] << 8) | (buf_in[i+6] << 16) | (buf_in[i+7] << 24);
125 | tmp |= (tmp1 << 32);
126 | if (!IGNORE_BAD_DATA && tmp != data_in) {
127 | read_ok = 0;
128 | fprintf(stderr, "Received invalid data %016llx, must be %016llx\n", tmp, data_in);
129 | if (!(DEBUG >= 2)) break;
130 | } else {
131 | if (DEBUG >= 2) fprintf(stderr, "%016llx\n",tmp);
132 | }
133 | }
134 | if (!read_ok)
135 | break;
136 | //else printf("PACKET RECEIVED OK\n");
137 | if (pkt_count == pkt_count_max && data_in == final_data) {
138 | gettimeofday(&tv1, NULL);
139 | unsigned long usec = (tv1.tv_sec - tv0.tv_sec)*1000000 + tv1.tv_usec - tv0.tv_usec;
140 | printf("in+out: %.1f MB/s\n", 2* (float)mbytes_total*1000000/usec );
141 | break;
142 | }
143 | }
144 |
145 | } // for(;;)
146 | }
147 |
148 | //============================================================================================
149 |
150 |
151 | void main(int argc, char **argv)
152 | {
153 | int result = libusb_init(NULL);
154 | if (result < 0) {
155 | printf("libusb_init(): %s\n", libusb_strerror(result));
156 | exit(EXIT_FAILURE);
157 | }
158 |
159 | struct ztex_dev_list *ztex_dev_list = ztex_dev_list_new();
160 | // find all ZTEX devices of supported type
161 | ztex_scan_new_devices(ztex_dev_list, NULL);
162 | printf("Found %d device(s) ZTEX 1.15y\n", ztex_dev_list_count(ztex_dev_list));
163 | ztex_dev_list_print(ztex_dev_list);
164 | if (!ztex_dev_list_count(ztex_dev_list))
165 | exit(0);
166 |
167 | printf("Simple test. Using 1st device, FPGA #0. Only most basic functions used.\n");
168 | printf("Expecting firmware and bitstream are already uploaded.\n");
169 |
170 | struct ztex_device *dev = ztex_dev_list->dev;
171 | struct libusb_device_handle *handle = dev->handle;
172 |
173 | //DEBUG=1;
174 |
175 | result = ztex_select_fpga(dev, 0);
176 | if (result < 0) {
177 | fprintf(stderr, "ztex_select_fpga() returns %d, usb_strerror: %s\n", result, libusb_strerror(result));
178 | exit(EXIT_FAILURE);
179 | }
180 |
181 | // Inouttraffic bitstreams have High-Speed interface disabled by default.
182 | // fpga_reset() enables High-Speed interface.
183 | result = fpga_reset(handle);
184 | if (result < 0) {
185 | fprintf(stderr, "fpga_reset() returns %d, usb_strerror: %s\n", result, libusb_strerror(result));
186 | fprintf(stderr, "Did you upload firmware?\n");
187 | exit(EXIT_FAILURE);
188 | }
189 |
190 | // With output limit disabled, FPGA sends data when it has data to send.
191 | result = fpga_output_limit_enable(handle,0);
192 | if (result < 0) {
193 | fprintf(stderr, "fpga_output_limit_enable() returns %d, usb_strerror: %s\n", result, libusb_strerror(result));
194 | exit(EXIT_FAILURE);
195 | }
196 | printf("Output limit disabled.\n");
197 |
198 | result = libusb_claim_interface(handle,0);
199 | if (result < 0) {
200 | fprintf(stderr, "libusb_claim_interface(): %d, error: %s\n", result, libusb_strerror(result));
201 | exit(0);
202 | }
203 |
204 | // FPGA application operates High-Speed interface with 8-byte words,
205 | // expects you don't write unaligned
206 | test_hs_inout(handle, 128, 4*1024*(test_factor > 4 ? 4 : test_factor));
207 |
208 | // "-8" or anything unaligned to buffer size (512) would test PKTEND of Slave FIFO
209 | test_hs_inout(handle, 1024, 2*1024*(test_factor > 16 ? 16 : test_factor));
210 |
211 | test_hs_inout(handle, 8192-8, 1*1024*test_factor);
212 |
213 | //printf("Using max. r/w size: 16K input + (8K -8B) output FPGA buffers + 2* 2K USB device controller's buffers\n");
214 | // It predictably returns with USB_ETIMEDOUT if 8 more bytes added.
215 | //test_hs_inout(handle, 16384 +8192-8 +2*2048, 1*1024/2*test_factor);
216 |
217 | // FPGA's I/O buffers increased to 32K each
218 | test_hs_inout(handle, 65536, 1024/4 * test_factor);
219 |
220 | test_select_fpga(dev, 4096*(test_factor > 8 ? 8 : test_factor));
221 |
222 |
223 | libusb_release_interface(handle,0);
224 | libusb_exit(NULL);
225 | }
226 |
227 |
--------------------------------------------------------------------------------
/host/ztex.h:
--------------------------------------------------------------------------------
1 |
2 | //===============================================================
3 | //
4 | // Contains functions for operating Ztex USB-FPGA modules.
5 | // Based on original Ztex SDK written in java.
6 | //
7 | //===============================================================
8 |
9 | #define USB_CMD_TIMEOUT 50
10 | #define USB_RW_TIMEOUT 200
11 |
12 | #define ZTEX_SNSTRING_LEN 11 // includes '\0' terminator
13 | #define ZTEX_SNSTRING_MIN_LEN 5
14 | #define ZTEX_PRODUCT_STRING_LEN 32 // includes '\0' terminator
15 |
16 | #define ZTEX_IDVENDOR 0x221A
17 | #define ZTEX_IDPRODUCT 0x0100
18 |
19 | // Capability index for EEPROM support.
20 | #define CAPABILITY_EEPROM 0,0
21 | // Capability index for FPGA configuration support.
22 | #define CAPABILITY_FPGA 0,1
23 | // Capability index for FLASH memory support.
24 | #define CAPABILITY_FLASH 0,2
25 | // Capability index for DEBUG helper support.
26 | #define CAPABILITY_DEBUG 0,3
27 | // Capability index for AVR XMEGA support.
28 | #define CAPABILITY_XMEGA 0,4
29 | // Capability index for AVR XMEGA support.
30 | #define CAPABILITY_HS_FPGA 0,5
31 | // Capability index for AVR XMEGA support.
32 | #define CAPABILITY_MAC_EEPROM 0,6
33 | // Capability index for multi FPGA support.
34 | #define CAPABILITY_MULTI_FPGA 0,7
35 | // Capability index for Temperature sensor support
36 | #define CAPABILITY_TEMP_SENSOR 0,8
37 | // Capability index for 2nd FLASH memory support
38 | #define CAPABILITY_FLASH2 0,9
39 |
40 |
41 | extern int ZTEX_DEBUG;
42 |
43 |
44 | int vendor_command(struct libusb_device_handle *handle, int cmd, int value, int index, char *buf, int length);
45 |
46 | int vendor_request(struct libusb_device_handle *handle, int cmd, int value, int index, char *buf, int length);
47 |
48 |
49 | // used by ZTEX SDK VR 0x30: getFpgaState
50 | // for debug purposes only
51 | // inouttraffic doesn't use that
52 | struct ztex_fpga_state {
53 | int fpgaConfigured;
54 | int fpgaChecksum;
55 | int fpgaBytes;
56 | int fpgaInitB;
57 | //int fpgaFlashResult; // present but not used in ZTEX
58 | //int fpgaFlashBitSwap;
59 | };
60 |
61 | struct ztex_device {
62 | struct libusb_device_handle *handle;
63 | libusb_device *usb_device;
64 | int busnum;
65 | int devnum;
66 | int num_of_fpgas;
67 | int selected_fpga;
68 | int valid;
69 | struct ztex_device *next;
70 | // ZTEX specific stuff from device
71 | unsigned char snString[ZTEX_SNSTRING_LEN];
72 | unsigned char productId[4];
73 | unsigned char fwVersion;
74 | unsigned char interfaceVersion;
75 | unsigned char interfaceCapabilities[6];
76 | unsigned char moduleReserved[12];
77 | char product_string[ZTEX_PRODUCT_STRING_LEN];
78 | };
79 |
80 | struct ztex_dev_list {
81 | struct ztex_device *dev;
82 | };
83 |
84 | int ztex_device_new(libusb_device *usb_dev, struct ztex_device **ztex_dev);
85 |
86 | void ztex_device_delete(struct ztex_device *dev);
87 |
88 | void ztex_device_invalidate(struct ztex_device *dev);
89 |
90 | int ztex_device_valid(struct ztex_device *dev);
91 |
92 |
93 | struct ztex_dev_list *ztex_dev_list_new();
94 |
95 | void ztex_dev_list_add(struct ztex_dev_list *dev_list, struct ztex_device *dev);
96 |
97 | // Moves valid devices from 'added_list' to 'dev_list'. Returns number of moved devices. 'added_list' emptied.
98 | int ztex_dev_list_merge(struct ztex_dev_list *dev_list, struct ztex_dev_list *added_list);
99 |
100 | // Device removed from list and deleted
101 | void ztex_dev_list_remove(struct ztex_dev_list *dev_list, struct ztex_device *dev_remove);
102 |
103 | int ztex_dev_list_count(struct ztex_dev_list *dev_list);
104 |
105 | void ztex_dev_list_print(struct ztex_dev_list *dev_list);
106 |
107 | struct ztex_device *ztex_find_by_sn(struct ztex_dev_list *dev_list, char *sn);
108 |
109 |
110 | // equal to reset_fpga() from ZTEX SDK (VR 0x31)
111 | // FPGA reset, removes bitstream
112 | int ztex_reset_fpga(struct ztex_device *dev);
113 |
114 | // equal to select_fpga() from ZTEX SDK (VR 0x51)
115 | int ztex_select_fpga(struct ztex_device *dev, int num);
116 |
117 | // Gets ZTEX-specific data from device (VR 0x22), including
118 | // device type and capabilities
119 | // Used in ztex_device_new()
120 | int ztex_get_descriptor(struct ztex_device *dev);
121 |
122 | // ZTEX Capabilities. Capabilities are pre-fetched and stored in 'struct ztex_device'
123 | int ztex_check_capability(struct ztex_device *dev, int i, int j);
124 |
125 | // Scans for devices that aren't already in dev_list, adds them to new_dev_list
126 | // Devices in question:
127 | // 1. Got ZTEX Vendor & Product ID, also SN
128 | // 2. Have ZTEX-specific descriptor
129 | // Returns:
130 | // >= 0 number of devices added
131 | // <0 error
132 | int ztex_scan_new_devices(struct ztex_dev_list *new_dev_list, struct ztex_dev_list *dev_list);
133 |
134 | // upload bitstream on FPGA
135 | int ztex_configureFpgaHS(struct ztex_device *dev, FILE *fp, int interfaceHS);
136 |
137 | // uploads bitsteam on every FPGA in the device
138 | int ztex_upload_bitstream(struct ztex_device *dev, FILE *fp);
139 |
140 | // reset_cpu used by firmware upload
141 | int ztex_reset_cpu(struct ztex_device *dev, int r);
142 |
143 | // firmware image loaded from an ihx (Intel Hex format) file.
144 | const int IHX_SIZE_MAX;
145 | struct ihx_data {
146 | short *data;
147 | };
148 |
149 | // Uploads firmware from .ihx file, device resets.
150 | // < 0 on error.
151 | int ztex_firmware_upload(struct ztex_device *dev, const char *filename);
152 |
153 | // resets device. firmware is lost.
154 | void ztex_device_reset(struct ztex_device *dev);
155 |
--------------------------------------------------------------------------------
/host/ztex_scan.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "ztex.h"
9 | #include "inouttraffic.h"
10 | #include "ztex_scan.h"
11 |
12 | ///////////////////////////////////////////////////////////////////
13 | //
14 | // Find Ztex devices (of supported type)
15 | // Upload firmware (device resets) if necessary
16 | // Returns number of newly found devices (excluding those that were reset)
17 | //
18 | ///////////////////////////////////////////////////////////////////
19 |
20 | int ztex_scan(struct ztex_dev_list *new_dev_list, struct ztex_dev_list *dev_list, int *fw_upload_count)
21 | {
22 | int count = 0;
23 | (*fw_upload_count) = 0;
24 |
25 | int result = ztex_scan_new_devices(new_dev_list, dev_list);
26 | if (result < 0) {
27 | //printf("ztex_scan_new_devices(): %s\n", libusb_strerror(result));
28 | return 0;
29 | }
30 |
31 | struct ztex_device *dev, *dev_next;
32 | for (dev = new_dev_list->dev; dev; dev = dev_next) {
33 | dev_next = dev->next;
34 |
35 | // Check device type
36 | // only 1.15y devices supported for now
37 | if (dev->productId[0] == 10 && dev->productId[1] == 15) {
38 | }
39 | else {
40 | if (ZTEX_DEBUG) printf("SN %s: unsupported ZTEX device: %d.%d, skipping\n",
41 | dev->snString, dev->productId[0], dev->productId[1]);
42 | ztex_dev_list_remove(new_dev_list, dev);
43 | continue;
44 | }
45 |
46 | // Check firmware
47 | if (!strncmp("inouttraffic", dev->product_string, 12)) {
48 | count++;
49 | continue;
50 | }
51 | // dummy firmware, do upload
52 | else if (!strncmp("USB-FPGA Module 1.15y (default)", dev->product_string, 31)) {
53 | // upload firmware
54 | result = ztex_firmware_upload(dev, "../inouttraffic.ihx");
55 | if (result >= 0)
56 | printf("SN %s: firmware uploaded\n", dev->snString);
57 | (*fw_upload_count)++;
58 | ztex_dev_list_remove(new_dev_list, dev);
59 | }
60 | // device with some 3rd party firmware - skip it
61 | else {
62 | if (ZTEX_DEBUG) printf("SN %s: 3rd party firmware \"%s\", skipping\n",
63 | dev->snString, dev->product_string);
64 | ztex_dev_list_remove(new_dev_list, dev);
65 | }
66 | }
67 | return count;
68 | }
69 |
70 | // Scan interval in seconds.
71 | int ztex_scan_interval = ZTEX_SCAN_INTERVAL_DEFAULT;
72 |
73 | struct timeval ztex_scan_prev_time = { 0, 0 };
74 |
75 | int ztex_scan_fw_upload_count = 0;
76 |
77 |
78 | ///////////////////////////////////////////////////////////////////
79 | //
80 | // ztex_timely_scan()
81 | // Function to be invoked timely to scan for new devices.
82 | // Upload firmware if necessary. After upload device resets.
83 | // Immediately returns number of ready devices.
84 | //
85 | ///////////////////////////////////////////////////////////////////
86 |
87 | int ztex_timely_scan(struct ztex_dev_list *new_dev_list, struct ztex_dev_list *dev_list)
88 | {
89 | struct timeval tv;
90 | gettimeofday(&tv, NULL);
91 | int time_diff = tv.tv_sec - ztex_scan_prev_time.tv_sec
92 | + (tv.tv_usec - ztex_scan_prev_time.tv_usec > 0 ? 0 : -1);
93 | if ( !(ztex_scan_fw_upload_count && time_diff >= ZTEX_FW_UPLOAD_DELAY
94 | || time_diff >= ztex_scan_interval) )
95 | return 0;
96 |
97 | int count, fw_upload_count;
98 | count = ztex_scan(new_dev_list, dev_list, &fw_upload_count);
99 | if (ztex_scan_fw_upload_count > count) {
100 | // Not exact; better record SNs of devices for fw upload
101 | fprintf(stderr, "%d device(s) lost after firmware upload\n",
102 | ztex_scan_fw_upload_count - count);
103 | }
104 |
105 | ztex_scan_fw_upload_count = fw_upload_count;
106 | gettimeofday(&ztex_scan_prev_time, NULL);
107 | return count;
108 | }
109 |
110 |
111 | ///////////////////////////////////////////////////////////////////
112 | //
113 | // ztex_init_scan()
114 | // Function to be invoked at program initialization.
115 | // Skip valid devices from 'dev_list'.
116 | // If no devices immediately ready and it was firmware upload - waits and rescans.
117 | // Returns number of ready devices with uploaded firmware.
118 | //
119 | ///////////////////////////////////////////////////////////////////
120 |
121 | int ztex_init_scan(struct ztex_dev_list *new_dev_list)
122 | {
123 | int count;
124 | count = ztex_scan(new_dev_list, NULL, &ztex_scan_fw_upload_count);
125 | // if some devices ready - return immediately
126 | gettimeofday(&ztex_scan_prev_time, NULL);
127 | if (count)
128 | return count;
129 | if (!ztex_scan_fw_upload_count)
130 | return 0;
131 | // no devices ready right now and there're some devices
132 | // in reset state after firmware upload
133 | usleep(ZTEX_FW_UPLOAD_DELAY* 1000*1000);
134 |
135 | int fw_upload_count_stage2;
136 | count = ztex_scan(new_dev_list, NULL, &fw_upload_count_stage2);
137 | //if (fw_upload_count_stage2) { // device just plugged in. wait for timely_scan
138 | if (ztex_scan_fw_upload_count > count) {
139 | // Not exact; better record SNs of devices for fw upload
140 | fprintf(stderr, "%d device(s) lost after firmware upload\n",
141 | ztex_scan_fw_upload_count - count);
142 | }
143 |
144 | ztex_scan_fw_upload_count = fw_upload_count_stage2;
145 | gettimeofday(&ztex_scan_prev_time, NULL);
146 | return count;
147 | }
148 |
149 |
150 |
--------------------------------------------------------------------------------
/host/ztex_scan.h:
--------------------------------------------------------------------------------
1 |
2 | // Find Ztex USB devices (of supported type)
3 | // Upload firmware (device resets) if necessary
4 | // Returns number of newly found devices (excluding those that were reset)
5 | int ztex_scan(struct ztex_dev_list *new_dev_list, struct ztex_dev_list *dev_list, int *fw_upload_count);
6 |
7 | // Scan interval in seconds. Consider following:
8 | // If some board is buggy it might timely upload bitstream then fail.
9 | // bitstream upload takes ~1s and other boards don't perform I/O during that time.
10 | extern int ztex_scan_interval;
11 | #define ZTEX_SCAN_INTERVAL_DEFAULT 15
12 |
13 | extern struct timeval ztex_scan_prev_time;
14 |
15 | // if firmware was uploaded, perform rescan after that many sec
16 | #define ZTEX_FW_UPLOAD_DELAY 2
17 |
18 | // Function to be invoked timely to scan for new devices.
19 | // Skip valid devices from 'dev_list'.
20 | // Upload firmware if necessary. After upload device resets.
21 | // Immediately returns number of ready devices.
22 | int ztex_timely_scan(struct ztex_dev_list *new_dev_list, struct ztex_dev_list *dev_list);
23 |
24 | // Function to be invoked at program initialization.
25 | // If no devices immediately ready and it was firmware upload - waits and rescans.
26 | // Returns number of ready devices with uploaded firmware.
27 | int ztex_init_scan(struct ztex_dev_list *new_dev_list);
28 |
--------------------------------------------------------------------------------
/inouttraffic.c:
--------------------------------------------------------------------------------
1 | /*!
2 | intraffic -- example showing how the EZ-USB FIFO interface is used on ZTEX USB-FPGA Module 1.15y and 1.15y2
3 | Copyright (C) 2009-2014 ZTEX GmbH.
4 | http://www.ztex.de
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License version 3 as
8 | published by the Free Software Foundation.
9 |
10 | This program is distributed in the hope that it will be useful, but
11 | WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program; if not, see http://www.gnu.org/licenses/.
17 | !*/
18 |
19 | #include[ztex-conf.h] // Loads the configuration macros, see ztex-conf.h for the available macros
20 | #include[ztex-utils.h] // include basic functions
21 |
22 | // configure endpoint 2, in, quad buffered, 512 bytes, interface 0
23 | EP_CONFIG(2,0,BULK,IN,512,4);
24 |
25 | // configure endpoint 6, out, quad buffered, 512 bytes, interface 0
26 | EP_CONFIG(6,0,BULK,OUT,512,4);
27 |
28 | // select ZTEX USB FPGA Module 1.15 as target (required for FPGA configuration)
29 | IDENTITY_UFM_1_15Y(10.15.0.0,0);
30 |
31 | // this product string is also used for identification by the host software
32 | #define[PRODUCT_STRING]["inouttraffic UFM 1.15y"]
33 |
34 | // enables high speed FPGA configuration via EP6
35 | ENABLE_HS_FPGA_CONF(6);
36 |
37 | // this is called automatically after FPGA configuration
38 | #define[POST_FPGA_CONFIG][POST_FPGA_CONFIG
39 | // During High-Speed FPGA configuration
40 | // IFCLK is set to 48 MHz.
41 | init_IO();
42 | ]
43 |
44 | void fifo_reset() {
45 | EP2CS &= ~bmBIT0; // clear stall bit
46 | EP6CS &= ~bmBIT0; // clear stall bit
47 |
48 | FIFORESET = 0x80; SYNCDELAY;
49 | EP6FIFOCFG = 0x00; SYNCDELAY; //switching to manual mode
50 | FIFORESET = 6; SYNCDELAY;
51 | OUTPKTEND = 0x86; SYNCDELAY; // skip uncommitted pkts in OUT endpoint
52 | OUTPKTEND = 0x86; SYNCDELAY;
53 | OUTPKTEND = 0x86; SYNCDELAY;
54 | OUTPKTEND = 0x86; SYNCDELAY;
55 | EP6FIFOCFG = bmBIT4 | bmBIT0; SYNCDELAY; // AUTOOUT, WORDWIDE
56 | FIFORESET = 0x00; SYNCDELAY; //Release NAKALL
57 |
58 | FIFORESET = 0x80; SYNCDELAY;
59 | EP2FIFOCFG = 0x00; SYNCDELAY;
60 | FIFORESET = 2; SYNCDELAY;
61 | EP2FIFOCFG = bmBIT3 | bmBIT0; SYNCDELAY; // AOTUOIN, WORDWIDE
62 | FIFORESET = 0x00; SYNCDELAY; //Release NAKALL
63 | }
64 |
65 | void init_IO() {
66 | OEA = bmBIT0 | bmBIT1 | bmBIT7;
67 | IOA0 = 0; IOA1 = 0; IOA7 = 0;
68 |
69 | REVCTL = 0x3; SYNCDELAY;
70 |
71 | // internal IFCLK, OE, slave FIFO interface
72 | // bit6: 48 MHz
73 | IFCONFIG = bmBIT7 | bmBIT6 | bmBIT5 | 3; SYNCDELAY;
74 |
75 | fifo_reset();
76 |
77 | PORTACFG = 0x00; SYNCDELAY; // used PA7/FLAGD as a port pin, not as a FIFO flag
78 | FIFOPINPOLAR = 0; SYNCDELAY; // set all slave FIFO interface pins as active low
79 |
80 | // EZ-USB automatically commits data in 512-byte chunks
81 | EP2AUTOINLENH = 0x02; SYNCDELAY;
82 | EP2AUTOINLENL = 0x00; SYNCDELAY;
83 |
84 | // Bits [7:4] FlagB / Flag D
85 | // Bits [3:0] FlagA / Flag C
86 | // 0100 EP2 PF (prog.full) {0x8}
87 | // 1100 EP2 Full {0xC}
88 | // 1010 EP6 Empty {0xA}
89 | PINFLAGSAB = 0xC8; SYNCDELAY;
90 | PINFLAGSCD = 0x0A; SYNCDELAY;
91 |
92 | // Programmable-level Flag (PF)
93 | // Active when zero bytes in endpoint buffer
94 | EP2FIFOPFH = bmBIT6 | 0; SYNCDELAY;
95 | EP2FIFOPFL = 0; SYNCDELAY;
96 | }
97 |
98 | //===========================================================
99 | // Vendor Commands / Requests 0xA0-0xAF reserved by Cypress
100 | // 0xA0 upload firmware
101 | // 0xA1-0xAF reserved
102 | //===========================================================
103 |
104 | //-----------------------------------------------
105 | // VC 0x71 : write to fpga
106 | // multi-byte write
107 | /*
108 | void ep0_write_data () {
109 | BYTE b;
110 | OEC = 0xff;
111 | IOA0 = 0;
112 | IOC = 0x71;//SETUPDAT[2];
113 | IOA0 = 1;
114 | IOA0 = 0;
115 |
116 | IOA7 = 0; //write
117 | IOA1 = 0;
118 | for ( b=0; b