handle eth TX packets of odd size in HW
Stefan Schuermans

Stefan Schuermans commited on 2012-03-24 17:30:33
Showing 2 changed files, with 27 additions and 10 deletions.

... ...
@@ -116,8 +116,6 @@ int eth_rx(void **pptr, unsigned int *psz)
116 116
  */
117 117
 void eth_tx(const void *ptr, unsigned int sz)
118 118
 {
119
-  while(sz & 3) /* pad with zeros */
120
-    ((unsigned char *)ptr)[sz++] = 0;
121 119
   eth_ptr[8] = (unsigned int)ptr; /* start */
122 120
   eth_ptr[9] = (unsigned int)ptr + sz; /* end */
123 121
   eth_ptr[10] = 1; /* set flag */
... ...
@@ -89,10 +89,9 @@ ARCHITECTURE a_io_eth OF e_io_eth IS
89 89
     SIGNAL n_rx_new_en:    std_logic;
90 90
 
91 91
     -- TX buffer registers
92
-    --   start: begin of buffer
93
-    --   end: address just behind buffer
92
+    --   start: begin of buffer (word-aligned)
93
+    --   end: address just behind buffer (NOT word-aligned)
94 94
     --   en: write 1 to start transmission, returns to zero if complete
95
-    --   all addresses are word-aligned
96 95
     SIGNAL r_tx_start: std_logic_vector(31 DOWNTO 0) := X"00000000";
97 96
     SIGNAL n_tx_start: std_logic_vector(31 DOWNTO 0);
98 97
     SIGNAL r_tx_end:   std_logic_vector(31 DOWNTO 0) := X"00000000";
... ...
@@ -105,8 +104,12 @@ ARCHITECTURE a_io_eth OF e_io_eth IS
105 104
     SIGNAL n_mac: std_logic_vector(47 DOWNTO 0);
106 105
 
107 106
     -- TX busmaster read state machine
107
+    --   pos: next address to read (NOT word-aligned)
108
+    --   rem: number of bytes remaining (NOT multiple of words size)
108 109
     SIGNAL r_tx_pos: std_logic_vector(31 DOWNTO 0) := X"00000000";
109 110
     SIGNAL n_tx_pos: std_logic_vector(31 DOWNTO 0);
111
+    SIGNAL r_tx_rem: signed          (31 DOWNTO 0) := X"00000000";
112
+    SIGNAL n_tx_rem: signed          (31 DOWNTO 0);
110 113
 
111 114
     -- busmaster write buffer
112 115
     SIGNAL s_wrbuf_wr_rdy:  std_logic;
... ...
@@ -528,13 +531,17 @@ BEGIN
528 531
         );
529 532
 
530 533
     -- TX busmaster read state machine
531
-    p_tx_rd_next: PROCESS(r_tx_pos, r_tx_start, s_txframe_en, s_txbuf_wr_en)
534
+    p_tx_rd_next: PROCESS(r_tx_pos, r_tx_rem, r_tx_start, r_tx_end,
535
+                          s_txframe_en, s_txbuf_wr_en)
532 536
     BEGIN
533 537
         n_tx_pos <= r_tx_pos;
538
+        n_tx_rem <= r_tx_rem;
534 539
         IF s_txframe_en = '1' THEN
535 540
             n_tx_pos <= r_tx_start;
541
+            n_tx_rem <= signed(r_tx_end) - signed(r_tx_start);
536 542
         ELSIF s_txbuf_wr_en = '1' THEN
537 543
             n_tx_pos <= std_logic_vector(unsigned(r_tx_pos) + X"00000004");
544
+            n_tx_rem <= r_tx_rem - X"00000004";
538 545
         END IF;
539 546
     END PROCESS p_tx_rd_next;
540 547
 
... ...
@@ -542,26 +549,38 @@ BEGIN
542 549
     BEGIN
543 550
         IF rst = '1' THEN
544 551
             r_tx_pos <= X"00000000";
552
+            r_tx_rem <= X"00000000";
545 553
         ELSIF rising_edge(clk) THEN
546 554
             r_tx_pos <= n_tx_pos;
555
+            r_tx_rem <= n_tx_rem;
547 556
         END IF;
548 557
     END PROCESS p_tx_rd_sync;
549 558
 
550 559
     -- busmaster read completed    
551
-    p_bm_rd: PROCESS(r_bm_rd, i_bm_rd_data)
560
+    p_bm_rd: PROCESS(r_bm_rd, r_tx_rem, i_bm_rd_data)
552 561
     BEGIN
553 562
         s_txbuf_wr_data <= X"00000000";
554 563
         s_txbuf_wr_en   <= '0';
555 564
         -- read was just completed
556 565
         IF r_bm_rd = '1' THEN
557
-            s_txbuf_wr_data <= i_bm_rd_data;
566
+            CASE r_tx_rem IS
567
+                WHEN X"00000000" => NULL;
568
+                WHEN X"00000001" => s_txbuf_wr_data( 7 DOWNTO 0)
569
+                                    <= i_bm_rd_data( 7 DOWNTO 0);
570
+                WHEN X"00000002" => s_txbuf_wr_data(15 DOWNTO 0)
571
+                                    <= i_bm_rd_data(15 DOWNTO 0);
572
+                WHEN X"00000003" => s_txbuf_wr_data(23 DOWNTO 0)
573
+                                    <= i_bm_rd_data(23 DOWNTO 0);
574
+                WHEN OTHERS      => s_txbuf_wr_data
575
+                                    <= i_bm_rd_data;
576
+            END CASE;
558 577
             s_txbuf_wr_en <= '1';
559 578
         END IF;
560 579
     END PROCESS p_bm_rd;
561 580
 
562 581
     -- bus master write (and request side of read)
563 582
     p_bm_wr: PROCESS(r_bm_rd,
564
-                     r_tx_en, r_tx_pos, r_tx_end, s_txbuf_wr_rdy,
583
+                     r_tx_en, r_tx_pos, r_tx_rem, s_txbuf_wr_rdy,
565 584
                      s_wrbuf_rd_rdy, s_wrbuf_rd_data, i_bm_grant)
566 585
         VARIABLE v_read:  boolean;
567 586
         VARIABLE v_write: boolean;
... ...
@@ -578,7 +597,7 @@ BEGIN
578 597
         --         space in buffer
579 598
         --   write: write request in write buffer
580 599
         v_read  := r_bm_rd = '0' AND r_tx_en = '1' AND
581
-                   r_tx_pos /= r_tx_end AND s_txbuf_wr_rdy = '1';
600
+                   r_tx_rem > X"00000000" AND s_txbuf_wr_rdy = '1';
582 601
         v_write := s_wrbuf_rd_rdy = '1';
583 602
         -- read access
584 603
         IF v_read THEN
585 604