Skip to content

Commit

Permalink
Support incremental builds for the bitstream.
Browse files Browse the repository at this point in the history
By patching the UDS and UDI into an already built bitstream, it is now
not necessary to rebuild the entire build flow when changing the UDS
and the UDI. This lowers re-build times significantly.

Signed-off-by: Joachim Strömbergson <[email protected]>
  • Loading branch information
secworks authored and dehanj committed Mar 14, 2024
1 parent 1a8be3c commit 3d469f1
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 15 deletions.
14 changes: 9 additions & 5 deletions hw/application_fpga/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ VERILOG_SRCS = \
$(P)/core/timer/rtl/timer_core.v \
$(P)/core/timer/rtl/timer.v \
$(P)/core/uds/rtl/uds.v \
$(P)/core/uds/rtl/uds_rom.v \
$(P)/core/touch_sense/rtl/touch_sense.v \
$(P)/core/tk1/rtl/tk1.v \
$(P)/core/tk1/rtl/udi_rom.v \
$(P)/core/uart/rtl/uart_core.v \
$(P)/core/uart/rtl/uart_fifo.v \
$(P)/core/uart/rtl/uart.v \
Expand Down Expand Up @@ -212,17 +214,18 @@ verilator: $(VERILATOR_FPGA_SRC) $(VERILOG_SRCS) firmware.hex $(ICE40_SIM_CELLS)
# Main FPGA build flow.
# Synthesis. Place & Route. Bitstream generation.
#-------------------------------------------------------------------
synth.json: $(FPGA_SRC) $(VERILOG_SRCS) bram_fw.hex $(P)/data/uds.hex $(P)/data/udi.hex
synth.json: $(FPGA_SRC) $(VERILOG_SRCS) bram_fw.hex
$(YOSYS_PATH)yosys -v3 -l synth.log -DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
-DFIRMWARE_HEX=\"$(P)/bram_fw.hex\" \
-DUDS_HEX=\"$(P)/data/uds.hex\" \
-DUDI_HEX=\"$(P)/data/udi.hex\" \
-p 'synth_ice40 -dsp -top application_fpga -json $@; write_verilog -attr2comment synth.v' \
$(filter %.v, $^)

application_fpga.asc: synth.json $(P)/data/$(PIN_FILE)
application_fpga_par.json: synth.json $(P)/data/$(PIN_FILE)
$(NEXTPNR_PATH)nextpnr-ice40 --ignore-loops --up5k --package sg48 --json $< \
--pcf $(P)/data/$(PIN_FILE) --asc $@
--pcf $(P)/data/$(PIN_FILE) --write $@

application_fpga.asc: application_fpga_par.json $(P)/data/uds.hex $(P)/data/udi.hex
UDS_HEX="$(P)/data/uds.hex" UDI_HEX="$(P)/data/udi.hex" OUT_ASC=$@ $(NEXTPNR_PATH)nextpnr-ice40 --up5k --package sg48 --ignore-loops --json $< --run tools/personalize.py

application_fpga.bin: application_fpga.asc bram_fw.hex firmware.hex
$(ICESTORM_PATH)icebram -v bram_fw.hex firmware.hex < $< > $<.tmp
Expand Down Expand Up @@ -304,6 +307,7 @@ clean: clean_fw
rm -f bram_fw.hex
rm -f synth.{log,v,json} route.v application_fpga.{asc,bin,vcd} application_fpga_testfw.bin
rm -f tb_application_fpga.vvp synth_tb.vvp route_tb.vvp
rm -f application_fpga_par.json
rm -f *.vcd
rm -f lint_issues.txt
rm -rf verilated
Expand Down
12 changes: 8 additions & 4 deletions hw/application_fpga/core/tk1/rtl/tk1.v
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,6 @@ module tk1(
reg [31 : 0] cdi_mem [0 : 7];
reg cdi_mem_we;

reg [31 : 0] udi_mem [0 : 1];
initial $readmemh(`UDI_HEX, udi_mem);

reg switch_app_reg;
reg switch_app_we;

Expand Down Expand Up @@ -154,6 +151,7 @@ module tk1(

reg [2 : 0] muxed_led;

wire [31:0] udi_rdata;

//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
Expand Down Expand Up @@ -194,6 +192,12 @@ module tk1(
/* verilator lint_on PINMISSING */


udi_rom rom_i(
.addr(address[0]),
.data(udi_rdata)
);


//----------------------------------------------------------------
// reg_update
//----------------------------------------------------------------
Expand Down Expand Up @@ -476,7 +480,7 @@ module tk1(

if ((address >= ADDR_UDI_FIRST) && (address <= ADDR_UDI_LAST)) begin
if (!switch_app_reg) begin
tmp_read_data = udi_mem[address[0]];
tmp_read_data = udi_rdata;
end
end
end
Expand Down
35 changes: 35 additions & 0 deletions hw/application_fpga/core/tk1/rtl/udi_rom.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//======================================================================
//
// udi_rom.v
// ---------
// UDI rom generated by instatiating named SB_LUT4 resources.
// Note: This makes the design tech specicific.
//
//
// Author: Claire Xiena Wolf.
// Copyright (C) 2023 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================

module udi_rom (
input wire [0:0] addr,
output wire [31:0] data
);
generate
genvar ii;
for (ii = 0; ii < 32; ii = ii + 1'b1) begin: luts
(* udi_rom_idx=ii, keep *) SB_LUT4
#(
.LUT_INIT({2'h1})
) lut_i (
.I0(addr[0]),
.O(data[ii])
);
end
endgenerate
endmodule

//======================================================================
// EOF udi_rom.v
//======================================================================
17 changes: 11 additions & 6 deletions hw/application_fpga/core/uds/rtl/uds.v
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ module uds(
//----------------------------------------------------------------
// 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;

Expand All @@ -57,6 +54,17 @@ module uds(
assign ready = tmp_ready;


//----------------------------------------------------------------
// uds rom instance.
//----------------------------------------------------------------
uds_rom rom_i(
.addr(address),
.re(uds_rd_we),
.data(tmp_read_data)
);



//----------------------------------------------------------------
// reg_update
//----------------------------------------------------------------
Expand Down Expand Up @@ -85,7 +93,6 @@ module uds(
always @*
begin : api
uds_rd_we = 1'h0;
tmp_read_data = 32'h0;
tmp_ready = 1'h0;

if (cs) begin
Expand All @@ -94,14 +101,12 @@ module uds(
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

//======================================================================
Expand Down
39 changes: 39 additions & 0 deletions hw/application_fpga/core/uds/rtl/uds_rom.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//======================================================================
//
// uds_rom.v
// ---------
// UDS rom. Generated by instantiating named SB_LUT4 resources.
// Note: This makes the design technology specific.
//
//
// Author: Claire Xenia Wolf
// Copyright (C) 2023 - YosysHQ, Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================

`default_nettype none

module uds_rom(
input wire [2:0] addr,
input wire re,
output wire [31:0] data
);

generate
genvar ii;
for (ii = 0; ii < 32; ii = ii + 1'b1) begin: luts
(* uds_rom_idx=ii, keep *) SB_LUT4
#(
.LUT_INIT({8'ha6 ^ ii[7:0], 8'h00})
) lut_i (
.I0(addr[0]), .I1(addr[1]), .I2(addr[2]), .I3(re),
.O(data[ii])
);
end
endgenerate
endmodule // uds_rom

//======================================================================
// EOF uds_rom.v
//======================================================================
63 changes: 63 additions & 0 deletions hw/application_fpga/tools/personalize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
#=======================================================================
#
# personalize.py
# --------------
# Python program that patches the UDS and UDI implemented using
# named LUT4 instances to have unique initial values, not the generic
# values used during synthesis, p&r and mapping. This allows us to
# generate device unique bitstreams without running the complete flow.
#
#
# Copyright (C) 2023 Tillitis AB
# Written by Myrtle Shah <[email protected]>
# SPDX-License-Identifier: GPL-2.0-only
#
#=======================================================================

import os

def parse_hex(file, length):
data = []
with open(file, "r") as f:
for line in f:
l = line.strip()
if len(l) > 0:
data.append(int(l, 16))
assert len(data) == length, len(data)
return data

def rewrite_lut(lut, idx, data, has_re=False):
# each LUT provides one bit per 32-bit word out of 64/256 bits total
new_init = 0
for i, word in enumerate(data):
if (word >> idx) & 0x1:
# repeat so inputs above address have a don't care value
repeat = (16 // len(data))
for k in range(repeat):
# UDS also has a read enable
# LUT output is zero if this isn't asserted
if has_re and k < (repeat // 2):
continue
new_init |= (1 << (k * len(data) + i))
lut.setParam("LUT_INIT", f"{new_init:016b}")

uds = parse_hex(os.environ["UDS_HEX"], 8)
udi = parse_hex(os.environ["UDI_HEX"], 2)

uds_lut_count = 0
udi_lut_count = 0

for cell_name, cell in ctx.cells:
if "uds_rom_idx" in cell.attrs:
index = int(cell.attrs["uds_rom_idx"], 2)
rewrite_lut(cell, index, uds, True)
uds_lut_count += 1
if "udi_rom_idx" in cell.attrs:
index = int(cell.attrs["udi_rom_idx"], 2)
rewrite_lut(cell, index, udi, False)
udi_lut_count += 1
assert uds_lut_count == 32, uds_lut_count
assert udi_lut_count == 32, udi_lut_count

write_bitstream(ctx, os.environ["OUT_ASC"])

0 comments on commit 3d469f1

Please sign in to comment.