finished the hub's logic, half done with the interfaces, and hopefully working on pi logic soon

This commit is contained in:
2025-06-05 22:38:26 -04:00
parent f61de84b4a
commit a94823b44a
8 changed files with 304 additions and 266 deletions

View File

@ -1,30 +1,35 @@
`include <params.sv>
`include <params.svh>
`include <routing.svh>
// IMPORTANT: interfaces are supposed to keep track of their own packet states
module hub(
input logic sys_clk,
input logic rst,
input logic [INTERFACE_CNT - 1][PACKET_ADDR_LEN - 1:0] rx_pkt_addr,
input logic [INTERFACE_CNT - 1:0][7:0] rx_byte,
input logic [INTERFACE_CNT - 1:0] rx_valid,
input logic [INTERFACE_CNT - 1:0] tx_ready,
input logic [INTERFACE_CNT - 1:0] tx_full,
input logic [INTERFACE_CNT - 1:0][PACKET_ADDR_LEN - 1:0] tx_pkt_addr,
input logic [INTERFACE_CNT - 1:0] rx_new_packet,
output logic [INTERFACE_CNT - 1:0] rx_ready,
output logic [INTERFACE_CNT - 1:0][PACKET_ADDR_LEN - 1:0] tx_queue_addr,
output logic [INTERFACE_CNT - 1:0] tx_queue_addr_valid,
output logic [INTERFACE_CNT - 1:0][7:0] tx_byte,
output logic [INTERFACE_CNT - 1:0] tx_valid);
input logic rst,
input logic sys_clk,
input logic [7:0] rx_byte [INTERFACE_CNT],
input logic rx_valid [INTERFACE_CNT],
output logic rx_ready [INTERFACE_CNT],
input logic [PACKET_ADDR_LEN - 1:0] rx_pkt_addr [INTERFACE_CNT],
output logic [7:0] tx_byte [INTERFACE_CNT],
output logic tx_valid [INTERFACE_CNT],
input logic tx_ready [INTERFACE_CNT],
input logic [PACKET_ADDR_LEN - 1:0] tx_pkt_addr [INTERFACE_CNT],
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],
output logic free_queue_empty);
timeunit 1ns;
timeprecision 1ps;
logic [INTERFACE_CNT - 1:0] curr_service;
logic request_new_slot;
logic [QUEUE_ADDR_LEN - 1:0] new_slot_addr;
logic free_queue_empty;
logic [QUEUE_ADDR_LEN - 1:0] empty_slot_addr;
logic [QUEUE_ADDR_LEN - 1:0] empty_slot_enqueue;
logic [INTERFACE_ADDR_LEN - 1:0] curr;
logic [INTERFACE_ADDR_LEN - 1:0] dest_buff [INTERFACE_CNT];
logic reuse_queue_slot [INTERFACE_CNT];
logic last_served_read;
logic request_new_slot;
logic [QUEUE_ADDR_LEN - 1:0] new_slot_addr;
logic [QUEUE_ADDR_LEN - 1:0] empty_slot_addr;
logic empty_slot_enqueue;
free_queue fqueue(.sys_clk(sys_clk),
.rst(rst),
@ -34,12 +39,13 @@ module hub(
.new_slot_addr(new_slot_addr),
.queue_empty(free_queue_empty));
logic [INTERFACE_CNT - 1:0][MEMORY_ADDR_LEN - 1:0] rx_mem_addr;
logic [MEMORY_POOL_ADDR_LEN - 1:0] mem_read_addr;
logic [7:0] mem_read_byte;
logic [MEMORY_POOL_ADDR_LEN - 1:0] mem_write_addr;
logic mem_write_enable;
logic [7:0] mem_write_byte;
logic [QUEUE_ADDR_LEN - 1:0] rx_queue_addr [INTERFACE_CNT];
logic [MEMORY_POOL_ADDR_LEN - 1:0] mem_read_addr;
logic [7:0] mem_read_byte;
logic [MEMORY_POOL_ADDR_LEN - 1:0] mem_write_addr;
logic mem_write_enable;
logic [7:0] mem_write_byte;
shortint new_slot_cooldown [INTERFACE_CNT];
memory_pool mpool(.sys_clk(sys_clk),
.rst(rst),
@ -49,49 +55,88 @@ module hub(
.write_enable(mem_write_enable),
.read_byte(mem_read_byte));
always_ff @ (posedge sys_clk or rst) begin
if (rst) begin
tx_queue_addr <= '0;
tx_queue_addr_valid <= '0;
tx_byte <= '0;
tx_valid <= '0;
curr_service <= '0;
rx_ready <= '0;
rx_mem_addr <= '0;
curr <= '0;
for (int i = 0; i < INTERFACE_CNT; i++) begin
tx_new_queue[i] <= '0;
tx_new_queue_valid[i] <= 0;
tx_byte[i] <= '0;
tx_valid[i] <= 0;
rx_ready[i] <= 0;
rx_queue_addr[i] <= '0;
dest_buff[i] <= '0;
reuse_queue_slot[i] <= 0;
new_slot_cooldown[i] <= 0;
end
mem_read_addr <= '0;
mem_write_addr <= '0;
mem_write_enable <= 0;
mem_write_byte <= '0;
end else begin
// NOTE: signaled the servicing interface in the last cycle
rx_ready[curr_service] <= 0;
rx_ready[curr_service + 1] <= 1;
rx_ready[curr] <= 0;
rx_ready[curr + 1] <= 1;
tx_new_queue_valid[dest_buff[curr - 1]] <= 0;
// IMPORTANT: interfaces should send the byte no matter what, rx_ready is to prevent sending a new byte
if (rx_valid[curr_service]) begin
if (rx_valid[curr]) begin
// IMPORTANT: memory_write_addr is ready on the next cycle
if (rx_new_packet[curr_service]) begin
if (rx_pkt_addr[curr] == 0 && !reuse_queue_slot[curr] &&
!(|new_slot_cooldown[curr])) begin
if (free_queue_empty) begin
// TODO: handle the drop logic
end else begin
request_new_slot <= 1;
rx_mem_addr[{curr_service,
MEMORY_POOL_ADDR_SHIFT'd0}
+:MEMORY_POOL_ADDR_LEN
] <= {new_slot_addr, PACKET_ADDR_LEN'd0};
mem_write_addr <= {new_slot_addr, PACKET_ADDR_LEN'd0};
rx_queue_addr[curr] <= new_slot_addr;
mem_write_addr <= {new_slot_addr, rx_pkt_addr[curr]};
new_slot_cooldown[curr] <= NEW_SLOT_COOLDOWN;
end
end else begin // if (rx_new_packet[curr_service])
// NOTE: if memory
mem_write_addr <= mem_write_addr + 1;
end else begin // if (rx_new_packet[curr])
reuse_queue_slot[curr] <= 0;
mem_write_addr <= {rx_queue_addr[curr], rx_pkt_addr[curr]};
request_new_slot <= 0;
end // else: !if(rx_new_packet[curr_service])
mem_write_byte <= rx_byte[{curr_service, 3'd0}+:8];
if (rx_pkt_addr[curr] == ROSE_DEST_INDEX) begin
dest_buff[curr] <= next_hop(rx_byte[curr]);
end
end // else: !if(rx_new_packet[curr])
if (|new_slot_cooldown[curr]) begin
new_slot_cooldown[curr] <= new_slot_cooldown[curr] - 1;
end
mem_write_byte <= rx_byte[curr];
mem_write_enable <= 1;
end else // if (rx_valid[curr_service])
if (&rx_pkt_addr[curr]) begin // packet complete
if (tx_new_queue_ready[dest_buff[curr]]) begin
tx_new_queue[dest_buff[curr]] <= rx_queue_addr[curr];
tx_new_queue_valid[dest_buff[curr]] <= 1;
end else begin
reuse_queue_slot[curr] <= 1;
end
end
end else begin // if (rx_valid[curr])
mem_write_enable <= 0;
end // else: !if(rx_valid[curr])
// IMPORTANT: tx_ready is only signaled when tx_pkt_addr is valid
if (tx_ready[curr]) begin
last_served_read <= 1;
mem_read_addr <= {tx_queue_addr[curr], tx_pkt_addr[curr]};
if (&tx_pkt_addr[curr]) begin
empty_slot_addr <= tx_queue_addr[curr];
empty_slot_enqueue <= 1;
end else begin
empty_slot_enqueue <= 0;
end
end else begin
empty_slot_enqueue <= 0;
last_served_read <= 0;
end // else: !if(tx_ready[curr])
if (last_served_read) begin
tx_byte[curr - 1] <= mem_read_byte;
tx_valid[curr - 1] <= 1;
end else begin
tx_valid[curr - 1] <= 0;
end
end
end
endmodule // hub
@ -123,8 +168,8 @@ module free_queue(input logic sys_clk,
always_ff @ (posedge sys_clk or rst) begin
if (rst) begin
head <= '0;
tail <= QUEUE_ADDR_LEN'd1;
queue_size = QUEUE_SIZE;
tail <= {QUEUE_ADDR_LEN{1'd1}};
queue_size <= QUEUE_SIZE;
new_slot_addr <= '0;
end else begin
if (request_new_slot) begin

View File

@ -1,23 +1,25 @@
// NOTE: The first byte is used for syncing due to using different clock domains
`define SYNC_2FF
`include <params.svh>
module spi_interface(
input logic rst,
input logic sys_clk,
input logic mosi,
input logic cs,
input logic sclk,
input logic rx_ready,
input logic tx_valid,
input logic [7:0] tx_byte,
input logic [1:0] tx_src,
input logic [1:0] packet_size,
output logic miso,
output logic tx_ready,
output logic rx_valid,
output logic [7:0] rx_byte,
output logic [7:0] rx_dest,
output logic [7:0] rx_cmd,
output logic rx_cmd_valid);
input logic rst,
input logic sys_clk,
input logic mosi,
input logic cs,
input logic sclk,
output logic miso,
output logic [7:0] rx_byte,
output logic rx_valid,
input logic rx_ready,
output logic [PACKET_ADDR_LEN - 1:0] rx_pkt_addr,
input logic [7:0] tx_byte,
input logic tx_valid,
output logic tx_ready,
output logic [PACKET_ADDR_LEN - 1:0] tx_pkt_addr,
output logic [QUEUE_ADDR_LEN - 1:0] tx_queue_addr,
input logic [QUEUE_ADDR_LEN - 1:0] tx_new_queue,
input logic tx_new_queue_valid,
output logic tx_new_queue_ready,
input logic free_queue_empty);
timeunit 1ns;
timeprecision 1ps;
@ -28,11 +30,11 @@ module spi_interface(
async_get_clk_edges sync (.rst(rst),
.ext_clk(sclk),
.sys_clk(sys_clk),
.clk_rising_edge(sclk_rising_edge),
.clk_falling_edge(sclk_falling_edge));
.sys_clk(sys_clk),
.clk_rising_edge(sclk_rising_edge),
.clk_falling_edge(sclk_falling_edge));
int bit_cnt = 0;
shortint bit_cnt = 0;
logic [7:0] rx_shift;
logic [7:0] tx_shift = 8'b00101010;
logic [7:0] rx_buff = '0;
@ -40,48 +42,72 @@ module spi_interface(
always_ff @ (posedge sclk_rising_edge or posedge rst) begin
if (rst) begin
rx_shift <= '0;
rx_buff <= '0;
bit_cnt <= '0;
rx_shift <= '0;
rx_buff <= '0;
bit_cnt <= '0;
byte_ready <= 0;
end
else begin
if (cs) begin
rx_shift <= 0;
rx_buff <= 0;
bit_cnt <= 0;
end else begin
rx_shift <= {rx_shift[6:0], mosi};
bit_cnt <= bit_cnt + 1;
if (bit_cnt == 7) begin
bit_cnt <= 0;
rx_buff <= {rx_shift[6:0], mosi};
if (cs) begin
rx_shift <= 0;
rx_buff <= 0;
bit_cnt <= 0;
end else begin
rx_shift <= {rx_shift[6:0], mosi};
bit_cnt <= bit_cnt + 1;
if (bit_cnt == 7) begin
bit_cnt <= 0;
rx_buff <= {rx_shift[6:0], mosi};
byte_ready <= 1;
end else
end else begin
byte_ready <= 0;
end // else: !if(cs)
end
end // else: !if(cs)
end // else: !if(rst)
$display("[%0d] current rx_shift: %b", $time, rx_shift);
$display("[%0d] current bit_cnt: %0d", $time, bit_cnt);
$display("[%0d] current rx_buff: %b", $time, rx_buff);
end // always_ff @ (posedge sclk)
always_ff @ (posedge sclk_falling_edge) begin
shortint idle_cntdn;
logic rx_drained;
always_ff @ (posedge sys_clk or rst) begin
if (rst) begin
tx_shift <= 0;
rx_drained <= 0;
rx_pkt_addr <= '1;
rx_byte <= '0;
rx_valid <= 0;
idle_cntdn <= 0;
end else begin
if (!rx_drained && byte_ready) begin
rx_byte <= rx_buff;
rx_valid <= 1;
idle_cntdn <= INTERFACE_IDLE_COUNTDOWN;
rx_drained <= 1;
rx_pkt_addr <= rx_pkt_addr + 1;
end else if (!byte_ready) begin
rx_drained <= 0;
if (!(|idle_cntdn)) begin
rx_valid <= 0;
end else begin
idle_cntdn <= idle_cntdn - 1;
end
end
end
else begin
if (cs) begin
tx_shift <= 0;
end else begin
if (bit_cnt == 0) begin
tx_shift <= rx_buff[7:0];
end else begin
tx_shift <= {tx_shift[6:0], 1'b0};
end
end
end
always_ff @ (posedge sclk_falling_edge or rst) begin
if (rst) begin
tx_shift <= 8'b00101010;
end else begin
if (cs) begin
tx_shift <= 0;
end else begin
if (bit_cnt == 0) begin
tx_shift <= rx_buff[7:0];
end else begin
tx_shift <= {tx_shift[6:0], 1'b0};
end
end
end // else: !if(rst)
$display("last bit sent: %b", miso);
$display("[%0d] current tx_shift: %b", $time, tx_shift);
@ -89,75 +115,19 @@ module spi_interface(
end // always_ff @ (negedge sclk)
assign miso = tx_shift[7];
// RX and TX logic
logic [9:0] rx_queue_head = 0;
logic [9:0] rx_queue_tail = 0;
logic [10:0] rx_size = 0;
logic rx_queue_write = 0;
logic [7:0] rx_read;
logic [7:0] dest_read;
logic packet_sending;
logic rx_queue_empty;
assign rx_size = (rx_queue_tail + 11'd1024 - rx_queue_head) & 11'h3FF;
assign rx_queue_empty = ~(|rx_size);
rx_queue_bram rx_queue (.sys_clk(sys_clk),
.write_enable(rx_queue_write),
.read_addr(rx_queue_head),
.write_addr(rx_queue_tail),
.write_data(rx_buff),
.read_data(rx_read),
.read_dest(dest_read));
always_ff @ (posedge sys_clk) begin
if (rst) begin
rx_queue_head <= '0;
rx_queue_tail <= '0;
rx_queue_write <= '0;
rx_read <= '0;
packet_sending <= 0;
end else begin
if (byte_ready)
rx_queue_write <= 1;
if (rx_queue_write) begin
rx_queue_write <= 0;
rx_queue_tail <= rx_queue_tail + 1;
end
if (!packet_sending) begin
if (rx_size > 2 && rx_ready) begin
rx_byte <= rx_read;
rx_dest <= dest_read;
rx_valid <= 1;
end else
rx_valid <= 0;
end else begin
if (is_packet_complete(rx_queue_head, packet_size))
packet_sending <= 0;
else if (rx_size > 0) begin
rx_byte <= rx_read;
rx_dest <= dest_read;
rx_valid <= 1;
end
end
end
end // always_ff @ (posedge sys_clk)
logic [13:0] tx_queue_head;
logic [13:0] tx_queue_tail;
endmodule // spi_interface
module async_get_clk_edges(
input logic rst,
input logic ext_clk,
input logic sys_clk,
output logic clk_rising_edge,
output logic clk_falling_edge);
input logic ext_clk,
input logic sys_clk,
output logic clk_rising_edge,
output logic clk_falling_edge);
timeunit 1ns;
timeprecision 1ps;
`ifdef SYNC_2FF
logic sync_0 = 0;
logic sync_1 = 0;
@ -173,71 +143,4 @@ module async_get_clk_edges(
assign clk_rising_edge = sync_0 & ~sync_1;
assign clk_falling_edge = ~sync_0 & sync_1;
`else // !`ifdef SYNC_2FF
logic [2:0] clk_sync = 0;
always_ff @ (posedge sys_clk) begin
if (rst)
clk_sync <= {clk_sync[1:0], ext_clk};
end
assign clk_rising_edge = (clk_sync[2:1] == 2'b01);
assign clk_falling_edge = (clk_sync[2:1] == 2'b10);
`endif // !`ifdef SYNC_2FF
endmodule // async_get_clk_edges
module rx_queue_bram (
input logic sys_clk,
input logic write_enable,
input logic [9:0] read_addr,
input logic [9:0] write_addr,
input logic [7:0] write_data,
output logic [7:0] read_data,
output logic [7:0] read_dest);
timeunit 1ns;
timeprecision 1ps;
logic [7:0] mem [1023:0];
always_ff @ (posedge sys_clk) begin
if (write_enable)
mem[write_addr] <= write_data;
read_data <= mem[read_addr];
read_dest <= mem[read_addr + 1];
end
endmodule // rx_queue_bram
module tx_queue_bram(input logic sys_clk,
input logic write_enable,
input logic [13:0] read_addr,
input logic [13:0] write_addr,
input logic [7:0] write_data,
output logic [7:0] read_data);
timeunit 1ns;
timeprecision 1ps;
logic [7:0] mem [16 * 1023:0];
always_ff @ (posedge sys_clk) begin
if (write_enable)
mem[write_addr] <= write_data;
read_data <= mem[read_addr];
end
endmodule // tx_queue_bram
function automatic logic is_packet_complete(input logic [9:0] head,
input logic [1:0] packet_size);
case(packet_size)
2'b00:
return &(head & 'd64);
2'b01:
return &(head & 'd128);
2'b10:
return &(head & 'd256);
2'b11:
return &head;
endcase // case (packet_size)
endfunction // packet_complete

View File

@ -1,6 +1,13 @@
`ifndef __PARAMS_SVH__
`define __PARAMS_SVH__
parameter int PACKET_SIZE = 64;
parameter int PACKET_ADDR_LEN = 6;
parameter int QUEUE_SIZE = 1024;
parameter int ROSE_ADDR_LEN = 8;
parameter logic [PACKET_ADDR_LEN - 1:0] ROSE_DEST_INDEX = 1;
parameter shortint QUEUE_SIZE = 1024;
parameter int QUEUE_ADDR_LEN = 10;
parameter int MEMORY_POOL_SIZE = QUEUE_SIZE * PACKET_SIZE;
parameter int MEMORY_POOL_ADDR_LEN = QUEUE_ADDR_LEN + PACKET_ADDR_LEN;
@ -8,4 +15,9 @@ parameter int MEMORY_POOL_ADDR_SHIFT = 4;
parameter int INTERFACE_QUEUE_SIZE = 512;
parameter int INTERFACE_QUEUE_ADDR_LEN = 9;
parameter int INTERFACE_CNT = 4;
parameter int INTERFACE_ADDR_LEN = 2;
parameter int CRC_BITS = 8;
parameter shortint NEW_SLOT_COOLDOWN = 500;
parameter shortint INTERFACE_IDLE_COUNTDOWN = 4;
`endif

21
fabric/src/routing.svh Normal file
View File

@ -0,0 +1,21 @@
`ifndef __ROUTING__SVH__
`define __ROUTING__SVH__
`include <params.svh>
function automatic logic [INTERFACE_ADDR_LEN - 1:0] next_hop(input logic [ROSE_ADDR_LEN - 1:0] interface_addr);
case(interface_addr)
0:
return 0;
1:
return 1;
2:
return 2;
3:
return 3;
default:
return 0;
endcase // case (interface_addr)
endfunction // next_hop
`endif