12.31 signal bit width conversion (integer, non-integer), clock frequency division (odd number, even number, arbitrary decimal, duty cycle), vending machine (1, 2), game console

Non-integer multiple data bit width conversion 8to12

The so-called non-integer multiple is to use a cnt to periodically determine how to output the register. The value of this cnt is the least common multiple.

The register is registered normally. How to input and register? 

`timescale 1ns/1ns

module width_8to12(
	input 				   clk 		,   
	input 			      rst_n		,
	input				      valid_in	,
	input	[7:0]			   data_in	,
 
 	output  reg			   valid_out,
	output  reg [11:0]   data_out
);
reg[7:0]data_lock;
reg[1:0]valid_cnt;
always@(posedge clk,negedge rst_n)begin
	if(!rst_n)
		data_lock<=0;
	else if(valid_in)
		data_lock<=data_in;
end
always@(posedge clk,negedge rst_n)begin
	if(!rst_n)
		valid_cnt<=0;
	else if(valid_in)begin
		if(valid_cnt==2'd2)
			valid_cnt<=0;
		else
			valid_cnt<=valid_cnt+1;
	end
end
always@(posedge clk,negedge rst_n)begin
	if(!rst_n)
		valid_out<=0;
	else if(valid_in&&valid_cnt==1)
		valid_out<=1;
	else if(valid_in&&valid_cnt==2)
		valid_out<=1;
	else
		valid_out<=0;
end
always@(posedge clk,negedge rst_n)begin
	if(!rst_n)
		data_out<=0;
	else if(valid_in&&valid_cnt==1)
		data_out<={data_lock,data_in[7:4]};
	else if(valid_in&&valid_cnt==2)
		data_out<={data_lock[3:0],data_in};
end
endmodule

Why don’t you need two 8-bit registers for data caching:

According to the timing diagram, data_out generates output in the next clock cycle after two data inputs. If two registers are used to cache two data, then the data must be output before the second data is cached in the register. This cannot meet the requirements. Data output for timing requirements.

According to the timing diagram, data is output after the second data arrives. When only one data arrives, no output is generated, so a counter (valid_cnt) is designed internally to indicate the data reception status. When it is detected that valid_in is pulled high, valid_cnt increases by 1, valid_cnt cycles between 0-2, and the reset value of valid_cnt is 0. When valid_cnt is 1 or 2 and valid_in is high, data is output and valid_out is pulled high.

When valid_cnt==1 and valid_in is high, data_out <= {data_lock, data_in[7:4]}; when valid_cnt==2 and valid_in is high, data_out <= {data_lock[3:0], data_in}.

That is to say, when resetting, there is no one in the register, so it cannot be output. Then after saving one, it is 1, and then it can be output. At this time, the output will output the 8 saved ones and the first 4 newly input ones. And enter 2, which means that the second input is stored in the register at this time, and the first half has been output, and the last four should be output, so the output at this time is the last four of the output register and the new input. All, at this time the inside of the register is actually equivalent to being empty.

In other words, valid_cnt determines the output signal, how to process the signal in the register

Circuit diagram

That is, sequential logic requires the use of flip-flops. <=The most direct one is the D flip-flop.  

 Integer multiple data bit width conversion 8to16

`timescale 1ns/1ns

module width_8to16(
	input 				   clk 		,   
	input 				   rst_n		,
	input				      valid_in	,
	input	   [7:0]		   data_in	,
 
 	output	reg			valid_out,
	output   reg [15:0]	data_out
);
reg[0:0]cnt;
reg[7:0]ram;
always@(posedge clk,negedge rst_n)begin
	if(!rst_n)
		cnt<=0;
	else if(valid_in)
		cnt<=(cnt)?0:1;
	else 
		cnt<=cnt;
end
always@(posedge clk,negedge rst_n)begin
	if(!rst_n)
		ram<=0;
	else if(valid_in)
		ram<=data_in; 
	else
		ram<=ram;
end
always@(posedge clk,negedge rst_n)begin
	if(!rst_n)begin
		data_out<=0;
		valid_out<=0;
	end
	else if(cnt&&valid_in)begin
		data_out<={ram,data_in};
		valid_out<=1;
	end
	else begin
		data_out<=data_out;
		valid_out<=0;
	end
end
endmodule

Note that when the if condition is omitted, the state before the latch is automatically generated.

Circuit diagram

QN stands for antistate, i.e. negation

An empty line means that the corresponding signal is not used, that is, no subsequent output is made. 

The simple logic is to generate a simple D flip-flop 

The D signal here is the signal that controls the current Q state of the flip-flop. After some processing, it becomes a two-way selector, and then there is an AND gate above it; there is no signal above because the latched signal is an 8-bit signal, not 0 or 1. 

 Clock divider (even

`timescale 1ns/1ns

module even_div
    (
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out2,
    output    wire clk_out4,
    output    wire clk_out8
    );
//*************code***********//
reg clk2,clk4,clk8;
always@(posedge clk_in,negedge rst)begin
    if(!rst)
        clk2<=0;
    else
        clk2<=~clk2;
end
always@(posedge clk2,negedge rst)begin
    if(!rst)
        clk4<=0;
    else
        clk4<=~clk4;
end
always@(posedge clk4,negedge rst)begin
    if(!rst)
        clk8<=0;
    else
        clk8<=~clk8;
end
assign clk_out8=clk8;
assign clk_out4=clk4;
assign clk_out2=clk2;
//*************code***********//
endmodule

D flip-flop

The D flip-flop constructs a circuit diagram, which is <= The right side is the input D signal, and the left side is the output Q current signal.

 The D flip-flop interface has the clock signal that controls the triggering of the flip-flop, and the D signal, which is the signal on the right side of the equation, and the output is the converted signal.

Odd frequency division with 50% duty cycle

`timescale 1ns/1ns


module odo_div_or
  #(parameter N = 7)
   (
    input    wire  rst ,
    input    wire  clk_in,
    output   wire  clk_out7
    );



   reg [3:0]            cnt ;
   always @(posedge clk_in or negedge rst) begin
      if (!rst) begin
         cnt    <= 'b0 ;
      end
      else if (cnt == N-1) begin
         cnt    <= 'b0 ;
      end
      else begin
         cnt    <= cnt + 1'b1 ;
      end
   end

   reg                  clkp ;
   always @(posedge clk_in or negedge rst) begin
      if (!rst) begin
         clkp <= 1'b0 ;
      end
      else if (cnt == (N>>1)) begin 
        clkp <= 1 ;
      end
      else if (cnt == N-1) begin 
        clkp <= 0 ;
      end
   end
  

   reg                  clkn ;
   always @(negedge clk_in or negedge rst) begin
      if (!rst) begin
         clkn <= 1'b0 ;
      end
      else if (cnt == (N>>1) ) begin 
        clkn <= 1 ;
      end
      else if (cnt == N-1) begin 
        clkn <= 0 ;
      end
   end


   assign clk_out7 = clkp | clkn ;


endmodule

For odd-numbered frequency division circuits, the main difficulty lies in the realization of 50% duty cycle. There is no way to achieve a 50% duty cycle with a single trigger edge in an odd-numbered frequency division, so you need to consider using double edges plus combinational logic to achieve a 50% duty cycle. 

The first flip of clkout7 is on the rising edge, and the second time is on the falling edge.

Any decimal frequency division

Please design a clock divider that can achieve arbitrary decimal frequency division, such as a clock signal divided by 8.7

Note that rst is a low level reset

hint:

In fact, it is essentially a simple mathematical problem, that is, how to use the least common multiple to obtain the frequency ratio of the clock cycle.

Let the decimal be nn, and here we take the clock cycle divided by 8.7 times as an example.

First of all, since decimal operations cannot be performed on hardware (for example, 2.1 clocks are unrealistic, and there are no 3.3 registers), fractional frequency division cannot achieve that after division, each clock cycle is nn of the source clock. times, it is impossible to achieve a duty cycle of 1/2. Therefore, considering the fractional frequency division, the implementation should be 53 clkout clock cycles is 8.7 times of 10 clkin clock cycles.

In fact, it is almost the same as the non-integer multiple data transposition width.

Non-integer multiples of data transposition width use a counter to record which stage the current output is to.

Use a register, then record the current input signal, and finally make the corresponding output based on the signal of the counter, combined with the signal output at this time;

The difference is that for non-integer multiple data bit width conversion, a signal will be output in each clock cycle

The decimal divider is 1 within a certain period of time and 0 within a certain period of time.

The frequency divider slows down the signal frequency. It used to jump 10 times in 10 seconds, but now it only jumps once.

The idea is to approximate simulation. For large periods, decimal frequency division is used. For small periods, odd frequency division and even frequency division are used for approximation. Then a counter is used to record the large periods, and a counter is used to realize each small period. The frequency divider on the large cycle determines what frequency divider is used on the small cycle at this time, whether it is an odd number or an even number; then a FLAG flag is used to record whether the odd number divider or the even number divider is currently used. device, this FLAG will be replaced at a certain point in the middle and at the end of the entire large cycle. A certain point in the middle is calculated. 

`timescale 1ns/1ns

module div_M_N(
     input  wire clk_in,
     input  wire rst,
     output wire clk_out
);
    parameter M_N = 8'd87; 
    parameter c89 = 8'd24;  // 8/9时钟切换点
    parameter div_e = 5'd8; //偶数周期
    parameter div_o = 5'd9; //奇数周期
//*************code***********//
    reg [3:0] clk_cnt;
    reg [6:0] cyc_cnt;
    reg div_flag;
    reg clk_out_r;
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            clk_cnt <= 0;
        else if(~div_flag)
            clk_cnt <= clk_cnt==(div_e-1)? 0: clk_cnt+1;
        else
            clk_cnt <= clk_cnt==(div_o-1)? 0: clk_cnt+1;
    end
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            cyc_cnt <= 0;
        else
            cyc_cnt <= cyc_cnt==(M_N-1)? 0: cyc_cnt+1;
    end
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            div_flag <= 0;
        else
            div_flag <= cyc_cnt==(M_N-1)||cyc_cnt==(c89-1)? ~div_flag: div_flag;
    end
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            clk_out_r <= 0;
        else if(~div_flag)
            clk_out_r <= clk_cnt<=((div_e>>2)+1);
        else
            clk_out_r <= clk_cnt<=((div_o>>2)+1);
    end
    
    assign clk_out = clk_out_r;
//*************code***********//
endmodule

 In the circuit diagram, when drawing a flip-flop, you need to first look at what the clock signal is and connect it, then look at what the reset signal is and connect it; then, corresponding to the D signal, select the flip-flop. For <=, use the D flip-flop, left The side is the output Q current signal, and the right side is the input D signal. When encountering a ternary expression or else if selection, it is the selector, which selects a signal and connects it to the D signal.

No duty cycle goes to the odd divider

The so-called duty cycle is the proportion of 0 and 1 in a cycle.

Take the question on a decimal frequency divider as an example. To implement a decimal frequency divider, in a large cycle, the flag is updated at the end of the period and at a certain point in the middle. The certain point in the middle determines when to reverse, and also determines the occupancy of the flag. empty ratio

Similarly, in the frequency divider, when the output frequency division signal is reversed, it corresponds to a certain point in the middle, but it will definitely be reversed , that is, when cnt == frequency division number.

When selecting the midpoint, the duty cycle is fifty percent

`timescale 1ns/1ns

module odd_div (    
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out5
);
//*************code***********//
reg[2:0]cnt;
reg clko;
always@(posedge clk_in,negedge rst)begin
    if(!rst)
        cnt<=0;
    else
        cnt<=cnt==4?0:cnt+1;
end
always@(posedge clk_in,negedge rst)begin
    if(!rst)
        clko<=0;
    else
        clko<=cnt<=1;
end
assign clk_out5=clko;
//*************code***********//
endmodule

vending machine 1

state machine

`timescale 1ns/1ns
module seller1(
	input wire clk  ,
	input wire rst  ,
	input wire d1 ,
	input wire d2 ,
	input wire d3 ,
	
	output reg out1,
	output reg [1:0]out2
);
parameter s0=0,s1=1,s2=2,s3=3,s4=4,s5=5,s6=6;
reg[2:0]cs;
reg[2:0]ns;
wire[2:0]is;
assign is={d1,d2,d3};//将输入的控制信号并在一起
always@(posedge clk,negedge rst)begin
	if(!rst)
		cs<=s0;
	else
		cs<=ns;
end

always@(*)begin
	case(cs)
		s0:begin
			case(is)
				3'b100:ns=s1;
				3'b010:ns=s2;
				3'b001:ns=s4;
				default:ns=ns;
			endcase
		end
		s1:begin
			case(is)
				3'b100:ns=s2;
				3'b010:ns=s3;
				3'b001:ns=s5;
				default:ns=ns;
			endcase
		end		
		s2:begin
			case(is)
				3'b100:ns=s3;
				3'b010:ns=s4;
				3'b001:ns=s6;
				default:ns=ns;
			endcase
		end
		default:begin
			ns=s0;
		end
	endcase
end

always@(posedge clk,negedge rst)begin
	if(!rst)begin
		out1<=0;
		out2<=0;
	end
	else begin
		case(ns)
			s3:begin 
				out1<=1;
				out2<=0;
			end
			s4:begin
				out1<=1;
				out2<=1;
			end
			s5:begin
				out1<=1;
				out2<=2;
			end
			s6:begin
				out1<=1;
				out2<=3;
			end
			default:begin
				out1<=0;
				out2<=0;
			end
		endcase
	end
end
endmodule

Vending machine 2

If sel is 0, buy the first drink, and if sel is 1, buy the second drink. You can buy it at s3, but you can only buy the first drink.

Once it can be purchased, the secondary state can only be 0, indicating the termination of this payment, and then the change will be executed on the output.

The output can only be a MEALY machine, that is, the output is related to the current state and the input signal. It cannot be a MOORE machine, otherwise there will be too many states.

It is a MEALY machine, which means that the output depends on the current state on the one hand, and the input signal on the other hand. Here is the SEL signal, or you can write a two-stage formula,

If you use a MOORE machine and use the secondary state to determine the output, you cannot be sure what you want to buy. You need SEL and the current state to jointly determine a state.

`timescale 1ns/1ns

module seller2(
	input wire clk  ,
	input wire rst  ,
	input wire d1 ,
	input wire d2 ,
	input wire sel ,
	
	output reg out1,
	output reg out2,
	output reg out3
);
//*************code***********//

    parameter S0=0, S0_5=1, S1=2, S1_5=3, S2=4, S2_5=5, S3=6;
    reg[2:0] state, nstate;
    
    always@(posedge clk or negedge rst) begin
        if(~rst)
            state <= 0;
        else
            state <= nstate;
    end
    
    always@(*) begin
        case(state)
            S0     : nstate = d1? S0_5:
                              d2? S1:
                              nstate;
            S0_5   : nstate = d1? S1:
                              d2? S1_5:
                              nstate;
            S1     : nstate = d1? S1_5:
                              d2? S2:
                              nstate;
            S1_5   : nstate = ~sel? S0:
                              d1? S2:
                              d2? S2_5:
                              nstate;
            S2     : nstate = ~sel? S0:
                              d1? S2_5:
                              d2? S3:
                              nstate;
            default: nstate = S0;
        endcase
    end
    
    always@(*) begin
        if(~rst) begin
            {out1, out2, out3} = 3'b000;
        end
        else begin
            case(state)
                S0, S0_5, S1: {out1, out2, out3} = 0;
                S1_5        : {out1, out2, out3} = ~sel? 3'b100: 3'b000;
                S2          : {out1, out2, out3} = ~sel? 3'b101: 3'b000;
                S2_5        : {out1, out2, out3} = ~sel? 3'b101: 3'b010;
                S3          : {out1, out2, out3} = ~sel? 3'b101: 3'b011;
                default     : {out1, out2, out3} = 3'b000;
            endcase
        end
    end
//*************code***********//
endmodule

Game console billing program

`timescale 1ns/1ns

module game_count
(
    input rst_n, //异位复位信号,低电平有效
    input clk, 	//时钟信号
    input [9:0]money,
    input set,
    input boost,
    output reg[9:0]remain,
    output reg yellow,
    output reg red
);
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            yellow <= 0;
            red    <= 0;
        end
        else begin
            yellow <= remain<10&&remain;
            red    <= boost? remain<2: remain<1;
        end
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) 
            remain <= 0;
        else if(boost)
            remain <= set     ? remain+money:
                      remain<2? remain: 
                      remain-2;
        else
            remain <= set     ? remain+money:
                      remain<1? remain: 
                      remain-1;
    end
endmodule
`timescale 1ns/1ns

module game_count
    (
		input rst_n, //异位复位信号,低电平有效
        input clk, 	//时钟信号
        input [9:0]money,
        input set,
		input boost,
		output reg[9:0]remain,
		output reg yellow,
		output reg red
    );
    
    always@(posedge clk or negedge rst_n)begin
        if(~rst_n)
            remain <= 0;
        else begin
            if(boost==0)
                remain <= set==1? remain+money: remain-1;
            else if(boost==1)
                remain <= set==1? remain+money: remain-2;
        end
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            yellow <= 0;
            red <= 0;
        end
        else begin
            if(remain < 1)begin
                yellow <= 0;
                red <= 1;
            end
            else if(remain < 10)begin
                yellow <= 1;
                red <= 0;
            end
            else begin
                yellow <= 0;
                red <= 0;
            end
        end
    end

endmodule

Guess you like

Origin blog.csdn.net/m0_73553411/article/details/135317971