tillitis-key/hw/application_fpga/core/timer/rtl/timer_core.v

226 lines
5.5 KiB
Verilog

//======================================================================
//
// timer_core.v
// ------------
// timer core.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module timer_core(
input wire clk,
input wire reset_n,
input wire [31 : 0] prescaler_value,
input wire [31 : 0] timer_value,
input wire start,
input wire stop,
output wire [31 : 0] curr_prescaler,
output wire [31 : 0] curr_timer,
output wire ready
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
localparam CTRL_IDLE = 2'h0;
localparam CTRL_PRESCALER = 2'h1;
localparam CTRL_TIMER = 2'h2;
localparam CTRL_DONE = 2'h3;
//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg ready_reg;
reg ready_new;
reg ready_we;
reg [31 : 0] prescaler_reg;
reg [31 : 0] prescaler_new;
reg prescaler_we;
reg prescaler_set;
reg prescaler_dec;
reg [31 : 0] timer_reg;
reg [31 : 0] timer_new;
reg timer_we;
reg timer_set;
reg timer_dec;
reg [1 : 0] core_ctrl_reg;
reg [1 : 0] core_ctrl_new;
reg core_ctrl_we;
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign curr_prescaler = prescaler_reg;
assign curr_timer = timer_reg;
assign ready = ready_reg;
//----------------------------------------------------------------
// reg_update
//----------------------------------------------------------------
always @ (posedge clk)
begin: reg_update
if (!reset_n)
begin
ready_reg <= 1'h1;
prescaler_reg <= 32'h0;
timer_reg <= 32'h0;
core_ctrl_reg <= CTRL_IDLE;
end
else
begin
if (ready_we) begin
ready_reg <= ready_new;
end
if (prescaler_we) begin
prescaler_reg <= prescaler_new;
end
if (timer_we) begin
timer_reg <= timer_new;
end
if (core_ctrl_we) begin
core_ctrl_reg <= core_ctrl_new;
end
end
end // reg_update
//----------------------------------------------------------------
// prescaler_ctr
//----------------------------------------------------------------
always @*
begin : prescaler_ctr
prescaler_new = 32'h0;
prescaler_we = 1'h0;
if (prescaler_set) begin
prescaler_new = prescaler_value;
prescaler_we = 1'h1;
end
else if (prescaler_dec) begin
prescaler_new = prescaler_reg - 1'h1;
prescaler_we = 1'h1;
end
end
//----------------------------------------------------------------
// timer_ctr
//----------------------------------------------------------------
always @*
begin : timer_ctr
timer_new = 32'h0;
timer_we = 1'h0;
if (timer_set) begin
timer_new = timer_value;
timer_we = 1'h1;
end
else if (timer_dec) begin
timer_new = timer_reg - 1'h1;
timer_we = 1'h1;
end
end
//----------------------------------------------------------------
// Core control FSM.
//----------------------------------------------------------------
always @*
begin : core_ctrl
ready_new = 1'h0;
ready_we = 1'h0;
prescaler_set = 1'h0;
prescaler_dec = 1'h0;
timer_set = 1'h0;
timer_dec = 1'h0;
core_ctrl_new = CTRL_IDLE;
core_ctrl_we = 1'h0;
case (core_ctrl_reg)
CTRL_IDLE: begin
if (start)
begin
ready_new = 1'h0;
ready_we = 1'h1;
prescaler_set = 1'h1;
timer_set = 1'h1;
core_ctrl_new = CTRL_PRESCALER;
core_ctrl_we = 1'h1;
end
end
CTRL_PRESCALER: begin
if (stop) begin
core_ctrl_new = CTRL_DONE;
core_ctrl_we = 1'h1;
end
else begin
if (prescaler_reg == 0) begin
core_ctrl_new = CTRL_TIMER;
core_ctrl_we = 1'h1;
end
else begin
prescaler_dec = 1'h1;
end
end
end
CTRL_TIMER: begin
if (stop) begin
core_ctrl_new = CTRL_DONE;
core_ctrl_we = 1'h1;
end
else begin
if (timer_reg == 0) begin
core_ctrl_new = CTRL_DONE;
core_ctrl_we = 1'h1;
end
else begin
prescaler_set = 1'h1;
timer_dec = 1'h1;
core_ctrl_new = CTRL_PRESCALER;
core_ctrl_we = 1'h1;
end
end
end
CTRL_DONE: begin
ready_new = 1'h1;
ready_we = 1'h1;
core_ctrl_new = CTRL_IDLE;
core_ctrl_we = 1'h1;
end
default: begin
end
endcase // case (core_ctrl_reg)
end // core_ctrl
endmodule // timer_core
//======================================================================
// EOF timer_core.v
//======================================================================