diff --git a/devlog/2025-07-02-Bootloader.md b/devlog/2025-07-02-Bootloader.md new file mode 100644 index 0000000..3118443 --- /dev/null +++ b/devlog/2025-07-02-Bootloader.md @@ -0,0 +1,49 @@ +# The Bootloader +Date: 2025-07-02 + +## Goals and expectations +Writing the bootloader logic for the fabric. This is for easy scaling +of the buffer size. + +And also add indicators (output logic) to signal the user and +interfaces that the fabric is ready. + +## Results +Done. A simple bootloader, much simpler than I expected, just a +simple FSM with some initializing logic. + +Just some logic inside the `free_queue` module to initialize it when +the FPGA boots. + +And in the meanwhile, I spawned a new server (one specifically for +running long term simulations), and also changed my shell to `fish` +from `zsh` for some more modern feel. + +## Reflections +1. Once again, I am bemused by the simplicity of combinational logic. + FSMs translate much better to SystemVerilog than to some + sequentially executed logic like C. +2. Keep it simple. A simple bootloader is much easier for future + implementations compared to initializing through other means, and + once complete, it's very scalable. +3. The plan isn't everything. This wasn't part of the plan, the plan + was to burn the initial values inside a hex file or some other + methods that would allow instant initialization. However, due to + the elements of the `free_queue` being not byte-aligned, this would + become much more trouble in the end. The plan was modified + accordingly. +4. Make the best out of the existing tools on hand. This is a + follow-up to the previous point. Don't go into coding with only + the plan and goals in mind, reassess when you've set foot on its + grounds, weigh the options, and something else might just come up. + +## Final thoughts +Find the right tools to do the right things. Trying to simulate +clocked behaviors in C++ is as awkward as trying to write sequential +logic in SystemVerilog. + +The first choice isn't always the best one, but the final choice +should the better one after weighing the options. + +## Next steps +THORN! diff --git a/src/fabric/hub.sv b/src/fabric/hub.sv index b0ecccb..fd6b982 100644 --- a/src/fabric/hub.sv +++ b/src/fabric/hub.sv @@ -15,7 +15,8 @@ module hub(input logic rst, input logic [QUEUE_ADDR_LEN - 1:0] tx_queue_addr [INTERFACE_CNT], output logic [QUEUE_ADDR_LEN - 1:0] tx_new_queue[INTERFACE_CNT], output logic tx_new_queue_valid [INTERFACE_CNT], - input logic tx_new_queue_ready [INTERFACE_CNT]); + input logic tx_new_queue_ready [INTERFACE_CNT], + output logic hub_ready); timeunit 1ns; timeprecision 1ps; @@ -36,7 +37,8 @@ module hub(input logic rst, .empty_slot_addr(empty_slot_addr), .empty_slot_enqueue(empty_slot_enqueue), .new_slot_addr(new_slot_addr), - .queue_empty(free_queue_empty)); + .queue_empty(free_queue_empty), + .queue_ready(hub_ready)); logic [QUEUE_ADDR_LEN - 1:0] rx_queue_addr [INTERFACE_CNT]; logic [MEMORY_POOL_ADDR_LEN - 1:0] mem_read_addr; @@ -148,7 +150,8 @@ module free_queue(input logic sys_clk, input logic [QUEUE_ADDR_LEN - 1:0] empty_slot_addr, input logic empty_slot_enqueue, output logic [QUEUE_ADDR_LEN - 1:0] new_slot_addr, - output logic queue_empty); + output logic queue_empty, + output logic queue_ready); timeunit 1ns; timeprecision 1ps; @@ -157,32 +160,39 @@ module free_queue(input logic sys_clk, logic [QUEUE_ADDR_LEN - 1:0] tail; shortint queue_size; + enum logic [1:0] {VOID, INIT, READY} state = VOID; + assign queue_empty = queue_size == 0; - initial begin - // TODO: pre-load the free queue with every slot possible - end - - // IMPORTANT: rst must be held high for at least 2 sys_clk cycles - always_ff @ (posedge sys_clk or rst) begin - if (rst) begin + always_ff @ (posedge sys_clk) begin + new_slot_addr <= fqueue[head]; + + if (state == VOID) begin + queue_ready <= '0; head <= '0; - tail <= {QUEUE_ADDR_LEN{1'd1}}; - queue_size <= QUEUE_SIZE; - new_slot_addr <= '0; + tail <= '0; + queue_size <= 0; + state <= INIT; + end else if (state == INIT) begin + if (tail != {QUEUE_ADDR_LEN{1'b1}}) begin + fqueue[tail] <= queue_size[QUEUE_ADDR_LEN - 1:0]; + tail <= tail + 1; + queue_size <= queue_size + 1; + end else begin + state <= READY; + queue_ready <= 1; + end end else begin if (request_new_slot) begin head <= head + 1; queue_size <= queue_size - 1; end - new_slot_addr <= fqueue[head]; - if (empty_slot_enqueue) begin fqueue[tail] <= empty_slot_addr; tail <= tail + 1; queue_size <= queue_size + 1; end - end + end // else: !if(fqueue_state_t == INIT) end endmodule // free_queue diff --git a/src/fabric/main.sv b/src/fabric/main.sv index ac0b8eb..967bb80 100644 --- a/src/fabric/main.sv +++ b/src/fabric/main.sv @@ -9,16 +9,20 @@ module fabric(input logic rst_raw, input logic [INTERFACE_CNT - 1:0] cs_n, input logic [INTERFACE_CNT - 1:0] mosi, output logic [INTERFACE_CNT - 1:0] miso, - output logic [INTERFACE_CNT - 1:0] tx_active); + output logic [INTERFACE_CNT - 1:0] tx_active, + output logic [INTERFACE_CNT - 1:0] sig_fabric_ready, + output logic fabric_ready, + output logic hub_ready); timeunit 1ns; timeprecision 1ps; logic sys_clk; - logic rst; - // TODO: add PPL module for a boosted system clock + logic rst; + assign fabric_ready = hub_ready & (~rst); + reset_sync rst_sync(.sys_clk(sys_clk), .rst_raw(rst_raw), .rst(rst)); @@ -39,6 +43,8 @@ module fabric(input logic rst_raw, genvar i; generate for (i = 0; i < INTERFACE_CNT; i = i + 1) begin : gen_interfaces + assign sig_fabric_ready[i] = fabric_ready; + spi_interface spi(.rst(rst), .sys_clk(sys_clk), .sclk(sclk[i]), @@ -74,7 +80,8 @@ module fabric(input logic rst_raw, .tx_queue_addr(tx_queue_addr), .tx_new_queue(tx_new_queue), .tx_new_queue_valid(tx_new_queue_valid), - .tx_new_queue_ready(tx_new_queue_ready)); + .tx_new_queue_ready(tx_new_queue_ready), + .hub_ready(hub_ready)); endmodule // fabric @@ -86,7 +93,8 @@ module reset_sync (input logic sys_clk, timeprecision 1ps; - logic rst_sync_0, rst_sync_1; + logic rst_sync_0 = 0; + logic rst_sync_1 = 0; always_ff @(posedge sys_clk or posedge rst_raw) begin if (rst_raw) begin