---
# System prepended metadata

title: SoC Lab 3 Fir
tags: [SoC Lab]

---

# Lab 3 Fir

[Code](https://github.com/Eltdot/SoC_Lab3_Fir)

## Introduction

[Workbook](https://drive.google.com/file/d/1PSqW4qURLvSZxRDxA4NAYPYXn8ixE6ib/view)


This design primarily implements a simple **convolution**:

$$
y[t] = \sum_{i = 0}^{\text{tap_num}-1} \left( h[i] \times x[t - i] \right)
$$

The main challenge lies in the fact that input and output data need to be transmitted via **AXI-Lite** and **AXI-Stream**, and **shift registers** cannot be used. The implementation must rely on only **32 DW of SRAM**, and the design allows for only one **32-bit adder** and one **32-bit multiplier**.




## Design Spec
- **Data_Width** 32bit (integer)
- **Tap_Num** max 32
  - **# of Tap is a programmable parameter**
  - Maximum storage of Tap and Data RAM is 32 DW
- **Data_Num** *programmable parameter* — Based on the size of the data file
- **Interface**
  - **axilite**: configuration data_in:
  - **axi-stream**: stream ( Xn ), stream ( Yn )

- **Using one Multiplier and one Adder:**
  - **Note**: Multiplication and Addition are run in separate pipeline cycle
  - **Note**: Don’t use DSP, use Xilinx directive `(* use_dsp = "no" *)`

- **Shift registers implemented with SRAM** ( Shift_RAM, size = 32 DW )
- **Tap coefficient implemented with SRAM** ( Tap_RAM = 32 DW ), initialized by axilite write

- **Operation** 
  1. Program `ap_start` to initiate FIR engine
  2. Stream in `Xn`. The rate is varied by testbench. `axi-stream` tvalid/tready for flow control.
  3. Stream out `Yn`, the rate of output transfer is varied by testbench. `axi-stream` tvalid/tready for flow control.
  
  
## AXI Transfer Protocal

### axi-lite write

![image](https://hackmd.io/_uploads/ryeJs3D4hye.png)
![image](https://hackmd.io/_uploads/rktdJdVh1g.png)
![image](https://hackmd.io/_uploads/Bk2TvlJTye.png)



In this design, only `awvalid`, `wvalid`, `awready`, and `wready` are used. It is important to note that a **single arrow (`→`)** indicates that these signals are related but does not imply a strict ordering. In contrast, a **double arrow (`⇒`)** denotes a sequential dependency, meaning that the referenced signal must be received before the next signal can be asserted.

### axi-lite read

![image](https://hackmd.io/_uploads/rJTVaDVhye.png)
![image](https://hackmd.io/_uploads/HyBwJOEhyg.png)
![image](https://hackmd.io/_uploads/rkmgig1pkl.png)



Here, it is important to note that `RREADY` might only be asserted **after detecting** `RVALID`. Therefore, during the design process, care must be taken **not to use** `RREADY` as a condition for `RVALID`.

### axi-stream
  
![image](https://hackmd.io/_uploads/HksngON3ye.png)

![image](https://hackmd.io/_uploads/S14oelka1g.png)




In this case, `tvalid` and `tready` do not have a strict order of precedence. Therefore, in the design process, `tready` can be asserted **before or after** `tvalid` without any rigid constraints.

# Code Explanation

## FSM

### state_tap

```verilog
  reg [1:0] state;
  reg [1:0] next_state;  
  // localparam for state
  localparam IDLE = 2'b00; // Initial
  localparam TRAN = 2'b01; // Write or Read Tap, data_len, Tap_num
  localparam WAIT = 2'b10; 
  localparam FIR = 2'b11; // do FIR  

  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      state <= IDLE;
    end else begin
      state <= next_state;
    end
  end

  // next_state update
  always @(*) begin
    case (state)
      IDLE: begin
        next_state <= TRAN;        
      end
      TRAN: begin
        if (w_permit | r_permit) begin
          next_state <= WAIT;
        end else begin
          next_state <= TRAN;
        end
      end
      WAIT: begin
        if (ap_start) begin
          next_state <= FIR;
        end else begin
          next_state <= TRAN;
        end
      end
      FIR: begin
        if (ap_done) begin
          next_state <= TRAN;
        end else begin
          next_state <= FIR;
        end
      end
      default: begin
        next_state <= IDLE;
      end 
    endcase
end
```

```mermaid
stateDiagram-v2
    [*] --> IDLE
    IDLE --> TRAN

    TRAN --> WAIT : w_permit | r_permit
    TRAN --> TRAN : !(w_permit | r_permit)

    WAIT --> FIR : ap_start
    WAIT --> TRAN : !ap_start

    FIR --> TRAN : ap_done
    FIR --> FIR : !ap_done
```



`state_tap` is primarily responsible for managing **AXI-Lite** operations and consists of four states: **IDLE, TRAN, WAIT, and FIR**.

#### **IDLE**  
The system enters the `IDLE` state whenever it is reset or after completing a full round of FIR computation.  
In this state, the system does nothing, and in the next cycle, it transitions to the `TRAN` state.

#### **TRAN**  
The `TRAN` state is used for inputting various coefficients for `tap_number`.  
In this state, **read and write operations** can be performed.  
After receiving a read or write signal, the system transitions to the `WAIT` state.

#### **WAIT**  
The system enters the `WAIT` state after receiving a read or write signal in the `TRAN` state.  
In this state, the corresponding **ready signal** is asserted.  
If `ap_start` is asserted during this phase, the system transitions to the `FIR` state, where FIR computation begins.

#### **FIR**  
`FIR` is the state where the system performs FIR computation.  
In this state, **writing to any register or reading tap coefficients is not allowed**.  
If such an operation is attempted, it will either be ignored or return `32'hffffffff`.
If the system reads from address `12'h0` in this state, it indicates that a full round of data processing has been completed, and the system transitions back to `IDLE`, preparing for the next round.

> **(Potential Bug Warning)**  
> If the previous round has not yet finished but `12'h0` is read prematurely, the system will transition to `IDLE`, preventing FIR from continuing. This behavior needs further verification.

### state_data

```verilog
  reg [1:0] state;
  reg [1:0] next_state;
  // state for data
  localparam IDLE = 2'b00;
  localparam TRAN = 2'b01;
  localparam FIR = 2'b10;

  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      state <= IDLE;
    end else begin
      state <= next_state;
    end
  end

  always @(*) begin
    case (state)
      IDLE: begin
        if (ap_start) begin
          next_state = TRAN;
        end else begin
          next_state = IDLE;
        end
      end
      TRAN: begin
        if (ss_tvalid) begin
          next_state = FIR;
        end else begin
          next_state = TRAN;
        end
      end
      FIR: begin
        if (sm_tvalid & sm_tready) begin
          if (sstlast_reg) begin
            next_state = IDLE;
          end else begin
            next_state = TRAN;
          end
        end else begin
          next_state = FIR;
        end
      end
      default: begin
        next_state = IDLE;
      end
    endcase
  end
```

```mermaid
stateDiagram-v2
    [*] --> IDLE

    IDLE --> TRAN : ap_start
    IDLE --> IDLE : !ap_start

    TRAN --> FIR : ss_tvalid
    TRAN --> TRAN : !ss_tvalid

    FIR --> IDLE : sm_tvalid & sm_tready & sstlast_reg
    FIR --> TRAN : sm_tvalid & sm_tready & !sstlast_reg
    FIR --> FIR : !(sm_tvalid & sm_tready)
```


`state_data` is primarily responsible for managing the **AXI-Stream** operations.  
It consists of three states: **IDLE, TRAN, and FIR**.

#### **IDLE**  
The system remains in the `IDLE` state when `ap_start` has not yet been received.  
In this state, **signals generated by AXI-Stream cannot be received**.  
Once `ap_start` is asserted, the system transitions to the `TRAN` state.

#### **TRAN**  
The `TRAN` state is active when the system has **not yet received** `ss_tvalid`.  
Once the system receives a valid `ss_tvalid` and `ss_tdata`, it transitions to the `FIR` state.

#### **FIR**  
The `FIR` state is entered after the system receives `ss_tvalid`.  
In this state, the system performs the computation corresponding to the current input data.  
Once the computation is complete and the output has been consumed, the system determines whether this is the **last data entry**:
- If **it is the last entry**, the system transitions to the `IDLE` state to prepare for the next round.
- If **it is not the last entry**, the system returns to the `TRAN` state and waits for the next `ss_tdata` input.




### state_ap

```verilog
  reg [1:0] state_ap;
  reg [1:0] next_state_ap;
  
  // state_ap
  localparam IDLE_AP = 2'b00;
  localparam CAL_AP = 2'b01;
  localparam DONE_AP = 2'b10; 

  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      state_ap <= IDLE_AP;
    end else begin
      state_ap <= next_state_ap;
    end
  end

  always @(*) begin
    case (state_ap)
      IDLE_AP: begin
        if (ap_start) begin
          next_state_ap = CAL_AP;
        end else begin
          next_state_ap = IDLE_AP;
        end
      end
      CAL_AP: begin
        if (sm_tvalid & sm_tready & sstlast_reg) begin 
          next_state_ap = DONE_AP;
        end else begin
          next_state_ap = CAL_AP;
        end
      end
      DONE_AP: begin
        if (r_permit & (address_reg == 12'h0) & arready) begin
          next_state_ap = IDLE_AP;
        end else begin
          next_state_ap = DONE_AP;
        end
      end
      default: begin
        next_state_ap = IDLE_AP;
      end
    endcase
  end
```

```mermaid
stateDiagram-v2
    [*] --> IDLE_AP

    IDLE_AP --> CAL_AP : ap_start
    IDLE_AP --> IDLE_AP : !ap_start

    CAL_AP --> DONE_AP : sm_tvalid & sm_tready & sstlast_reg
    CAL_AP --> CAL_AP : otherwise

    DONE_AP --> IDLE_AP : r_permit & (address_reg == 0x0) & arready
    DONE_AP --> DONE_AP : otherwise
```


`IDLE_AP` refers to the state where the system resides before `ap_start` is asserted. After every reset, the system also returns to this state.  
If `ap_start` is asserted while in the `IDLE_AP` state, the state machine transitions to the `CAL_AP` state.

`CAL_AP` refers to the state where the system is performing FIR computations.  
If the system receives `sm_tvalid & sm_tready & sstlast_reg`, it indicates that the system has received the final `y` value, and the system will transition to the `DONE_AP` state.

`DONE_AP` refers to the state where the system has completed one full round of data processing and all `y` values have been output.  
At this point, if the system detects `address == 12'h0`, it can transition back to the `IDLE_AP` state, allowing the system to proceed to the next round.

```verilog
 assign ap_done = (state_ap == DONE_AP);
 assign ap_idle = (state_ap != CAL_AP);
```

`ap_done` and `ap_idle` can be directly controlled by `state_ap`.  
`ap_idle` is only **0** when FIR processing is in progress, while `ap_done` is **1** only in the `DONE_AP` state.  

Once `ap_done` is read, `state_ap` will transition to the `IDLE_AP` mode, and `ap_done` should also be set to **0**.

```verilog
assign ap_start = (w_permit & (address_reg == 12'h0)) ? data_reg : ((state == FIR) ? 0 : ap_start_prev); 

 always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      ap_start_prev <= 0;
    end else begin
      ap_start_prev <= ap_start;
    end
  end
```

`ap_start` is written when `address` is **0** and `w_permit` is asserted.  
It is reset to **0** when `state_ap` and `state_tap` transition to FIR computation.  
At all other times, it retains its previous value.



## axi-lite

### address_reg and data_reg

```verilog
  reg [(pADDR_WIDTH-1):0] address_reg_prev;
  reg [(pDATA_WIDTH-1):0] data_reg_prev;
  reg [(pDATA_WIDTH-1):0] data_reg;
  reg [(pADDR_WIDTH-1):0] address_reg;  
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      address_reg_prev <= address_reg;
      data_reg_prev <= data_reg;
    end else begin
      address_reg_prev <= address_reg;
      data_reg_prev <= data_reg;
    end
  end
 
  always @(*) begin
    case (state)
      IDLE: begin
        address_reg = 0;
        data_reg = 0;
      end 
      TRAN: begin
        if (awvalid) begin
          address_reg = awaddr;
        end else if (arvalid) begin
          address_reg = araddr;
        end else begin
          address_reg = address_reg_prev;
        end
        if (wvalid) begin
          data_reg = wdata;
        end else begin
          data_reg = data_reg_prev;
        end 
      end
      WAIT: begin
        address_reg = address_reg_prev;
        data_reg = data_reg_prev;
      end
      FIR: begin
        if (arvalid) begin
          address_reg = araddr;
        end else begin
          address_reg = address_reg_prev;
        end
        data_reg = data_reg_prev;
      end
      default: begin
        address_reg = 0;
        data_reg = 0;
      end
    endcase
  end
```

`address_reg` and `data_reg` are registers that store the addresses or data transmitted via **AXI-Lite**.  
Their signals are determined based on the system state and whether a **write** or **read** operation is being performed.


### data_len_reg and tap_num_reg

```verilog
  reg [(pDATA_WIDTH-1):0] tap_num_reg_prev;
  reg [(pDATA_WIDTH-1):0] data_len_reg_prev;
  wire [(pDATA_WIDTH-1):0] tap_num_reg;
  wire [(pDATA_WIDTH-1):0] data_len_reg;


always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      data_len_reg_prev <= 0;
      tap_num_reg_prev <= 0;
    end else begin
      data_len_reg_prev <= data_len_reg;
      tap_num_reg_prev <= tap_num_reg;
    end
  end  

  assign data_len_reg = (w_permit & (address_reg == 12'h10)) ? data_reg : data_len_reg_prev;
  assign tap_num_reg = (w_permit & (address_reg == 12'h14)) ? data_reg : tap_num_reg_prev;
```

`data_len_reg` and `tap_num_reg` store the data written to input addresses **0x10** and **0x14**, respectively.

### wready awready rvalid arready

```verilog
  assign writing = awvalid & wvalid;
  assign w_permit = writing & (state == TRAN);
  assign r_permit = arvalid & (state != IDLE);
  assign rvalid = (arready ? 1 : (rvaild_down ? 0 : rvalid_reg));
  assign arready = (~(writing) & arvalid) & (state == WAIT | fir_read_d1);
  assign awready = writing & ((state == WAIT) | (state == FIR));
  assign wready = writing & ((state == WAIT) | (state == FIR));
  assign fir_read_ok = (state == FIR) & arvalid;
  
  always @(posedge axis_clk) begin
    fir_read_d1 <= fir_read; 
  end
  
   always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      rvaild_down <= 0;  
    end else if (rvalid & rready) begin
      rvaild_down <= 1;
    end else begin
      rvaild_down <= 0;
    end
  end

  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      rvalid_reg <= 0;
    end else begin
      rvalid_reg <= rvalid;
    end
  end

```

- `AWREADY` and `WREADY` are asserted (`1`) when both `awvalid` and `wvalid` are high simultaneously.  
  They are designed to be asserted **one cycle after** `awvalid` and `wvalid`.

- `ARREADY` is asserted when `arvalid` is high and the system is **not in a write operation**.  
  It is also designed to be asserted **one cycle after** `arvalid`.

- `RVALID` is asserted **after** `arready` is received.  
  It remains high until `rready` is asserted, at which point it is deasserted (`0`).

### Tap Ram

```verilog
  assign tap_WE = {4{(state == TRAN) & (awaddr[7] & (awaddr[11:8] == 0))}};
  assign tap_EN = (state != IDLE);
  assign tap_A = (state == FIR) ? {4'b0, fir_data_count, 2'b0} : (((w_permit | r_permit) & (address_reg[7] & (address_reg[11:8] == 0))) ? {5'b0, address_reg[6:2], 2'b0} : tap_A_prev);
  assign tap_Di = (w_permit & (address_reg[7] & (address_reg[11:8] == 0))) ? data_reg : tap_Di_prev;

  reg [(pADDR_WIDTH-1):0] tap_A_prev;
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      tap_A_prev <= 0;
    end else begin
      tap_A_prev <= tap_A;
    end
  end

  reg [(pDATA_WIDTH-1):0] tap_Di_prev;
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      tap_Di_prev <= 0;
    end else begin
      tap_Di_prev <= tap_Di;
    end
  end
```

- `tap_WE` is enabled **only when** `state_tap` is in `TRAN` and `awaddr` is within the range `12'h80 ~ 12'hFF`.

- `tap_EN` is designed to be `1` in all `state_tap` states **except** `IDLE`.

- `tap_A` is divided into two parts to accommodate both **AXI-Lite** operations and **FIR computation**:
  - If `state_tap == FIR`, `tap_A` is controlled by `fir_data_count` to ensure correct FIR operation.
  - If `state_ap != FIR`, `tap_A` changes based on read/write requests. Otherwise, it retains its previous value.

- `tap_Di` is enabled **only when AXI-Lite needs to write data**. If no write operation is required, it retains its previous value.

### rdata

```verilog
  reg [(pDATA_WIDTH-1):0] read_data_reg; 
  assign rdata = read_data_reg;

 always @(*) begin
    if (r_permit) begin
      if (address_reg == 12'h0) begin
        read_data_reg = ap_crtl;
      end else if (address_reg == 12'h10) begin
        read_data_reg = data_len_reg;
      end else if (address_reg == 12'h14) begin
        read_data_reg = tap_num_reg;
      end else if ((address_reg[7] & (address_reg[11:8] == 0)) & state != FIR) begin
        read_data_reg = tap_Do;
      end else begin
        read_data_reg = 32'hffffffff;
      end
    end else begin
      read_data_reg = read_data_reg_prev;
    end
  end
endmodule

  reg [(pDATA_WIDTH-1):0] read_data_reg_prev;
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      read_data_reg_prev <= 0;
    end else begin
      read_data_reg_prev <= read_data_reg;
    end
  end
```

`read_data_reg` is a register used to retrieve the value from the specified address.  

- If the read address is **not used in this design** or if **tap coefficients are read during FIR computation**, it returns `32'hffffffff`.  
- Otherwise, it retains its previous value.

## axi-stream

### ss_tready

```verilog
  assign ss_tready = (state == IDLE) ? 0 : ss_tready_reg;
  wire ss_tready_reg_tmp;
  assign ss_tready_reg_tmp = (state == TRAN) & ss_tvalid;
  always @(posedge axis_clk) begin
    ss_tready_reg <= ss_tready_reg_tmp;
  end
```

`ss_tready` remains **0** when `state_data == IDLE`.  

- It is asserted **one cycle after** receiving `ss_tvalid` when `state_data == TRAN`.  
- It stays high for **only one cycle** before being deasserted.


### ss_tlast_reg

```verilog
  reg sstlast_reg; 
  reg sstlast_reg_prev;
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      sstlast_reg_prev <= 0;
    end else begin
      sstlast_reg_prev <= sstlast_reg;
    end
  end

  always @(*) begin
    case (state)
      IDLE: begin
        sstlast_reg = 0;
      end
      TRAN: begin
        if (ss_tvalid & ss_tlast) begin
          sstlast_reg = 1;
        end else begin
          sstlast_reg = 0;
        end
      end
      default: begin
        sstlast_reg = sstlast_reg_prev;
      end
    endcase
  end
```

`ss_tlast_reg` is a register used to store whether the current data is the **last data entry**.  
It serves as a reference when outputting `y` to determine whether the current round should end.

### total_num_data tape_num

```verilog
  wire [5:0] tape_num;
  wire [5:0] total_num_data_tmp;
  assign total_num_data_tmp = (state == IDLE) ? 0 : (total_num_data == tape_num ? total_num_data : (ss_tready) ? (total_num_data + 1) : total_num_data);
  assign tape_num = (tap_num_reg - 1) & 6'b111111;

  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      total_num_data <= 0;
    end else begin
      total_num_data <= total_num_data_tmp;
    end
  end
```

- `tap_num` records the **tap_number count**, using **0-based indexing**.  
- `total_num_data` keeps track of the total number of data entries received in the current round.  
  - If `total_num_data` reaches `tap_num`, it remains fixed at `tap_num`.

### this_round_num base_addr next_sstdata_addr

```verilog
 assign this_round_num = ((state == TRAN) & (ss_tvalid)) ? total_num_data : this_round_num_prev;
 assign base_addr = (state == TRAN) ? next_sstdata_addr : base_addr_prev; 

  reg [5:0] next_sstdata_addr_tmp;
  always @(*) begin
    if (state == IDLE) begin
      next_sstdata_addr_tmp = 0;
    end else if ((state == FIR) & ss_tready) begin
      if (next_sstdata_addr == tape_num) begin
        next_sstdata_addr_tmp = 0;
      end else begin
        next_sstdata_addr_tmp = next_sstdata_addr + 1;
      end
    end else begin
      next_sstdata_addr_tmp = next_sstdata_addr;
    end
  end

  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      next_sstdata_addr <= 0;
    end else begin
      next_sstdata_addr <= next_sstdata_addr_tmp;
    end
  end
```

- `this_round_num` records the **number of data entries used in the current round** during the `TRAN` state.  

- `base_addr` is updated **in the `TRAN` state** to store the **starting address** of data for the current round.  

- `next_sstdata_addr` is updated **in the `FIR` state** to store the **starting address** of data for the next round.


### data_addr_gen fir_data_count

```verilog
  reg [5:0] data_addr_gen;   
  always @(*) begin
    case (state)
      TRAN: begin
        data_addr_gen = base_addr;
      end
      FIR: begin
        data_addr_gen = (base_addr >= fir_data_count) ? (base_addr - fir_data_count) : (tap_num_reg + base_addr - fir_data_count);
      end
      default: begin
        data_addr_gen = 0;
      end
    endcase
  end

  reg [5:0] fir_data_count
  wire [5:0] fir_data_count_tmp;
  assign fir_data_count_tmp = (state == FIR) ? fir_data_count + 1 : 0;
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      fir_data_count <= 0;
    end else begin
      fir_data_count <= fir_data_count_tmp;
    end
  end
```

- `data_addr_gen` generates the corresponding **address** based on the **starting address** and the **current data index**.  
  - If `count > base_addr`, `tap_num` is added to correctly map to the actual address.

- `fur_data_count` is a register that records the **current data index** when the system transitions to the `FIR` state.  
  - It is used to **control `data_address` and `tap_address`**.  
  - It also determines when to **clear the `y` register**.

### countdown

```verilog
  wire [31:0] countdown_tmp;
  assign countdown_tmp = (state != FIR) ? 32'hffffffff : ((fir_data_count == this_round_num) ? 3 : countdown - 1);
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      countdown <= 32'hffffffff;
    end else begin
      countdown <= countdown_tmp;
    end
  end
```

`countdown` is used to determine when to retrieve the `y` value.  
When `countdown` reaches **0**, `y` should be retrieved and wait for `sm` to read it.


### data Ram

```verilog
  assign data_EN = (state != IDLE);
  assign data_WE = {4{ss_tready}};
  assign data_A = {4'b0, data_addr_gen, 2'b0};
  assign data_Di = ss_tdata;
```

- `data_EN` is asserted **after `ap_start` is received**.  

- Data can only be input when `ss_tready` is high, so `data_WE` is **asserted only when `ss_tready` is active**.  

- `data_A` controls which data is being read or written and is **directly controlled by `data_addr_gen`**.  

- `data_Di` is **directly connected to `ss_tdata`**, as `data_WE` is only asserted when `ss_tready` is high.  

### sm_tvalid sm_tdata sm_tlast

```verilog
  assign sm_tdata = sm_tdata_reg;
  assign sm_tlast = (sm_tvalid) & (sstlast_reg);
  always @(*) begin 
    if (state != FIR) begin
      sm_tvalid = 0;
      sm_tdata_reg = 0;
    end else if (countdown == 0) begin
      sm_tvalid = 1;
      sm_tdata_reg = y_tmp_reg;
    end else begin
      sm_tvalid = sm_tvalid_prev;
      sm_tdata_reg = sm_tdata_reg_prev;
    end
  end

  reg [(pDATA_WIDTH-1):0] sm_tdata_reg_prev;
  reg sm_tvalid_prev;
  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      sm_tdata_reg_prev <= 0;
      sm_tvalid_prev <= 0;
    end else begin
      sm_tdata_reg_prev <= sm_tdata_reg;
      sm_tvalid_prev <= sm_tvalid;
    end
  end
```

- `sm_tdata` retrieves the value from the `y` register **when `countdown` reaches 0**.  
  - It maintains the same value **until it is read**.  

- `sm_tvalid` behaves the same as `sm_tdata`:  
  - It is asserted **when `countdown` reaches 0** and remains high **until `sm_tready` is received**.  

- `sm_tlast` is asserted **when both `sstlast_reg` and `sm_tvalid` are high**.  
  - Since `sstlast_reg == 1` indicates that the **last data input has been received**, this output is also the **final data entry**.  
  - `sm_tlast` is asserted to notify the system.

## FIR Processing Flow

```verilog
always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      data_tmp <= 0;
    end else begin
      data_tmp <= data_Do;
    end
  end

  always @(posedge axis_clk or negedge axis_rst_n) begin
     if (~axis_rst_n) begin
      tap_tmp <= 0;
    end else begin
      tap_tmp <= tap_Do;
    end
  end
 
  assign Multi_tmp = data_tmp * tap_tmp;

  always @(posedge axis_clk or negedge axis_rst_n) begin
    if (~axis_rst_n) begin
      Multi_tmp_reg <= 0;
    end else begin
      Multi_tmp_reg <= Multi_tmp;
    end
  end

  assign y_tmp = Multi_tmp_reg + y_tmp_reg;

  always @(posedge axis_clk) begin
    if (fir_data_count == 2) begin
      y_tmp_reg <= 0;
    end else begin
      y_tmp_reg <= y_tmp;
    end
  end
```
![螢幕擷取畫面 2025-03-24 001534](https://hackmd.io/_uploads/SykgD6A2yg.png)

### **Important Note**  
When `fir_data_count == 2`, `y_tmp` will be **cleared**.  

- This is because, in the next cycle, **the first value of a new round** will enter the `y` register.  
- Therefore, clearing `y_tmp` at this point is necessary to ensure proper data handling.

![image](https://hackmd.io/_uploads/ByyGc9Sh1l.png)

The waveform diagram above represents the case when there is only **one data**.  

- As shown, when `fir_data_count == 2`, `y_tmp_reg` needs to be **cleared**.  
- This is because, on the next **posedge of `axis_clk`**, a new round's `y_tmp` will be stored.  



# Waveform and Area Report

## Axilite
![image](https://hackmd.io/_uploads/HkyeqvB3yg.png)

## Axistream

![image](https://hackmd.io/_uploads/SkszqDH2yl.png)

## Area Report

![image](https://hackmd.io/_uploads/By55cwBnJx.png)

## Throuput

![image](https://hackmd.io/_uploads/HJRipNanye.png)
