mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-05-02 06:06:24 -04:00
FPGA: Move all sub modules into separate cores
Signed-off-by: Joachim Strömbergson <joachim@assured.se>
This commit is contained in:
parent
b8f22a9810
commit
d1cff273d7
5 changed files with 4 additions and 4 deletions
137
hw/application_fpga/core/clk_reset_gen/rtl/clk_reset_gen.v
Normal file
137
hw/application_fpga/core/clk_reset_gen/rtl/clk_reset_gen.v
Normal file
|
@ -0,0 +1,137 @@
|
|||
//======================================================================
|
||||
//
|
||||
// clk_reset_gen.v
|
||||
// -----------
|
||||
// Clock and reset generator used in the Tillitis Key 1 design.
|
||||
// This module instantiate the internal SB_HFOSC clock source in the
|
||||
// Lattice ice40 UP device. It then connects it to the PLL, and
|
||||
// finally connects the output from the PLL to the global clock net.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module clk_reset_gen #(parameter RESET_CYCLES = 200)
|
||||
(
|
||||
input wire sys_reset,
|
||||
|
||||
output wire clk,
|
||||
output wire rst_n
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers with associated wires.
|
||||
//----------------------------------------------------------------
|
||||
reg [7 : 0] rst_ctr_reg = 8'h0;
|
||||
reg [7 : 0] rst_ctr_new;
|
||||
reg rst_ctr_we;
|
||||
|
||||
reg rst_n_reg = 1'h0;
|
||||
reg rst_n_new;
|
||||
|
||||
reg sys_reset_reg;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Wires.
|
||||
//----------------------------------------------------------------
|
||||
wire hfosc_clk;
|
||||
wire pll_clk;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent assignment.
|
||||
//----------------------------------------------------------------
|
||||
assign rst_n = rst_n_reg;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Core instantiations.
|
||||
//----------------------------------------------------------------
|
||||
/* verilator lint_off PINMISSING */
|
||||
|
||||
// Use the FPGA internal High Frequency OSCillator as clock source.
|
||||
// 00: 48MHz, 01: 24MHz, 10: 12MHz, 11: 6MHz
|
||||
SB_HFOSC #(.CLKHF_DIV("0b10")
|
||||
) hfosc_inst (.CLKHFPU(1'b1),.CLKHFEN(1'b1),.CLKHF(hfosc_clk));
|
||||
|
||||
|
||||
// Use a PLL to generate a new clock frequency based on the HFOSC clock.
|
||||
//
|
||||
// Given FEEDBACK_PATH=="SIMPLE", clock calculation according to 3.5.2 in
|
||||
// FPGA-TN-02052-1-4-iCE40-sysCLOCK-PLL-Design-User-Guide.pdf
|
||||
// https://www.latticesemi.com/view_document?document_id=47778 follows:
|
||||
//
|
||||
// F_pllout == (F_referenceclk * (DIVF + 1)) / (2^DIVQ * (DIVR + 1))
|
||||
//
|
||||
// Given the 12 MHz HFOSC clock set above, we get a final 21 MHz:
|
||||
//
|
||||
// (12000000 * (55 + 1)) / (2^5 * (0 + 1)) = 21000000
|
||||
SB_PLL40_CORE #(
|
||||
.FEEDBACK_PATH("SIMPLE"),
|
||||
.DIVR(4'd0), // DIVR = 0
|
||||
.DIVF(7'd55), // DIVF = 55
|
||||
.DIVQ(3'd5), // DIVQ = 5
|
||||
.FILTER_RANGE(3'b001) // FILTER_RANGE = 1
|
||||
) pll_inst (
|
||||
.RESETB(1'b1),
|
||||
.BYPASS(1'b0),
|
||||
.REFERENCECLK(hfosc_clk),
|
||||
.PLLOUTCORE(pll_clk)
|
||||
);
|
||||
|
||||
|
||||
// Use a Global Buffer to distribute the clock.
|
||||
SB_GB gb_inst (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER (pll_clk),
|
||||
.GLOBAL_BUFFER_OUTPUT (clk)
|
||||
);
|
||||
|
||||
/* verilator lint_on PINMISSING */
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update.
|
||||
//----------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
begin : reg_update
|
||||
rst_n_reg <= rst_n_new;
|
||||
sys_reset_reg <= sys_reset;
|
||||
|
||||
if (rst_ctr_we)
|
||||
rst_ctr_reg <= rst_ctr_new;
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// rst_logic.
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : rst_logic
|
||||
rst_n_new = 1'h1;
|
||||
rst_ctr_new = 8'h0;
|
||||
rst_ctr_we = 1'h0;
|
||||
|
||||
if (sys_reset_reg) begin
|
||||
rst_ctr_new = 8'h0;
|
||||
rst_ctr_we = 1'h1;
|
||||
end
|
||||
|
||||
else if (rst_ctr_reg < RESET_CYCLES) begin
|
||||
rst_n_new = 1'h0;
|
||||
rst_ctr_new = rst_ctr_reg + 1'h1;
|
||||
rst_ctr_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // reset_gen
|
||||
|
||||
//======================================================================
|
||||
// EOF reset_gen.v
|
||||
//======================================================================
|
150
hw/application_fpga/core/fw_ram/rtl/fw_ram.v
Normal file
150
hw/application_fpga/core/fw_ram/rtl/fw_ram.v
Normal file
|
@ -0,0 +1,150 @@
|
|||
//======================================================================
|
||||
//
|
||||
// fw_ram.v
|
||||
// --------
|
||||
// A 512 x 32 RAM (2048 bytes) for use by the FW. The memory has
|
||||
// support for mode based access control.
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module fw_ram(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire fw_app_mode,
|
||||
|
||||
input wire cs,
|
||||
input wire [3 : 0] we,
|
||||
input wire [8 : 0] address,
|
||||
input wire [31 : 0] write_data,
|
||||
output wire [31 : 0] read_data,
|
||||
output wire ready
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers and wires.
|
||||
//----------------------------------------------------------------
|
||||
reg [31 : 0] tmp_read_data;
|
||||
reg [31 : 0] mem_read_data0;
|
||||
reg [31 : 0] mem_read_data1;
|
||||
reg ready_reg;
|
||||
wire fw_app_cs;
|
||||
reg bank0;
|
||||
reg bank1;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent assignment of ports.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = ready_reg;
|
||||
assign fw_app_cs = cs && ~fw_app_mode;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Block RAM instances.
|
||||
//----------------------------------------------------------------
|
||||
SB_RAM40_4K fw_ram0_0(
|
||||
.RDATA(mem_read_data0[15 : 0]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(fw_app_cs & bank0),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[15 : 0]),
|
||||
.WE((|we & fw_app_cs & bank0)),
|
||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K fw_ram0_1(
|
||||
.RDATA(mem_read_data0[31 : 16]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(fw_app_cs & bank0),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[31 : 16]),
|
||||
.WE((|we & fw_app_cs & bank0)),
|
||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||
);
|
||||
|
||||
|
||||
SB_RAM40_4K fw_ram1_0(
|
||||
.RDATA(mem_read_data1[15 : 0]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(fw_app_cs & bank1),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[15 : 0]),
|
||||
.WE((|we & fw_app_cs & bank1)),
|
||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K fw_ram1_1(
|
||||
.RDATA(mem_read_data1[31 : 16]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(fw_app_cs & bank1),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[31 : 16]),
|
||||
.WE((|we & fw_app_cs & bank1)),
|
||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//----------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
begin : reg_update
|
||||
if (!reset_n) begin
|
||||
ready_reg <= 1'h0;
|
||||
end
|
||||
else begin
|
||||
ready_reg <= cs;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// rw_mux
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : rw_mux;
|
||||
bank0 = 1'h0;
|
||||
bank1 = 1'h0;
|
||||
tmp_read_data = 32'h0;
|
||||
|
||||
if (fw_app_cs) begin
|
||||
if (address[8]) begin
|
||||
bank1 = 1'h1;
|
||||
tmp_read_data = mem_read_data1;
|
||||
end
|
||||
else begin
|
||||
bank0 = 1'h1;
|
||||
tmp_read_data = mem_read_data0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // fw_ram
|
||||
|
||||
//======================================================================
|
||||
// EOF fw_ram.v
|
||||
//======================================================================
|
142
hw/application_fpga/core/ram/rtl/ram.v
Normal file
142
hw/application_fpga/core/ram/rtl/ram.v
Normal file
|
@ -0,0 +1,142 @@
|
|||
//======================================================================
|
||||
//
|
||||
// ram.v
|
||||
// -----
|
||||
// Module that encapsulates the four SPRAM blocks in the Lattice
|
||||
// iCE40UP 5K device. This creates a single 32-bit wide,
|
||||
// 128 kByte large memory.
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module ram(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
input wire cs,
|
||||
input wire [03 : 0] we,
|
||||
input wire [14 : 0] address,
|
||||
input wire [31 : 0] write_data,
|
||||
output wire [31 : 0] read_data,
|
||||
output wire ready
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers and wires.
|
||||
//----------------------------------------------------------------
|
||||
reg ready_reg;
|
||||
|
||||
reg cs0;
|
||||
reg cs1;
|
||||
reg [31 : 0] read_data0;
|
||||
reg [31 : 0] read_data1;
|
||||
reg [31 : 0] muxed_read_data;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent assignment of ports.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = muxed_read_data;
|
||||
assign ready = ready_reg;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// SPRAM instances.
|
||||
//----------------------------------------------------------------
|
||||
SB_SPRAM256KA spram0(
|
||||
.ADDRESS(address[13:0]),
|
||||
.DATAIN(write_data[15:0]),
|
||||
.MASKWREN({we[1], we[1], we[0], we[0]}),
|
||||
.WREN(we[1] | we[0]),
|
||||
.CHIPSELECT(cs0),
|
||||
.CLOCK(clk),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1),
|
||||
.DATAOUT(read_data0[15:0])
|
||||
);
|
||||
|
||||
SB_SPRAM256KA spram1(
|
||||
.ADDRESS(address[13:0]),
|
||||
.DATAIN(write_data[31:16]),
|
||||
.MASKWREN({we[3], we[3], we[2], we[2]}),
|
||||
.WREN(we[3] | we[2]),
|
||||
.CHIPSELECT(cs0),
|
||||
.CLOCK(clk),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1),
|
||||
.DATAOUT(read_data0[31:16])
|
||||
);
|
||||
|
||||
|
||||
SB_SPRAM256KA spram2(
|
||||
.ADDRESS(address[13:0]),
|
||||
.DATAIN(write_data[15:0]),
|
||||
.MASKWREN({we[1], we[1], we[0], we[0]}),
|
||||
.WREN(we[1] | we[0]),
|
||||
.CHIPSELECT(cs1),
|
||||
.CLOCK(clk),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1),
|
||||
.DATAOUT(read_data1[15:0])
|
||||
);
|
||||
|
||||
SB_SPRAM256KA spram3(
|
||||
.ADDRESS(address[13:0]),
|
||||
.DATAIN(write_data[31:16]),
|
||||
.MASKWREN({we[3], we[3], we[2], we[2]}),
|
||||
.WREN(we[3] | we[2]),
|
||||
.CHIPSELECT(cs1),
|
||||
.CLOCK(clk),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1),
|
||||
.DATAOUT(read_data1[31:16])
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//
|
||||
// Posedge triggered with synchronous, active low reset.
|
||||
// This simply creates a one cycle access latency to match
|
||||
// the latency of the spram blocks.
|
||||
//----------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
begin : reg_update
|
||||
if (!reset_n) begin
|
||||
ready_reg <= 1'h0;
|
||||
end
|
||||
else begin
|
||||
ready_reg <= cs;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// mem_mux
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : mem_mux
|
||||
cs0 = ~address[14] & cs;
|
||||
cs1 = address[14] & cs;
|
||||
|
||||
if (address[14]) begin
|
||||
muxed_read_data = read_data1;
|
||||
end else begin
|
||||
muxed_read_data = read_data0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // ram
|
||||
|
||||
//======================================================================
|
||||
// EOF ram.v
|
||||
//======================================================================
|
86
hw/application_fpga/core/rom/rtl/rom.v
Normal file
86
hw/application_fpga/core/rom/rtl/rom.v
Normal file
|
@ -0,0 +1,86 @@
|
|||
//======================================================================
|
||||
//
|
||||
// rom..v
|
||||
// ------
|
||||
// Firmware ROM module. Implemented using Embedded Block RAM
|
||||
// in the FPGA.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2022 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module rom(
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire cs,
|
||||
/* verilator lint_off UNUSED */
|
||||
input wire [11 : 0] address,
|
||||
/* verilator lint_on UNUSED */
|
||||
output wire [31 : 0] read_data,
|
||||
output wire ready
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers, memories with associated wires.
|
||||
//----------------------------------------------------------------
|
||||
// Size of the sysMem Embedded Block RAM (EBR) memory primarily
|
||||
// used for code storage (ROM). The size is number of
|
||||
// 32-bit words. Each EBR is 4kbit in size, and (at most)
|
||||
// 16-bit wide. Thus means that we use pairs of EBRs, and
|
||||
// each pair store 256 32bit words.
|
||||
// The size of the EBR allocated to memory must match the
|
||||
// size of the firmware file generated by the Makefile.
|
||||
//
|
||||
// Max size for the ROM is 3072 words, and the address is
|
||||
// 12 bits to support ROM with this number of words.
|
||||
localparam EBR_MEM_SIZE = `BRAM_FW_SIZE;
|
||||
reg [31 : 0] memory [0 : (EBR_MEM_SIZE - 1)];
|
||||
initial $readmemh(`FIRMWARE_HEX, memory);
|
||||
|
||||
reg [31 : 0] rom_rdata;
|
||||
reg ready_reg;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Concurrent assignments of ports.
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = rom_rdata;
|
||||
assign ready = ready_reg;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reg_update
|
||||
//----------------------------------------------------------------
|
||||
always @ (posedge clk)
|
||||
begin : reg_update
|
||||
if (!reset_n) begin
|
||||
ready_reg <= 1'h0;
|
||||
end
|
||||
else begin
|
||||
ready_reg <= cs;
|
||||
end
|
||||
end // reg_update
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// rom_logic
|
||||
//----------------------------------------------------------------
|
||||
always @*
|
||||
begin : rom_logic
|
||||
/* verilator lint_off WIDTH */
|
||||
rom_rdata = memory[address];
|
||||
/* verilator lint_on WIDTH */
|
||||
end
|
||||
|
||||
endmodule // rom
|
||||
|
||||
//======================================================================
|
||||
// EOF rom..v
|
||||
//======================================================================
|
Loading…
Add table
Add a link
Reference in a new issue