Kyrie ZHAO
Created March 30, 2022

ML-enabled radiation-hardened application of SEL detection

KNN algorithm is implemented on FPGA to detect Single-event Latch ups (SEL).

13
ML-enabled radiation-hardened application of SEL detection

Things used in this project

Story

Read more

Schematics

SEL detection

KNN_schematics

The implementation of FPGA for KNN algorithm

Code

KNN_exe.v

Verilog
KNN execute module
`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

Mem_ctrl.v

Verilog
memory control module for the 7 features and label of the samples
`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

Edge.v

Verilog
edge detection part
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

K_Min_PE.v

Verilog
based on the K-nearest number of K, select the K min values
`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

Min_PE.v

Verilog
keep comparing to leave the smallest value
`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
Sum the label in the K min values. for the labels, 1'b1 means SEL, 1'b0 means no SEL
`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

Judge.v

Verilog
Judge whether SEL happened
`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

Dist_PE.v

Verilog
calculate the Manhattan distance between the samples and test data
`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

Credits

Kyrie ZHAO

Kyrie ZHAO

1 project • 0 followers

Comments