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 | // IMPORTANT: interfaces are supposed to keep track of their own packet states | ||||||
| module hub( | module hub( | ||||||
|             input logic                                               sys_clk, |            input logic                         rst, | ||||||
|             input logic                                               rst, |            input logic                         sys_clk, | ||||||
|             input logic [INTERFACE_CNT - 1][PACKET_ADDR_LEN - 1:0]    rx_pkt_addr, |            input logic [7:0]                   rx_byte [INTERFACE_CNT], | ||||||
|             input logic [INTERFACE_CNT - 1:0][7:0]                    rx_byte, |            input logic                         rx_valid [INTERFACE_CNT], | ||||||
|             input logic [INTERFACE_CNT - 1:0]                         rx_valid, |            output logic                        rx_ready [INTERFACE_CNT], | ||||||
|             input logic [INTERFACE_CNT - 1:0]                         tx_ready, |            input logic [PACKET_ADDR_LEN - 1:0] rx_pkt_addr [INTERFACE_CNT], | ||||||
|             input logic [INTERFACE_CNT - 1:0]                         tx_full, |            output logic [7:0]                  tx_byte [INTERFACE_CNT], | ||||||
|             input logic [INTERFACE_CNT - 1:0][PACKET_ADDR_LEN - 1:0]  tx_pkt_addr, |            output logic                        tx_valid [INTERFACE_CNT], | ||||||
|             input logic [INTERFACE_CNT - 1:0]                         rx_new_packet, |            input logic                         tx_ready [INTERFACE_CNT], | ||||||
|             output logic [INTERFACE_CNT - 1:0]                        rx_ready, |            input logic [PACKET_ADDR_LEN - 1:0] tx_pkt_addr [INTERFACE_CNT], | ||||||
|             output logic [INTERFACE_CNT - 1:0][PACKET_ADDR_LEN - 1:0] tx_queue_addr, |            input logic [QUEUE_ADDR_LEN - 1:0]  tx_queue_addr [INTERFACE_CNT], | ||||||
|             output logic [INTERFACE_CNT - 1:0]                        tx_queue_addr_valid, |            output logic [QUEUE_ADDR_LEN - 1:0] tx_new_queue[INTERFACE_CNT], | ||||||
|             output logic [INTERFACE_CNT - 1:0][7:0]                   tx_byte, |            output logic                        tx_new_queue_valid [INTERFACE_CNT], | ||||||
|             output logic [INTERFACE_CNT - 1:0]                        tx_valid); |            input logic                         tx_new_queue_ready [INTERFACE_CNT], | ||||||
|  |            output logic                        free_queue_empty); | ||||||
|     timeunit 1ns; |     timeunit 1ns; | ||||||
|     timeprecision 1ps; |     timeprecision 1ps; | ||||||
|  |  | ||||||
|     logic [INTERFACE_CNT - 1:0]                  curr_service; |     logic [INTERFACE_ADDR_LEN - 1:0] curr; | ||||||
|     logic                                        request_new_slot; |     logic [INTERFACE_ADDR_LEN - 1:0] dest_buff [INTERFACE_CNT]; | ||||||
|     logic [QUEUE_ADDR_LEN - 1:0]                 new_slot_addr; |     logic                            reuse_queue_slot [INTERFACE_CNT]; | ||||||
|     logic                                        free_queue_empty; |     logic                            last_served_read; | ||||||
|     logic [QUEUE_ADDR_LEN - 1:0]                 empty_slot_addr; |      | ||||||
|     logic [QUEUE_ADDR_LEN - 1:0]                 empty_slot_enqueue; |     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), |     free_queue fqueue(.sys_clk(sys_clk), | ||||||
|                       .rst(rst), |                       .rst(rst), | ||||||
| @@ -34,12 +39,13 @@ module hub( | |||||||
|                       .new_slot_addr(new_slot_addr), |                       .new_slot_addr(new_slot_addr), | ||||||
|                       .queue_empty(free_queue_empty)); |                       .queue_empty(free_queue_empty)); | ||||||
|      |      | ||||||
|     logic [INTERFACE_CNT - 1:0][MEMORY_ADDR_LEN - 1:0] rx_mem_addr; |     logic [QUEUE_ADDR_LEN - 1:0]       rx_queue_addr [INTERFACE_CNT]; | ||||||
|     logic [MEMORY_POOL_ADDR_LEN - 1:0]                 mem_read_addr; |     logic [MEMORY_POOL_ADDR_LEN - 1:0] mem_read_addr; | ||||||
|     logic [7:0]                                        mem_read_byte; |     logic [7:0]                        mem_read_byte; | ||||||
|     logic [MEMORY_POOL_ADDR_LEN - 1:0]                 mem_write_addr; |     logic [MEMORY_POOL_ADDR_LEN - 1:0] mem_write_addr; | ||||||
|     logic                                              mem_write_enable; |     logic                              mem_write_enable; | ||||||
|     logic [7:0]                                        mem_write_byte; |     logic [7:0]                        mem_write_byte; | ||||||
|  |     shortint                           new_slot_cooldown [INTERFACE_CNT]; | ||||||
|  |  | ||||||
|     memory_pool mpool(.sys_clk(sys_clk), |     memory_pool mpool(.sys_clk(sys_clk), | ||||||
|                       .rst(rst), |                       .rst(rst), | ||||||
| @@ -49,49 +55,88 @@ module hub( | |||||||
|                       .write_enable(mem_write_enable), |                       .write_enable(mem_write_enable), | ||||||
|                       .read_byte(mem_read_byte)); |                       .read_byte(mem_read_byte)); | ||||||
|      |      | ||||||
|      |  | ||||||
|      |  | ||||||
|     always_ff @ (posedge sys_clk or rst) begin |     always_ff @ (posedge sys_clk or rst) begin | ||||||
|         if (rst) begin |         if (rst) begin | ||||||
|             tx_queue_addr <= '0; |             curr <= '0; | ||||||
|             tx_queue_addr_valid <= '0; |             for (int i = 0; i < INTERFACE_CNT; i++) begin | ||||||
|             tx_byte <= '0; |                 tx_new_queue[i] <= '0; | ||||||
|             tx_valid <= '0; |                 tx_new_queue_valid[i] <= 0; | ||||||
|             curr_service <= '0; |                 tx_byte[i] <= '0; | ||||||
|             rx_ready <= '0; |                 tx_valid[i] <= 0; | ||||||
|             rx_mem_addr <= '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_read_addr <= '0; | ||||||
|             mem_write_addr <= '0; |             mem_write_addr <= '0; | ||||||
|             mem_write_enable <= 0; |             mem_write_enable <= 0; | ||||||
|             mem_write_byte <= '0; |             mem_write_byte <= '0; | ||||||
|         end else begin |         end else begin | ||||||
|             // NOTE: signaled the servicing interface in the last cycle |             // NOTE: signaled the servicing interface in the last cycle | ||||||
|             rx_ready[curr_service] <= 0; |             rx_ready[curr] <= 0; | ||||||
|             rx_ready[curr_service + 1] <= 1; |             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 |             // 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 |                 // 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 |                     if (free_queue_empty) begin | ||||||
|                         // TODO: handle the drop logic |                         // TODO: handle the drop logic | ||||||
|                     end else begin |                     end else begin | ||||||
|                         request_new_slot <= 1; |                         request_new_slot <= 1; | ||||||
|                         rx_mem_addr[{curr_service, |                         rx_queue_addr[curr] <= new_slot_addr; | ||||||
|                                      MEMORY_POOL_ADDR_SHIFT'd0} |                         mem_write_addr <= {new_slot_addr, rx_pkt_addr[curr]}; | ||||||
|                                     +:MEMORY_POOL_ADDR_LEN |                         new_slot_cooldown[curr] <= NEW_SLOT_COOLDOWN; | ||||||
|                                     ] <= {new_slot_addr, PACKET_ADDR_LEN'd0}; |  | ||||||
|                         mem_write_addr <= {new_slot_addr, PACKET_ADDR_LEN'd0}; |  | ||||||
|                     end |                     end | ||||||
|                 end else begin // if (rx_new_packet[curr_service]) |                 end else begin // if (rx_new_packet[curr]) | ||||||
|                     // NOTE: if memory  |                     reuse_queue_slot[curr] <= 0; | ||||||
|                     mem_write_addr <= mem_write_addr + 1; |                     mem_write_addr <= {rx_queue_addr[curr], rx_pkt_addr[curr]}; | ||||||
|                     request_new_slot <= 0; |                     request_new_slot <= 0; | ||||||
|                 end // else: !if(rx_new_packet[curr_service]) |                     if (rx_pkt_addr[curr] == ROSE_DEST_INDEX) begin | ||||||
|                 mem_write_byte <= rx_byte[{curr_service, 3'd0}+:8]; |                         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; |                 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; |                 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 | ||||||
|     end |     end | ||||||
| endmodule // hub | endmodule // hub | ||||||
| @@ -123,8 +168,8 @@ module free_queue(input logic                         sys_clk, | |||||||
|     always_ff @ (posedge sys_clk or rst) begin |     always_ff @ (posedge sys_clk or rst) begin | ||||||
|         if (rst) begin |         if (rst) begin | ||||||
|             head <= '0; |             head <= '0; | ||||||
|             tail <= QUEUE_ADDR_LEN'd1; |             tail <= {QUEUE_ADDR_LEN{1'd1}}; | ||||||
|             queue_size = QUEUE_SIZE; |             queue_size <= QUEUE_SIZE; | ||||||
|             new_slot_addr <= '0; |             new_slot_addr <= '0; | ||||||
|         end else begin |         end else begin | ||||||
|             if (request_new_slot) begin |             if (request_new_slot) begin | ||||||
|   | |||||||
| @@ -1,23 +1,25 @@ | |||||||
| // NOTE: The first byte is used for syncing due to using different clock domains | // NOTE: The first byte is used for syncing due to using different clock domains | ||||||
| `define SYNC_2FF | `include <params.svh> | ||||||
| module spi_interface( | module spi_interface( | ||||||
|                      input logic        rst, |                      input logic                          rst, | ||||||
| 		     input logic        sys_clk, |                      input logic                          sys_clk, | ||||||
| 		     input logic        mosi, |                      input logic                          mosi, | ||||||
| 		     input logic        cs, |                      input logic                          cs, | ||||||
| 		     input logic        sclk, |                      input logic                          sclk, | ||||||
|                      input logic        rx_ready, |                      output logic                         miso, | ||||||
|                      input logic        tx_valid, |                      output logic [7:0]                   rx_byte, | ||||||
|                      input logic [7:0]  tx_byte, |                      output logic                         rx_valid, | ||||||
|                      input logic [1:0]  tx_src, |                      input logic                          rx_ready, | ||||||
|                      input logic [1:0]  packet_size, |                      output logic [PACKET_ADDR_LEN - 1:0] rx_pkt_addr, | ||||||
| 		     output logic       miso, |                      input logic [7:0]                    tx_byte, | ||||||
|                      output logic       tx_ready, |                      input logic                          tx_valid, | ||||||
|                      output logic       rx_valid, |                      output logic                         tx_ready, | ||||||
|                      output logic [7:0] rx_byte, |                      output logic [PACKET_ADDR_LEN - 1:0] tx_pkt_addr, | ||||||
|                      output logic [7:0] rx_dest, |                      output logic [QUEUE_ADDR_LEN - 1:0]  tx_queue_addr, | ||||||
|                      output logic [7:0] rx_cmd, |                      input logic [QUEUE_ADDR_LEN - 1:0]   tx_new_queue, | ||||||
|                      output logic       rx_cmd_valid); |                      input logic                          tx_new_queue_valid, | ||||||
|  |                      output logic                         tx_new_queue_ready, | ||||||
|  |                      input logic                          free_queue_empty); | ||||||
|      |      | ||||||
|     timeunit 1ns; |     timeunit 1ns; | ||||||
|     timeprecision 1ps; |     timeprecision 1ps; | ||||||
| @@ -28,11 +30,11 @@ module spi_interface( | |||||||
|      |      | ||||||
|     async_get_clk_edges sync (.rst(rst), |     async_get_clk_edges sync (.rst(rst), | ||||||
|                               .ext_clk(sclk), |                               .ext_clk(sclk), | ||||||
| 			      .sys_clk(sys_clk), |                               .sys_clk(sys_clk), | ||||||
| 			      .clk_rising_edge(sclk_rising_edge), |                               .clk_rising_edge(sclk_rising_edge), | ||||||
| 			      .clk_falling_edge(sclk_falling_edge)); |                               .clk_falling_edge(sclk_falling_edge)); | ||||||
|      |      | ||||||
|     int	        bit_cnt = 0; |     shortint    bit_cnt = 0; | ||||||
|     logic [7:0] rx_shift; |     logic [7:0] rx_shift; | ||||||
|     logic [7:0] tx_shift = 8'b00101010; |     logic [7:0] tx_shift = 8'b00101010; | ||||||
|     logic [7:0] rx_buff = '0; |     logic [7:0] rx_buff = '0; | ||||||
| @@ -40,48 +42,72 @@ module spi_interface( | |||||||
|  |  | ||||||
|     always_ff @ (posedge sclk_rising_edge or posedge rst) begin |     always_ff @ (posedge sclk_rising_edge or posedge rst) begin | ||||||
|         if (rst) begin |         if (rst) begin | ||||||
| 	    rx_shift <= '0; |             rx_shift <= '0; | ||||||
| 	    rx_buff <= '0; |             rx_buff <= '0; | ||||||
| 	    bit_cnt <= '0; |             bit_cnt <= '0; | ||||||
|             byte_ready <= 0; |             byte_ready <= 0; | ||||||
|         end |         end | ||||||
|         else begin |         else begin | ||||||
| 	    if (cs) begin |             if (cs) begin | ||||||
| 	        rx_shift <= 0; |                 rx_shift <= 0; | ||||||
| 	        rx_buff <= 0; |                 rx_buff <= 0; | ||||||
| 	        bit_cnt <= 0; |                 bit_cnt <= 0; | ||||||
| 	    end else begin |             end else begin | ||||||
| 	        rx_shift <= {rx_shift[6:0], mosi}; |                 rx_shift <= {rx_shift[6:0], mosi}; | ||||||
| 	        bit_cnt <= bit_cnt + 1; |                 bit_cnt <= bit_cnt + 1; | ||||||
| 	         |                  | ||||||
| 	        if (bit_cnt == 7) begin |                 if (bit_cnt == 7) begin | ||||||
| 	            bit_cnt <= 0; |                     bit_cnt <= 0; | ||||||
| 	            rx_buff <= {rx_shift[6:0], mosi}; |                     rx_buff <= {rx_shift[6:0], mosi}; | ||||||
|                     byte_ready <= 1; |                     byte_ready <= 1; | ||||||
| 	        end else |                 end else begin | ||||||
|                     byte_ready <= 0; |                     byte_ready <= 0; | ||||||
| 	    end // else: !if(cs) |                 end | ||||||
|  |             end // else: !if(cs) | ||||||
|         end // else: !if(rst) |         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) |     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 |         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 |         end | ||||||
|         else begin |     end | ||||||
| 	    if (cs) begin |      | ||||||
| 	        tx_shift <= 0; |     always_ff @ (posedge sclk_falling_edge or rst) begin | ||||||
| 	    end else begin |         if (rst) begin | ||||||
| 	        if (bit_cnt == 0) begin |             tx_shift <= 8'b00101010; | ||||||
| 	            tx_shift <= rx_buff[7:0]; |         end else begin | ||||||
| 	        end else begin |             if (cs) begin | ||||||
| 	            tx_shift <= {tx_shift[6:0], 1'b0}; |                 tx_shift <= 0; | ||||||
| 	        end |             end else begin | ||||||
| 	    end |                 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) |         end // else: !if(rst) | ||||||
|         $display("last bit sent: %b", miso); |         $display("last bit sent: %b", miso); | ||||||
|         $display("[%0d] current tx_shift: %b", $time, tx_shift); |         $display("[%0d] current tx_shift: %b", $time, tx_shift); | ||||||
| @@ -89,75 +115,19 @@ module spi_interface( | |||||||
|     end // always_ff @ (negedge sclk) |     end // always_ff @ (negedge sclk) | ||||||
|  |  | ||||||
|     assign miso = tx_shift[7]; |     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 | endmodule // spi_interface | ||||||
|  |  | ||||||
| module async_get_clk_edges( | module async_get_clk_edges( | ||||||
|                            input logic  rst, |                            input logic  rst, | ||||||
| 			   input logic  ext_clk, |                            input logic  ext_clk, | ||||||
| 			   input logic  sys_clk, |                            input logic  sys_clk, | ||||||
| 			   output logic clk_rising_edge, |                            output logic clk_rising_edge, | ||||||
| 			   output logic clk_falling_edge); |                            output logic clk_falling_edge); | ||||||
|     timeunit 1ns; |     timeunit 1ns; | ||||||
|     timeprecision 1ps; |     timeprecision 1ps; | ||||||
| `ifdef SYNC_2FF |  | ||||||
|     logic sync_0 = 0; |     logic sync_0 = 0; | ||||||
|     logic sync_1 = 0; |     logic sync_1 = 0; | ||||||
|  |  | ||||||
| @@ -173,71 +143,4 @@ module async_get_clk_edges( | |||||||
|  |  | ||||||
|     assign clk_rising_edge = sync_0 & ~sync_1; |     assign clk_rising_edge = sync_0 & ~sync_1; | ||||||
|     assign clk_falling_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 | 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_SIZE = 64; | ||||||
| parameter int PACKET_ADDR_LEN = 6; | 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 QUEUE_ADDR_LEN = 10; | ||||||
| parameter int MEMORY_POOL_SIZE = QUEUE_SIZE * PACKET_SIZE; | parameter int MEMORY_POOL_SIZE = QUEUE_SIZE * PACKET_SIZE; | ||||||
| parameter int MEMORY_POOL_ADDR_LEN = QUEUE_ADDR_LEN + PACKET_ADDR_LEN; | 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_SIZE = 512; | ||||||
| parameter int INTERFACE_QUEUE_ADDR_LEN = 9; | parameter int INTERFACE_QUEUE_ADDR_LEN = 9; | ||||||
| parameter int INTERFACE_CNT = 4; | parameter int INTERFACE_CNT = 4; | ||||||
|  | parameter int INTERFACE_ADDR_LEN = 2; | ||||||
| parameter int CRC_BITS = 8; | 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 | # 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. | devlogs for specific decisions on changes. | ||||||
|  |  | ||||||
| ## Packet specifications | ## 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 | ### Header | ||||||
|  | #### (1 byte) Command | ||||||
| #### (1 byte) Command + packet size | - Commands are 8 bits with 256 possibilities, see the **Commands** | ||||||
| - 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** |  | ||||||
|   section for details. |   section for details. | ||||||
|  |  | ||||||
| #### (1 byte) Destination address | #### (1 byte) Destination address | ||||||
| @@ -19,13 +20,14 @@ devlogs for specific decisions on changes. | |||||||
|  |  | ||||||
| ### Payload | ### Payload | ||||||
| Via commands, leading or trailing bytes in the payload can also be | 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 | ### (1 byte) CRC-8 | ||||||
| To ensure delivery. | To ensure delivery. | ||||||
|  |  | ||||||
| ## Commands | ## Commands | ||||||
| TBD. | 1. `[CMD: 0]` Idle. | ||||||
|  | 2. `[CMD: 1]` Send packet. | ||||||
| ### Feature Extensions | ### Feature Extensions | ||||||
| #### [CMD: TBD] Include timestamp | #### [CMD: TBD] Include timestamp | ||||||
| #### [CMD: TBD] Include sequence number | #### [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 | 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. | 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 | ## Naming schemes | ||||||
| Names are only meaningful to humans, and the rationale behind the | Names are only meaningful to humans, and the rationale behind the | ||||||
| following guidelines is to allow anyone reading the code to know what | following guidelines is to allow anyone reading the code to know what | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user