原创 基于apb3片内总线的计数器

2009-1-17 13:20 2164 4 4 分类: FPGA/CPLD

rtl代码


//地址:
// 3'b000:counter0[7:0]<=pwdata;
// 3'b001:counter0[15:8]<=pwdata;
// 3'b010:counter1[7:0]<=pwdata;
// 3'b011:counter1[15:8]<=pwdata;
// 3'b100:counter2[7:0]<=pwdata;
// 3'b101:counter2[15:8]<=pwdata;
// 110时为ctr
// ctr[0]为enable0
// ctr[1]为enable1
// ctr[2]为enable2
///////////////
//中断只是一个信号
////////////
//apb3全为写
module time_top(
  //input
  timer0_clk,
  timer1_clk,
  timer2_clk,
  pclk,
  rest,
  paddr,
  pwdata,
  psel,
  penable,
  pwrite,////apb3全为写
  //output
  pready,
  ti0,//timer0 interrupt
  ti1,//timer1 interrupt
  ti2//timer2 interrupt
  );


  input  timer0_clk,timer1_clk,timer2_clk,pclk,rest,psel,penable,pwrite;
  input[2:0] paddr;
  input[7:0] pwdata;


  output reg ti0,ti1,ti2;
  output pready;


  reg ctr;//控制字
  reg[15:0] counter0;
  reg[15:0] counter1;
  reg[15:0] counter2;//计数器
  reg pready0,pready1,pready2,pready_ctr;
  //用于多时钟
  reg timer0_clk_reg0,timer0_clk_reg1,timer1_clk_reg0,timer1_clk_reg1,timer2_clk_reg0,timer2_clk_reg1;
  wire clk0,clk1,clk2;
  //控制字
  wire enable0,enable1,enable2;
  
  //counter0
  always@(posedge pclk or posedge rest)
  if(rest)
  begin
   pready0<=1'b0;
   counter0<=16'b0000_0000_0000_0000;
   ti0<=1'b0;
  end
  else
  begin
   counter0<=counter0;
   pready0<=1'b0;
   ti0<=1'b0;
   if(psel&(!penable))
   begin
    pready0<=1'b1;
    case(paddr)
    3'b000:counter0[7:0]<=pwdata;
    3'b001:counter0[15:8]<=pwdata;
    default:counter0<=counter0;
    endcase
   end
   else
   if(clk0&enable0)
   begin
    if(counter0==16'b1111_1111_1111_1111)
    begin
     counter0<=0000_0000_0000_0000;
     ti0<=1'b1;
    end
    else
     counter0<=counter0+1'b1;
   end
  end
  always@(posedge pclk or posedge rest)
  if(rest)
  begin
   timer0_clk_reg0<=1'b0;
   timer0_clk_reg1<=1'b0;
  end
  else
  begin
   timer0_clk_reg0<=timer0_clk;
   timer0_clk_reg1<=timer0_clk_reg0;
  end
  assign clk0=(~timer0_clk_reg0)&timer0_clk_reg1;


  //counter1
  always@(posedge pclk or posedge rest)
  if(rest)
  begin
   ti1<=1'b0;
   pready1<=1'b0;
   counter1<=16'b0000_0000_0000_0000;
  end
  else
  begin
   counter1<=counter1;
   ti1<=1'b0;
   pready1<=1'b0;
   if(psel&(!penable))
   begin
    pready1<=1'b1;
    case(paddr)
    3'b010:counter1[7:0]<=pwdata;
    3'b011:counter1[15:8]<=pwdata;
    default:counter1<=counter1;
    endcase
   end
   else
   if(clk1&enable1)
   begin
    if(counter1==16'b1111_1111_1111_1111)
    begin
     counter1<=0000_0000_0000_0000;
     ti1<=1'b1;
    end
    else
     counter1<=counter1+1'b1;
   end
  end
  always@(posedge pclk or posedge rest)
  if(rest)
  begin
   timer1_clk_reg0<=1'b0;
   timer1_clk_reg1<=1'b0;
  end
  else
  begin
   timer1_clk_reg0<=timer1_clk;
   timer1_clk_reg1<=timer1_clk_reg0;
  end
  assign clk1=(~timer1_clk_reg0)&timer1_clk_reg1;


  //counter2
  always@(posedge pclk or posedge rest)
  if(rest)
  begin
   ti2<=1'b0;
   pready2<=1'b0;
   counter2<=16'b0000_0000_0000_0000;
  end
  else
  begin
   counter2<=counter2;
   ti2<=1'b0;
   pready2<=1'b0;
   if(psel&(!penable))
   begin
    pready2<=1'b1;
    case(paddr)
    3'b100:counter2[7:0]<=pwdata;
    3'b101:counter2[15:8]<=pwdata;
    default:counter2<=counter2;
    endcase
   end
   else
   if(clk2&enable2)
   begin
    if(counter2==16'b1111_1111_1111_1111)
    begin
     counter2<=0000_0000_0000_0000;
     ti2<=1'b1;
    end
    else
     counter2<=counter2+1'b1;
   end
  end
  always@(posedge pclk or posedge rest)
  if(rest)
  begin
   timer2_clk_reg0<=1'b0;
   timer2_clk_reg1<=1'b0;
  end
  else
  begin
   timer2_clk_reg0<=timer2_clk;
   timer2_clk_reg1<=timer2_clk_reg0;
  end
  assign clk2=(~timer2_clk_reg0)&timer2_clk_reg1;
  
  //pready
  assign pready="pready0|pready1|pready2|pready"_ctr;


  //ctr
  always@(posedge pclk or posedge rest)
  if(rest)
  begin
   ctr<=8'b0000_0000;
   pready_ctr<=1'b0;
  end
  else
  begin
   pready_ctr<=1'b0;
   if(psel&(!penable)&(paddr==3'b110))
   begin
    pready_ctr<=1'b1;
    ctr<=pwdata;
   end
  end


  //enable0/1/2
  assign enable0=ctr[0];
  assign enable1=ctr[1];
  assign enable2=ctr[2];
endmodule


 测试文件:


`timescale  1 ns /  1 ps
module testbench();



//////////////////////////////////////////////////////////
reg rest;
reg pclk;
reg pwrite;
reg    psel;
reg    penable;
reg    timer0_clk,timer1_clk,timer2_clk;
reg[2:0]  paddr;
reg[7:0]           pwdata;


//////////////////////////////////////////////////////////
wire   pready;
wire ti0;
wire ti1;
wire ti2;
////////////////////////////////////////////////////////
 time_top uu1(
   //input
   .timer0_clk(timer0_clk),
   .timer1_clk(timer1_clk),
   .timer2_clk(timer2_clk), 
   .rest(rest),
                    .pclk(pclk),
                    .paddr(paddr),
                    .pwdata(pwdata),
                    .pwrite(pwrite),
                    .psel(psel),
                    .penable(penable),
                    //output
                    .pready(pready),
   .ti0(ti0),
   .ti1(ti1),
   .ti2(ti2)
   );


initial
begin
 timer0_clk=1'b0;
 timer1_clk=1'b0;
 timer2_clk=1'b0;
 rest=1'b1;
 pclk=1'b0;
 pwrite=1'b0;
     psel=1'b0;
     penable=1'b0;
 paddr=3'b00000;
       pwdata="8"'b0000_0000;
 
 # 300 rest="1"'b0;
 # 50
 //写入计数器0的初值
 cpu_write(3'b000,8'b1000_0010); //写低字节
 # 10 cpu_write(3'b001,8'b1111_1111);//写矢咦纸? # 10 cpu_write(3'b110,8'b0000_0001);//写控制字,让计数器0工作



    # 14000 $stop;
end
//clock
always
begin
# 50 timer0_clk=~timer0_clk;
end


always
begin
# 150 timer1_clk=~timer1_clk;
end


always
begin
# 300 timer2_clk=~timer2_clk;
end


always
begin
# 5 pclk=~pclk;
end


 


task cpu_write;
input [4:0] address;
input [7:0] data;
begin
  // $display("CPU Write %04x = %04x",address,data);
  @(negedge pclk); 
  pwrite  = 1'b0;
  @(negedge pclk); 
  penable  = 1'b0;
  psel  = 1'b1;
  paddr= address;
  pwdata = data; 
  pwrite  = 1'b1;
  @(negedge pclk); 
  penable = 1'b1;
  @(negedge pclk); 
  pwrite  = 1'b0;
  penable  = 1'b0;
  psel = 1'b0;
end
endtask



endmodule

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
4
关闭 站长推荐上一条 /3 下一条