finished the hub's logic, half done with the interfaces, and hopefully working on pi logic soon
This commit is contained in:
71
devlog/2025-06-05-Much-progress.md
Normal file
71
devlog/2025-06-05-Much-progress.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Reworking Almost Done
|
||||
Date: 2025-06-05
|
||||
|
||||
## Goals and expectations
|
||||
Build the framework for the entire fabric's logic.
|
||||
|
||||
## Results
|
||||
Nicely done.
|
||||
|
||||
This should've been split into several commits, but it's still work on
|
||||
the same project. The following is all that's been done:
|
||||
|
||||
1. Completed the hub's logic.
|
||||
2. Began reworking the interfaces' logic, already done with the RX
|
||||
side of things (the RX side always seem simpler).
|
||||
3. Built my own `git` server using `gitea` and `nginx` to host my
|
||||
stuff (ROSE included).
|
||||
4. Removed `specifications.md` and revised `protocol.md` to keep them
|
||||
updated with the reworked routing logic.
|
||||
|
||||
## Is KISS elegance?
|
||||
> Keep It Simple, Stupid.
|
||||
Is this elegance?
|
||||
|
||||
It could be, when everything else is working within strict bounds
|
||||
(e.g. the hub's strict logic), leveraging that strictness to simplify
|
||||
some logic (e.g. adding a cooldown period for queue slot allocation)
|
||||
is elegance. Leveraging the strictness allows the logic to be
|
||||
simplified, and the simplicity is elegance in its most natural form.
|
||||
|
||||
## Reflections
|
||||
1. KISS. Letting the interfaces manage the packet addresses was a
|
||||
great decision. It dumbed down the hub's logic at the cost of
|
||||
adding a bit of complexity to the interfaces' logic. This would
|
||||
also make things do one thing and do that thing well.
|
||||
2. Be organized. Organize the components by their functionalities.
|
||||
It would prove to be very useful when there's a dozen latches
|
||||
coming in and out of the interfaces/hub and you'd like to know if
|
||||
you missed something.
|
||||
3. Get sidetracked, absorb outside stimulation. Even though my last
|
||||
devlog said to focus, there's still the need to know how other
|
||||
things operate, even if they may seem irrelevant. I remember
|
||||
reading the code for `SMaRTT-REPS` and `STrack` and some new CC
|
||||
algorithms for UET during my time at Huawei, and then reading one
|
||||
of their proprietary CC algorithms, which had a much simpler logic
|
||||
but performs similar to the above-mentioned more complex ones.
|
||||
Getting sidetracked would help you think - is there a simpler way
|
||||
to achieve what I want?
|
||||
4. Get started. I think I might stress this every time two commits
|
||||
happen days away from each other, but I can never stress this
|
||||
enough. I spent hours deciding whether or not to start coding with
|
||||
the time I have on hand, but the real action only took a fraction
|
||||
of that time. Begin, progress is progress, no matter how much it
|
||||
is.
|
||||
|
||||
## Final thoughts
|
||||
There are a lot of ideas that are still "under validation" in my mind,
|
||||
like for example implementing a dual-issue round-robin scheme for the
|
||||
hub to increase the maximum throughput and prepare ROSE for scale.
|
||||
They don't go unnoticed, I'd add them to the devlog and hoping that
|
||||
someday when I get the leisure to return to them, I can implement
|
||||
them.
|
||||
|
||||
Also, finding time for ROSE has been hard, only fragments of time has
|
||||
been found on most days. But there's no say that I can't do something
|
||||
with that time.
|
||||
|
||||
## Next steps
|
||||
Complete the TX logic, figure out the byte syncing for the SPI side of
|
||||
things, and also test the things out on a TB and hopefully start
|
||||
making my way back to C land on RPi's.
|
@ -1,21 +0,0 @@
|
||||
# Protocol Specifications for ROSE
|
||||
|
||||
## Protocol header
|
||||
|
||||
Rose will use a 20-byte header for its packets. The headers contain
|
||||
the following components:
|
||||
|
||||
1. *CMD* (8 bits): Contains the command to the fabric or
|
||||
interconnected devices, see *Commands* for details.
|
||||
2. *SRC* (16 bits): Contains the packet source address.
|
||||
3. *DEST* (16 bits): contains the packet destination address.
|
||||
4. *ID* (32 bits): contains a packet identifier unique to the source
|
||||
in a large time frame.
|
||||
5. *RESERVED* (64 bits): reserved for future iterations.
|
||||
6. *CRC* (8 bits): reserved for future iterations incorporating CRC
|
||||
checksums.
|
||||
7. *LEN* (16 bits): length of payload.
|
||||
|
||||
## SPI Specifications
|
||||
We will be using SPI in mode 0, where data is sampled on the falling
|
||||
edge of the clock pulse and shifted out on the rising edge.
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
21
fabric/src/routing.svh
Normal 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
|
18
protocol.md
18
protocol.md
@ -1,14 +1,15 @@
|
||||
# The Specifications for ROSE
|
||||
Extensions to the protocol may change the specifications, see the
|
||||
Development on the protocol may change the specifications, see the
|
||||
devlogs for specific decisions on changes.
|
||||
|
||||
## Packet specifications
|
||||
### Packet size
|
||||
This is determined by the users after considering their applications
|
||||
during compilation/synthesis of their ROSE setup, the size must be a
|
||||
power of 2 (and long enough, >16 bytes is recommended).
|
||||
### Header
|
||||
|
||||
#### (1 byte) Command + packet size
|
||||
- Packet sizes are chosen out of 4 predetermined sizes. Using only 2
|
||||
bits in this byte to be represented.
|
||||
- Commands are 6 bits with 64 possibilities, see the **Commands**
|
||||
#### (1 byte) Command
|
||||
- Commands are 8 bits with 256 possibilities, see the **Commands**
|
||||
section for details.
|
||||
|
||||
#### (1 byte) Destination address
|
||||
@ -19,13 +20,14 @@ devlogs for specific decisions on changes.
|
||||
|
||||
### Payload
|
||||
Via commands, leading or trailing bytes in the payload can also be
|
||||
repurposed to timestamps or other feature extensions.
|
||||
repurposed to feature extensions.
|
||||
|
||||
### (1 byte) CRC-8
|
||||
To ensure delivery.
|
||||
|
||||
## Commands
|
||||
TBD.
|
||||
1. `[CMD: 0]` Idle.
|
||||
2. `[CMD: 1]` Send packet.
|
||||
### Feature Extensions
|
||||
#### [CMD: TBD] Include timestamp
|
||||
#### [CMD: TBD] Include sequence number
|
||||
|
5
style.md
5
style.md
@ -44,6 +44,11 @@ each line.
|
||||
Unless it's the bit-length of a byte or something that's commonly
|
||||
known and obvious at first glance, use a constant to store it.
|
||||
|
||||
## Arrays
|
||||
Avoid using arrays that are more than 2 dimensions. If you need to
|
||||
store multiple dimensions of data, consider using `struct` to clarify
|
||||
what each dimension stores.
|
||||
|
||||
## Naming schemes
|
||||
Names are only meaningful to humans, and the rationale behind the
|
||||
following guidelines is to allow anyone reading the code to know what
|
||||
|
Reference in New Issue
Block a user