Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
|
Firstly, a flash-based FPGA is used as the DUT for the laser test. Because of the special performance of the Flash-based FPGA, the radiation tolerance should be better than the SRAM-based FPGA. But we still observed the SEL in the Flash-based FPGA.
In this case, the picoscope is used to capture the current profile of the SEL to characterize the rapid current increase. That is the database of SEL.
Based on the laser test result, the KNN algorithm is implemented on MATLAB. The dataset has 8000 samples and each sample has 100 points from the current profile. And we extracted 7 features for each sample. So, there is a mapping from 100 points to 7 features. The calculation part for FPGA will be easier. And considering that using multiplication within the FPGA would use too many resources, we use Manhattan distance instead of Euclidean distance for distance calculation.
For the accuracy, the highest accuracy is around 97%.
Then, the KNN algorithm is implemented on FPGA by Verilog. All the components are used to test the function. The 7 features are 16-bit. As for the label, which is 1bit, 1 means SEL happened, and 0 means SEL not happened.
From the waveform, the Verilog part is valid to detect SEL.
`include "Parameter.vh"
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module KNN_exe(
input wire clk,
input wire rst_l,
//for initial input state
input wire [`DATA_W-1:0] data_in,
input wire valid_i,
// output reg init_compl,
//for distance
// input wire rd_en,
// input wire dist_en,
// output reg dist_compl,
//for judge
// input wire sum_en,
// output reg sum_compl,
// input wire judge_en,
output wire SEL,
output wire valid_o
);
integer i;
/************************* state == S_INIT_INPUT ***************************/
wire init_en;
assign init_en = valid_i;
reg [2:0] init_cnt;
reg [`DATA_W-1:0] data_test [0:`NUM_FEATURE-1];
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
init_cnt <= 3'b0;
else if(init_cnt >= `NUM_FEATURE - 1)
init_cnt <= 3'b0;
else if(init_en)
init_cnt <= init_cnt + 3'b1;
else
init_cnt <= 3'b0;
end
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
for (i=0; i < `NUM_FEATURE - 1; i=i+1) begin
data_test[i] <= `DATA_W'b0; //reset array
end
// begin
// data_test[0] <= 0;
// data_test[1] <= 0;
// data_test[2] <= 0;
// data_test[3] <= 0;
// data_test[4] <= 0;
// data_test[5] <= 0;
// data_test[6] <= 0;
// end
else if(init_en && init_cnt <= `NUM_FEATURE - 1)
begin
data_test[init_cnt] <= data_in;
end
else
for (i=0; i < `NUM_FEATURE - 1; i=i+1) begin
data_test[i] <= data_test[i]; //sustain data
end
// begin
// data_test[0] <= 0;
// data_test[1] <= 0;
// data_test[2] <= 0;
// data_test[3] <= 0;
// data_test[4] <= 0;
// data_test[5] <= 0;
// data_test[6] <= 0;
// end
end
//init_en posedge detection
wire init_en_pos;
Edge Edge_init_en(
.clk(clk),
.rst_l(rst_l),
.signal(init_en),
.pos_edge(init_en_pos),
.neg_edge()
);
//init_compl can sustain
reg init_compl;
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
init_compl <= 1'b0;
else if(init_en_pos)
init_compl <= 1'b0;
else if(init_cnt >= `NUM_FEATURE - 1)
init_compl <= 1'b1;
else
init_compl <= init_compl;
end
/************************* state change ***************************/
reg rd_en;
//init_compl can sustain, so the rd_en can sustain
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
rd_en <= 1'b0;
else if(init_compl == 1'b1)
rd_en <= 1'b1;
else
rd_en <= 1'b0;
end
/************************* state == S_DIST ***************************/
wire [`DATA_W-1:0] data_sample [0:`NUM_FEATURE-1]; //feature of samples
wire [`DATA_W-1:0] data_out [0:`NUM_FEATURE-1]; //distance
reg [`DIST_W-1:0] accum_dist;
///////////////////////// Read data from ROMs ////////////////////////
wire [`ADDR_W-1:0] rd_addr;
wire rom_output_valid;
wire rd_compl; // all the samples are read
Mem_ctrl Mem_ctrl_0(
.clk(clk),
.rst_l(rst_l),
.rd_en(rd_en),
.rd_compl(rd_compl),
.rd_addr(rd_addr),
////////////// rom_output_valid is dist_en //////////////
.rom_output_valid(rom_output_valid)
);
///////short of ROM read code and labels read code///////////////////////
//instance label ROM
wire label;
reg label_delay0; // to match with the sum of distance
reg label_delay1; // to match with the sum of distance
blk_mem_gen_0 rom_label (
.clka(clk), // input wire clka
.ena(rd_en), // input wire ena
.addra(rd_addr), // input wire [11 : 0] addra
.douta(label) // output wire [15 : 0] douta
);
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)begin
label_delay0 <= 1'b0;
label_delay1 <= 1'b0;
end
else
{label_delay1,label_delay0} <= {label_delay0,label};
end
//instance 7 feature ROMs
//wire [`DATA_W-1:0] data_test [0:`NUM_FEATURE-1];
genvar l;
generate
for(l=0;l<`NUM_FEATURE;l=l+1)begin
blk_mem_gen_1 rom_feature (
.clka(clk), // input wire clka
.ena(rd_en), // input wire ena
.addra(rd_addr), // input wire [11 : 0] addra
.douta(data_sample[l]) // output wire [15 : 0] douta
);
end
endgenerate
///////////////////////// Distance calculation ////////////////////////////
wire dist_en;
assign dist_en = rom_output_valid; //start calculate distance in each feature
genvar k;
generate
for(k=0;k<`NUM_FEATURE;k=k+1)begin
Dist_PE Dist_PE_0(
.clk(clk),
.rst_l(rst_l),
.en(dist_en),
.data_in_x(data_test[k]), //test data
.data_in_y(data_sample[k]), //feature
.data_out(data_out[k]) //distance for each feature
);
end
endgenerate
// dist counter
// reg [2:0]dist_cnt;
// always @(posedge clk or negedge rst_l)
// begin
// if(!rst_l)
// dist_cnt <= 0;
// else if (dist_cnt >= `NUM_FEATURE-1)
// dist_cnt <= 0;
// else if(dist_en)
// dist_cnt <= dist_cnt + 1;
// else
// dist_cnt <= 0;
// end
//sum the distance
reg [1:0]dist_en_delay;
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
dist_en_delay[1:0] <= 2'b0;
else
dist_en_delay[1:0] <= {dist_en_delay[0],dist_en};
end
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
accum_dist <= {`DIST_W{1'b1}};
else if (dist_en_delay[1])
accum_dist <= data_out[0] + data_out[1] + data_out[2] + data_out[3] + data_out[4] + data_out[5] + data_out[6];
else
accum_dist <= {`DIST_W{1'b1}};
end
//K_MIN
wire [`K_NEAR-1:0] label_min;
K_Min_PE K_Min_PE_0(
.clk(clk),
.rst_l(rst_l),
.dist_i(accum_dist),
.label_i(label_delay1),
.label_min(label_min)
);
/************************* state change ***************************/
wire sum_en; // connect with the end of dist_compl_delay
reg dist_compl; //rd_compl
reg [5:0]dist_compl_delay;
//rd_compl can sustain, so the dist_compl can sustain
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
dist_compl <= 1'b0;
else if(rd_compl == 1'b1)
dist_compl <= 1'b1;
else
dist_compl <= 1'b0;
end
//dist_compl_delay for 5 period
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
dist_compl_delay <= 5'b0;
else
dist_compl_delay[5:0] <= {dist_compl_delay[4:0],dist_compl};
end
Edge Edge_sum_en(
.clk(clk),
.rst_l(rst_l),
.signal(dist_compl_delay[5]),
.pos_edge(sum_en),
.neg_edge()
);
/************************* state == S_JUDGE ***************************/
wire [3:0] sum_K;
wire sum_compl;
Sum_label Sum_label_0(
.clk(clk),
.rst_l(rst_l),
.sum_en(sum_en),
.sum_compl(sum_compl),
.label_min(label_min),
.sum_K(sum_K)
);
wire judge_en;
assign judge_en = sum_compl;
wire judge_compl;
assign valid_o = judge_compl;
Judge Judge_0(
.clk(clk),
.rst_l(rst_l),
.judge_en(judge_en),
.judge_compl(judge_compl),
.sum_K(sum_K),
.SEL(SEL)
);
endmodule
`include "Parameter.vh"
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module Mem_ctrl(
input wire clk,
input wire rst_l,
input wire rd_en, // start generate addr
output reg rd_compl, // all the samples are read
output reg [`ADDR_W-1:0] rd_addr, // address in mem
output wire rom_output_valid // the data is valid
);
wire output_valid_temp;
reg output_valid_temp_0, output_valid_temp_1;
assign output_valid_temp = (rd_en == 1'b1) && (rd_addr < `NUM_SAMPLE) && (rd_compl == 1'b0);
assign rom_output_valid = output_valid_temp_1; // flag to show rom output is valid
// there are two period delay
//rd_en posedge detection
wire rd_en_pos;
Edge Edge_init_en(
.clk(clk),
.rst_l(rst_l),
.signal(rd_en),
.pos_edge(rd_en_pos),
.neg_edge()
);
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
rd_addr <= `ADDR_W'b0;
else if(rd_en)
if(rd_addr >= `NUM_SAMPLE)
rd_addr <= `ADDR_W'b0;
else
rd_addr <= rd_addr + `ADDR_W'b1;
else
rd_addr <= `ADDR_W'b0;
end
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
rd_compl <= 1'b0;
else if(rd_en_pos)
rd_compl <= 1'b0;
else if(rd_addr >= `NUM_SAMPLE)
rd_compl <= 1'b1;
else
rd_compl <= rd_compl;
end
//delay for Mem read data
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
{output_valid_temp_0, output_valid_temp_1} <= 1'b0;
else
{output_valid_temp_0, output_valid_temp_1} <= {output_valid_temp, output_valid_temp_0};
end
endmodule
module Edge(clk,rst_l,signal,pos_edge,neg_edge);
input clk;
input rst_l;
input signal;
output pos_edge;
output neg_edge;
reg sig_r0,sig_r1;
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
begin
sig_r0 <= 1'b0;
sig_r1 <= 1'b0;
end
else
begin
sig_r0 <= signal;
sig_r1 <= sig_r0;
end
end
assign pos_edge = ~sig_r1 & sig_r0;
assign neg_edge = sig_r1 & ~sig_r0;
endmodule
`include "Parameter.vh"
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module K_Min_PE (
input wire clk,
input wire rst_l,
// input wire Min_en,
// output reg Min_compl,
input wire [`DIST_W-1:0] dist_i,
input wire label_i,
output wire [`K_NEAR-1:0] label_min
);
wire [`K_NEAR-2:0] label_temp;
wire [`DIST_W-1:0] dist_temp [0:`K_NEAR-2];
//the first KNN PE
Min_PE Min_PE_0(
.clk(clk),
.rst_l(rst_l),
.dist_i(dist_i),
.label_i(label_i),
.dist_min(/*dist_min[0]*/),
.label_min(label_min[0]),
.dist_max(dist_temp[0]),
.label_max(label_temp[0])
);
//middle KNN PEs
genvar i;
generate
for (i = 1; i < `K_NEAR - 1 ; i = i + 1) begin
Min_PE Min_PE_1(
.clk(clk),
.rst_l(rst_l),
.dist_i(dist_temp[i-1]),
.label_i(label_temp[i-1]),
.dist_min(/*dist_min[i]*/),
.label_min(label_min[i]),
.dist_max(dist_temp[i]),
.label_max(label_temp[i])
);
end
endgenerate
//the last KNN PE
Min_PE Min_PE_2(
.clk(clk),
.rst_l(rst_l),
.dist_i(dist_temp[`K_NEAR-2]),
.label_i(label_temp[`K_NEAR-2]),
.dist_min(/*dist_min[`K_NEAR-1]*/),
.label_min(label_min[`K_NEAR-1]),
.dist_max(),
.label_max()
);
endmodule
`include "Parameter.vh"
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module Min_PE (
input wire clk,
input wire rst_l,
input wire [`DIST_W-1:0]dist_i,
input wire label_i,
output reg [`DIST_W-1:0] dist_min,
output reg label_min,
output reg [`DIST_W-1:0] dist_max,
output reg label_max
);
// reg label_temp;
// reg [`DIST_W-1:0] dist_temp;
// always @(posedge clk or negedge rst_l) begin
// if(!rst_l)begin
// dist_temp <= {`DIST_W{1'b1}};
// label_temp<= 1'b0;
// end
// else begin
// dist_temp <= dist_min;
// label_temp<= label_min;
// end
// end
always @(posedge clk or negedge rst_l) begin
if(!rst_l)begin
dist_min <= {`DIST_W{1'b1}};
label_min <= 1'b0;
dist_max <= {`DIST_W{1'b1}};
label_max <= 1'b0;
// dist_temp <= {`DIST_W{1'b1}};
// label_temp<= 1'b0;
end
else if (dist_i <= dist_min) begin
dist_min <= dist_i;
label_min <= label_i;
dist_max <= dist_min;
label_max <= label_min;
end
else begin
dist_min <= dist_min;
label_min <= label_min;
dist_max <= dist_i;
label_max <= label_i;
end
end
endmodule
Sum_label.v
Verilog`include "Parameter.vh"
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module Sum_label (
input wire clk,
input wire rst_l,
input wire sum_en,
output reg sum_compl,
input wire [`K_NEAR-1:0] label_min,
output reg [3:0] sum_K //the register for counting labels
);
reg sum_en_reg;
// counter
reg [3:0]k_cnt;
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
k_cnt <= 1'b0;
else if (k_cnt >= `K_NEAR - 1)
k_cnt <= 1'b0;
else if(sum_en_reg)
k_cnt <= k_cnt + 1'b1;
else
k_cnt <= 1'b0;
end
// latch enable signal and reset when conter is full
always @(posedge clk)
begin
if(!rst_l)
sum_en_reg <= 1'b0;
else if(k_cnt >= `K_NEAR - 1)
sum_en_reg <= 1'b0;
else if(sum_en)
sum_en_reg <= 1'b1;
else
sum_en_reg <= sum_en_reg;//sum_en_reg can sustain
end
//sum the labels
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
sum_K <= 0;
else if (sum_en_reg)
sum_K <= sum_K + label_min[k_cnt];
end
// summing complete flag
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
sum_compl <= 1'b0;
else if (k_cnt >= `K_NEAR - 1)
sum_compl <= 1'b1;
else
sum_compl <= 1'b0;
end
endmodule
`include "Parameter.vh"
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module Judge (
input wire clk,
input wire rst_l,
input wire judge_en,
output reg judge_compl,
input wire [3:0]sum_K,
output reg SEL
);
//Judge SEL
always @(posedge clk or negedge rst_l)
begin
if(!rst_l)
begin
SEL <= 1'b0;
judge_compl <= 1'b0;
end
else if(judge_en)
begin
judge_compl <= 1'b1;
if(sum_K >= `K_JUDGE)
SEL <= 1'b1;
else
SEL <= 1'b0;
end
else
begin
judge_compl <= 1'b0;
SEL <= 1'b0;
end
end
endmodule
`include "Parameter.vh"
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module Dist_PE (
input wire clk,
input wire rst_l,
input wire en,
input wire [`DATA_W-1:0] data_in_x,
input wire [`DATA_W-1:0] data_in_y,
output reg [`DATA_W-1:0] data_out
);
always @(posedge clk or negedge rst_l) begin
if(!rst_l)begin
data_out <= 0;
end
else if(en)begin
if(data_in_x > data_in_y)
data_out <= data_in_x - data_in_y;
else
data_out <= data_in_y - data_in_x;
end
end
endmodule
Comments