PWM RTL Code from opencores
diff --git a/verilog/rtl/pwm/PWM.v b/verilog/rtl/pwm/PWM.v new file mode 100644 index 0000000..8653ae6 --- /dev/null +++ b/verilog/rtl/pwm/PWM.v
@@ -0,0 +1,230 @@ +/*Author: Zhuxu + m99a1@yahoo.cn +Pulse Width Generators/timers with 16-bit main counter. +Period or timers target number is controlled by register [15:0]period. +Duty cycle is controlled by register [15:0]DC. +Clock used for PWM signal generation can be switched between Wishbone Bus clock and external clock. It is down clocked first. +o_pwm outputs PWM signal or timers interrupt. + +control register [7:0]ctrl: +bit 0: When set, external clock is chosen for PWM/timer. When cleared, wb clock is used for PWM/timer. +bit 1: When set, PWM is enabled. When cleared, timer is enabled. +bit 2: When set, PWM/timer starts. When cleared, PWM/timer stops. +bit 3: When set, timer runs continuously. When cleared, timer runs one time. +bit 4: When set, o_pwm enabled. +bit 5: timer interrupt bit When it is written with 0, interrupt request is cleared. +bit 6: When set, a 16-bit external signal i_DC is used as duty cycle. When cleared, register DC is used. +bit 7: When set, counter reset for PWM/timer, it's output and bit 5 will also be cleared. When changing from PWM mode to timer mode reset is needed before timer starts. +*/ + +module PWM ( + +input i_wb_clk, +input i_wb_rst, +input i_wb_cyc, +input i_wb_stb, +input i_wb_we, +input [15:0]i_wb_adr, +input [15:0]i_wb_data, +output [15:0]o_wb_data, +output o_wb_ack, + +input [15:0]i_DC, +input i_valid_DC, +output o_pwm + +); + +////////////////////control logic//////////////////////////// +parameter adr_ctrl=0, + adr_divisor=2, + adr_period=4, + adr_DC=6; +reg [7:0]ctrl; +reg [15:0]period; +reg [15:0]DC; +reg [15:0]divisor; +integer i; +wire write; +wire pwm; +reg [1:0]state; +reg clrint; +wire ack_clrint; +wire int1; + +assign write=i_wb_cyc&i_wb_stb&i_wb_we; +assign o_wb_ack=i_wb_stb; + +always@(posedge i_wb_clk or posedge i_wb_rst) + if(i_wb_rst) begin + ctrl[4:0]<=0; + ctrl[7:6]<=0; + DC<=0; + period<=0; + divisor<=0; + end + else if(write) begin + case(i_wb_adr) + adr_ctrl:begin + ctrl[4:0]<=i_wb_data[4:0]; + ctrl[7:6]<=i_wb_data[7:6]; + end + adr_divisor: divisor<=i_wb_data; + adr_period: period<=i_wb_data; + adr_DC: DC<=i_wb_data; + endcase + end + +assign pwm = ctrl[1]; + +always@(posedge i_wb_clk or posedge i_wb_rst) + if(i_wb_rst)begin + ctrl[5]<=0; + state<=0; + clrint<=0; + end + else begin + case(state) + 1:begin + if(write)begin + if(i_wb_data[7])begin + ctrl[5]<=0; + state<=0; + end + else if(!i_wb_data[5])begin + ctrl[5]<=0; + if(!pwm)begin + clrint<=1; + state<=2; + end + else state<=0; + end + end + end + 2:if(ack_clrint)begin + clrint<=0; + state<=0; + end + default:begin + if(!pwm)ctrl[5]<=int1; + if(int1)state<=1; + end + endcase + end + + +/////////////////////////////////////////////////////////// + +//////down clocking for pwm/timer/////////////////// +wire clk_source; +wire eclk,oclk; +assign clk_source= i_wb_clk; +down_clocking_even down_clocking_even_0( +clk_source, +(!i_wb_rst), +{1'b0,divisor[15:1]}, +eclk +); +down_clocking_odd down_clocking_odd_0( +clk_source, +(!i_wb_rst), +{1'b0,divisor[15:1]}, +oclk +); +wire clk; +assign clk=divisor[0]?oclk:eclk; +/////////////////////////////////////////////////////// + +/////////////////main counter ////////////////////////// +reg [15:0]ct; +reg pts; //PWM signal or timer interrupt signal +reg [15:0]extDC; +wire [15:0]DC_1; +assign DC_1=ctrl[6]? extDC:DC; //external or internal duty cycle toggle +wire [15:0]period_1; +assign period_1= (period==0) ? 0:(period-1); +reg switch_ack_clrint; +wire state_timer; +assign state_timer=ctrl[3]; +wire rst_ct; +assign rst_ct=i_wb_rst|ctrl[7]; +assign int1=pwm?0:pts; +assign ack_clrint=switch_ack_clrint?clrint:0; +always@(posedge clk or posedge rst_ct) + if(rst_ct)begin + pts<=0; + ct<=0; + switch_ack_clrint<=0; + extDC<=0; + end + else begin + if(i_valid_DC) + extDC<=i_DC; + if(switch_ack_clrint&&(!clrint)) + switch_ack_clrint<=0; + if(ctrl[2])begin + case(pwm) + 1:begin + if(ct>=period_1) + ct<=0; + else + ct<=ct+1; + + if(ct<DC_1) + pts<=1; + else + pts<=0; + end + 0:begin + + case(state_timer) + 0:begin + if(clrint) + switch_ack_clrint<=1; + if(ct>=period_1)begin + if(clrint)begin + pts<=0; + ct<=0; + end + else + pts<=1; + + end + else + ct<=ct+1; + end + 1:begin + if(ct>=period_1)begin + pts<=1; + ct<=0; + end + else begin + if(clrint)begin + switch_ack_clrint<=1; + pts<=0; + end + ct<=ct+1; + end + end + endcase + end + endcase + end + else if(clrint)begin + switch_ack_clrint<=1; + if(!pwm)begin + pts<=0; + ct<=0; + end + end + end +////////////////////////////////////////////////////////// + +assign o_pwm=ctrl[4]?pts:0; +assign o_wb_data= i_wb_adr==adr_ctrl?{8'h0,ctrl}: + i_wb_adr==adr_divisor?divisor: + i_wb_adr==adr_period?period: + i_wb_adr==adr_DC?DC:0; + + +endmodule
diff --git a/verilog/rtl/pwm/down_clocking_even.v b/verilog/rtl/pwm/down_clocking_even.v new file mode 100644 index 0000000..bfebb01 --- /dev/null +++ b/verilog/rtl/pwm/down_clocking_even.v
@@ -0,0 +1,37 @@ +/*Down clocking module +Output clock frequency is the original frequency divided by an even number +*/ +module down_clocking_even( +input i_clk, +input i_rst, +input [15:0]i_divisor, +output o_clk +); + +wire [15:0]divisor; +wire borrow; + +minus_one minus_one_0( +i_divisor, +divisor, +borrow +); + +wire go; +assign go=((i_divisor!=0)&&i_rst); +reg [15:0]ct; +reg clk; +always@(posedge i_clk or negedge i_rst) + if(!i_rst)begin + ct<=0; + clk<=0; + end + else if(go)begin + if(ct>=divisor)begin + ct<=0; + clk<=~clk; + end + else ct<=ct+1; + end +assign o_clk=go?clk:i_clk; +endmodule \ No newline at end of file
diff --git a/verilog/rtl/pwm/down_clocking_odd.v b/verilog/rtl/pwm/down_clocking_odd.v new file mode 100644 index 0000000..52f48de --- /dev/null +++ b/verilog/rtl/pwm/down_clocking_odd.v
@@ -0,0 +1,69 @@ +/*Author: Zhuxu + m99a1@yahoo.cn +Down clocking module +Output clock frequency is the original frequency divided by an odd number +*/ +module down_clocking_odd( +input i_clk, +input i_rst, +input [15:0]i_divisor, +output o_clk +); + +reg a,b; +wire c; + +assign c=(~a)&(~b); +wire [15:0]divisor; +wire borrow; +minus_one minus_one_0( +i_divisor, +divisor, +borrow +); + +wire go; +assign go=((i_divisor!=0)&&i_rst); +reg [15:0]ct_0; +always@(posedge i_clk or negedge i_rst) + if(!i_rst)begin + a<=0; + ct_0<=0; + end + else if(go)begin + if(a)begin + if(ct_0>=divisor)begin + ct_0<=0; + a<=0; + end + else ct_0<=ct_0+1; + end + else if(c)a<=c; + end + + +reg [15:0]ct_1; +always@(negedge i_clk or negedge i_rst) + if(!i_rst)begin + b<=0; + ct_1<=0; + end + else if(go)begin + if(b)begin + if(ct_1>=divisor)begin + ct_1<=0; + b<=0; + end + else ct_1<=ct_1+1; + end + else if(c)b<=c; + end + +reg clk; +always@(posedge c or negedge i_rst) + if(!i_rst)clk<=0; + else clk<=~clk; + +assign o_clk=go?clk:i_clk; + +endmodule \ No newline at end of file
diff --git a/verilog/rtl/pwm/minus_one.v b/verilog/rtl/pwm/minus_one.v new file mode 100644 index 0000000..f3575c9 --- /dev/null +++ b/verilog/rtl/pwm/minus_one.v
@@ -0,0 +1,122 @@ +/*Author: Zhuxu + m99a1@yahoo.cn +Use parallel prefix tree structure to reduce a 16-bit number by one. + +stage 0: number of genration=16; number of logic operation=16; G_0[xx]=~i_operand[xx]; +stage 1: NOG=16; NOO=8; G_1[2n-1]=G_0[2n-1]&&G_0[2n-2]; n=8:1 +stage 2: NOG=16; NOO=7; G_2[2n-1]=G_1[2n-1]&&G_1[2n-3]; n=8:2 +stage 3: NOG=16; NOO=6; G_3[2n-1]=G_2[2n-1]&&G_2[2n-5]; n=8:3 +stage 4: NOG=16; NOO=4; G_4[2n-1]=G_3[2n-1]&&G_3[2n-9]; n=8:5 +stage 5: NOG=16; NOO=7; G_5[2n]=G_4[2n]&&G_4[2n-1]; n=7:1 + +*/ +module minus_one( +input [15:0]i_operand, +output [15:0]o_result, +output o_borrow +); +//stage 0 +wire [15:0]G_0; +assign G_0=~i_operand; + +//stage 1 +wire [15:0]G_1; +assign G_1[1]=G_0[1]&G_0[0]; +assign G_1[3]=G_0[3]&G_0[2]; +assign G_1[5]=G_0[5]&G_0[4]; +assign G_1[7]=G_0[7]&G_0[6]; +assign G_1[9]=G_0[9]&G_0[8]; +assign G_1[11]=G_0[11]&G_0[10]; +assign G_1[13]=G_0[13]&G_0[12]; +assign G_1[15]=G_0[15]&G_0[14]; +assign G_1[0]=G_0[0]; +assign G_1[2]=G_0[2]; +assign G_1[4]=G_0[4]; +assign G_1[6]=G_0[6]; +assign G_1[8]=G_0[8]; +assign G_1[10]=G_0[10]; +assign G_1[12]=G_0[12]; +assign G_1[14]=G_0[14]; + +//stage 2 +wire [15:0]G_2; +assign G_2[3]=G_1[3]&G_1[1]; +assign G_2[5]=G_1[5]&G_1[3]; +assign G_2[7]=G_1[7]&G_1[5]; +assign G_2[9]=G_1[9]&G_1[7]; +assign G_2[11]=G_1[11]&G_1[9]; +assign G_2[13]=G_1[13]&G_1[11]; +assign G_2[15]=G_1[15]&G_1[13]; +assign G_2[0]=G_1[0]; +assign G_2[2]=G_1[2]; +assign G_2[1]=G_1[1]; +assign G_2[4]=G_1[4]; +assign G_2[6]=G_1[6]; +assign G_2[8]=G_1[8]; +assign G_2[10]=G_1[10]; +assign G_2[12]=G_1[12]; +assign G_2[14]=G_1[14]; + +//stage 3 +wire [15:0]G_3; +assign G_3[5]=G_2[5]&G_2[1]; +assign G_3[7]=G_2[7]&G_2[3]; +assign G_3[9]=G_2[9]&G_2[5]; +assign G_3[11]=G_2[11]&G_2[7]; +assign G_3[13]=G_2[13]&G_2[9]; +assign G_3[15]=G_2[15]&G_2[11]; +assign G_3[0]=G_2[0]; +assign G_3[2]=G_2[2]; +assign G_3[1]=G_2[1]; +assign G_3[4]=G_2[4]; +assign G_3[3]=G_2[3]; +assign G_3[6]=G_2[6]; +assign G_3[8]=G_2[8]; +assign G_3[10]=G_2[10]; +assign G_3[12]=G_2[12]; +assign G_3[14]=G_2[14]; + +//stage 4 +wire [15:0]G_4; +assign G_4[9]=G_3[9]&G_3[1]; +assign G_4[11]=G_3[11]&G_3[3]; +assign G_4[13]=G_3[13]&G_3[5]; +assign G_4[15]=G_3[15]&G_3[7]; +assign G_4[0]=G_3[0]; +assign G_4[2]=G_3[2]; +assign G_4[1]=G_3[1]; +assign G_4[4]=G_3[4]; +assign G_4[3]=G_3[3]; +assign G_4[6]=G_3[6]; +assign G_4[5]=G_3[5]; +assign G_4[8]=G_3[8]; +assign G_4[7]=G_3[7]; +assign G_4[10]=G_3[10]; +assign G_4[12]=G_3[12]; +assign G_4[14]=G_3[14]; + +//stage 5 +wire [15:0]G_5; +assign G_5[2]=G_4[2]&G_4[1]; +assign G_5[4]=G_4[4]&G_4[3]; +assign G_5[6]=G_4[6]&G_4[5]; +assign G_5[8]=G_4[8]&G_4[7]; +assign G_5[10]=G_4[10]&G_4[9]; +assign G_5[12]=G_4[12]&G_4[11]; +assign G_5[14]=G_4[14]&G_4[13]; +assign G_5[1]=G_4[1]; +assign G_5[3]=G_4[3]; +assign G_5[5]=G_4[5]; +assign G_5[7]=G_4[7]; +assign G_5[9]=G_4[9]; +assign G_5[11]=G_4[11]; +assign G_5[13]=G_4[13]; +assign G_5[15]=G_4[15]; +assign G_5[0]=G_4[0]; + +//stage 6 +assign o_result[0]=~i_operand[0]; +assign o_result[15:1]=(G_5[14:0]&(~i_operand[15:1]))|((~G_5[14:0])&i_operand[15:1]); +assign o_borrow=G_5[15]; + +endmodule \ No newline at end of file