参考《数字逻辑基础与Verilog设计》的第七章内容
四个8位寄存器,载入四个数据,并进行排序,最终将四个数据从小到大排列。
用两个循环,内循环作比较。外循环计数器cnti,0~2,内循环cntj,1~3。
首先,cnti=0,cntj=1,将R1中、R2数据分别寄存到A\B中,若A大于B,则将A放入R2,B放入A,再将A放入R1。然后计数cntj+1,R3放入B,A\B作比较...直到比较完R4后,跳出内循环,外循环中cnti+1,cntj=cnti+2将此时R2、R3放到A、B进行比较...直到R3、R4完成比较后,结束运算
代码如下。
`timescale 1ns/1ps
module sort(clk,rst_n,s,a,b,c,d,d1,d2,d3,d4,done);
input clk,rst_n,s;
input [7:0] a,b,c,d;
output [7:0] d1,d2,d3,d4;
output done;
reg [7:0] R1,R2,R3,R4,A,B;
parameter S1=8'd0,S2=8'd1,S3=8'd2,S4=8'd3,S5=8'd4,S6=8'd5,S7=8'd6,S8=8'd7;
reg [7:0] state,next_state;
wire co_ab,z1,z0,wrdata,R1_in,R2_in,R3_in,R4_in,A_in,B_in;
reg [1:0] cnti,cntj;
wire en_cnti,en_cntj;
always@(posedge clk or negedge rst_n) begin
if(~rst_n) state <= S1;
else state <= next_state;
end
always@(*) begin
case(state)
S1:next_state=s?S2:S1;
S2:next_state=S3;
S3:next_state=S4;
S4:next_state=co_ab?S5:S7;
S5:next_state=S6;
S6:next_state=S7;
S7:next_state=z1?(z0?S8:S2):S3;
S8:next_state=s?S8:S1;
default:next_state = S1;
endcase
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
R1 <= 8'd0;
else if (R1_in)
R1 <= wrdata?a:A;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
R2 <= 8'd0;
else if (R2_in)
R2 <= wrdata?b:A;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
R3 <= 8'd0;
else if (R3_in)
R3 <= wrdata?c:A;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
R4 <= 8'd0;
else if (R4_in)
R4 <= wrdata?d:A;
end
always@(posedge clk or negedge rst_n ) begin
if(~rst_n)
A <= 8'd0;
else if (A_in) begin
if(co_ab) A <= B ;
else begin
case(cnti)
2'd0: A <= R1;
2'd1: A <= R2;
2'd2: A <= R3;
2'd3: A <= R4;
endcase
end
end
end
always@(posedge clk or negedge rst_n ) begin
if(~rst_n)
B <= 8'd0;
else if (B_in) begin
case(cntj)
2'd0: B <= R1;
2'd1: B <= R2;
2'd2: B <= R3;
2'd3: B <= R4;
default:;
endcase
end
end
always@(posedge clk,negedge rst_n) begin
if(~rst_n)
cnti <= 0;
else if(en_cnti)
cnti <= cnti + 1'b1;
else if(state==S7&z0)
cnti <= 2'd0;
end
always@(posedge clk,negedge rst_n) begin
if(~rst_n)
cntj <= 0;
else if (state==S1&s)
cntj <= cnti + 1'b1;
else if (state==S7&z1)
cntj <= cnti + 2'b10;
else if (en_cntj)
cntj <= cntj + 1'b1;
else if (state==S7&z0)
cntj <= 2'd0;
end
assign wrdata = state==S1&~s;
assign co_ab = (A>B);
assign z1 = cntj==2'b11;
assign z0 = cnti==2'b10;
assign en_cntj = (state==S7&~z1);
assign en_cnti = (state==S7)&(z1)&(~z0);
assign R1_in = (state==S1&~s)|(state==S7&cnti==2'd0)|(state==S5&cntj==2'd0);
assign R2_in = (state==S1&~s)|(state==S7&cnti==2'd1)|(state==S5&cntj==2'd1);
assign R3_in = (state==S1&~s)|(state==S7&cnti==2'd2)|(state==S5&cntj==2'd2);
assign R4_in = (state==S1&~s)|(state==S7&cnti==2'd3)|(state==S5&cntj==2'd3);
assign A_in = (state==S2)|(state==S6);
assign B_in = state==S3;
assign done = state==S8&~s;
assign d1 = state==S8?R1:d1;
assign d2 = state==S8?R2:d2;
assign d3 = state==S8?R3:d3;
assign d4 = state==S8?R4:d4;
endmodule
易错点在于,给出Ain Bin的周期要比给出en_cnti,en_cntj滞后一拍。在状态S7时,转到S2或者S3,这时就要确定给出encnt的信号,在状态S2\S3时,cnt被更新(这一时钟周期开始时,采样到上个周期的encnt有效信号),这时根据encnt可以判断出A\B分别应该写入哪个寄存器的数据。
寄存到R中的周期有,最开始载入S1状态下,以及交换数据的周期S5,S7。
寄存到A中的时钟周期有,进入计算时S2,交换数据周期S6;
寄存到B中的时钟周期有,进入内循环后S3。
下图是ASM图