-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconv2d_binary.sv
More file actions
104 lines (91 loc) · 3.08 KB
/
Copy pathconv2d_binary.sv
File metadata and controls
104 lines (91 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
module conv2d_binary #(
parameter N_IMAGE = 8,
parameter K_KERNEL = 3,
parameter BWD = 1
)(
input logic clk,
input logic clear,
input logic [BWD-1:0] i_data,
input logic i_data_valid,
// Use unpack array for top level simulation!
input logic[BWD-1:0] i_kernel [K_KERNEL*K_KERNEL-1:0],
output logic o_data_clip,
output logic o_data_valid
);
//----------------------------------------
// Repack Unpacked Array back to packed
//----------------------------------------
typedef logic [K_KERNEL-1:0][K_KERNEL-1:0][BWD-1:0] kernel_mat_t;
kernel_mat_t kernel;
logic [K_KERNEL*K_KERNEL-1:0][BWD-1:0] kernel_packed_1d;
always_comb begin
for (int i=0; i<$size(i_kernel); i++) begin
// Inverse order to match window shape
kernel_packed_1d[i] = i_kernel[$size(i_kernel)-1-i];
end
kernel = kernel_packed_1d;
end
//----------------------------------------
// Accumulate 2D Window
//----------------------------------------
// Two versions are presented, but only one is actually used
// Unused will be optimized away after synth
kernel_mat_t window, window_v1, window_v2;
logic window_valid, window_valid_v1, window_valid_v2;
logic window_end, window_end_v1, window_end_v2;
// Timing optimized, use FFs
window_buffer #(
.N_IMAGE(N_IMAGE),
.K_KERNEL(K_KERNEL),
.BWD(BWD)
) i_window_buffer (
.clk ( clk )
, .clear ( clear )
, .i_data ( i_data )
, .i_data_valid ( i_data_valid )
, .o_window ( window_v1 )
, .o_window_valid ( window_valid_v1 )
, .o_window_end ( window_end_v1 )
);
// Resource optimized, use Shift Registers
window_buffer_v2 #(
.N_IMAGE(N_IMAGE),
.K_KERNEL(K_KERNEL),
.BWD(BWD)
) i_window_buffer_2 (
.clk ( clk )
, .clear ( clear )
, .i_data ( i_data )
, .i_data_valid ( i_data_valid )
, .o_window ( window_v2 )
, .o_window_valid ( window_valid_v2 )
, .o_window_end ( window_end_v2 )
);
localparam USE_V2 = 1;
assign window = ( USE_V2 ) ? window_v1 : window_v2;
assign window_valid = ( USE_V2 ) ? window_valid_v1 : window_valid_v2;
assign window_end = ( USE_V2 ) ? window_end_v1 : window_end_v2;
//---------------------------------
// Apply Kernel
//---------------------------------
logic [$clog2($bits(window)+1) -1:0] prod_sum;
// Note: prod_sum is asserted from CocoTB, don't rename!
kernel_1b_nxor#(
.BW_BUS($bits(window))
)i_kernel_1b_nxor(
.kernel( kernel )
, .i_data( window )
, .o_data( prod_sum )
);
assign o_data_valid = window_valid;
assign o_data_clip = (prod_sum > K_KERNEL/2);
// Simulation only code, can be use for debug
int valid_cnt = 0;
always_ff @(posedge clk) begin
if (o_data_valid)
valid_cnt += 1;
end
initial begin
$dumpfile("dump.vcd");
end
endmodule