592 lines
16 KiB
Verilog
592 lines
16 KiB
Verilog
/*Copyright 2020-2021 T-Head Semiconductor Co., Ltd.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
// &ModuleBeg; @23
|
|
module timer(
|
|
paddr,
|
|
pclk,
|
|
penable,
|
|
prdata,
|
|
presetn,
|
|
psel,
|
|
pwdata,
|
|
pwrite,
|
|
timer_int
|
|
);
|
|
|
|
// &Ports; @24
|
|
input [15:0] paddr;
|
|
input pclk;
|
|
input penable;
|
|
input presetn;
|
|
input psel;
|
|
input [31:0] pwdata;
|
|
input pwrite;
|
|
output [31:0] prdata;
|
|
output [3 :0] timer_int;
|
|
|
|
// &Regs; @25
|
|
reg [31:0] prdata;
|
|
reg [2 :0] timer_1_control_reg;
|
|
reg [31:0] timer_1_load_count;
|
|
reg timer_1_raw_int_status;
|
|
reg [2 :0] timer_2_control_reg;
|
|
reg [31:0] timer_2_load_count;
|
|
reg timer_2_raw_int_status;
|
|
reg [2 :0] timer_3_control_reg;
|
|
reg [31:0] timer_3_load_count;
|
|
reg timer_3_raw_int_status;
|
|
reg [2 :0] timer_4_control_reg;
|
|
reg [31:0] timer_4_load_count;
|
|
reg timer_4_raw_int_status;
|
|
|
|
// &Wires; @26
|
|
wire [15:0] paddr;
|
|
wire pclk;
|
|
wire presetn;
|
|
wire psel;
|
|
wire [31:0] pwdata;
|
|
wire pwrite;
|
|
wire [31:0] timer_1_current_value;
|
|
wire timer_1_int_clear;
|
|
wire timer_1_int_status;
|
|
wire timer_1_interrupt;
|
|
wire [31:0] timer_2_current_value;
|
|
wire timer_2_int_clear;
|
|
wire timer_2_int_status;
|
|
wire timer_2_interrupt;
|
|
wire [31:0] timer_3_current_value;
|
|
wire timer_3_int_clear;
|
|
wire timer_3_int_status;
|
|
wire timer_3_interrupt;
|
|
wire [31:0] timer_4_current_value;
|
|
wire timer_4_int_clear;
|
|
wire timer_4_int_status;
|
|
wire timer_4_interrupt;
|
|
wire [3 :0] timer_int;
|
|
wire timers_int_clear;
|
|
|
|
|
|
// &Force("bus","paddr",15,0); @28
|
|
// &Force("bus","pwdata",31,0); @29
|
|
// &Force("input","penable"); @30
|
|
// &Force("output","prdata"); @31
|
|
// &Force("bus","prdata",31,0); @32
|
|
// &Force("output","timer_int"); @33
|
|
// &Force("bus","timer_int",3,0); @34
|
|
|
|
// &Instance("counter", "timer_1"); @36
|
|
counter timer_1 (
|
|
.interrupt (timer_1_interrupt ),
|
|
.pclk (pclk ),
|
|
.presetn (presetn ),
|
|
.timer_current_value (timer_1_current_value ),
|
|
.timer_enable (timer_1_control_reg[0]),
|
|
.timer_load_count (timer_1_load_count ),
|
|
.timer_mode (timer_1_control_reg[1])
|
|
);
|
|
|
|
// &Connect(.pclk (pclk ), @37
|
|
// .presetn (presetn ), @38
|
|
// .timer_enable (timer_1_control_reg[0] ), @39
|
|
// .timer_mode (timer_1_control_reg[1] ), @40
|
|
// .timer_load_count (timer_1_load_count ), @41
|
|
// .timer_current_value (timer_1_current_value ), @42
|
|
// .interrupt (timer_1_interrupt ) @43
|
|
// ); @44
|
|
|
|
// &Instance("counter", "timer_2"); @46
|
|
counter timer_2 (
|
|
.interrupt (timer_2_interrupt ),
|
|
.pclk (pclk ),
|
|
.presetn (presetn ),
|
|
.timer_current_value (timer_2_current_value ),
|
|
.timer_enable (timer_2_control_reg[0]),
|
|
.timer_load_count (timer_2_load_count ),
|
|
.timer_mode (timer_2_control_reg[1])
|
|
);
|
|
|
|
// &Connect(.pclk (pclk ), @47
|
|
// .presetn (presetn ), @48
|
|
// .timer_enable (timer_2_control_reg[0] ), @49
|
|
// .timer_mode (timer_2_control_reg[1] ), @50
|
|
// .timer_load_count (timer_2_load_count ), @51
|
|
// .timer_current_value (timer_2_current_value ), @52
|
|
// .interrupt (timer_2_interrupt ) @53
|
|
// ); @54
|
|
|
|
// &Instance("counter", "timer_3"); @56
|
|
counter timer_3 (
|
|
.interrupt (timer_3_interrupt ),
|
|
.pclk (pclk ),
|
|
.presetn (presetn ),
|
|
.timer_current_value (timer_3_current_value ),
|
|
.timer_enable (timer_3_control_reg[0]),
|
|
.timer_load_count (timer_3_load_count ),
|
|
.timer_mode (timer_3_control_reg[1])
|
|
);
|
|
|
|
// &Connect(.pclk (pclk ), @57
|
|
// .presetn (presetn ), @58
|
|
// .timer_enable (timer_3_control_reg[0] ), @59
|
|
// .timer_mode (timer_3_control_reg[1] ), @60
|
|
// .timer_load_count (timer_3_load_count ), @61
|
|
// .timer_current_value (timer_3_current_value ), @62
|
|
// .interrupt (timer_3_interrupt ) @63
|
|
// ); @64
|
|
|
|
// &Instance("counter", "timer_4"); @66
|
|
counter timer_4 (
|
|
.interrupt (timer_4_interrupt ),
|
|
.pclk (pclk ),
|
|
.presetn (presetn ),
|
|
.timer_current_value (timer_4_current_value ),
|
|
.timer_enable (timer_4_control_reg[0]),
|
|
.timer_load_count (timer_4_load_count ),
|
|
.timer_mode (timer_4_control_reg[1])
|
|
);
|
|
|
|
// &Connect(.pclk (pclk ), @67
|
|
// .presetn (presetn ), @68
|
|
// .timer_enable (timer_4_control_reg[0] ), @69
|
|
// .timer_mode (timer_4_control_reg[1] ), @70
|
|
// .timer_load_count (timer_4_load_count ), @71
|
|
// .timer_current_value (timer_4_current_value ), @72
|
|
// .interrupt (timer_4_interrupt ) @73
|
|
// ); @74
|
|
|
|
//==========================================================
|
|
// APB PWDATA
|
|
//==========================================================
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
timer_1_load_count <= 32'b0;
|
|
timer_1_control_reg <= 3'b0;
|
|
timer_2_load_count <= 32'b0;
|
|
timer_2_control_reg <= 3'b0;
|
|
timer_3_load_count <= 32'b0;
|
|
timer_3_control_reg <= 3'b0;
|
|
timer_4_load_count <= 32'b0;
|
|
timer_4_control_reg <= 3'b0;
|
|
end
|
|
else
|
|
begin
|
|
if(psel && pwrite && penable)
|
|
begin
|
|
case(paddr[7:2])
|
|
6'b000000:
|
|
begin
|
|
timer_1_load_count <= pwdata;
|
|
end
|
|
6'b000010:
|
|
begin
|
|
timer_1_control_reg <= pwdata[2:0];
|
|
end
|
|
6'b000101:
|
|
begin
|
|
timer_2_load_count <= pwdata;
|
|
end
|
|
6'b000111:
|
|
begin
|
|
timer_2_control_reg <= pwdata[2:0];
|
|
end
|
|
6'b001010:
|
|
begin
|
|
timer_3_load_count <= pwdata;
|
|
end
|
|
6'b001100:
|
|
begin
|
|
timer_3_control_reg <= pwdata[2:0];
|
|
end
|
|
6'b001111:
|
|
begin
|
|
timer_4_load_count <= pwdata;
|
|
end
|
|
6'b010001:
|
|
begin
|
|
timer_4_control_reg <= pwdata[2:0];
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
//==========================================================
|
|
// APB PRDATA
|
|
//==========================================================
|
|
always @(posedge pclk)
|
|
begin
|
|
if(psel && !pwrite)
|
|
begin
|
|
if (!penable)
|
|
begin
|
|
case(paddr[7:2])
|
|
6'b000000:
|
|
begin
|
|
prdata <= timer_1_load_count;
|
|
end
|
|
6'b000001:
|
|
begin
|
|
prdata <= timer_1_current_value;
|
|
end
|
|
6'b000010:
|
|
begin
|
|
prdata <= {29'b0, timer_1_control_reg};
|
|
end
|
|
6'b000011:
|
|
begin
|
|
prdata <= 32'b0;
|
|
end
|
|
6'b000100:
|
|
begin
|
|
prdata <= {31'b0, timer_1_int_status};
|
|
end
|
|
6'b000101:
|
|
begin
|
|
prdata <= timer_2_load_count;
|
|
end
|
|
6'b000110:
|
|
begin
|
|
prdata <= timer_2_current_value;
|
|
end
|
|
6'b000111:
|
|
begin
|
|
prdata <= {29'b0, timer_2_control_reg};
|
|
end
|
|
6'b001000:
|
|
begin
|
|
prdata <= 32'b0;
|
|
end
|
|
6'b001001:
|
|
begin
|
|
prdata <= {31'b0, timer_2_int_status};
|
|
end
|
|
6'b001010:
|
|
begin
|
|
prdata <= timer_3_load_count;
|
|
end
|
|
6'b001011:
|
|
begin
|
|
prdata <= timer_3_current_value;
|
|
end
|
|
6'b001100:
|
|
begin
|
|
prdata <= {29'b0, timer_3_control_reg};
|
|
end
|
|
6'b001101:
|
|
begin
|
|
prdata <= 32'b0;
|
|
end
|
|
6'b001110:
|
|
begin
|
|
prdata <= {31'b0, timer_3_int_status};
|
|
end
|
|
6'b001111:
|
|
begin
|
|
prdata <= timer_4_load_count;
|
|
end
|
|
6'b010000:
|
|
begin
|
|
prdata <= timer_4_current_value;
|
|
end
|
|
6'b010001:
|
|
begin
|
|
prdata <= {29'b0, timer_4_control_reg};
|
|
end
|
|
6'b010010:
|
|
begin
|
|
prdata <= 32'b0;
|
|
end
|
|
6'b010011:
|
|
begin
|
|
prdata <= {31'b0, timer_4_int_status};
|
|
end
|
|
6'b101000:
|
|
begin
|
|
prdata <= {28'b0, timer_int};
|
|
end
|
|
6'b101001:
|
|
begin
|
|
prdata <= 32'b0;
|
|
end
|
|
6'b101010:
|
|
begin
|
|
prdata <= {28'b0, timer_4_raw_int_status, timer_3_raw_int_status, timer_2_raw_int_status, timer_1_raw_int_status};
|
|
end
|
|
default:
|
|
begin
|
|
prdata <= 32'bx;
|
|
end
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
prdata <= 32'bx;
|
|
end
|
|
end
|
|
end
|
|
|
|
assign timer_int = {timer_4_int_status, timer_3_int_status, timer_2_int_status, timer_1_int_status};
|
|
|
|
//==========================================================
|
|
// Clear Interrupt when reads EOI
|
|
//==========================================================
|
|
assign timer_1_int_clear = (paddr[7:2] == 6'b000011) && psel && !pwrite;
|
|
assign timer_2_int_clear = (paddr[7:2] == 6'b001000) && psel && !pwrite;
|
|
assign timer_3_int_clear = (paddr[7:2] == 6'b001101) && psel && !pwrite;
|
|
assign timer_4_int_clear = (paddr[7:2] == 6'b010010) && psel && !pwrite;
|
|
assign timers_int_clear = (paddr[7:2] == 6'b101001) && psel && !pwrite;
|
|
|
|
//==========================================================
|
|
// Timer 1 interrupt set and clear
|
|
//==========================================================
|
|
assign timer_1_int_status = timer_1_raw_int_status && !timer_1_control_reg[2];
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
timer_1_raw_int_status <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_1_control_reg[0])
|
|
begin
|
|
if(timer_1_interrupt)
|
|
begin
|
|
timer_1_raw_int_status <= 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_1_int_clear || timers_int_clear)
|
|
begin
|
|
timer_1_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
timer_1_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
//==========================================================
|
|
// Timer 2 interrupt set and clear
|
|
//==========================================================
|
|
assign timer_2_int_status = timer_2_raw_int_status && !timer_2_control_reg[2];
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
timer_2_raw_int_status <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_2_control_reg[0])
|
|
begin
|
|
if(timer_2_interrupt)
|
|
begin
|
|
timer_2_raw_int_status <= 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_2_int_clear || timers_int_clear)
|
|
begin
|
|
timer_2_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
timer_2_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
//==========================================================
|
|
// Timer 3 interrupt set and clear
|
|
//==========================================================
|
|
assign timer_3_int_status = timer_3_raw_int_status && !timer_3_control_reg[2];
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
timer_3_raw_int_status <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_3_control_reg[0])
|
|
begin
|
|
if(timer_3_interrupt)
|
|
begin
|
|
timer_3_raw_int_status <= 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_3_int_clear || timers_int_clear)
|
|
begin
|
|
timer_3_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
timer_3_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
//==========================================================
|
|
// Timer 4 interrupt set and clear
|
|
//==========================================================
|
|
assign timer_4_int_status = timer_4_raw_int_status && !timer_4_control_reg[2];
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
timer_4_raw_int_status <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_4_control_reg[0])
|
|
begin
|
|
if(timer_4_interrupt)
|
|
begin
|
|
timer_4_raw_int_status <= 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
if(timer_4_int_clear || timers_int_clear)
|
|
begin
|
|
timer_4_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
timer_4_raw_int_status <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
// &ModuleEnd; @385
|
|
endmodule
|
|
|
|
module counter(
|
|
interrupt,
|
|
pclk,
|
|
presetn,
|
|
timer_current_value,
|
|
timer_enable,
|
|
timer_load_count,
|
|
timer_mode
|
|
);
|
|
|
|
// &Ports; @24
|
|
input pclk;
|
|
input presetn;
|
|
input timer_enable;
|
|
input [31:0] timer_load_count;
|
|
input timer_mode;
|
|
output interrupt;
|
|
output [31:0] timer_current_value;
|
|
|
|
// &Regs; @25
|
|
reg [31:0] counter;
|
|
reg interrupt;
|
|
reg timer_enable_flop;
|
|
|
|
// &Wires; @26
|
|
wire load_cnt_en;
|
|
wire pclk;
|
|
wire presetn;
|
|
wire [31:0] timer_current_value;
|
|
wire timer_enable;
|
|
wire [31:0] timer_load_count;
|
|
wire timer_mode;
|
|
|
|
|
|
//==========================================================
|
|
// Counter
|
|
//==========================================================
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
timer_enable_flop <=0;
|
|
end
|
|
else
|
|
begin
|
|
timer_enable_flop <=timer_enable ;
|
|
end
|
|
end
|
|
|
|
assign load_cnt_en= (timer_enable && !timer_enable_flop)
|
|
|| !(|counter[31:0]);
|
|
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
counter[31:0] <=32'hffffffff;
|
|
end
|
|
else if(load_cnt_en)
|
|
begin
|
|
if(timer_mode)
|
|
begin
|
|
counter[31:0]<=timer_load_count[31:0];
|
|
end
|
|
else
|
|
begin
|
|
counter[31:0]<=32'hffffffff;
|
|
end
|
|
end
|
|
else if (timer_enable)
|
|
begin
|
|
counter[31:0]<=counter[31:0]-1'b1;
|
|
end
|
|
else
|
|
begin
|
|
counter[31:0]<=counter[31:0];
|
|
end
|
|
end
|
|
|
|
assign timer_current_value[31:0]=counter[31:0];
|
|
//==========================================================
|
|
// Interrupt sigals
|
|
//==========================================================
|
|
//internel interrupt
|
|
always @(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
begin
|
|
interrupt <=1'b0;
|
|
end
|
|
else if(!{|counter[31:0]})
|
|
begin
|
|
interrupt <=1'b1;
|
|
end
|
|
else
|
|
begin
|
|
interrupt<=1'b0 ;
|
|
end
|
|
end
|
|
|
|
// &ModuleEnd; @94
|
|
endmodule
|
|
|