Task: Q4_HC


---

# Human Version — Huffman Coding Hardware: Complete Design Specification

## 1) Problem Description

Design and implement a hardware **Huffman Coding generator** (`huffman` core) for lossless compression. The input is a stream of grayscale pixels. For this contest, pixels are restricted to **six symbols** A1..A6 with fixed values:

* A1 = 0x01, A2 = 0x02, A3 = 0x03, A4 = 0x04, A5 = 0x05, A6 = 0x06.
* Exactly **100 pixels** are provided per run.

Your circuit must:

1. **Count** occurrences of each symbol across the 100-pixel input (statistics phase).
2. **Build Huffman codes** from those statistics using the specified ordering and tie-breaking rules (see §4).
3. **Output** the counts and the per-symbol Huffman codes in a fixed-width format (8-bit code field + 8-bit mask), with single-cycle valid strobes for each output phase (see §5 Timing).

> Restrictions: You must **compute** Huffman codes from the input statistics as specified. **Exhaustive lookup / precomputed table solutions are forbidden.**

---

## 2) Top-Level Rules & Naming

* **Top module name**: `TOP`.
* **Do not modify** the provided testbench (assumed). Your design must conform strictly to the interface below.
* Synchronous design on **posedge `clk`**. rst is **synchronous active-high**.

---

## 3) Interface (Ports and Semantics)

### 3.1 Signals

| Signal       | Dir |  Width | Description                                                                                                     |
| ------------ | --: | -----: | --------------------------------------------------------------------------------------------------------------- |
| `clk`        |   I |      1 | System clock; all design logic is posedge-triggered.                                                            |
| `rst`        |   I |      1 | **Synchronous, active-high** system rst. While `rst=1`: internal state cleared; no valid outputs asserted. |
| `gray_valid` |   I |      1 | When High, **one pixel per cycle** is present on `gray_data`.                                                   |
| `gray_data`  |   I |      8 | Grayscale pixel value. For this problem, values are in {0x01..0x06} corresponding to A1..A6.                    |
| `CNT_valid`  |   O |      1 | Single-cycle pulse indicating that symbol **counts** are valid on `CNT1..CNT6`.                                 |
| `CNT1..CNT6` |   O | 8 each | 8-bit **counts** of A1..A6, respectively, captured when `CNT_valid=1`.                                          |
| `code_valid` |   O |      1 | Single-cycle pulse indicating that **codes/masks** are valid on `HC1..HC6` and `M1..M6`.                        |
| `HC1..HC6`   |   O | 8 each | 8-bit **Huffman code fields** for A1..A6 (variable-length codes packed into 8 bits; see §4.4).                  |
| `M1..M6`     |   O | 8 each | 8-bit **mask fields** for A1..A6 (which bits of HC are valid; see §4.4).                                        |

### 3.2 Input assumptions

* Exactly **100 pixels** are streamed **contiguously** while `gray_valid=1`.
* The testbench **presents pixels once per cycle** during the input phase; your design samples on the **posedge** (you need not track the bench’s negedge driving—just meet the posedge sampling requirement with `gray_valid`).
* After the 100th pixel, `gray_valid` is deasserted (low).

---

## 4) Functional Requirements

### 4.1 Symbols and indices

* Symbols are labeled A1..A6 with **indices 1..6**, respectively. Use these indices whenever a tie-break requires “smaller index” first.

### 4.2 Overview of the 3 stages

1. **Initialization (sort)**: Sort the six symbols in **descending** order of occurrence probability (i.e., by their counts). If probabilities are equal, the symbol with **smaller index** appears **higher** in the list.
2. **Combination (C1, C2, …)**: Repeatedly **merge the two bottom items** (the current **lowest** probabilities) to form one group whose probability is the **sum** of its members. Re-insert the merged group and **resort** in descending probability. **Tie rule in combination**: if the merged group’s probability ties other entries, the **merged group is placed last within that tie group** (i.e., at the lowest position among equal probabilities). Continue until only **two items** remain.
3. **Split (code assignment)**: Starting from the final 2-item list, assign codes and **propagate upward** (reverse of combination): for each split step, the **upper** item gets bit **‘0’**, the **lower** item gets bit **‘1’**. Codes are built by **inheriting parent bits and appending** the split bit at each step until reaching individual symbols.

> Tree view conventions (if you draw a tree internally): for any 2-child node, place the **smaller probability on the left** and the **larger on the right**; during the split/code assignment that corresponds to the described **upper=‘0’ / lower=‘1’** rule when using the table-style lists.

### 4.3 Counting and probability

* With 100 pixels, each symbol’s probability is `count/100`. You may work directly with **counts** (no need to normalize), since ordering by counts is equivalent to ordering by probabilities.

### 4.4 Code representation on outputs (HC/M)

Because Huffman codes are **variable-length**, each symbol’s code is conveyed as:

* `HCx` (8 bits): the **code bits packed into the 8 LSBs**, and
* `Mx` (8 bits): a **bitmask** marking which bits of `HCx` are valid.

**Rules:**

* If a symbol’s code length is `L` (1 ≤ L ≤ 8):

  * Set `Mx[L-1:0] = 1` and `Mx[7:L] = 0`.
  * Put the code’s bit string into `HCx[L-1:0]` **in the same left-to-right order that you write the code**. (Example below.)
  * Force `HCx[7:L] = 0`.
* **Examples**:

  * If A6’s code is `00` (length 2): `M6 = 0000_0011 (0x03)`, `HC6 = 0000_0000 (0x00)`.
  * If A3’s code is `01010` (length 5): `M3 = 0001_1111 (0x1F)`, `HC3 = 0000_1010 (0x0A)`.

> Note: The code strings shown in figures (e.g., `00`, `011`, `01010`) are the **exact bit patterns** to place into `HCx[L-1:0]` (so the numeric value of `HCx[L-1:0]` equals the binary code read left-to-right).

### 4.5 Prohibited approach

* It is **not allowed** to solve by **exhaustive enumeration** / prebuilt mapping. The Huffman construction must follow the specified **initialize → combination (with tie rules) → split** process on the **actual input counts**.

---

## 5) Timing and Phases

### 5.1 rst and input (T1, T2, T3)

* **T1**: `rst=1` is asserted for at least two cycles. During `rst=1`, clear all internal state and do **not** assert `CNT_valid` or `code_valid`. After `rst` deasserts (1→0), the core is ready.
* **T2**: **Input phase** — the testbench sets `gray_valid=1` and streams **100 pixels**, one per cycle, on `gray_data`. Your design samples at the **posedge** while `gray_valid=1`.
* **T3**: End of input — the testbench deasserts `gray_valid` to 0. The design must then proceed to compute counts (if not already complete) and the Huffman codes.

### 5.2 Outputs (T4, T5)

* **T4 (Counts available)**: When the six symbol counts are ready, assert `CNT_valid=1` for **one clock cycle** and **simultaneously** drive:

  * `CNT1..CNT6` with the counts of A1..A6 (8-bit each).
* **T5 (Codes available)**: When all Huffman codes are ready, assert `code_valid=1` for **one clock cycle** and **simultaneously** drive:

  * `HC1..HC6` (8-bit each) with the packed codes per §4.4, and
  * `M1..M6` (8-bit each) with the masks per §4.4.
    After `code_valid` returns Low, verification may complete; no further outputs are required in that run.

> All outputs are synchronous to `clk`. Valid strobes (`CNT_valid`, `code_valid`) are **one-cycle pulses**.

---

## 6) Determinism & Tie-Breaking (must-follow)

To ensure every implementation produces the **same codes** for a given input:

1. **Initialization**: Sort symbols by **descending** probability (count). **If equal**, the **smaller index** (A1 < A2 < … < A6) is **higher** (earlier) in the list.
2. **Combination**: At each combination round, always **merge the bottom two** entries (the two with **lowest** probabilities in the current sorted list). The merged group’s probability is the **sum** of its members. After merging, **resort**; **if the merged group ties** with others, place the merged group **last** within that tie group.
3. **Split / Code assignment**: Starting from the final 2-item list, at each split step:

   * The **upper** item gets bit **‘0’**,
   * The **lower** item gets bit **‘1’**,
     and codes are formed by **appending** these bits while moving from the final list back to the individual symbols.
4. **Output packing**: Place the resulting bit strings into `HCx`/`Mx` exactly as in §4.4.

---

## 7) Verification Expectations (what the bench assumes)

* Input values are limited to {0x01..0x06}.
* Exactly 100 samples per run.
* The checker latches counts on `CNT_valid=1` and codes/masks on `code_valid=1`.
* Code equivalence is judged using the **deterministic procedure** above (including tie-break rules).

---

## 8) Examples (mirroring the brief)

* If counts yield codes like:
  A2:`1`, A6:`00`, A1:`011`, A4:`0100`, A3:`01010`, A5:`01011`,
  then (lengths in brackets):

  * `HC2=0000_0001`, `M2=0000_0001` (L=1)
  * `HC6=0000_0000`, `M6=0000_0011` (L=2)
  * `HC1=0000_0111`, `M1=0000_0111` (L=3)
  * `HC4=0000_0100`, `M4=0000_1111` (L=4)
  * `HC3=0000_1010`, `M3=0001_1111` (L=5)
  * `HC5=0000_1011`, `M5=0001_1111` (L=5)

(Exact codes depend on the measured counts; use the specified rules so your results match the reference for any pattern.)

---


## Reference RTL Implementation

module TOP (
input clk,
input rst,
output  [2:0] W,
output  [2:0] J,
input [6:0] Cost,
output reg [3:0] MatchCount,
output reg [9:0] MinCost,
output Valid );

//================================================================
//  integer / genvar / parameters
//================================================================
integer i;
localparam IDLE = 0, SORT0 = 1,
          INPUT = 2, OUTPUT = 3;
genvar idx;

reg [1:0] state_r, state_w;
reg [2:0] job[0:7];
reg [3:0] cnt;
reg [9:0] costTemp;
reg [2:0]  index; //changepoint index
reg [2:0] index2[0:7];
reg [6:0]  match;
wire flag[0:7];



//// job ///
always @(posedge clk or posedge rst) begin
    if(rst) begin
        for(i=0;i<8;i=i+1) job[i] <= i;
    end
    else if(state_r == OUTPUT) begin
        if( flag[1] ) begin
            job[index] <= job[index2[1]];
            job[index2[1]] <= job[index];  
        end
        else if( flag[2] ) begin
            job[index] <= job[index2[2]];
            job[index2[2]] <= job[index];
        end
        else if( flag[3] ) begin
            job[index] <= job[index2[3]];
            job[index2[3]] <= job[index]; 
        end
        else if( flag[4] ) begin
            job[index] <= job[index2[4]];
            job[index2[4]] <= job[index];  
        end
        else if( flag[5] ) begin
            job[index] <= job[index2[5]];
            job[index2[5]] <= job[index];  
        end
        else if( flag[6] ) begin
            job[index] <= job[index2[6]];
            job[index2[6]] <= job[index]; 
        end
        else begin // flag[7]
            job[index] <= job[index2[7]];
            job[index2[7]] <= job[index];  
        end
    end
    else if(state_r == SORT0) begin
        case(index) 
            5:  begin
                job[7] <= job[6];
                job[6] <= job[7];
            end
            4:  begin
                job[7] <= job[5];
                job[5] <= job[7];
            end
            3:  begin
                job[7] <= job[4];
                job[6] <= job[5];
                job[5] <= job[6];
                job[4] <= job[7];
            end
            2:  begin
                job[7] <= job[3];
                job[6] <= job[4];
                job[4] <= job[6];
                job[3] <= job[7];
            end 
            1:  begin
                job[7] <= job[2];
                job[6] <= job[3];
                job[5] <= job[4];
                job[4] <= job[5];
                job[3] <= job[6];
                job[2] <= job[7];
            end
            0:  begin
                job[7] <= job[1];
                job[6] <= job[2];
                job[5] <= job[3];
                job[3] <= job[5];
                job[2] <= job[6];
                job[1] <= job[7];
            end
        endcase
    end
end


always @(posedge clk or posedge rst) begin
    if(rst) begin
        for(i=0; i<7; i=i+1) match[i] <= 1;
    end
    else if( state_w == INPUT && cnt <7 ) match[cnt] <= ( job[cnt+1] > job[cnt] );
end

always @(posedge clk or posedge rst) begin
    if(rst) begin
        for( i=0; i<8; i=i+1 ) index2[i] <= i;
    end
    else if( state_w == INPUT ) index2[job[cnt]] <= cnt;
end
assign flag[0] = 0; 

generate
    for( idx=1; idx<8; idx=idx+1 ) begin
        assign flag[idx] = ( index2[idx] > index && job[index2[idx]] > job[index] ) ;
    end
endgenerate

//// match ////
always @( * ) begin
    if(match[6] == 1) index = 6;
    else if(match[5] == 1) index = 5;
    else if(match[4] == 1) index = 4;
    else if(match[3] == 1) index = 3;
    else if(match[2] == 1) index = 2;
    else if(match[1] == 1) index = 1;
    else index = 0;
end
 
always @(posedge clk or posedge rst) begin
    if(rst) cnt <= 0;
    else if(state_w == INPUT)  cnt <=  cnt + 1;
    else    cnt <= 0;
end

assign W = job[cnt] ;
assign J = cnt ;

//// costTemp ////
always @(posedge clk or posedge rst) begin
    if(rst) costTemp <= 0;
    else if(state_r == INPUT) begin
        if( cnt == 1 ) costTemp <= Cost;
        else costTemp <= costTemp + Cost;
    end
end

//// MinCost ////
always @(posedge clk or posedge rst) begin
    if(rst) MinCost <= 0;
    else if(state_r == OUTPUT) begin
        if(MinCost == 0)      MinCost <= costTemp;
        else if(costTemp < MinCost) MinCost <= costTemp;
    end
end

//// MatchCount ////
always @(posedge clk or posedge rst) begin
    if(rst) MatchCount <= 1;
    else if(state_r == OUTPUT) begin
        if(MinCost == 0 || costTemp < MinCost)    MatchCount <= 1;
        else if(costTemp == MinCost)    MatchCount <= MatchCount + 1;
    end
end  

//// Valid ////

assign Valid = ( state_r == IDLE && match == 0);

//================================================================
//  FSM
//================================================================
always @( posedge clk or posedge rst ) begin
	if( rst ) state_r <= IDLE;
	else state_r <= state_w;
end

always @( * ) begin
	case( state_r ) 
	IDLE:     state_w = INPUT;
    SORT0:    state_w = INPUT;
	INPUT:    state_w = (cnt == 8) ? OUTPUT : INPUT;
    OUTPUT:   state_w = ( match == 0  ) ? IDLE : SORT0;
    default:        state_w = IDLE;
	endcase	
end

endmodule




## Testbench

`timescale 1ns/10ps
`define CYCLE      10.0  
`define End_CYCLE  1000000
`define PAT        "./00_TB/cost_rom"

`ifdef P1
    `define PAT_NUM 1 
`elsif P2
    `define PAT_NUM 2 
`elsif P3
    `define PAT_NUM 3 
`else
    `define PAT_NUM 1 
`endif


module test;
integer fd;
localparam LINE_MAX = 256; 
integer charcount;
reg[LINE_MAX*8-1:0] line_buf;
string line;
integer freturn;

integer patnum;

reg clk = 0;
wire Valid;
reg rst = 1;
wire [2:0] W;
wire [2:0] J;
reg [6:0] Cost;
wire [3:0] MatchCount;
wire [9:0] MinCost;
TOP TOP(.clk(clk),
        .rst(rst),
        .W(W),
        .J(J),
        .Cost(Cost),
        .MatchCount(MatchCount),
        .MinCost(MinCost),
        .Valid(Valid));
        
localparam SDFFILE = "../02_SYN/Netlist/top_syn.sdf";
`ifdef SDF
	initial $sdf_annotate(SDFFILE, TOP);
`endif
always begin #(`CYCLE/2) clk = ~clk; end

initial begin
	$display(" Cycle Period = %0f ns", `CYCLE);
end

// initial begin
//     $fsdbDumpfile("top.fsdb");
//     $fsdbDumpvars(0, TOP);
// end

//initial begin
//    $dumpvars();
//    $dumpfile("JAM.vcd");
//end

initial begin
    $display("*******************************");
    $display("** Simulation Start          **");
    $display("*******************************");
    @(posedge clk);  #2 rst = 1'b1; 
    #(`CYCLE*2);  
    @(posedge clk);  #2  rst = 1'b0;
end

reg [30:0] cycle=0;
reg [6:0] costrom [0:63];
always @(posedge clk) begin
    cycle=cycle+1;
    if (cycle > `End_CYCLE) begin
        $display("-              Total Error: %0d               -", 1);
        $display("********************************************************************");
        $display("**  Failed waiting Valid signal, Simulation STOP at cycle %d **",cycle);
        $display("**  If needed, You can increase End_CYCLE value in tp.v           **");
        $display("********************************************************************");
        $fclose(fd);
        $finish;
    end
end
integer key_value;
string key;
integer v0,v1,v2,v3,v4,v5,v6,v7;
integer worker = -1;
integer i;
integer j;
reg [3:0] goldMatchCount;
reg [8:0] goldMinCost;
initial begin : MAIN
    //------------------------------------------------------------------
    // 1) 開檔
    //------------------------------------------------------------------
    fd = $fopen(`PAT,"r");
    if (fd == 0) begin
        $display("pattern handle null");
        $finish;
    end

    //------------------------------------------------------------------
    // 2) 讀第一行
    //------------------------------------------------------------------
    charcount = $fgets(line_buf, fd);
    line      = line_buf;          // reg → string

    //------------------------------------------------------------------
    // 3) 主迴圈：掃完整個檔案
    //------------------------------------------------------------------
    while (charcount > 0) begin : READ_PATTERN

        //------------------------------------------------------------------
        // 3‑1) 先把空行與註解行全部跳過
        //------------------------------------------------------------------
        while (charcount > 0 &&
            (charcount == 1 ||
            line_buf[8*LINE_MAX-1 -:16] == 16'h2f2f)) begin
            charcount = $fgets(line_buf, fd);
            line      = line_buf;
        end
        if (charcount == 0) disable READ_PATTERN;   // EOF 時提早離開

        //------------------------------------------------------------------
        // 3‑2) 判斷這行是 pattern 標頭還是資料
        //------------------------------------------------------------------
        if (line.substr(0, 6) == "pattern") begin
            freturn = $sscanf(line, "pattern %d", patnum);
            if (patnum == `PAT_NUM) $display("PATTERN: %3d", patnum);
        end
        else if (patnum == `PAT_NUM) begin
            // 只處理目標樣本的屬性或矩陣
            if ($sscanf(line, "min_cost %d", key_value) == 1) begin
                goldMinCost = key_value;
            end
            else if ($sscanf(line, "match_count %d", key_value) == 1) begin
                goldMatchCount = key_value;
            end
            else if ($sscanf(line,
                      "%d %d %d %d %d %d %d %d",
                      v0,v1,v2,v3,v4,v5,v6,v7) == 8) begin
                if (worker == -1) begin
                    $display("-------------- Cost Table --------------");
                    $display("Jobs       0   1   2   3   4   5   6   7");
                end
                worker = worker + 1;
                $display("worker%1d: %3d %3d %3d %3d %3d %3d %3d %3d",
                         worker,v0,v1,v2,v3,v4,v5,v6,v7);

                // 存進 ROM（一維展平）
                costrom[worker*8+0] = v0;
                costrom[worker*8+1] = v1;
                costrom[worker*8+2] = v2;
                costrom[worker*8+3] = v3;
                costrom[worker*8+4] = v4;
                costrom[worker*8+5] = v5;
                costrom[worker*8+6] = v6;
                costrom[worker*8+7] = v7;
            end
            else begin
                $display("unknown line: -%s-", line);
            end
        end

        //------------------------------------------------------------------
        // 3‑3) 讀下一行，再回到 while 判斷
        //------------------------------------------------------------------
        charcount = $fgets(line_buf, fd);
        line      = line_buf;
    end : READ_PATTERN
end : MAIN

reg wait_valid;
reg [2:0] W_s;
reg [2:0] J_s;
assign Cost=costrom[8*W_s+J_s];
always @(posedge clk ) begin
    W_s <=  #1 W;
    J_s <=  #1 J;
end

integer total_error;
always @(posedge clk ) begin
    total_error = 0;
    if (rst) begin
        wait_valid=1;
    end
    else begin
        if(cycle[20:0] == 20'b00000000000000000000) begin
            $display("cycle: %d, still running...", cycle);
        end
        if(wait_valid == 1) begin
            if (Valid ==1) begin
                wait_valid=0;
                $display("receive MinCost/MatchCount= %d/%d , golden MinCost/MatchCount= %d/%d",MinCost,MatchCount,goldMinCost,goldMatchCount);
                $display("----------------------------------------------");
                $display("------------total time: %0d cycles-----------------", cycle);
                $display("----------------------------------------------");
                if((goldMatchCount == MatchCount) && (goldMinCost == MinCost)) begin
            		$display("------------------------------------------------");
            		$display("----------------All tests PASS!-----------------");
            		$display("------------------------------------------------");
            	end else begin
                    total_error = 1;
            		$display("------------------------------------------------");
            		$display("-              Total Error: %0d               -", total_error);
            		$display("------------------------------------------------");
            	end

                $finish;
            end
        end
//assert (W<10) else $display("ERROR,at cycle %-d,  W = %d >10",cycle,W);
//assert (J<10) else $display("ERROR,at cycle %-d,  J = %d >10",cycle,J);
    end
end


endmodule