mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-05-02 14:16:28 -04:00
Make initial public release
This commit is contained in:
commit
715de60f4a
251 changed files with 881225 additions and 0 deletions
4
hw/application_fpga/core/mta1/README.md
Normal file
4
hw/application_fpga/core/mta1/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# mta1
|
||||
|
||||
## Introduction
|
||||
Top level core that provides chip info, debug support and chip level control.
|
326
hw/application_fpga/core/mta1/rtl/mta1.v
Normal file
326
hw/application_fpga/core/mta1/rtl/mta1.v
Normal file
|
@ -0,0 +1,326 @@
|
|||
//======================================================================
|
||||
//
|
||||
// mta1.v
|
||||
// ------
|
||||
// Top level information, debug and control core for the mta1 design.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module mta1(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
output wire fw_app_mode,
|
||||
|
||||
output wire led_r,
|
||||
output wire led_g,
|
||||
output wire led_b,
|
||||
|
||||
input wire gpio1,
|
||||
input wire gpio2,
|
||||
output wire gpio3,
|
||||
output wire gpio4,
|
||||
|
||||
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_SWITCH_APP = 8'h08;
|
||||
|
||||
localparam ADDR_LED = 8'h09;
|
||||
localparam LED_R_BIT = 2;
|
||||
localparam LED_G_BIT = 1;
|
||||
localparam LED_B_BIT = 0;
|
||||
|
||||
localparam ADDR_GPIO = 8'h0a;
|
||||
localparam GPIO1_BIT = 0;
|
||||
localparam GPIO2_BIT = 1;
|
||||
localparam GPIO3_BIT = 2;
|
||||
localparam GPIO4_BIT = 3;
|
||||
|
||||
localparam ADDR_APP_START = 8'h0c;
|
||||
localparam ADDR_APP_SIZE = 8'h0d;
|
||||
|
||||
localparam ADDR_DEBUG = 8'h10;
|
||||
|
||||
localparam ADDR_CDI_FIRST = 8'h20;
|
||||
localparam ADDR_CDI_LAST = 8'h27;
|
||||
|
||||
localparam ADDR_UDI_FIRST = 8'h30;
|
||||
localparam ADDR_UDI_LAST = 8'h31;
|
||||
|
||||
localparam MTA1_NAME0 = 32'h6d746131; // "mta1"
|
||||
localparam MTA1_NAME1 = 32'h6d6b6466; // "mkdf"
|
||||
localparam MTA1_VERSION = 32'h00000004;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers including update variables and write enable.
|
||||
//----------------------------------------------------------------
|
||||
reg [31 : 0] cdi_mem [0 : 7];
|
||||
reg [31 : 0] cdi_mem_we;
|
||||
|
||||
reg [31 : 0] udi_mem [0 : 1];
|
||||
initial $readmemh(`UDI_HEX, udi_mem);
|
||||
|
||||
reg switch_app_reg;
|
||||
reg switch_app_we;
|
||||
|
||||
reg [2 : 0] led_reg;
|
||||
reg led_we;
|
||||
|
||||
reg [1 : 0] gpio1_reg;
|
||||
reg [1 : 0] gpio2_reg;
|
||||
reg gpio3_reg;
|
||||
reg gpio3_we;
|
||||
reg gpio4_reg;
|
||||
reg gpio4_we;
|
||||
|
||||
reg [31 : 0] app_start_reg;
|
||||
reg app_start_we;
|
||||
|
||||
reg [31 : 0] app_size_reg;
|
||||
reg app_size_we;
|
||||
|
||||
reg [31 : 0] debug_reg;
|
||||
reg debug_we;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Wires.
|
||||
//----------------------------------------------------------------
|
||||
/* verilator lint_off UNOPTFLAT */
|
||||
reg [31 : 0] tmp_read_data;
|
||||
reg tmp_ready;
|
||||
/* verilator lint_on UNOPTFLAT */
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = tmp_ready;
|
||||
|
||||
assign fw_app_mode = switch_app_reg;
|
||||
|
||||
assign gpio3 = gpio3_reg;
|
||||
assign gpio4 = gpio4_reg;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Module instance.
|
||||
//----------------------------------------------------------------
|
||||
SB_RGBA_DRV #(
|
||||
.CURRENT_MODE("0b1"), // half-current mode
|
||||
.RGB0_CURRENT("0b000001"), // 2 mA
|
||||
.RGB1_CURRENT("0b000001"), // 2 mA
|
||||
.RGB2_CURRENT("0b000001") // 2 mA
|
||||
) RGBA_DRV (
|
||||
.RGB0(led_r),
|
||||
.RGB1(led_g),
|
||||
.RGB2(led_b),
|
||||
.RGBLEDEN(1'h1),
|
||||
.RGB0PWM(led_reg[LED_R_BIT]),
|
||||
.RGB1PWM(led_reg[LED_G_BIT]),
|
||||
.RGB2PWM(led_reg[LED_B_BIT]),
|
||||
.CURREN(1'b1)
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//----------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
begin : reg_update
|
||||
if (!reset_n) begin
|
||||
switch_app_reg <= 1'h0;
|
||||
led_reg <= 3'h6;
|
||||
gpio1_reg <= 2'h0;
|
||||
gpio2_reg <= 2'h0;
|
||||
gpio3_reg <= 1'h0;
|
||||
gpio4_reg <= 1'h0;
|
||||
app_start_reg <= 32'h0;
|
||||
app_size_reg <= 32'h0;
|
||||
debug_reg <= 32'h0;
|
||||
cdi_mem[0] <= 32'h0;
|
||||
cdi_mem[1] <= 32'h0;
|
||||
cdi_mem[2] <= 32'h0;
|
||||
cdi_mem[3] <= 32'h0;
|
||||
cdi_mem[4] <= 32'h0;
|
||||
cdi_mem[5] <= 32'h0;
|
||||
cdi_mem[6] <= 32'h0;
|
||||
cdi_mem[7] <= 32'h0;
|
||||
end
|
||||
|
||||
else begin
|
||||
gpio1_reg[0] <= gpio1;
|
||||
gpio1_reg[1] <= gpio1_reg[0];
|
||||
|
||||
gpio2_reg[0] <= gpio2;
|
||||
gpio2_reg[1] <= gpio2_reg[0];
|
||||
|
||||
if (switch_app_we) begin
|
||||
switch_app_reg <= 1'h1;
|
||||
end
|
||||
|
||||
if (led_we) begin
|
||||
led_reg <= write_data[2 : 0];
|
||||
end
|
||||
|
||||
if (gpio3_we) begin
|
||||
gpio3_reg <= write_data[GPIO3_BIT];
|
||||
end
|
||||
|
||||
if (gpio4_we) begin
|
||||
gpio4_reg <= write_data[GPIO4_BIT];
|
||||
end
|
||||
|
||||
if (app_start_we) begin
|
||||
app_start_reg <= write_data;
|
||||
end
|
||||
|
||||
if (app_size_we) begin
|
||||
app_size_reg <= write_data;
|
||||
end
|
||||
|
||||
if (debug_we) begin
|
||||
debug_reg <= write_data;
|
||||
end
|
||||
|
||||
if (cdi_mem_we) begin
|
||||
cdi_mem[address[2 : 0]] <= write_data;
|
||||
end
|
||||
end
|
||||
end // reg_update
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// api
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : api
|
||||
switch_app_we = 1'h0;
|
||||
led_we = 1'h0;
|
||||
gpio3_we = 1'h0;
|
||||
gpio4_we = 1'h0;
|
||||
app_start_we = 1'h0;
|
||||
app_size_we = 1'h0;
|
||||
debug_we = 1'h0;
|
||||
cdi_mem_we = 1'h0;
|
||||
cdi_mem_we = 1'h0;
|
||||
tmp_read_data = 32'h00000000;
|
||||
tmp_ready = 1'h0;
|
||||
|
||||
if (cs) begin
|
||||
tmp_ready = 1'h1;
|
||||
if (we) begin
|
||||
if (address == ADDR_SWITCH_APP) begin
|
||||
switch_app_we = 1'h1;
|
||||
end
|
||||
|
||||
if (address == ADDR_LED) begin
|
||||
led_we = 1'h1;
|
||||
end
|
||||
|
||||
if (address == ADDR_GPIO) begin
|
||||
gpio3_we = 1'h1;
|
||||
gpio4_we = 1'h1;
|
||||
end
|
||||
|
||||
if (address == ADDR_APP_START) begin
|
||||
if (!switch_app_reg) begin
|
||||
app_start_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_APP_SIZE) begin
|
||||
if (!switch_app_reg) begin
|
||||
app_size_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_DEBUG) begin
|
||||
debug_we = 1'h1;
|
||||
end
|
||||
|
||||
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
||||
if (!switch_app_reg) begin
|
||||
cdi_mem_we = 1'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else begin
|
||||
if (address == ADDR_NAME0) begin
|
||||
tmp_read_data = MTA1_NAME0;
|
||||
end
|
||||
|
||||
if (address == ADDR_NAME1) begin
|
||||
tmp_read_data = MTA1_NAME1;
|
||||
end
|
||||
|
||||
if (address == ADDR_VERSION) begin
|
||||
tmp_read_data = MTA1_VERSION;
|
||||
end
|
||||
|
||||
if (address == ADDR_SWITCH_APP) begin
|
||||
tmp_read_data = {32{switch_app_reg}};
|
||||
end
|
||||
|
||||
if (address == ADDR_LED) begin
|
||||
tmp_read_data = {29'h0, led_reg};
|
||||
end
|
||||
|
||||
if (address == ADDR_GPIO) begin
|
||||
tmp_read_data = {28'h0, gpio4_reg, gpio3_reg,
|
||||
gpio2_reg[1], gpio1_reg[1]};
|
||||
end
|
||||
|
||||
if (address == ADDR_APP_START) begin
|
||||
tmp_read_data = app_start_reg;
|
||||
end
|
||||
|
||||
if (address == ADDR_APP_SIZE) begin
|
||||
tmp_read_data = app_size_reg;
|
||||
end
|
||||
|
||||
if (address == ADDR_DEBUG) begin
|
||||
tmp_read_data = debug_reg;
|
||||
end
|
||||
|
||||
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
||||
tmp_read_data = cdi_mem[address[2 : 0]];
|
||||
end
|
||||
|
||||
if ((address >= ADDR_UDI_FIRST) && (address <= ADDR_UDI_LAST)) begin
|
||||
tmp_read_data = udi_mem[address[0]];
|
||||
end
|
||||
end
|
||||
end
|
||||
end // api
|
||||
|
||||
endmodule // mta1
|
||||
|
||||
//======================================================================
|
||||
// EOF mta1.v
|
||||
//======================================================================
|
15
hw/application_fpga/core/picorv32/LICENSE
Normal file
15
hw/application_fpga/core/picorv32/LICENSE
Normal file
|
@ -0,0 +1,15 @@
|
|||
ISC License
|
||||
|
||||
Copyright (C) 2015 - 2021 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
4
hw/application_fpga/core/picorv32/README.md
Normal file
4
hw/application_fpga/core/picorv32/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# PicoRV32 - A Size-Optimized RISC-V CPU
|
||||
|
||||
This is a local copy of the
|
||||
[PicoRV32](https://github.com/cliffordwolf/picorv32) RISC-V CPU core.
|
3044
hw/application_fpga/core/picorv32/rtl/picorv32.v
Normal file
3044
hw/application_fpga/core/picorv32/rtl/picorv32.v
Normal file
File diff suppressed because it is too large
Load diff
5
hw/application_fpga/core/timer/README.md
Normal file
5
hw/application_fpga/core/timer/README.md
Normal 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.
|
194
hw/application_fpga/core/timer/rtl/timer.v
Normal file
194
hw/application_fpga/core/timer/rtl/timer.v
Normal 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
|
||||
//======================================================================
|
225
hw/application_fpga/core/timer/rtl/timer_core.v
Normal file
225
hw/application_fpga/core/timer/rtl/timer_core.v
Normal 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
|
||||
//======================================================================
|
293
hw/application_fpga/core/timer/tb/tb_timer.v
Normal file
293
hw/application_fpga/core/timer/tb/tb_timer.v
Normal 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
|
||||
//======================================================================
|
247
hw/application_fpga/core/timer/tb/tb_timer_core.v
Normal file
247
hw/application_fpga/core/timer/tb/tb_timer_core.v
Normal 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
|
||||
//======================================================================
|
75
hw/application_fpga/core/timer/toolruns/Makefile
Executable file
75
hw/application_fpga/core/timer/toolruns/Makefile
Executable 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
|
||||
#===================================================================
|
5
hw/application_fpga/core/touch_sense/README.md
Normal file
5
hw/application_fpga/core/touch_sense/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# touch_sense
|
||||
Core that handles touch senor events and provides them via an API.
|
||||
|
||||
## Introduction
|
||||
This core implements a touch sensor handler. The core detects and holds events for SW to read. The user must lift the finger between touch events.
|
211
hw/application_fpga/core/touch_sense/rtl/touch_sense.v
Normal file
211
hw/application_fpga/core/touch_sense/rtl/touch_sense.v
Normal file
|
@ -0,0 +1,211 @@
|
|||
//======================================================================
|
||||
//
|
||||
// touch_sense.v
|
||||
// -------------
|
||||
// Touch sensor handler.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module touch_sense(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire touch_event,
|
||||
|
||||
input wire cs,
|
||||
input wire we,
|
||||
|
||||
input wire [7 : 0] address,
|
||||
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_STATUS = 8'h09;
|
||||
localparam STATUS_EVENT_BIT = 0;
|
||||
|
||||
localparam CORE_NAME0 = 32'h745f7365; // "t_se"
|
||||
localparam CORE_NAME1 = 32'h6e736520; // "nse "
|
||||
localparam CORE_VERSION = 32'h00000001;
|
||||
|
||||
localparam CTRL_IDLE = 2'h0;
|
||||
localparam CTRL_EVENT = 2'h1;
|
||||
localparam CTRL_WAIT = 2'h2;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers including update variables and write enable.
|
||||
//----------------------------------------------------------------
|
||||
reg touch_event_sample0_reg;
|
||||
reg touch_event_sample1_reg;
|
||||
|
||||
reg touch_event_reg;
|
||||
reg touch_event_new;
|
||||
reg touch_event_set;
|
||||
reg touch_event_rst;
|
||||
reg touch_event_we;
|
||||
|
||||
reg [1 : 0] touch_sense_ctrl_reg;
|
||||
reg [1 : 0] touch_sense_ctrl_new;
|
||||
reg touch_sense_ctrl_we;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Wires.
|
||||
//----------------------------------------------------------------
|
||||
reg [31 : 0] tmp_read_data;
|
||||
reg [31 : 0] tmp_ready;
|
||||
reg api_clear_event;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = tmp_ready;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//----------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
begin : reg_update
|
||||
if (!reset_n) begin
|
||||
touch_sense_ctrl_reg <= CTRL_IDLE;
|
||||
touch_event_sample0_reg <= 1'h0;
|
||||
touch_event_sample1_reg <= 1'h0;
|
||||
touch_event_reg <= 1'h0;
|
||||
end
|
||||
|
||||
else begin
|
||||
touch_event_sample0_reg <= touch_event;
|
||||
touch_event_sample1_reg <= touch_event_sample0_reg;
|
||||
|
||||
if (touch_event_we) begin
|
||||
touch_event_reg <= touch_event_new;
|
||||
end
|
||||
|
||||
if (touch_sense_ctrl_we) begin
|
||||
touch_sense_ctrl_reg <= touch_sense_ctrl_new;
|
||||
end
|
||||
end
|
||||
end // reg_update
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// api
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : api
|
||||
api_clear_event = 1'h0;
|
||||
tmp_read_data = 32'h0;
|
||||
tmp_ready = 1'h0;
|
||||
|
||||
if (cs) begin
|
||||
tmp_ready = 1'h1;
|
||||
|
||||
if (we) begin
|
||||
if (address == ADDR_STATUS) begin
|
||||
api_clear_event = 1'h1;
|
||||
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[STATUS_EVENT_BIT] = touch_event_reg;
|
||||
end
|
||||
end
|
||||
end
|
||||
end // api
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// touch_event_reg_logic
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : touch_event_reg_logic
|
||||
touch_event_new = 1'h0;
|
||||
touch_event_we = 1'h0;
|
||||
|
||||
if (touch_event_set) begin
|
||||
touch_event_new = 1'h1;
|
||||
touch_event_we = 1'h1;
|
||||
end
|
||||
|
||||
else if (touch_event_rst) begin
|
||||
touch_event_new = 1'h0;
|
||||
touch_event_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// touch_sense_ctrl
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : touch_sense_ctrl
|
||||
touch_event_set = 1'h0;
|
||||
touch_event_rst = 1'h0;
|
||||
touch_sense_ctrl_new = CTRL_IDLE;
|
||||
touch_sense_ctrl_we = 1'h0;
|
||||
|
||||
case (touch_sense_ctrl_reg)
|
||||
CTRL_IDLE : begin
|
||||
if (touch_event_sample1_reg) begin
|
||||
touch_event_set = 1'h1;
|
||||
touch_sense_ctrl_new = CTRL_EVENT;
|
||||
touch_sense_ctrl_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
CTRL_EVENT: begin
|
||||
if (api_clear_event) begin
|
||||
touch_event_rst = 1'h1;
|
||||
touch_sense_ctrl_new = CTRL_WAIT;
|
||||
touch_sense_ctrl_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
CTRL_WAIT: begin
|
||||
if (!touch_event_sample1_reg) begin
|
||||
touch_sense_ctrl_new = CTRL_IDLE;
|
||||
touch_sense_ctrl_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
default : begin
|
||||
end
|
||||
endcase // case (touch_sense_ctrl_reg)
|
||||
end
|
||||
|
||||
endmodule // touch_sense
|
||||
|
||||
//======================================================================
|
||||
// EOF touch_sense.v
|
||||
//======================================================================
|
276
hw/application_fpga/core/touch_sense/tb/tb_touch_sense.v
Normal file
276
hw/application_fpga/core/touch_sense/tb/tb_touch_sense.v
Normal file
|
@ -0,0 +1,276 @@
|
|||
//======================================================================
|
||||
//
|
||||
// tb_touch_sense.v
|
||||
// ----------------
|
||||
// Testbench for the touch sense core.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module tb_touch_sense();
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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_STATUS = 8'h09;
|
||||
localparam STATUS_READY_BIT = 0;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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_touch_event;
|
||||
reg tb_cs;
|
||||
reg tb_we;
|
||||
reg [7 : 0] tb_address;
|
||||
wire [31 : 0] tb_read_data;
|
||||
|
||||
reg [31 : 0] read_data;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Device Under Test.
|
||||
//----------------------------------------------------------------
|
||||
touch_sense dut(
|
||||
.clk(tb_clk),
|
||||
.reset_n(tb_reset_n),
|
||||
|
||||
.touch_event(tb_touch_event),
|
||||
|
||||
.cs(tb_cs),
|
||||
.we(tb_we),
|
||||
.address(tb_address),
|
||||
.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_touch_event = 1'h0;
|
||||
tb_cs = 1'h0;
|
||||
tb_we = 1'h0;
|
||||
tb_address = 8'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_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
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// touch_sense_test
|
||||
//----------------------------------------------------------------
|
||||
initial
|
||||
begin : timer_test
|
||||
$display("");
|
||||
$display(" -= Testbench for touch_sense started =-");
|
||||
$display(" ====================================");
|
||||
$display("");
|
||||
|
||||
init_sim();
|
||||
reset_dut();
|
||||
test1();
|
||||
|
||||
display_test_result();
|
||||
$display("");
|
||||
$display(" -= Testbench for touch_sense completed =-");
|
||||
$display(" ======================================");
|
||||
$display("");
|
||||
$finish;
|
||||
end // touch_sense_test
|
||||
endmodule // tb_touch_sense
|
||||
|
||||
//======================================================================
|
||||
// EOF tb_touch_sense.v
|
||||
//======================================================================
|
56
hw/application_fpga/core/touch_sense/toolruns/Makefile
Executable file
56
hw/application_fpga/core/touch_sense/toolruns/Makefile
Executable file
|
@ -0,0 +1,56 @@
|
|||
#===================================================================
|
||||
#
|
||||
# Makefile
|
||||
# --------
|
||||
# Makefile for building the touch sense top simulations.
|
||||
#
|
||||
#
|
||||
# Author: Joachim Strombergson
|
||||
# Copyright (C) 2022 - Tillitis AB
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
#===================================================================
|
||||
|
||||
TOP_SRC=../rtl/touch_sense.v
|
||||
TB_TOP_SRC =../tb/tb_touch_sense.v
|
||||
|
||||
CC = iverilog
|
||||
CC_FLAGS = -Wall
|
||||
|
||||
LINT = verilator
|
||||
LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
|
||||
|
||||
|
||||
all: top.sim
|
||||
|
||||
|
||||
top.sim: $(TB_TOP_SRC) $(TOP_SRC)
|
||||
$(CC) $(CC_FLAGS) -o top.sim $(TB_TOP_SRC) $(TOP_SRC)
|
||||
|
||||
|
||||
sim-top: top.sim
|
||||
./top.sim
|
||||
|
||||
|
||||
lint-top: $(TOP_SRC)
|
||||
$(LINT) $(LINT_FLAGS) $(TOP_SRC)
|
||||
|
||||
|
||||
clean:
|
||||
rm -f top.sim
|
||||
|
||||
|
||||
help:
|
||||
@echo "Build system for simulation of touch sense core"
|
||||
@echo ""
|
||||
@echo "Supported targets:"
|
||||
@echo "------------------"
|
||||
@echo "all: Build all simulation targets."
|
||||
@echo "top.sim: Build top level simulation target."
|
||||
@echo "sim-top: Run top level simulation."
|
||||
@echo "lint-top: Lint top rtl source files."
|
||||
@echo "clean: Delete all built files."
|
||||
|
||||
#===================================================================
|
||||
# EOF Makefile
|
||||
#===================================================================
|
29
hw/application_fpga/core/trng/README.md
Normal file
29
hw/application_fpga/core/trng/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
# trng
|
||||
Implementation of the FiGaRO TRNG for FPGAs
|
||||
|
||||
## Introduction
|
||||
# figaro
|
||||
|
||||
|
||||
## Status
|
||||
First version completed. In testing. Use with caution.
|
||||
|
||||
|
||||
## Introduction
|
||||
This is a an implementation of the FiGaRO true random
|
||||
number generator (TRNG) [1]. The main FPGA target is Lattice iCE40
|
||||
UltraPlus, but adaption to other FPGAs should be easy to do.
|
||||
|
||||
|
||||
## Implementation details
|
||||
The implementation instantiates four FiRO and four GaRO modules. The
|
||||
modules includes state sampling. The polynomials used for the
|
||||
oscillators are given by equotions (9)..(16) in paper [1]. The eight
|
||||
outputs are then XORed together to form a one bit random value.
|
||||
|
||||
The random bit value is sampled at a rate controlled by a 24 bit
|
||||
divisor.
|
||||
|
||||
## References
|
||||
[1] [True Random Number Generator Based on Fibonacci-Galois
|
||||
Ring Oscillators for FPGA](https://www.mdpi.com/2076-3417/11/8/3330/pdf)
|
129
hw/application_fpga/core/trng/rtl/figaro.v
Normal file
129
hw/application_fpga/core/trng/rtl/figaro.v
Normal file
|
@ -0,0 +1,129 @@
|
|||
//======================================================================
|
||||
//
|
||||
// figaro.v
|
||||
// --------
|
||||
// Top level wrapper for the figaro core.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module figaro(
|
||||
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_STATUS = 8'h09;
|
||||
localparam STATUS_READY_BIT = 0;
|
||||
|
||||
localparam ADDR_SAMPLE_RATE = 8'h10;
|
||||
|
||||
localparam ADDR_ENTROPY = 8'h20;
|
||||
|
||||
localparam CORE_NAME0 = 32'h66696761; // "figa"
|
||||
localparam CORE_NAME1 = 32'h726f2020; // "ro "
|
||||
localparam CORE_VERSION = 32'h00000001;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Wires.
|
||||
//----------------------------------------------------------------
|
||||
reg core_read_entropy;
|
||||
reg core_set_sample_rate;
|
||||
wire [31 : 0] core_entropy;
|
||||
wire core_ready;
|
||||
reg [31 : 0] tmp_read_data;
|
||||
reg tmp_ready;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = tmp_ready;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// core instantiation.
|
||||
//----------------------------------------------------------------
|
||||
figaro_core core(
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
.read_entropy(core_read_entropy),
|
||||
.set_sample_rate(core_set_sample_rate),
|
||||
.sample_rate(write_data[23 : 0]),
|
||||
.entropy(core_entropy),
|
||||
.ready(core_ready)
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// api
|
||||
//
|
||||
// The interface command decoding logic.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : api
|
||||
core_read_entropy = 1'h0;
|
||||
core_set_sample_rate = 1'h0;
|
||||
tmp_read_data = 32'h0;
|
||||
tmp_ready = 1'h0;
|
||||
|
||||
if (cs) begin
|
||||
tmp_ready = 1'h1;
|
||||
|
||||
if (we) begin
|
||||
if (address == ADDR_SAMPLE_RATE) begin
|
||||
core_set_sample_rate = 1'h1;
|
||||
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_ENTROPY) begin
|
||||
tmp_read_data = core_entropy;
|
||||
core_read_entropy = 1'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end // api
|
||||
endmodule // figaro
|
||||
|
||||
//======================================================================
|
||||
// EOF figaro.v
|
||||
//======================================================================
|
204
hw/application_fpga/core/trng/rtl/figaro_core.v
Normal file
204
hw/application_fpga/core/trng/rtl/figaro_core.v
Normal file
|
@ -0,0 +1,204 @@
|
|||
//======================================================================
|
||||
//
|
||||
// figaro_core.v
|
||||
// -----------
|
||||
// FiGaRO based FIGARO for iCE40 device.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
module figaro_core(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire set_sample_rate,
|
||||
input wire [23 : 0] sample_rate,
|
||||
|
||||
input wire read_entropy,
|
||||
output wire [31 : 0] entropy,
|
||||
|
||||
output wire ready
|
||||
);
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Local parameters.
|
||||
//---------------------------------------------------------------
|
||||
localparam DEFAULT_SAMPLE_RATE = 24'h010000;
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Registers.
|
||||
//---------------------------------------------------------------
|
||||
reg [23 : 0] sample_rate_ctr_reg;
|
||||
reg [23 : 0] sample_rate_ctr_new;
|
||||
|
||||
reg [23 : 0] sample_rate_reg;
|
||||
reg sample_rate_we;
|
||||
|
||||
reg [5 : 0] bit_ctr_reg;
|
||||
reg [5 : 0] bit_ctr_new;
|
||||
reg bit_ctr_rst;
|
||||
reg bit_ctr_inc;
|
||||
reg bit_ctr_we;
|
||||
|
||||
reg [31 : 0] entropy_reg;
|
||||
reg [31 : 0] entropy_new;
|
||||
reg entropy_we;
|
||||
|
||||
reg ready_reg;
|
||||
reg ready_new;
|
||||
reg ready_we;
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Firo oscillator instances and XOR combined result.
|
||||
//---------------------------------------------------------------
|
||||
wire firo_ent[3 : 0];
|
||||
wire firo_entropy;
|
||||
|
||||
firo #(.POLY(10'b1111110111)) firo0(.clk(clk), .entropy(firo_ent[0]));
|
||||
firo #(.POLY(10'b1011111001)) firo1(.clk(clk), .entropy(firo_ent[1]));
|
||||
firo #(.POLY(10'b1100000001)) firo2(.clk(clk), .entropy(firo_ent[2]));
|
||||
firo #(.POLY(10'b1011111111)) firo3(.clk(clk), .entropy(firo_ent[3]));
|
||||
|
||||
assign firo_entropy = firo_ent[0] ^ firo_ent[1] ^
|
||||
firo_ent[2] ^ firo_ent[3];
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// garo oscillator instances and XOR combined result.
|
||||
//---------------------------------------------------------------
|
||||
wire garo_ent[3 : 0];
|
||||
wire garo_entropy;
|
||||
|
||||
garo #(.POLY(11'b11111101111)) garo0(.clk(clk), .entropy(garo_ent[0]));
|
||||
garo #(.POLY(11'b10111110011)) garo1(.clk(clk), .entropy(garo_ent[1]));
|
||||
garo #(.POLY(11'b11000000011)) garo2(.clk(clk), .entropy(garo_ent[2]));
|
||||
garo #(.POLY(11'b10111111111)) garo3(.clk(clk), .entropy(garo_ent[3]));
|
||||
|
||||
assign garo_entropy = garo_ent[0] ^ garo_ent[1] ^
|
||||
garo_ent[2] ^ garo_ent[3];
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Assignments.
|
||||
//---------------------------------------------------------------
|
||||
assign ready = ready_reg;
|
||||
assign entropy = entropy_reg;
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// reg_update
|
||||
//---------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
begin : reg_update
|
||||
if (!reset_n) begin
|
||||
sample_rate_reg <= DEFAULT_SAMPLE_RATE;
|
||||
sample_rate_ctr_reg <= 24'h0;
|
||||
bit_ctr_reg <= 6'h0;
|
||||
entropy_reg <= 32'h0;
|
||||
ready_reg <= 1'h0;
|
||||
end
|
||||
else begin
|
||||
sample_rate_ctr_reg <= sample_rate_ctr_new;
|
||||
|
||||
if (sample_rate_we) begin
|
||||
sample_rate_reg <= sample_rate;
|
||||
end
|
||||
|
||||
if (bit_ctr_we) begin
|
||||
bit_ctr_reg <= bit_ctr_new;
|
||||
end
|
||||
|
||||
if (entropy_we) begin
|
||||
entropy_reg <= entropy_new;
|
||||
end
|
||||
|
||||
if (ready_we) begin
|
||||
ready_reg <= ready_new;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// ready_logic
|
||||
//
|
||||
// After an entropy word has been read we wait 32 bits before
|
||||
// setting ready again, indicating that a new word is ready.
|
||||
//---------------------------------------------------------------
|
||||
always @*
|
||||
begin : ready_logic;
|
||||
bit_ctr_new = 6'h0;
|
||||
bit_ctr_we = 1'h0;
|
||||
ready_new = 1'h0;
|
||||
ready_we = 1'h0;
|
||||
|
||||
if (bit_ctr_reg >= 6'h20) begin
|
||||
ready_new = 1'h1;
|
||||
ready_we = 1'h1;
|
||||
end
|
||||
|
||||
if (bit_ctr_rst) begin
|
||||
bit_ctr_new = 6'h0;
|
||||
bit_ctr_we = 1'h1;
|
||||
ready_new = 1'h0;
|
||||
ready_we = 1'h1;
|
||||
end
|
||||
|
||||
else if (bit_ctr_inc) begin
|
||||
if (bit_ctr_reg < 6'h24) begin
|
||||
bit_ctr_new = bit_ctr_reg + 1'h1;
|
||||
bit_ctr_we = 1'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// figaro_sample_logic
|
||||
//
|
||||
// Wait sample_rate_reg number of cycles between sampling a bit
|
||||
// from the entropy source.
|
||||
//---------------------------------------------------------------
|
||||
always @*
|
||||
begin : figaro_sample_logic
|
||||
sample_rate_we = 1'h0;
|
||||
bit_ctr_rst = 1'h0;
|
||||
bit_ctr_inc = 1'h0;
|
||||
entropy_we = 1'h0;
|
||||
|
||||
entropy_new = {entropy_reg[30 : 0], firo_entropy ^ garo_entropy};
|
||||
|
||||
if (read_entropy) begin
|
||||
bit_ctr_rst = 1'h1;
|
||||
sample_rate_ctr_new = 24'h0;
|
||||
end
|
||||
|
||||
else if (set_sample_rate) begin
|
||||
bit_ctr_rst = 1'h1;
|
||||
sample_rate_we = 1'h1;
|
||||
sample_rate_ctr_new = 24'h0;
|
||||
end
|
||||
|
||||
else if (sample_rate_ctr_reg == sample_rate_reg) begin
|
||||
sample_rate_ctr_new = 24'h0;
|
||||
entropy_we = 1'h1;
|
||||
bit_ctr_inc = 1'h1;
|
||||
end
|
||||
|
||||
else begin
|
||||
sample_rate_ctr_new = sample_rate_ctr_reg + 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // figaro_core
|
||||
|
||||
//======================================================================
|
||||
// EOF figaro_core.v
|
||||
//======================================================================
|
75
hw/application_fpga/core/trng/rtl/firo.v
Normal file
75
hw/application_fpga/core/trng/rtl/firo.v
Normal file
|
@ -0,0 +1,75 @@
|
|||
//======================================================================
|
||||
//
|
||||
// firo.v
|
||||
// ------
|
||||
// Fibonacci Ring Oscillator with state sampling.
|
||||
// The Fibonacci depth is 10 bits, and the bits are always sampled.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module firo(
|
||||
input wire clk,
|
||||
output wire entropy
|
||||
);
|
||||
|
||||
parameter POLY = 10'b1111111111;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers and wires.
|
||||
//----------------------------------------------------------------
|
||||
reg entropy_reg;
|
||||
wire [10 : 0] f;
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Combinational loop inverters.
|
||||
//---------------------------------------------------------------
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv1 (.I0(f[0]), .O(f[1]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv2 (.I0(f[1]), .O(f[2]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv3 (.I0(f[2]), .O(f[3]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv4 (.I0(f[3]), .O(f[4]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv5 (.I0(f[4]), .O(f[5]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv6 (.I0(f[5]), .O(f[6]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv7 (.I0(f[6]), .O(f[7]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv8 (.I0(f[7]), .O(f[8]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv9 (.I0(f[8]), .O(f[9]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv10 (.I0(f[9]), .O(f[10]));
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// parameterized feedback logic.
|
||||
//---------------------------------------------------------------
|
||||
assign f[0] = (POLY[0] & f[1]) ^ (POLY[1] & f[2]) ^
|
||||
(POLY[2] & f[3]) ^ (POLY[3] & f[4]) ^
|
||||
(POLY[4] & f[5]) ^ (POLY[5] & f[6]) ^
|
||||
(POLY[6] & f[7]) ^ (POLY[7] & f[8]) ^
|
||||
(POLY[8] & f[9]) ^ (POLY[9] & f[10]);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign entropy = entropy_reg;
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// reg_update
|
||||
//---------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
begin : reg_update
|
||||
entropy_reg <= ^f;
|
||||
end
|
||||
|
||||
endmodule // firo
|
||||
|
||||
//======================================================================
|
||||
// EOF firo.v
|
||||
//======================================================================
|
85
hw/application_fpga/core/trng/rtl/garo.v
Normal file
85
hw/application_fpga/core/trng/rtl/garo.v
Normal file
|
@ -0,0 +1,85 @@
|
|||
//======================================================================
|
||||
//
|
||||
// garo.v
|
||||
// ------
|
||||
// GaloisRing Oscillator with state sampling.
|
||||
// The Galois depth is 11 bits, and the bits are always sampled.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module garo(
|
||||
input wire clk,
|
||||
output wire entropy
|
||||
);
|
||||
|
||||
parameter POLY = 11'b11111111111;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers and wires.
|
||||
//----------------------------------------------------------------
|
||||
reg entropy_reg;
|
||||
wire [11 : 0] g;
|
||||
wire [11 : 0] gp;
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Combinational loop inverters.
|
||||
//---------------------------------------------------------------
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv1 (.I0(g[0]), .O(gp[0]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv2 (.I0(g[1]), .O(gp[1]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv3 (.I0(g[2]), .O(gp[2]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv4 (.I0(g[3]), .O(gp[3]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv5 (.I0(g[4]), .O(gp[4]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv6 (.I0(g[5]), .O(gp[5]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv7 (.I0(g[6]), .O(gp[6]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv8 (.I0(g[7]), .O(gp[7]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv9 (.I0(g[8]), .O(gp[8]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv10 (.I0(g[9]), .O(gp[9]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv11 (.I0(g[10]), .O(gp[10]));
|
||||
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv12 (.I0(g[11]), .O(gp[11]));
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// parameterized feedback logic.
|
||||
//---------------------------------------------------------------
|
||||
assign g[11] = gp[0];
|
||||
assign g[10] = gp[11] ^ (POLY[10] & gp[0]);
|
||||
assign g[9] = gp[10] ^ (POLY[9] & gp[0]);
|
||||
assign g[8] = gp[9] ^ (POLY[8] & gp[0]);
|
||||
assign g[7] = gp[8] ^ (POLY[7] & gp[0]);
|
||||
assign g[6] = gp[7] ^ (POLY[6] & gp[0]);
|
||||
assign g[5] = gp[6] ^ (POLY[5] & gp[0]);
|
||||
assign g[4] = gp[5] ^ (POLY[4] & gp[0]);
|
||||
assign g[3] = gp[4] ^ (POLY[3] & gp[0]);
|
||||
assign g[2] = gp[3] ^ (POLY[2] & gp[0]);
|
||||
assign g[1] = gp[2] ^ (POLY[1] & gp[0]);
|
||||
assign g[0] = gp[1] ^ (POLY[0] & gp[0]);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign entropy = entropy_reg;
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// reg_update
|
||||
//---------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
begin : reg_update
|
||||
entropy_reg <= ^g;
|
||||
end
|
||||
|
||||
endmodule // garo
|
||||
|
||||
//======================================================================
|
||||
// EOF garo.v
|
||||
//======================================================================
|
23
hw/application_fpga/core/uart/LICENSE
Normal file
23
hw/application_fpga/core/uart/LICENSE
Normal file
|
@ -0,0 +1,23 @@
|
|||
Copyright (c) 2014, Joachim Strömbergson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
9
hw/application_fpga/core/uart/README.md
Normal file
9
hw/application_fpga/core/uart/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
uart
|
||||
====
|
||||
|
||||
A simple universal asynchronous receiver/transmitter (UART) core
|
||||
implemented in Verilog.
|
||||
|
||||
|
||||
# Status
|
||||
The core is completed and has been used in several FPGA designs.
|
306
hw/application_fpga/core/uart/rtl/uart.v
Normal file
306
hw/application_fpga/core/uart/rtl/uart.v
Normal file
|
@ -0,0 +1,306 @@
|
|||
//======================================================================
|
||||
//
|
||||
// uart.v
|
||||
// ------
|
||||
// Top level wrapper for the uart core.
|
||||
//
|
||||
// A simple universal asynchronous receiver/transmitter (UART)
|
||||
// interface. The interface contains 16 byte wide transmit and
|
||||
// receivea buffers and can handle start and stop bits. But in
|
||||
// general is rather simple. The primary purpose is as host
|
||||
// interface for the coretest design. The core also has a
|
||||
// loopback mode to allow testing of a serial link.
|
||||
//
|
||||
// Note that the UART has a separate API interface to allow
|
||||
// a control core to change settings such as speed. But the core
|
||||
// has default values to allow it to start operating directly
|
||||
// after reset. No config should be needed.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (c) 2014, Secworks Sweden AB
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or
|
||||
// without modification, are permitted provided that the following
|
||||
// conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
module uart(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire rxd,
|
||||
output wire txd,
|
||||
|
||||
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_CORE_NAME0 = 8'h00;
|
||||
localparam ADDR_CORE_NAME1 = 8'h01;
|
||||
localparam ADDR_CORE_VERSION = 8'h02;
|
||||
|
||||
localparam ADDR_BIT_RATE = 8'h10;
|
||||
localparam ADDR_DATA_BITS = 8'h11;
|
||||
localparam ADDR_STOP_BITS = 8'h12;
|
||||
|
||||
localparam ADDR_RX_STATUS = 8'h20;
|
||||
localparam ADDR_RX_DATA = 8'h21;
|
||||
|
||||
localparam ADDR_TX_STATUS = 8'h40;
|
||||
localparam ADDR_TX_DATA = 8'h41;
|
||||
|
||||
|
||||
localparam CORE_NAME0 = 32'h75617274; // "uart"
|
||||
localparam CORE_NAME1 = 32'h20202020; // " "
|
||||
localparam CORE_VERSION = 32'h00000004;
|
||||
|
||||
|
||||
// The default bit rate is based on target clock frequency
|
||||
// divided by the bit rate times in order to hit the
|
||||
// center of the bits. I.e.
|
||||
// Clock: 12 MHz, 38400 bps
|
||||
// Divisor = 12*10E6 / 38400 = 312
|
||||
localparam DEFAULT_BIT_RATE = 16'd312;
|
||||
localparam DEFAULT_DATA_BITS = 4'h8;
|
||||
localparam DEFAULT_STOP_BITS = 2'h1;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers including update variables and write enable.
|
||||
//----------------------------------------------------------------
|
||||
reg [15 : 0] bit_rate_reg;
|
||||
reg bit_rate_we;
|
||||
|
||||
reg [3 : 0] data_bits_reg;
|
||||
reg data_bits_we;
|
||||
|
||||
reg [1 : 0] stop_bits_reg;
|
||||
reg stop_bits_we;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Wires.
|
||||
//----------------------------------------------------------------
|
||||
wire core_rxd_syn;
|
||||
wire [7 : 0] core_rxd_data;
|
||||
wire core_rxd_ack;
|
||||
|
||||
reg core_txd_syn;
|
||||
reg [7 : 0] core_txd_data;
|
||||
wire core_txd_ready;
|
||||
|
||||
wire fifo_out_syn;
|
||||
wire [7 : 0] fifo_out_data;
|
||||
reg fifo_out_ack;
|
||||
|
||||
reg [31 : 0] tmp_read_data;
|
||||
reg tmp_ready;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = tmp_ready;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Module instantiations.
|
||||
//----------------------------------------------------------------
|
||||
uart_core core(
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
// Configuration parameters
|
||||
.bit_rate(bit_rate_reg),
|
||||
.data_bits(data_bits_reg),
|
||||
.stop_bits(stop_bits_reg),
|
||||
|
||||
// External data interface
|
||||
.rxd(rxd),
|
||||
.txd(txd),
|
||||
|
||||
// Internal receive interface.
|
||||
.rxd_syn(core_rxd_syn),
|
||||
.rxd_data(core_rxd_data),
|
||||
.rxd_ack(core_rxd_ack),
|
||||
|
||||
// Internal transmit interface.
|
||||
.txd_syn(core_txd_syn),
|
||||
.txd_data(core_txd_data),
|
||||
.txd_ready(core_txd_ready)
|
||||
);
|
||||
|
||||
|
||||
uart_fifo fifo(
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.in_syn(core_rxd_syn),
|
||||
.in_data(core_rxd_data),
|
||||
.in_ack(core_rxd_ack),
|
||||
|
||||
.out_syn(fifo_out_syn),
|
||||
.out_data(fifo_out_data),
|
||||
.out_ack(fifo_out_ack)
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//
|
||||
// Update functionality for all registers in the core.
|
||||
// All registers are positive edge triggered with synchronous
|
||||
// active low reset.
|
||||
//----------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
begin: reg_update
|
||||
if (!reset_n) begin
|
||||
bit_rate_reg <= DEFAULT_BIT_RATE;
|
||||
data_bits_reg <= DEFAULT_DATA_BITS;
|
||||
stop_bits_reg <= DEFAULT_STOP_BITS;
|
||||
end
|
||||
else begin
|
||||
if (bit_rate_we) begin
|
||||
bit_rate_reg <= write_data[15 : 0];
|
||||
end
|
||||
|
||||
if (data_bits_we) begin
|
||||
data_bits_reg <= write_data[3 : 0];
|
||||
end
|
||||
|
||||
if (stop_bits_we) begin
|
||||
stop_bits_reg <= write_data[1 : 0];
|
||||
end
|
||||
end
|
||||
end // reg_update
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// api
|
||||
//
|
||||
// The core API that allows an internal host to control the
|
||||
// core functionality.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin: api
|
||||
// Default assignments.
|
||||
bit_rate_we = 1'h0;
|
||||
data_bits_we = 1'h0;
|
||||
stop_bits_we = 1'h0;
|
||||
core_txd_syn = 1'h0;
|
||||
fifo_out_ack = 1'h0;
|
||||
tmp_read_data = 32'h0;
|
||||
tmp_ready = 1'h0;
|
||||
|
||||
core_txd_data = write_data[7 : 0];
|
||||
|
||||
if (cs) begin
|
||||
tmp_ready = 1'h1;
|
||||
|
||||
if (we) begin
|
||||
case (address)
|
||||
ADDR_BIT_RATE: begin
|
||||
bit_rate_we = 1;
|
||||
end
|
||||
|
||||
ADDR_DATA_BITS: begin
|
||||
data_bits_we = 1;
|
||||
end
|
||||
|
||||
ADDR_STOP_BITS: begin
|
||||
stop_bits_we = 1;
|
||||
end
|
||||
|
||||
ADDR_TX_DATA: begin
|
||||
core_txd_syn = 1'h1;
|
||||
end
|
||||
|
||||
default: begin
|
||||
end
|
||||
endcase // case (address)
|
||||
end
|
||||
|
||||
else begin
|
||||
case (address)
|
||||
ADDR_CORE_NAME0: begin
|
||||
tmp_read_data = CORE_NAME0;
|
||||
end
|
||||
|
||||
ADDR_CORE_NAME1: begin
|
||||
tmp_read_data = CORE_NAME1;
|
||||
end
|
||||
|
||||
ADDR_CORE_VERSION: begin
|
||||
tmp_read_data = CORE_VERSION;
|
||||
end
|
||||
|
||||
ADDR_BIT_RATE: begin
|
||||
tmp_read_data = {16'h0, bit_rate_reg};
|
||||
end
|
||||
|
||||
ADDR_DATA_BITS: begin
|
||||
tmp_read_data = {28'h0, data_bits_reg};
|
||||
end
|
||||
|
||||
ADDR_STOP_BITS: begin
|
||||
tmp_read_data = {30'h0, stop_bits_reg};
|
||||
end
|
||||
|
||||
ADDR_RX_STATUS: begin
|
||||
tmp_read_data = {31'h0, fifo_out_syn};
|
||||
end
|
||||
|
||||
ADDR_RX_DATA: begin
|
||||
fifo_out_ack = 1'h1;
|
||||
tmp_read_data = {24'h0, fifo_out_data};
|
||||
end
|
||||
|
||||
ADDR_TX_STATUS: begin
|
||||
tmp_read_data = {31'h0, core_txd_ready};
|
||||
end
|
||||
|
||||
default: begin
|
||||
end
|
||||
endcase // case (address)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // uart
|
||||
|
||||
//======================================================================
|
||||
// EOF uart.v
|
||||
//======================================================================
|
532
hw/application_fpga/core/uart/rtl/uart_core.v
Normal file
532
hw/application_fpga/core/uart/rtl/uart_core.v
Normal file
|
@ -0,0 +1,532 @@
|
|||
//======================================================================
|
||||
//
|
||||
// uart_core.v
|
||||
// -----------
|
||||
// A simple universal asynchronous receiver/transmitter (UART)
|
||||
// interface. The interface contains 16 byte wide transmit and
|
||||
// receivea buffers and can handle start and stop bits. But in
|
||||
// general is rather simple. The primary purpose is as host
|
||||
// interface for the coretest design. The core also has a
|
||||
// loopback mode to allow testing of a serial link.
|
||||
//
|
||||
// Note that the UART has a separate API interface to allow
|
||||
// a control core to change settings such as speed. But the core
|
||||
// has default values to allow it to start operating directly
|
||||
// after reset. No config should be needed.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (c) 2014, Secworks Sweden AB
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
// Redistribution and use in source and binary forms, with or
|
||||
// without modification, are permitted provided that the following
|
||||
// conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
module uart_core(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
// Configuration parameters
|
||||
input wire [15 : 0] bit_rate,
|
||||
input wire [3 : 0] data_bits,
|
||||
input wire [1 : 0] stop_bits,
|
||||
|
||||
// External data interface
|
||||
input wire rxd,
|
||||
output wire txd,
|
||||
|
||||
// Internal receive interface.
|
||||
output wire rxd_syn,
|
||||
output [7 : 0] rxd_data,
|
||||
input wire rxd_ack,
|
||||
|
||||
// Internal transmit interface.
|
||||
input wire txd_syn,
|
||||
input wire [7 : 0] txd_data,
|
||||
output wire txd_ready
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Internal constant and parameter definitions.
|
||||
//----------------------------------------------------------------
|
||||
parameter ERX_IDLE = 0;
|
||||
parameter ERX_START = 1;
|
||||
parameter ERX_BITS = 2;
|
||||
parameter ERX_STOP = 3;
|
||||
parameter ERX_SYN = 4;
|
||||
|
||||
parameter ETX_IDLE = 0;
|
||||
parameter ETX_ACK = 1;
|
||||
parameter ETX_START = 2;
|
||||
parameter ETX_BITS = 3;
|
||||
parameter ETX_STOP = 4;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers including update variables and write enable.
|
||||
//----------------------------------------------------------------
|
||||
reg rxd0_reg;
|
||||
reg rxd_reg;
|
||||
|
||||
reg [7 : 0] rxd_byte_reg;
|
||||
reg rxd_byte_we;
|
||||
|
||||
reg [4 : 0] rxd_bit_ctr_reg;
|
||||
reg [4 : 0] rxd_bit_ctr_new;
|
||||
reg rxd_bit_ctr_we;
|
||||
reg rxd_bit_ctr_rst;
|
||||
reg rxd_bit_ctr_inc;
|
||||
|
||||
reg [15 : 0] rxd_bitrate_ctr_reg;
|
||||
reg [15 : 0] rxd_bitrate_ctr_new;
|
||||
reg rxd_bitrate_ctr_we;
|
||||
reg rxd_bitrate_ctr_rst;
|
||||
reg rxd_bitrate_ctr_inc;
|
||||
|
||||
reg rxd_syn_reg;
|
||||
reg rxd_syn_new;
|
||||
reg rxd_syn_we;
|
||||
|
||||
reg [2 : 0] erx_ctrl_reg;
|
||||
reg [2 : 0] erx_ctrl_new;
|
||||
reg erx_ctrl_we;
|
||||
|
||||
reg txd_reg;
|
||||
reg txd_new;
|
||||
reg txd_we;
|
||||
|
||||
reg [7 : 0] txd_byte_reg;
|
||||
reg [7 : 0] txd_byte_new;
|
||||
reg txd_byte_we;
|
||||
|
||||
reg [4 : 0] txd_bit_ctr_reg;
|
||||
reg [4 : 0] txd_bit_ctr_new;
|
||||
reg txd_bit_ctr_we;
|
||||
reg txd_bit_ctr_rst;
|
||||
reg txd_bit_ctr_inc;
|
||||
|
||||
reg [15 : 0] txd_bitrate_ctr_reg;
|
||||
reg [15 : 0] txd_bitrate_ctr_new;
|
||||
reg txd_bitrate_ctr_we;
|
||||
reg txd_bitrate_ctr_rst;
|
||||
reg txd_bitrate_ctr_inc;
|
||||
|
||||
reg txd_ready_reg;
|
||||
reg txd_ready_new;
|
||||
reg txd_ready_we;
|
||||
|
||||
reg [2 : 0] etx_ctrl_reg;
|
||||
reg [2 : 0] etx_ctrl_new;
|
||||
reg etx_ctrl_we;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Wires.
|
||||
//----------------------------------------------------------------
|
||||
wire [15 : 0] half_bit_rate;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign txd = txd_reg;
|
||||
assign rxd_syn = rxd_syn_reg;
|
||||
assign rxd_data = rxd_byte_reg;
|
||||
assign txd_ready = txd_ready_reg;
|
||||
|
||||
assign half_bit_rate = {1'b0, bit_rate[15 : 1]};
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//
|
||||
// Update functionality for all registers in the core.
|
||||
// All registers are positive edge triggered with
|
||||
// synchronous active low reset.
|
||||
//----------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
begin: reg_update
|
||||
if (!reset_n) begin
|
||||
rxd0_reg <= 1'b0;
|
||||
rxd_reg <= 1'b0;
|
||||
rxd_byte_reg <= 8'h0;
|
||||
rxd_bit_ctr_reg <= 5'h0;
|
||||
rxd_bitrate_ctr_reg <= 16'h0;
|
||||
rxd_syn_reg <= 0;
|
||||
erx_ctrl_reg <= ERX_IDLE;
|
||||
|
||||
txd_reg <= 1'b1;
|
||||
txd_byte_reg <= 8'h0;
|
||||
txd_bit_ctr_reg <= 5'h0;
|
||||
txd_bitrate_ctr_reg <= 16'h0;
|
||||
txd_ready_reg <= 1'b1;
|
||||
etx_ctrl_reg <= ETX_IDLE;
|
||||
end
|
||||
|
||||
else begin
|
||||
rxd0_reg <= rxd;
|
||||
rxd_reg <= rxd0_reg;
|
||||
|
||||
if (rxd_byte_we) begin
|
||||
rxd_byte_reg <= {rxd_reg, rxd_byte_reg[7 : 1]};
|
||||
end
|
||||
|
||||
if (rxd_bit_ctr_we) begin
|
||||
rxd_bit_ctr_reg <= rxd_bit_ctr_new;
|
||||
end
|
||||
|
||||
if (rxd_bitrate_ctr_we) begin
|
||||
rxd_bitrate_ctr_reg <= rxd_bitrate_ctr_new;
|
||||
end
|
||||
|
||||
if (rxd_syn_we) begin
|
||||
rxd_syn_reg <= rxd_syn_new;
|
||||
end
|
||||
|
||||
if (erx_ctrl_we) begin
|
||||
erx_ctrl_reg <= erx_ctrl_new;
|
||||
end
|
||||
|
||||
if (txd_we) begin
|
||||
txd_reg <= txd_new;
|
||||
end
|
||||
|
||||
if (txd_byte_we) begin
|
||||
txd_byte_reg <= txd_byte_new;
|
||||
end
|
||||
|
||||
if (txd_bit_ctr_we) begin
|
||||
txd_bit_ctr_reg <= txd_bit_ctr_new;
|
||||
end
|
||||
|
||||
if (txd_bitrate_ctr_we) begin
|
||||
txd_bitrate_ctr_reg <= txd_bitrate_ctr_new;
|
||||
end
|
||||
|
||||
if (txd_ready_we) begin
|
||||
txd_ready_reg <= txd_ready_new;
|
||||
end
|
||||
|
||||
if (etx_ctrl_we) begin
|
||||
etx_ctrl_reg <= etx_ctrl_new;
|
||||
end
|
||||
end
|
||||
end // reg_update
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// rxd_bit_ctr
|
||||
//
|
||||
// Bit counter for receiving data on the external
|
||||
// serial interface.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin: rxd_bit_ctr
|
||||
rxd_bit_ctr_new = 5'h0;
|
||||
rxd_bit_ctr_we = 1'b0;
|
||||
|
||||
if (rxd_bit_ctr_rst) begin
|
||||
rxd_bit_ctr_new = 5'h0;
|
||||
rxd_bit_ctr_we = 1'b1;
|
||||
end
|
||||
|
||||
else if (rxd_bit_ctr_inc) begin
|
||||
rxd_bit_ctr_new = rxd_bit_ctr_reg + 1'h1;
|
||||
rxd_bit_ctr_we = 1'b1;
|
||||
end
|
||||
end // rxd_bit_ctr
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// rxd_bitrate_ctr
|
||||
//
|
||||
// Bitrate counter for receiving data on the external
|
||||
// serial interface.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin: rxd_bitrate_ctr
|
||||
rxd_bitrate_ctr_new = 16'h0;
|
||||
rxd_bitrate_ctr_we = 1'h0;
|
||||
|
||||
if (rxd_bitrate_ctr_rst) begin
|
||||
rxd_bitrate_ctr_new = 16'h0;
|
||||
rxd_bitrate_ctr_we = 1'b1;
|
||||
end
|
||||
|
||||
else if (rxd_bitrate_ctr_inc) begin
|
||||
rxd_bitrate_ctr_new = rxd_bitrate_ctr_reg + 1'h1;
|
||||
rxd_bitrate_ctr_we = 1'b1;
|
||||
end
|
||||
end // rxd_bitrate_ctr
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// txd_bit_ctr
|
||||
//
|
||||
// Bit counter for transmitting data on the external
|
||||
// serial interface.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin: txd_bit_ctr
|
||||
txd_bit_ctr_new = 5'h0;
|
||||
txd_bit_ctr_we = 1'h0;
|
||||
|
||||
if (txd_bit_ctr_rst) begin
|
||||
txd_bit_ctr_new = 5'h0;
|
||||
txd_bit_ctr_we = 1'h1;
|
||||
end
|
||||
|
||||
else if (txd_bit_ctr_inc) begin
|
||||
txd_bit_ctr_new = txd_bit_ctr_reg + 1'h1;
|
||||
txd_bit_ctr_we = 1'b1;
|
||||
end
|
||||
end // txd_bit_ctr
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// txd_bitrate_ctr
|
||||
//
|
||||
// Bitrate counter for transmitting data on the external
|
||||
// serial interface.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin: txd_bitrate_ctr
|
||||
txd_bitrate_ctr_new = 16'h0;
|
||||
txd_bitrate_ctr_we = 0;
|
||||
|
||||
if (txd_bitrate_ctr_rst) begin
|
||||
txd_bitrate_ctr_new = 16'h0;
|
||||
txd_bitrate_ctr_we = 1;
|
||||
end
|
||||
|
||||
else if (txd_bitrate_ctr_inc) begin
|
||||
txd_bitrate_ctr_new = txd_bitrate_ctr_reg + 1'h1;
|
||||
txd_bitrate_ctr_we = 1;
|
||||
end
|
||||
end // txd_bitrate_ctr
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// external_rx_engine
|
||||
//
|
||||
// Logic that implements the receive engine towards
|
||||
// the external interface. Detects incoming data, collects it,
|
||||
// if required checks parity and store correct data into
|
||||
// the rx buffer.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin: external_rx_engine
|
||||
rxd_bit_ctr_rst = 0;
|
||||
rxd_bit_ctr_inc = 0;
|
||||
rxd_bitrate_ctr_rst = 0;
|
||||
rxd_bitrate_ctr_inc = 0;
|
||||
rxd_byte_we = 0;
|
||||
rxd_syn_new = 0;
|
||||
rxd_syn_we = 0;
|
||||
erx_ctrl_new = ERX_IDLE;
|
||||
erx_ctrl_we = 0;
|
||||
|
||||
case (erx_ctrl_reg)
|
||||
ERX_IDLE: begin
|
||||
if (!rxd_reg) begin
|
||||
// Possible start bit detected.
|
||||
rxd_bitrate_ctr_rst = 1;
|
||||
erx_ctrl_new = ERX_START;
|
||||
erx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
|
||||
ERX_START: begin
|
||||
rxd_bitrate_ctr_inc = 1;
|
||||
if (rxd_reg) begin
|
||||
// Just a glitch.
|
||||
erx_ctrl_new = ERX_IDLE;
|
||||
erx_ctrl_we = 1;
|
||||
end
|
||||
|
||||
else begin
|
||||
if (rxd_bitrate_ctr_reg == half_bit_rate) begin
|
||||
// start bit assumed. We start sampling data.
|
||||
rxd_bit_ctr_rst = 1;
|
||||
rxd_bitrate_ctr_rst = 1;
|
||||
erx_ctrl_new = ERX_BITS;
|
||||
erx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ERX_BITS: begin
|
||||
if (rxd_bitrate_ctr_reg < bit_rate) begin
|
||||
rxd_bitrate_ctr_inc = 1;
|
||||
end
|
||||
|
||||
else begin
|
||||
rxd_byte_we = 1;
|
||||
rxd_bit_ctr_inc = 1;
|
||||
rxd_bitrate_ctr_rst = 1;
|
||||
if (rxd_bit_ctr_reg == data_bits - 1) begin
|
||||
erx_ctrl_new = ERX_STOP;
|
||||
erx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ERX_STOP: begin
|
||||
rxd_bitrate_ctr_inc = 1;
|
||||
if (rxd_bitrate_ctr_reg == bit_rate * stop_bits) begin
|
||||
rxd_syn_new = 1;
|
||||
rxd_syn_we = 1;
|
||||
erx_ctrl_new = ERX_SYN;
|
||||
erx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ERX_SYN: begin
|
||||
if (rxd_ack) begin
|
||||
rxd_syn_new = 0;
|
||||
rxd_syn_we = 1;
|
||||
erx_ctrl_new = ERX_IDLE;
|
||||
erx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
end
|
||||
|
||||
endcase // case (erx_ctrl_reg)
|
||||
end // external_rx_engine
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// external_tx_engine
|
||||
//
|
||||
// Logic that implements the transmit engine towards
|
||||
// the external interface.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin: external_tx_engine
|
||||
txd_new = 0;
|
||||
txd_we = 0;
|
||||
txd_byte_new = 0;
|
||||
txd_byte_we = 0;
|
||||
txd_bit_ctr_rst = 0;
|
||||
txd_bit_ctr_inc = 0;
|
||||
txd_bitrate_ctr_rst = 0;
|
||||
txd_bitrate_ctr_inc = 0;
|
||||
txd_ready_new = 0;
|
||||
txd_ready_we = 0;
|
||||
etx_ctrl_new = ETX_IDLE;
|
||||
etx_ctrl_we = 0;
|
||||
|
||||
case (etx_ctrl_reg)
|
||||
ETX_IDLE: begin
|
||||
txd_new = 1;
|
||||
txd_we = 1;
|
||||
if (txd_syn) begin
|
||||
txd_byte_new = txd_data;
|
||||
txd_byte_we = 1;
|
||||
txd_ready_new = 0;
|
||||
txd_ready_we = 1;
|
||||
txd_bitrate_ctr_rst = 1;
|
||||
etx_ctrl_new = ETX_ACK;
|
||||
etx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ETX_ACK: begin
|
||||
if (!txd_syn) begin
|
||||
txd_new = 0;
|
||||
txd_we = 1;
|
||||
etx_ctrl_new = ETX_START;
|
||||
etx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ETX_START: begin
|
||||
if (txd_bitrate_ctr_reg == bit_rate) begin
|
||||
txd_bit_ctr_rst = 1;
|
||||
etx_ctrl_new = ETX_BITS;
|
||||
etx_ctrl_we = 1;
|
||||
end
|
||||
|
||||
else begin
|
||||
txd_bitrate_ctr_inc = 1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ETX_BITS: begin
|
||||
if (txd_bitrate_ctr_reg < bit_rate) begin
|
||||
txd_bitrate_ctr_inc = 1;
|
||||
end
|
||||
|
||||
else begin
|
||||
txd_bitrate_ctr_rst = 1;
|
||||
if (txd_bit_ctr_reg == data_bits) begin
|
||||
txd_new = 1;
|
||||
txd_we = 1;
|
||||
etx_ctrl_new = ETX_STOP;
|
||||
etx_ctrl_we = 1;
|
||||
end
|
||||
|
||||
else begin
|
||||
txd_new = txd_byte_reg[txd_bit_ctr_reg];
|
||||
txd_we = 1;
|
||||
txd_bit_ctr_inc = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ETX_STOP: begin
|
||||
txd_bitrate_ctr_inc = 1;
|
||||
if (txd_bitrate_ctr_reg == bit_rate * stop_bits) begin
|
||||
txd_ready_new = 1;
|
||||
txd_ready_we = 1;
|
||||
etx_ctrl_new = ETX_IDLE;
|
||||
etx_ctrl_we = 1;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
end
|
||||
|
||||
endcase // case (etx_ctrl_reg)
|
||||
end // external_tx_engine
|
||||
|
||||
endmodule // uart
|
||||
|
||||
//======================================================================
|
||||
// EOF uart.v
|
||||
//======================================================================
|
179
hw/application_fpga/core/uart/rtl/uart_fifo.v
Normal file
179
hw/application_fpga/core/uart/rtl/uart_fifo.v
Normal file
|
@ -0,0 +1,179 @@
|
|||
//======================================================================
|
||||
//
|
||||
// uart_fifo.v
|
||||
// -----------
|
||||
// FIFO for rx and tx data buffering in the UART.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (c) 2022, Tillitis AB
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or
|
||||
// without modification, are permitted provided that the following
|
||||
// conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
module uart_fifo(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire in_syn,
|
||||
input wire [7 : 0] in_data,
|
||||
output wire in_ack,
|
||||
|
||||
output wire out_syn,
|
||||
output wire [7 : 0] out_data,
|
||||
input wire out_ack
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers including update variables and write enable.
|
||||
//----------------------------------------------------------------
|
||||
reg [7 : 0] fifo_mem [0 : 255];
|
||||
reg fifo_mem_we;
|
||||
|
||||
reg [7: 0] in_ptr_reg;
|
||||
reg [7: 0] in_ptr_new;
|
||||
reg in_ptr_inc;
|
||||
reg in_ptr_we;
|
||||
|
||||
reg [7: 0] out_ptr_reg;
|
||||
reg [7: 0] out_ptr_new;
|
||||
reg out_ptr_inc;
|
||||
reg out_ptr_we;
|
||||
|
||||
reg [7: 0] byte_ctr_reg;
|
||||
reg [7: 0] byte_ctr_new;
|
||||
reg byte_ctr_inc;
|
||||
reg byte_ctr_dec;
|
||||
reg byte_ctr_we;
|
||||
|
||||
reg in_ack_reg;
|
||||
reg in_ack_new;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign in_ack = in_ack_reg;
|
||||
|
||||
assign out_syn = |byte_ctr_reg;
|
||||
assign out_data = fifo_mem[out_ptr_reg];
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//----------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
begin: reg_update
|
||||
if (!reset_n) begin
|
||||
in_ptr_reg <= 8'h0;
|
||||
out_ptr_reg <= 8'h0;
|
||||
byte_ctr_reg <= 8'h0;
|
||||
in_ack_reg <= 1'h0;
|
||||
end
|
||||
else begin
|
||||
in_ack_reg <= in_ack_new;
|
||||
|
||||
if (fifo_mem_we) begin
|
||||
fifo_mem[in_ptr_reg] <= in_data;
|
||||
end
|
||||
|
||||
if (in_ptr_we) begin
|
||||
in_ptr_reg <= in_ptr_new;
|
||||
end
|
||||
|
||||
if (out_ptr_we) begin
|
||||
out_ptr_reg <= out_ptr_new;
|
||||
end
|
||||
|
||||
if (byte_ctr_we) begin
|
||||
byte_ctr_reg <= byte_ctr_new;
|
||||
end
|
||||
end
|
||||
end // reg_update
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// byte_ctr
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : byte_ctr
|
||||
byte_ctr_new = 8'h0;
|
||||
byte_ctr_we = 1'h0;
|
||||
|
||||
if ((byte_ctr_inc) && (!byte_ctr_dec)) begin
|
||||
byte_ctr_new = byte_ctr_reg + 1'h1;
|
||||
byte_ctr_we = 1'h1;
|
||||
end
|
||||
|
||||
else if ((!byte_ctr_inc) && (byte_ctr_dec)) begin
|
||||
byte_ctr_new = byte_ctr_reg - 1'h1;
|
||||
byte_ctr_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// in_logic
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : in_logic
|
||||
fifo_mem_we = 1'h0;
|
||||
in_ack_new = 1'h0;
|
||||
byte_ctr_inc = 1'h0;
|
||||
in_ptr_new = in_ptr_reg + 1'h1;
|
||||
in_ptr_we = 1'h0;
|
||||
|
||||
if ((in_syn) && (!in_ack) && (byte_ctr_reg < 8'hff)) begin
|
||||
fifo_mem_we = 1'h1;
|
||||
in_ack_new = 1'h1;
|
||||
byte_ctr_inc = 1'h1;
|
||||
in_ptr_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// out_logic
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : out_logic
|
||||
byte_ctr_dec = 1'h0;
|
||||
out_ptr_new = out_ptr_reg + 1'h1;
|
||||
out_ptr_we = 1'h0;
|
||||
|
||||
if ((out_ack) && (byte_ctr_reg > 8'h0)) begin
|
||||
byte_ctr_dec = 1'h1;
|
||||
out_ptr_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // uart_fifo
|
||||
|
||||
//======================================================================
|
||||
// EOF uart_fifo.v
|
||||
//======================================================================
|
389
hw/application_fpga/core/uart/tb/tb_uart.v
Normal file
389
hw/application_fpga/core/uart/tb/tb_uart.v
Normal file
|
@ -0,0 +1,389 @@
|
|||
//======================================================================
|
||||
//
|
||||
// tb_uart.v
|
||||
// ---------
|
||||
// Testbench for the UART core.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (c) 2014, Secworks Sweden AB
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or
|
||||
// without modification, are permitted provided that the following
|
||||
// conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
module tb_uart();
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Internal constant and parameter definitions.
|
||||
//----------------------------------------------------------------
|
||||
parameter DEBUG = 0;
|
||||
parameter VERBOSE = 0;
|
||||
|
||||
parameter CLK_HALF_PERIOD = 1;
|
||||
parameter CLK_PERIOD = CLK_HALF_PERIOD * 2;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Register and Wire declarations.
|
||||
//----------------------------------------------------------------
|
||||
reg [31 : 0] cycle_ctr;
|
||||
reg [31 : 0] error_ctr;
|
||||
reg [31 : 0] tc_ctr;
|
||||
|
||||
reg tb_clk;
|
||||
reg tb_reset_n;
|
||||
reg tb_rxd;
|
||||
wire tb_txd;
|
||||
wire tb_rxd_syn;
|
||||
wire [7 : 0] tb_rxd_data;
|
||||
wire tb_rxd_ack;
|
||||
wire tb_txd_syn;
|
||||
wire [7 : 0] tb_txd_data;
|
||||
wire tb_txd_ack;
|
||||
reg tb_cs;
|
||||
reg tb_we;
|
||||
reg [7 : 0] tb_address;
|
||||
reg [31 : 0] tb_write_data;
|
||||
wire [31 : 0] tb_read_data;
|
||||
wire tb_error;
|
||||
wire [7 : 0] tb_debug;
|
||||
|
||||
reg txd_state;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Device Under Test.
|
||||
//----------------------------------------------------------------
|
||||
uart dut(
|
||||
.clk(tb_clk),
|
||||
.reset_n(tb_reset_n),
|
||||
|
||||
.rxd(tb_rxd),
|
||||
.txd(tb_txd),
|
||||
|
||||
.rxd_syn(tb_rxd_syn),
|
||||
.rxd_data(tb_rxd_data),
|
||||
.rxd_ack(tb_rxd_ack),
|
||||
|
||||
// Internal transmit interface.
|
||||
.txd_syn(tb_txd_syn),
|
||||
.txd_data(tb_txd_data),
|
||||
.txd_ack(tb_txd_ack),
|
||||
|
||||
// API interface.
|
||||
.cs(tb_cs),
|
||||
.we(tb_we),
|
||||
.address(tb_address),
|
||||
.write_data(tb_write_data),
|
||||
.read_data(tb_read_data),
|
||||
.error(tb_error),
|
||||
|
||||
.debug(tb_debug)
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent assignments.
|
||||
//----------------------------------------------------------------
|
||||
// We connect the internal facing ports on the dut together.
|
||||
assign tb_txd_syn = tb_rxd_syn;
|
||||
assign tb_txd_data = tb_rxd_data;
|
||||
assign tb_rxd_ack = tb_txd_ack;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// clk_gen
|
||||
//
|
||||
// Clock generator process.
|
||||
//----------------------------------------------------------------
|
||||
always
|
||||
begin : clk_gen
|
||||
#CLK_HALF_PERIOD tb_clk = !tb_clk;
|
||||
end // clk_gen
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// sys_monitor
|
||||
//----------------------------------------------------------------
|
||||
always
|
||||
begin : sys_monitor
|
||||
#(CLK_PERIOD);
|
||||
if (DEBUG)
|
||||
begin
|
||||
dump_rx_state();
|
||||
dump_tx_state();
|
||||
$display("");
|
||||
end
|
||||
if (VERBOSE)
|
||||
begin
|
||||
$display("cycle: 0x%016x", cycle_ctr);
|
||||
end
|
||||
cycle_ctr = cycle_ctr + 1;
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tx_monitor
|
||||
//
|
||||
// Observes what happens on the dut tx port and reports it.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : tx_monitor
|
||||
if ((!tb_txd) && txd_state)
|
||||
begin
|
||||
$display("txd going low.");
|
||||
txd_state = 0;
|
||||
end
|
||||
|
||||
if (tb_txd && (!txd_state))
|
||||
begin
|
||||
$display("txd going high");
|
||||
txd_state = 1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// dump_dut_state()
|
||||
//
|
||||
// Dump the state of the dut when needed.
|
||||
//----------------------------------------------------------------
|
||||
task dump_dut_state;
|
||||
begin
|
||||
$display("State of DUT");
|
||||
$display("------------");
|
||||
$display("Inputs and outputs:");
|
||||
$display("rxd = 0x%01x, txd = 0x%01x,",
|
||||
dut.core.rxd, dut.core.txd);
|
||||
$display("");
|
||||
|
||||
$display("Sample and data registers:");
|
||||
$display("rxd_reg = 0x%01x, rxd_byte_reg = 0x%01x",
|
||||
dut.core.rxd_reg, dut.core.rxd_byte_reg);
|
||||
$display("");
|
||||
|
||||
$display("Counters:");
|
||||
$display("rxd_bit_ctr_reg = 0x%01x, rxd_bitrate_ctr_reg = 0x%02x",
|
||||
dut.core.rxd_bit_ctr_reg, dut.core.rxd_bitrate_ctr_reg);
|
||||
$display("");
|
||||
|
||||
|
||||
$display("Control signals and FSM state:");
|
||||
$display("erx_ctrl_reg = 0x%02x",
|
||||
dut.core.erx_ctrl_reg);
|
||||
$display("");
|
||||
end
|
||||
endtask // dump_dut_state
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// dump_rx_state()
|
||||
//
|
||||
// Dump the state of the rx engine.
|
||||
//----------------------------------------------------------------
|
||||
task dump_rx_state;
|
||||
begin
|
||||
$display("rxd = 0x%01x, rxd_reg = 0x%01x, rxd_byte_reg = 0x%01x, rxd_bit_ctr_reg = 0x%01x, rxd_bitrate_ctr_reg = 0x%02x, rxd_syn = 0x%01x, erx_ctrl_reg = 0x%02x",
|
||||
dut.core.rxd, dut.core.rxd_reg, dut.core.rxd_byte_reg, dut.core.rxd_bit_ctr_reg,
|
||||
dut.core.rxd_bitrate_ctr_reg, dut.core.rxd_syn, dut.core.erx_ctrl_reg);
|
||||
end
|
||||
endtask // dump_dut_state
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// dump_tx_state()
|
||||
//
|
||||
// Dump the state of the tx engine.
|
||||
//----------------------------------------------------------------
|
||||
task dump_tx_state;
|
||||
begin
|
||||
$display("txd = 0x%01x, txd_reg = 0x%01x, txd_byte_reg = 0x%01x, txd_bit_ctr_reg = 0x%01x, txd_bitrate_ctr_reg = 0x%02x, txd_ack = 0x%01x, etx_ctrl_reg = 0x%02x",
|
||||
dut.core.txd, dut.core.txd_reg, dut.core.txd_byte_reg, dut.core.txd_bit_ctr_reg,
|
||||
dut.core.txd_bitrate_ctr_reg, dut.core.txd_ack, dut.core.etx_ctrl_reg);
|
||||
end
|
||||
endtask // dump_dut_state
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reset_dut()
|
||||
//----------------------------------------------------------------
|
||||
task reset_dut;
|
||||
begin
|
||||
$display("*** Toggle reset.");
|
||||
tb_reset_n = 0;
|
||||
#(2 * CLK_PERIOD);
|
||||
tb_reset_n = 1;
|
||||
end
|
||||
endtask // reset_dut
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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_clk = 0;
|
||||
tb_reset_n = 1;
|
||||
tb_rxd = 1;
|
||||
tb_cs = 0;
|
||||
tb_we = 0;
|
||||
tb_address = 8'h00;
|
||||
tb_write_data = 32'h00000000;
|
||||
|
||||
txd_state = 1;
|
||||
end
|
||||
endtask // init_sim
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// transmit_byte
|
||||
//
|
||||
// Transmit a byte of data to the DUT receive port.
|
||||
//----------------------------------------------------------------
|
||||
task transmit_byte(input [7 : 0] data);
|
||||
integer i;
|
||||
begin
|
||||
$display("*** Transmitting byte 0x%02x to the dut.", data);
|
||||
|
||||
#10;
|
||||
|
||||
// Start bit
|
||||
$display("*** Transmitting start bit.");
|
||||
tb_rxd = 0;
|
||||
#(CLK_PERIOD * dut.DEFAULT_BIT_RATE);
|
||||
|
||||
// Send the bits LSB first.
|
||||
for (i = 0 ; i < 8 ; i = i + 1)
|
||||
begin
|
||||
$display("*** Transmitting data[%1d] = 0x%01x.", i, data[i]);
|
||||
tb_rxd = data[i];
|
||||
#(CLK_PERIOD * dut.DEFAULT_BIT_RATE);
|
||||
end
|
||||
|
||||
// Send two stop bits. I.e. two bit times high (mark) value.
|
||||
$display("*** Transmitting two stop bits.");
|
||||
tb_rxd = 1;
|
||||
#(2 * CLK_PERIOD * dut.DEFAULT_BIT_RATE * dut.DEFAULT_STOP_BITS);
|
||||
$display("*** End of transmission.");
|
||||
end
|
||||
endtask // transmit_byte
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// check_transmit
|
||||
//
|
||||
// Transmits a byte and checks that it was captured internally
|
||||
// by the dut.
|
||||
//----------------------------------------------------------------
|
||||
task check_transmit(input [7 : 0] data);
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
|
||||
transmit_byte(data);
|
||||
|
||||
if (dut.core.rxd_byte_reg == data)
|
||||
begin
|
||||
$display("*** Correct data: 0x%01x captured by the dut.",
|
||||
dut.core.rxd_byte_reg);
|
||||
end
|
||||
else
|
||||
begin
|
||||
$display("*** Incorrect data: 0x%01x captured by the dut Should be: 0x%01x.",
|
||||
dut.core.rxd_byte_reg, data);
|
||||
error_ctr = error_ctr + 1;
|
||||
end
|
||||
end
|
||||
endtask // check_transmit
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test_transmit
|
||||
//
|
||||
// Transmit a number of test bytes to the dut.
|
||||
//----------------------------------------------------------------
|
||||
task test_transmit;
|
||||
begin
|
||||
check_transmit(8'h55);
|
||||
check_transmit(8'h42);
|
||||
check_transmit(8'hde);
|
||||
check_transmit(8'had);
|
||||
end
|
||||
endtask // test_transmit
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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 test cases did not complete successfully.", error_ctr);
|
||||
end
|
||||
end
|
||||
endtask // display_test_result
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// uart_test
|
||||
// The main test functionality.
|
||||
//----------------------------------------------------------------
|
||||
initial
|
||||
begin : uart_test
|
||||
$display(" -- Testbench for uart core started --");
|
||||
|
||||
init_sim();
|
||||
dump_dut_state();
|
||||
reset_dut();
|
||||
dump_dut_state();
|
||||
|
||||
test_transmit();
|
||||
|
||||
display_test_result();
|
||||
$display("*** Simulation done.");
|
||||
$finish;
|
||||
end // uart_test
|
||||
endmodule // tb_uart
|
||||
|
||||
//======================================================================
|
||||
// EOF tb_uart.v
|
||||
//======================================================================
|
7
hw/application_fpga/core/uds/README.txt
Normal file
7
hw/application_fpga/core/uds/README.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
# uds
|
||||
|
||||
Unique Device Secret core
|
||||
|
||||
## Introduction
|
||||
This core store and protect the Unique Device Secret. The
|
||||
storage is implemented in discrete registers. The contents can be read once between chip reset, and only if the system is in not in application access mode.
|
129
hw/application_fpga/core/uds/rtl/uds.v
Normal file
129
hw/application_fpga/core/uds/rtl/uds.v
Normal file
|
@ -0,0 +1,129 @@
|
|||
//======================================================================
|
||||
//
|
||||
// uds.v
|
||||
// --------
|
||||
// Top level wrapper for the uds core.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module uds(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
output wire fw_app_mode,
|
||||
|
||||
input wire cs,
|
||||
input wire [7 : 0] address,
|
||||
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_UDS_FIRST = 8'h10;
|
||||
localparam ADDR_UDS_LAST = 8'h17;
|
||||
|
||||
localparam CORE_NAME0 = 32'h7564735f; // "uds_"
|
||||
localparam CORE_NAME1 = 32'h6d656d20; // "mem "
|
||||
localparam CORE_VERSION = 32'h00000001;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers including update variables and write enable.
|
||||
//----------------------------------------------------------------
|
||||
reg [31 : 0] uds_reg [0 : 7];
|
||||
initial $readmemh(`UDS_HEX, uds_reg);
|
||||
|
||||
reg uds_rd_reg [0 : 7];
|
||||
reg uds_rd_we;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Wires.
|
||||
//----------------------------------------------------------------
|
||||
reg [31 : 0] tmp_read_data;
|
||||
reg tmp_ready;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent connectivity for ports etc.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = tmp_ready;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//----------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
begin : reg_update
|
||||
integer i;
|
||||
|
||||
if (!reset_n) begin
|
||||
for (i = 0 ; i < 8 ; i = i + 1) begin
|
||||
uds_rd_reg[i] <= 1'h0;;
|
||||
end
|
||||
end
|
||||
else begin
|
||||
if (uds_rd_we) begin
|
||||
uds_rd_reg[address[2 : 0]] <= 1'h1;
|
||||
end
|
||||
end
|
||||
end // reg_update
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// api
|
||||
//
|
||||
// The interface command decoding logic.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : api
|
||||
uds_rd_we = 1'h0;
|
||||
tmp_read_data = 32'h0;
|
||||
tmp_ready = 1'h0;
|
||||
|
||||
if (cs) begin
|
||||
tmp_ready = 1'h1;
|
||||
|
||||
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_UDS_FIRST) && (address <= ADDR_UDS_LAST)) begin
|
||||
if (!fw_app_mode) begin
|
||||
if (uds_rd_reg[address[2 : 0]] == 1'h0) begin
|
||||
tmp_read_data = uds_reg[address[2 : 0]];
|
||||
uds_rd_we = 1'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // uds
|
||||
|
||||
//======================================================================
|
||||
// EOF uds.v
|
||||
//======================================================================
|
300
hw/application_fpga/core/uds/tb/tb_uds.v
Normal file
300
hw/application_fpga/core/uds/tb/tb_uds.v
Normal file
|
@ -0,0 +1,300 @@
|
|||
//======================================================================
|
||||
//
|
||||
// tb_uds.v
|
||||
// -----------
|
||||
// Testbench for the UDS core.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module tb_uds();
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Internal constant and parameter definitions.
|
||||
//----------------------------------------------------------------
|
||||
parameter DEBUG = 1;
|
||||
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_UDS_FIRST = 8'h10;
|
||||
localparam ADDR_UDS_LAST = 8'h17;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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 [7 : 0] tb_address;
|
||||
wire [31 : 0] tb_read_data;
|
||||
|
||||
reg [31 : 0] read_data;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Device Under Test.
|
||||
//----------------------------------------------------------------
|
||||
uds dut(
|
||||
.clk(tb_clk),
|
||||
.reset_n(tb_reset_n),
|
||||
|
||||
.cs(tb_cs),
|
||||
|
||||
.address(tb_address),
|
||||
.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 : dump_dut_state
|
||||
integer i;
|
||||
$display("State of DUT");
|
||||
$display("------------");
|
||||
$display("Cycle: %08d", cycle_ctr);
|
||||
for (i = 0 ; i < 8 ; i = i + 1) begin
|
||||
$display("uds_reg[%1d]: 0x%08x, uds_rd_reg[%1d]: 0x%1x",
|
||||
i, dut.uds_reg[i], i, dut.uds_rd_reg[i]);
|
||||
end
|
||||
$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("--- 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_address = 8'h0;
|
||||
end
|
||||
endtask // init_sim
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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;
|
||||
#(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
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test1()
|
||||
//----------------------------------------------------------------
|
||||
task test1;
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
tb_monitor = 1'h0;
|
||||
|
||||
$display("");
|
||||
$display("--- test1: started.");
|
||||
|
||||
$display("--- test1: Reading NAME and version info.");
|
||||
read_word(ADDR_NAME0);
|
||||
read_word(ADDR_NAME1);
|
||||
read_word(ADDR_VERSION);
|
||||
|
||||
$display("--- test1: Dumping DUT state to show UDS contents");
|
||||
dump_dut_state();
|
||||
|
||||
$display("--- test1: Reading UDS words.");
|
||||
read_word(ADDR_UDS_FIRST + 0);
|
||||
read_word(ADDR_UDS_FIRST + 1);
|
||||
read_word(ADDR_UDS_FIRST + 2);
|
||||
|
||||
$display("--- test1: Dumping state again to see read bits.");
|
||||
dump_dut_state();
|
||||
|
||||
$display("--- test1: Reading rest of the words.");
|
||||
read_word(ADDR_UDS_FIRST + 3);
|
||||
read_word(ADDR_UDS_FIRST + 4);
|
||||
read_word(ADDR_UDS_FIRST + 5);
|
||||
read_word(ADDR_UDS_FIRST + 6);
|
||||
read_word(ADDR_UDS_FIRST + 7);
|
||||
|
||||
$display("--- test1: Dumping state again to see read bits.");
|
||||
dump_dut_state();
|
||||
|
||||
$display("--- test1: Reading UDS words again.");
|
||||
read_word(ADDR_UDS_FIRST + 0);
|
||||
read_word(ADDR_UDS_FIRST + 1);
|
||||
read_word(ADDR_UDS_FIRST + 2);
|
||||
read_word(ADDR_UDS_FIRST + 3);
|
||||
read_word(ADDR_UDS_FIRST + 4);
|
||||
read_word(ADDR_UDS_FIRST + 5);
|
||||
read_word(ADDR_UDS_FIRST + 6);
|
||||
read_word(ADDR_UDS_FIRST + 7);
|
||||
|
||||
$display("--- test1: Resetting DUT.");
|
||||
reset_dut();
|
||||
|
||||
$display("--- test1: Dumping state again to see read bits.");
|
||||
dump_dut_state();
|
||||
|
||||
$display("--- test1: Reading UDS words.");
|
||||
read_word(ADDR_UDS_FIRST + 0);
|
||||
read_word(ADDR_UDS_FIRST + 1);
|
||||
read_word(ADDR_UDS_FIRST + 2);
|
||||
read_word(ADDR_UDS_FIRST + 3);
|
||||
read_word(ADDR_UDS_FIRST + 4);
|
||||
read_word(ADDR_UDS_FIRST + 5);
|
||||
read_word(ADDR_UDS_FIRST + 6);
|
||||
read_word(ADDR_UDS_FIRST + 7);
|
||||
|
||||
$display("--- test1: Reading UDS words again.");
|
||||
read_word(ADDR_UDS_FIRST + 0);
|
||||
read_word(ADDR_UDS_FIRST + 1);
|
||||
read_word(ADDR_UDS_FIRST + 2);
|
||||
read_word(ADDR_UDS_FIRST + 3);
|
||||
read_word(ADDR_UDS_FIRST + 4);
|
||||
read_word(ADDR_UDS_FIRST + 5);
|
||||
read_word(ADDR_UDS_FIRST + 6);
|
||||
read_word(ADDR_UDS_FIRST + 7);
|
||||
|
||||
$display("--- test1: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // tes1
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// uds_test
|
||||
//----------------------------------------------------------------
|
||||
initial
|
||||
begin : uds_test
|
||||
$display("");
|
||||
$display(" -= Testbench for uds started =-");
|
||||
$display(" ===========================");
|
||||
$display("");
|
||||
|
||||
init_sim();
|
||||
reset_dut();
|
||||
test1();
|
||||
|
||||
display_test_result();
|
||||
$display("");
|
||||
$display(" -= Testbench for uds started =-");
|
||||
$display(" ===========================");
|
||||
$display("");
|
||||
$finish;
|
||||
end // uds_test
|
||||
endmodule // tb_uds
|
||||
|
||||
//======================================================================
|
||||
// EOF tb_uds.v
|
||||
//======================================================================
|
55
hw/application_fpga/core/uds/toolruns/Makefile
Executable file
55
hw/application_fpga/core/uds/toolruns/Makefile
Executable file
|
@ -0,0 +1,55 @@
|
|||
#===================================================================
|
||||
#
|
||||
# Makefile
|
||||
# --------
|
||||
# Makefile for building the UDS core.
|
||||
#
|
||||
#
|
||||
# Author: Joachim Strombergson
|
||||
# Copyright (C) 2022 - Tillitis AB
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
#===================================================================
|
||||
|
||||
TOP_SRC=../rtl/uds.v
|
||||
TB_TOP_SRC =../tb/tb_uds.v
|
||||
|
||||
CC = iverilog
|
||||
CC_FLAGS = -Wall
|
||||
|
||||
LINT = verilator
|
||||
LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
|
||||
|
||||
|
||||
all: top.sim
|
||||
|
||||
|
||||
top.sim: $(TB_TOP_SRC) $(TOP_SRC)
|
||||
$(CC) $(CC_FLAGS) -o top.sim $(TB_TOP_SRC) $(TOP_SRC)
|
||||
|
||||
|
||||
sim-top: top.sim
|
||||
./top.sim
|
||||
|
||||
|
||||
lint-top: $(TOP_SRC)
|
||||
$(LINT) $(LINT_FLAGS) $(TOP_SRC)
|
||||
|
||||
|
||||
clean:
|
||||
rm -f top.sim
|
||||
|
||||
|
||||
help:
|
||||
@echo "Build system for simulation of UDS core"
|
||||
@echo ""
|
||||
@echo "Supported targets:"
|
||||
@echo "------------------"
|
||||
@echo "top.sim: Build top level simulation target."
|
||||
@echo "sim-top: Run top level simulation."
|
||||
@echo "lint-top: Lint top rtl source files."
|
||||
@echo "clean: Delete all built files."
|
||||
|
||||
#===================================================================
|
||||
# EOF Makefile
|
||||
#===================================================================
|
Loading…
Add table
Add a link
Reference in a new issue