Make initial public release

This commit is contained in:
Joachim Strömbergson 2022-09-19 08:51:11 +02:00 committed by Daniel Lublin
commit 715de60f4a
251 changed files with 881225 additions and 0 deletions

View file

@ -0,0 +1,5 @@
# timer
A simple timer with prescaler written in Verilog.
## Introduction
This core implements a simple timer with a prescaler. The purpose of the prescaler is to more easily time durations rather than cycles. If for example setting the timer to the clock frequency, the timer can cound seconds.

View file

@ -0,0 +1,194 @@
//======================================================================
//
// timer.v
// --------
// Top level wrapper for the timer core.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module timer(
input wire clk,
input wire reset_n,
input wire cs,
input wire we,
input wire [7 : 0] address,
input wire [31 : 0] write_data,
output wire [31 : 0] read_data,
output wire ready
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_CTRL = 8'h08;
localparam CTRL_START_BIT = 0;
localparam CTRL_STOP_BIT = 1;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_PRESCALER = 8'h0a;
localparam ADDR_TIMER = 8'h0b;
localparam CORE_NAME0 = 32'h74696d65; // "time"
localparam CORE_NAME1 = 32'h72202020; // "r "
localparam CORE_VERSION = 32'h00000003;
//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg [31 : 0] prescaler_reg;
reg prescaler_we;
reg [31 : 0] timer_reg;
reg timer_we;
reg start_reg;
reg start_new;
reg stop_reg;
reg stop_new;
//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
reg [31 : 0] tmp_read_data;
reg tmp_ready;
wire core_ready;
wire [31 : 0] core_curr_prescaler;
wire [31 : 0] core_curr_timer;
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign read_data = tmp_read_data;
assign ready = tmp_ready;
//----------------------------------------------------------------
// core instantiation.
//----------------------------------------------------------------
timer_core core(
.clk(clk),
.reset_n(reset_n),
.prescaler_value(prescaler_reg),
.timer_value(timer_reg),
.start(start_reg),
.stop(stop_reg),
.curr_prescaler(core_curr_prescaler),
.curr_timer(core_curr_timer),
.ready(core_ready)
);
//----------------------------------------------------------------
// reg_update
//----------------------------------------------------------------
always @ (posedge clk)
begin : reg_update
if (!reset_n) begin
start_reg <= 1'h0;
stop_reg <= 1'h0;
prescaler_reg <= 32'h0;
timer_reg <= 32'h0;
end
else begin
start_reg <= start_new;
stop_reg <= stop_new;
if (prescaler_we) begin
prescaler_reg <= write_data;
end
if (timer_we) begin
timer_reg <= write_data;
end
end
end // reg_update
//----------------------------------------------------------------
// api
//
// The interface command decoding logic.
//----------------------------------------------------------------
always @*
begin : api
start_new = 1'h0;
stop_new = 1'h0;
prescaler_we = 1'h0;
timer_we = 1'h0;
tmp_read_data = 32'h0;
tmp_ready = 1'h0;
if (cs) begin
tmp_ready = 1'h1;
if (we) begin
if (address == ADDR_CTRL) begin
start_new = write_data[CTRL_START_BIT];
stop_new = write_data[CTRL_STOP_BIT];
end
if (core_ready) begin
if (address == ADDR_PRESCALER) begin
prescaler_we = 1'h1;
end
if (address == ADDR_TIMER) begin
timer_we = 1'h1;
end
end
end
else begin
if (address == ADDR_NAME0) begin
tmp_read_data = CORE_NAME0;
end
if (address == ADDR_NAME1) begin
tmp_read_data = CORE_NAME1;
end
if (address == ADDR_VERSION) begin
tmp_read_data = CORE_VERSION;
end
if (address == ADDR_STATUS) begin
tmp_read_data = {31'h0, core_ready};
end
if (address == ADDR_PRESCALER) begin
tmp_read_data = core_curr_prescaler;
end
if (address == ADDR_TIMER) begin
tmp_read_data = core_curr_timer;
end
end
end
end // addr_decoder
endmodule // timer
//======================================================================
// EOF timer.v
//======================================================================

View file

@ -0,0 +1,225 @@
//======================================================================
//
// 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
//======================================================================

View file

@ -0,0 +1,293 @@
//======================================================================
//
// tb_timer.v
// -----------
// Testbench for the timer top level wrapper.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module tb_timer();
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
parameter DEBUG = 0;
parameter DUMP_WAIT = 0;
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_CTRL = 8'h08;
localparam CTRL_NEXT_BIT = 0;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_CONFIG = 8'h0a;
localparam CONFIG_ENCDEC_BIT = 0;
localparam ADDR_KEY0 = 8'h10;
localparam ADDR_KEY1 = 8'h11;
localparam ADDR_KEY2 = 8'h12;
localparam ADDR_KEY3 = 8'h13;
localparam ADDR_BLOCK0 = 8'h20;
localparam ADDR_BLOCK1 = 8'h21;
localparam ADDR_RESULT0 = 8'h30;
localparam ADDR_RESULT1 = 8'h31;
//----------------------------------------------------------------
// Register and Wire declarations.
//----------------------------------------------------------------
reg [31 : 0] cycle_ctr;
reg [31 : 0] error_ctr;
reg [31 : 0] tc_ctr;
reg tb_monitor;
reg tb_clk;
reg tb_reset_n;
reg tb_cs;
reg tb_we;
reg [7 : 0] tb_address;
reg [31 : 0] tb_write_data;
wire [31 : 0] tb_read_data;
reg [31 : 0] read_data;
//----------------------------------------------------------------
// Device Under Test.
//----------------------------------------------------------------
timer dut(
.clk(tb_clk),
.reset_n(tb_reset_n),
.cs(tb_cs),
.we(tb_we),
.address(tb_address),
.write_data(tb_write_data),
.read_data(tb_read_data)
);
//----------------------------------------------------------------
// clk_gen
//
// Always running clock generator process.
//----------------------------------------------------------------
always
begin : clk_gen
#CLK_HALF_PERIOD;
tb_clk = !tb_clk;
end // clk_gen
//----------------------------------------------------------------
// sys_monitor()
//
// An always running process that creates a cycle counter and
// conditionally displays information about the DUT.
//----------------------------------------------------------------
always
begin : sys_monitor
cycle_ctr = cycle_ctr + 1;
#(CLK_PERIOD);
if (tb_monitor)
begin
dump_dut_state();
end
end
//----------------------------------------------------------------
// dump_dut_state()
//
// Dump the state of the dump when needed.
//----------------------------------------------------------------
task dump_dut_state;
begin
$display("State of DUT");
$display("------------");
$display("Cycle: %08d", cycle_ctr);
$display("");
end
endtask // dump_dut_state
//----------------------------------------------------------------
// reset_dut()
//
// Toggle reset to put the DUT into a well known state.
//----------------------------------------------------------------
task reset_dut;
begin
$display("--- Toggle reset.");
tb_reset_n = 0;
#(2 * CLK_PERIOD);
tb_reset_n = 1;
end
endtask // reset_dut
//----------------------------------------------------------------
// display_test_result()
//
// Display the accumulated test results.
//----------------------------------------------------------------
task display_test_result;
begin
if (error_ctr == 0)
begin
$display("--- All %02d test cases completed successfully", tc_ctr);
end
else
begin
$display("--- %02d tests completed - %02d test cases did not complete successfully.",
tc_ctr, error_ctr);
end
end
endtask // display_test_result
//----------------------------------------------------------------
// init_sim()
//
// Initialize all counters and testbed functionality as well
// as setting the DUT inputs to defined values.
//----------------------------------------------------------------
task init_sim;
begin
cycle_ctr = 0;
error_ctr = 0;
tc_ctr = 0;
tb_monitor = 0;
tb_clk = 1'h0;
tb_reset_n = 1'h1;
tb_cs = 1'h0;
tb_we = 1'h0;
tb_address = 8'h0;
tb_write_data = 32'h0;
end
endtask // init_sim
//----------------------------------------------------------------
// write_word()
//
// Write the given word to the DUT using the DUT interface.
//----------------------------------------------------------------
task write_word(input [11 : 0] address,
input [31 : 0] word);
begin
if (DEBUG)
begin
$display("--- Writing 0x%08x to 0x%02x.", word, address);
$display("");
end
tb_address = address;
tb_write_data = word;
tb_cs = 1;
tb_we = 1;
#(2 * CLK_PERIOD);
tb_cs = 0;
tb_we = 0;
end
endtask // write_word
//----------------------------------------------------------------
// read_word()
//
// Read a data word from the given address in the DUT.
// the word read will be available in the global variable
// read_data.
//----------------------------------------------------------------
task read_word(input [11 : 0] address);
begin
tb_address = address;
tb_cs = 1;
tb_we = 0;
#(CLK_PERIOD);
read_data = tb_read_data;
tb_cs = 0;
if (DEBUG)
begin
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
$display("");
end
end
endtask // read_word
//----------------------------------------------------------------
// wait_ready()
//
// Wait for the ready flag to be set in dut.
//----------------------------------------------------------------
task wait_ready;
begin : wready
read_word(ADDR_STATUS);
while (read_data == 0)
read_word(ADDR_STATUS);
end
endtask // wait_ready
//----------------------------------------------------------------
// test1()
//----------------------------------------------------------------
task test1;
begin
tc_ctr = tc_ctr + 1;
$display("");
$display("--- test1: started.");
$display("--- test1: completed.");
$display("");
end
endtask // tes1
//----------------------------------------------------------------
// timer_test
//----------------------------------------------------------------
initial
begin : timer_test
$display("");
$display(" -= Testbench for timer started =-");
$display(" =============================");
$display("");
init_sim();
reset_dut();
test1();
display_test_result();
$display("");
$display(" -= Testbench for timer started =-");
$display(" =============================");
$display("");
$finish;
end // timer_test
endmodule // tb_timer
//======================================================================
// EOF tb_timer.v
//======================================================================

View file

@ -0,0 +1,247 @@
//======================================================================
//
// tb_timer_core.v
// --------------
// Testbench for the timer core.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module tb_timer_core();
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
parameter DEBUG = 0;
parameter DUMP_WAIT = 0;
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
//----------------------------------------------------------------
// Register and Wire declarations.
//----------------------------------------------------------------
reg [31 : 0] cycle_ctr;
reg [31 : 0] error_ctr;
reg [31 : 0] tc_ctr;
reg tb_monitor;
reg tb_clk;
reg tb_reset_n;
reg tb_start;
reg tb_stop;
reg [31 : 0] tb_prescaler;
reg [31 : 0] tb_timer;
wire [31 : 0] tb_curr_prescaler;
wire [31 : 0] tb_curr_timer;
wire tb_ready;
//----------------------------------------------------------------
// Device Under Test.
//----------------------------------------------------------------
timer_core dut(
.clk(tb_clk),
.reset_n(tb_reset_n),
.prescaler_value(tb_prescaler),
.timer_value(tb_timer),
.start(tb_start),
.stop(tb_stop),
.curr_prescaler(tb_curr_prescaler),
.curr_timer(tb_curr_timer),
.ready(tb_ready)
);
//----------------------------------------------------------------
// clk_gen
//
// Always running clock generator process.
//----------------------------------------------------------------
always
begin : clk_gen
#CLK_HALF_PERIOD;
tb_clk = !tb_clk;
end // clk_gen
//----------------------------------------------------------------
// sys_monitor()
//
// An always running process that creates a cycle counter and
// conditionally displays information about the DUT.
//----------------------------------------------------------------
always
begin : sys_monitor
cycle_ctr = cycle_ctr + 1;
#(CLK_PERIOD);
if (tb_monitor)
begin
dump_dut_state();
end
end
//----------------------------------------------------------------
// dump_dut_state()
//
// Dump the state of the dump when needed.
//----------------------------------------------------------------
task dump_dut_state;
begin
$display("State of DUT");
$display("------------");
$display("Cycle: %08d", cycle_ctr);
$display("");
$display("Inputs and outputs:");
$display("start: 0x%1x, stop: 0x%1x, ready: 0x%1x",
dut.start, dut.stop, dut.ready);
$display("prescaler_value: 0x%08x, timer_value: 0x%08x",
dut.prescaler_value, dut.timer_value);
$display("");
$display("Internal state:");
$display("prescaler_reg: 0x%08x, prescaler_new: 0x%08x",
dut.prescaler_reg, dut.prescaler_new);
$display("prescaler_set: 0x%1x, prescaler_dec: 0x%1x",
dut.prescaler_set, dut.prescaler_dec);
$display("");
$display("timer_reg: 0x%08x, timer_new: 0x%08x",
dut.timer_reg, dut.timer_new);
$display("timer_set: 0x%1x, timer_dec: 0x%1x",
dut.timer_set, dut.timer_dec);
$display("");
$display("core_ctrl_reg: 0x%02x, core_ctrl_new: 0x%02x, core_ctrl_we: 0x%1x",
dut.core_ctrl_reg, dut.core_ctrl_new, dut.core_ctrl_we);
$display("");
$display("");
end
endtask // dump_dut_state
//----------------------------------------------------------------
// reset_dut()
//
// Toggle reset to put the DUT into a well known state.
//----------------------------------------------------------------
task reset_dut;
begin
$display("--- DUT before reset:");
dump_dut_state();
$display("--- Toggling reset.");
tb_reset_n = 0;
#(2 * CLK_PERIOD);
tb_reset_n = 1;
$display("--- DUT after reset:");
dump_dut_state();
end
endtask // reset_dut
//----------------------------------------------------------------
// wait_ready()
//
// Wait for the ready flag in the dut to be set.
//
// Note: It is the callers responsibility to call the function
// when the dut is actively processing and will in fact at some
// point set the flag.
//----------------------------------------------------------------
task wait_ready;
begin
#(2 * CLK_PERIOD);
while (!tb_ready)
begin
#(CLK_PERIOD);
if (DUMP_WAIT)
begin
dump_dut_state();
end
end
end
endtask // wait_ready
//----------------------------------------------------------------
// init_sim()
//
// Initialize all counters and testbed functionality as well
// as setting the DUT inputs to defined values.
//----------------------------------------------------------------
task init_sim;
begin
cycle_ctr = 0;
error_ctr = 0;
tc_ctr = 0;
tb_monitor = 0;
tb_clk = 0;
tb_reset_n = 1;
tb_start = 1'h0;
tb_stop = 1'h0;
tb_prescaler = 32'h0;
tb_timer = 32'h0;
end
endtask // init_sim
//----------------------------------------------------------------
// test()
// Runs an encipher, decipher test with given key and plaintext
// The generated ciphertext is verified with the given ciphertet.
// The generated plaintxt is also verified against the
// given plaintext.
//----------------------------------------------------------------
task test1;
begin
tc_ctr = tc_ctr + 1;
tb_monitor = 1;
$display("--- test1 started.");
dump_dut_state();
tb_prescaler = 32'h6;
tb_timer = 32'h9;
#(CLK_PERIOD);
tb_start = 1'h1;
#(CLK_PERIOD);
tb_start = 1'h0;
wait_ready();
#(CLK_PERIOD);
tb_monitor = 0;
$display("--- test1 completed.");
$display("");
end
endtask // test1
//----------------------------------------------------------------
// timer_core_test
//
// Test vectors from:
//----------------------------------------------------------------
initial
begin : timer_core_test
$display("--- Simulation of TIMER core started.");
$display("");
init_sim();
reset_dut();
test1();
$display("");
$display("--- Simulation of timer core completed.");
$finish;
end // timer_core_test
endmodule // tb_timer_core
//======================================================================
// EOF tb_timer_core.v
//======================================================================

View file

@ -0,0 +1,75 @@
#===================================================================
#
# Makefile
# --------
# Makefile for building the timer core and top simulations.
#
#
# Author: Joachim Strombergson
# Copyright (C) 2022 - Tillitis AB
# SPDX-License-Identifier: GPL-2.0-only
#
#===================================================================
CORE_SRC=../rtl/timer_core.v
TB_CORE_SRC =../tb/tb_timer_core.v
TOP_SRC=../rtl/timer.v $(CORE_SRC)
TB_TOP_SRC =../tb/tb_timer.v
CC = iverilog
CC_FLAGS = -Wall
LINT = verilator
LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
all: top.sim core.sim
top.sim: $(TB_TOP_SRC) $(TOP_SRC)
$(CC) $(CC_FLAGS) -o top.sim $(TB_TOP_SRC) $(TOP_SRC)
core.sim: $(TB_CORE_SRC) $(CORE_SRC)
$(CC) $(CC_FLAGS) -o core.sim $(TB_CORE_SRC) $(CORE_SRC)
sim-top: top.sim
./top.sim
sim-core: core.sim
./core.sim
lint-core: $(CORE_SRC)
$(LINT) $(LINT_FLAGS) $(CORE_SRC)
lint-top: $(TOP_SRC)
$(LINT) $(LINT_FLAGS) $(TOP_SRC)
clean:
rm -f top.sim
rm -f core.sim
help:
@echo "Build system for simulation of Prince core"
@echo ""
@echo "Supported targets:"
@echo "------------------"
@echo "all: Build all simulation targets."
@echo "top.sim: Build top level simulation target."
@echo "core.sim: Build core level simulation target."
@echo "sim-top: Run top level simulation."
@echo "sim-core: Run core level simulation."
@echo "lint-core: Lint core rtl source files."
@echo "lint-core: Lint top rtl source files."
@echo "clean: Delete all built files."
#===================================================================
# EOF Makefile
#===================================================================