|
本帖最后由 HDL 于 2023-3-11 10:39 编辑
- `define leap_year(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0) //是否闰年?
- module is_idcard(
- input [59:0] id, //[60位宽] 18位中国居民身份证号码
- input x, //校验位是否为X
- output reg ok, //校验是否正确
- output gender, //性别:0女 1男
- output [13:0] year, //[14位宽] 出生年:0~9999
- output [3:0] month, //[4位宽] 出生月:1~12
- output [4:0] day //[5位宽] 出生日:1~31
- );
- wire [59:0] i [18:1];
- wire [3:0] j [18:1]; //定义18个4位宽线网
- assign i[1] = (id / 60'd100000000000000000) % 60'd10; //省份代码十位
- assign i[2] = (id / 60'd10000000000000000) % 60'd10; //省份代码个位
- assign i[3] = (id / 60'd1000000000000000) % 60'd10; //城市代码十位
- assign i[4] = (id / 60'd100000000000000) % 60'd10; //城市代码个位
- assign i[5] = (id / 60'd10000000000000) % 60'd10; //区县代码十位
- assign i[6] = (id / 60'd1000000000000) % 60'd10; //区县代码个位
- assign i[7] = (id / 60'd100000000000) % 60'd10; //出生年千位
- assign i[8] = (id / 60'd10000000000) % 60'd10; //出生年百位
- assign i[9] = (id / 60'd1000000000) % 60'd10; //出生年十位
- assign i[10] = (id / 60'd100000000) % 60'd10; //出生年个位
- assign i[11] = (id / 60'd10000000) % 60'd10; //出生月十位
- assign i[12] = (id / 60'd1000000) % 60'd10; //出生月个位
- assign i[13] = (id / 60'd100000) % 60'd10; //出生日十位
- assign i[14] = (id / 60'd10000) % 60'd10; //出生日个位
- assign i[15] = (id / 60'd1000) % 60'd10; //派出所代码十位
- assign i[16] = (id / 60'd100) % 60'd10; //派出所代码个位
- assign i[17] = (id / 60'd10) % 60'd10; //奇数:男 偶数:女
- assign i[18] = x ? 60'd10 : (id % 60'd10); //校验位
- genvar k;
- generate
- for(k=1;k<=18;k=k+1) begin:gen
- assign j[k] = i[k][3:0];
- end
- endgenerate
- wire [13:0] y = j[7]*14'd1000 + j[8]*14'd100 + j[9]*14'd10 + j[10]; //年范围:0~9999
- wire [6:0] m = j[11]*7'd10 + j[12]; //月范围:0~99 有效范围:1~12
- wire [6:0] d = j[13]*7'd10 + j[14]; //日范围:0~99 有效范围:1~31
- function [4:0] ym2d; //已知年月 获取该月有多少天
- input [13:0] y;
- input [3:0] m;
- begin
- case(m)
- 1:ym2d = 5'd31;
- 2:ym2d = `leap_year(y) ? 5'd29 : 5'd28;
- 3:ym2d = 5'd31;
- 4:ym2d = 5'd30;
- 5:ym2d = 5'd31;
- 6:ym2d = 5'd30;
- 7:ym2d = 5'd31;
- 8:ym2d = 5'd31;
- 9:ym2d = 5'd30;
- 10:ym2d = 5'd31;
- 11:ym2d = 5'd30;
- 12:ym2d = 5'd31;
- default:ym2d = 5'd0;
- endcase
- end
- endfunction
- assign gender = j[17][0];
- assign year = ok ? y : 14'd0;
- assign month = ok ? m[3:0] : 4'd0;
- assign day = ok ? d[4:0] : 5'd0;
- wire [9:0] l = //校验码
- (j[1]*10'd7)+
- (j[2]*10'd9)+
- (j[3]*10'd10)+
- (j[4]*10'd5)+
- (j[5]*10'd8)+
- (j[6]*10'd4)+
- (j[7]*10'd2)+
- (j[8]*10'd1)+
- (j[9]*10'd6)+
- (j[10]*10'd3)+
- (j[11]*10'd7)+
- (j[12]*10'd9)+
- (j[13]*10'd10)+
- (j[14]*10'd5)+
- (j[15]*10'd8)+
- (j[16]*10'd4)+
- (j[17]*10'd2);
- wire [3:0] n [10:0];
- assign n[0] = 4'd1;
- assign n[1] = 4'd0;
- assign n[2] = 4'd10; //X
- assign n[3] = 4'd9;
- assign n[4] = 4'd8;
- assign n[5] = 4'd7;
- assign n[6] = 4'd6;
- assign n[7] = 4'd5;
- assign n[8] = 4'd4;
- assign n[9] = 4'd3;
- assign n[10] = 4'd2;
- always @(*) begin
- ok = 1'd1;
- if(y > 9999) begin //年大于9999
- ok = 1'd0;
- end else if(m < 1 || m > 12) begin //月小于1或大于12
- ok = 1'd0;
- end else if(d < 1 || d > ym2d(y,m[3:0]) || d > 31) begin //日小于1或大于月天数或大于31
- ok = 1'd0;
- end else if(n[l%11] != j[18]) begin //校验位错误
- ok = 1'd0;
- end
- end
- endmodule
- module main(
- input clk,
- output ok,
- output gender,
- output [13:0] year,
- output [3:0] month,
- output [4:0] day
- );
- is_idcard U1(
- .id(60'd524288204810248192),
- .x(1'd0),
- .ok(ok),
- .gender(gender),
- .year(year),
- .month(month),
- .day(day)
- );
- endmodule
复制代码 |
|