# Human-Readable Spec (LBP Accelerator)

## 1. Goal & Scope

Design an RTL hardware module **LBP** that:

* Reads an **8-bit** grayscale image from a host memory interface (**gray\_mem**, 128×128, linear address 0…16383).
* Computes **Local Binary Pattern (LBP)** for every pixel independently using a **3×3, 8-neighbor** definition.
* Writes each 8-bit result to a host memory interface (**lbp\_mem**, 128×128, address-aligned 1:1 with the source pixel).
* Sets **`finish=1`** when all required pixels are written.
* Excludes appendices and scoring/benchmark rules—this is a **functional** spec sufficient to implement and verify correctness.

## 2. Top-Level Module & Ports

**Module name:** `TOP`
**Clocking:** rising-edge synchronous (`clk`).
**rst:** `rst` is **active-high Synchronous**; design must reach a defined idle state after deassertion.

**Ports**

* `clk` (input, 1b): system clock, positive-edge synchronous.
* `rst` (input, 1b): Synchronous, active-high; initialize internal state when asserted; leave in a clean idle when deasserted.
* `gray_addr` (output, **14b**): read address to `gray_mem` (0…16383). **At most one address may be requested per clock cycle.**
* `gray_req` (output, 1b): read-request enable for `gray_mem`.
* `gray_ready` (input, 1b): host indicates `gray_mem` can accept requests. **Do not issue reads unless `gray_ready=1`.** If it ever deasserts, pause issuing new requests until it reasserts.
* `gray_data` (input, **8b**): data returned by host for the address requested.
* `lbp_addr` (output, **14b**): write address to `lbp_mem` (0…16383).
* `lbp_valid` (output, 1b): write-enable; when high, `lbp_addr` and `lbp_data` are valid and must be written by the host.
* `lbp_data` (output, **8b**): LBP result to be written.
* `finish` (output, 1b): assert high when the full frame is processed and all required writes have been performed; keep high until rst.

> **Interfaces:** `gray_mem` is read-only; `lbp_mem` is write-only. There is **no** `lbp_ready` input.

## 3. Image, Addressing & Mapping

* **Input image:** 128×128 pixels, each 8-bit unsigned (0…255), stored in `gray_mem`.
* **Output image:** 128×128 pixels, each 8-bit unsigned (0…255), stored in `lbp_mem`.
* **Linear address mapping (row-major):**
  `addr = y * 128 + x`, where `x,y ∈ [0,127]` and therefore `addr ∈ [0,16383]`.
* **1:1 address rule:** The LBP result derived from `gray_mem[k]` must be written to **`lbp_mem[k]`** (same `x,y` → same address).
* **Border rule:** The outermost ring (`x=0`, `x=127`, `y=0`, `y=127`) **must be 0** in `lbp_mem`. The host **pre-initializes** `lbp_mem` to 0. Your design may either:

  * Skip writing border addresses (preferred), or
  * Write explicit zeros to border addresses,
    but **must not** write any non-zero value at the border.

## 4. Read & Write Handshakes (with timing semantics)

**General:** Your RTL is rising-edge synchronous. The host side *acts* on the **negative edge** of the same clock.

### 4.1 Read (LBP → `gray_mem`)

* Issue a read by driving `gray_req=1` and a stable `gray_addr`.
* On the **next falling edge**, the host detects `gray_req=1` and places the byte at `gray_mem[gray_addr]` onto `gray_data`.
* Your RTL should **sample `gray_data`** on the **next rising edge** after that falling edge.
* **Burst reads**: keep `gray_req=1` and update `gray_addr` every cycle to stream one byte per cycle.
* **Pause**: deassert `gray_req`; host stops returning data from the next falling edge onward.
* **Constraint:** at most **one** read address may be issued per clock cycle. There is **no limit** on total requests over the whole run.

### 4.2 Write (LBP → `lbp_mem`)

* To write a result, drive `lbp_valid=1` with stable `lbp_addr` and `lbp_data` in the same cycle.
* On the **next falling edge**, the host performs the write to `lbp_mem[lbp_addr] = lbp_data`.
* **Burst writes**: hold `lbp_valid=1` and update `lbp_addr`/`lbp_data` each cycle to stream one byte per cycle.
* **Stop**: deassert `lbp_valid` to pause writes.

### 4.3 Start & Finish

* Do **not** issue reads until `gray_ready=1` has been observed after rst deassertion.
* After all required pixels are written to `lbp_mem` (respecting border rule and address mapping), assert `finish=1`.

## 5. LBP Algorithm (3×3, 8 neighbors)

Let `gc` be the center pixel; `gp` for neighbors `p=0..7`. Use the **row-major** 3×3 labeling below and weight each neighbor by `2^p`.

```
p=0  p=1  p=2        (-1,-1) (-1, 0) (-1,+1)
p=3  gc   p=4   ==   ( 0,-1) ( 0, 0) ( 0,+1)
p=5  p=6  p=7        (+1,-1) (+1, 0) (+1,+1)
```

**Definition**

```
bit_p = 1 if (gp - gc) >= 0 else 0
LBP(x,y) = sum_{p=0..7} bit_p << p
```

* Each pixel’s LBP is **independent** of others (suitable for internal parallelism).
* The LBP value naturally fits in 8 bits (0…255); no saturation or sign handling is required.

## 6. Iteration Domain & Control

* **Compute only for non-border pixels:** `x ∈ [1,126]`, `y ∈ [1,126]`.
* For each `(x,y)` in that range:

  1. Gather the 3×3 window around `(x,y)` using the address mapping.
  2. Compute `LBP(x,y)` per Section 5.
  3. Write the result to `lbp_mem[ y*128 + x ]`.
* **Order freedom:** You may process pixels in any order (scanline, tiled, micro-pipelined…), provided all protocol rules and mapping constraints are satisfied.

## 7. rst & Initialization Requirements

* Asserting `rst=1` must Synchronously clear internal state and outputs to safe defaults:

  * `gray_req=0`, `lbp_valid=0`, `finish=0`.
  * Optional: clear internal FIFOs/buffers.
* After deasserting `rst`, wait for `gray_ready=1` before starting reads.

## 8. Legal/Illegal Behaviors (Protocol Safety)

**Legal**

* Issue at most one read request per cycle; stream reads/writes by holding enable high.
* Pause/resume cleanly by dropping `gray_req`/`lbp_valid`.
* Skip border writes (since host pre-zeros the frame).

**Illegal**

* Issuing read requests while `gray_ready=0`.
* Writing any **non-zero** to border addresses.
* Writing a result to an address different from the source pixel’s address (`1:1` rule).

## 9. Reference Pseudocode (behavioral, cycle-agnostic)

```c
// Assume gray(y,x) reads gray_mem[y*128 + x]
// and lbp(y,x) writes lbp_mem[y*128 + x].

for (int y = 1; y <= 126; ++y) {
  for (int x = 1; x <= 126; ++x) {
    uint8_t gc = gray(y, x);
    uint8_t g[8] = {
      gray(y-1,x-1), gray(y-1,x),   gray(y-1,x+1),
      gray(y,  x-1),                 gray(y,  x+1),
      gray(y+1,x-1), gray(y+1,x),   gray(y+1,x+1)
    };
    uint8_t v = 0;
    for (int p=0; p<8; ++p) v |= ((g[p] >= gc) ? 1 : 0) << p;
    lbp(y, x) = v;
  }
}
// border rows/cols remain 0 in lbp_mem.
```

## 10. Implementation Notes (non-normative)

* A sliding 3×3 window with **two line buffers** (for previous rows) is typical; still, external protocol limits you to **one** read address per cycle.
* You may pipeline comparison and bit-packing; write as soon as the byte is ready.
* Any internal parallelism is allowed if external protocol, mapping, and outputs are preserved.

---

`timescale 1ns/10ps
module TOP ( clk, rst, gray_addr, gray_req, gray_ready, gray_data, lbp_addr, lbp_valid, lbp_data, finish);
input   	clk;
input   	rst;

// ask data
output  reg       	gray_req;
output  reg [13:0] 	gray_addr;
input   	    gray_ready;
input   [7:0] 	gray_data;

// write data
output  reg [13:0] 	lbp_addr;
output  reg 	    lbp_valid;
output  reg [7:0] 	lbp_data;
output  reg  	    finish;

reg [7:0] buffer [8:0];
reg [1:0] state_r, state_w;

wire [13:0] minus = gray_addr - 255;
wire [13:0] plus  = gray_addr + 128;
wire valid = (lbp_addr[6:0]== 7'b111_1111 || lbp_addr[6:0]== 7'b000_0000);
wire fin = (lbp_addr==14'd16254);

localparam 	DATA1 = 0,
			DATA2 = 1,
			DATA3 = 2,
			WRITE_DATA   = 3;

always @(posedge clk or posedge rst) begin
	if (rst) begin
		state_r   <= DATA1;
		gray_addr <= 0;
		lbp_addr  <= 126;
		finish    <= 0;
	end
	else begin
		state_r  <= state_w;
		gray_req <= 1;
		case(state_r)
			DATA1:begin
				lbp_valid <= 0;
				gray_addr <= plus;
				buffer[2] <= gray_data;     // get 2
			end
			DATA2:begin
				gray_addr <= plus;
				buffer[5] <= gray_data;     // get 130
			end
			DATA3:begin
				gray_addr <= minus;
				buffer[8] <= gray_data;     // get 258
				lbp_addr  <= lbp_addr + 1;
			end
			WRITE_DATA:begin
				// shift
				lbp_valid   <= (valid)? 0 : 1;
				lbp_data[0] <= (buffer[0]>=buffer[4])? 1 : 0;
				lbp_data[1] <= (buffer[1]>=buffer[4])? 1 : 0;
				lbp_data[2] <= (buffer[2]>=buffer[4])? 1 : 0;
				lbp_data[3] <= (buffer[3]>=buffer[4])? 1 : 0;
				lbp_data[4] <= (buffer[5]>=buffer[4])? 1 : 0;
				lbp_data[5] <= (buffer[6]>=buffer[4])? 1 : 0;
				lbp_data[6] <= (buffer[7]>=buffer[4])? 1 : 0;
				lbp_data[7] <= (buffer[8]>=buffer[4])? 1 : 0;

				buffer[0] <= buffer[1];
				buffer[1] <= buffer[2];
				buffer[3] <= buffer[4];
				buffer[4] <= buffer[5];
				buffer[6] <= buffer[7];
				buffer[7] <= buffer[8];
				if(fin) finish <= 1;
			end
		endcase
	end
end

always@(*)begin
	case(state_r)
			DATA1: state_w = DATA2;
			DATA2: state_w = DATA3;
			DATA3: state_w = WRITE_DATA;
			WRITE_DATA: state_w = DATA1;
	endcase
end

endmodule

`timescale 1ns/10ps
`define CYCLE      10          	  // Modify your clock period here
`define End_CYCLE  10000000              // Modify cycle times once your design need more cycle times!
`define PAT        "./00_TB/pattern1.dat"

`define EXP        "./00_TB/golden1.dat"

module test;

parameter N_EXP   = 16384; // 128 x 128 pixel
parameter N_PAT   = N_EXP;

reg   [7:0]   gray_mem   [0:N_PAT-1];
reg   [7:0]   exp_mem    [0:N_EXP-1];

reg [7:0] LBP_dbg;
reg [7:0] exp_dbg;
wire [7:0] lbp_data;
reg   clk = 0;
reg   rst = 0;
reg   result_compare = 0;

integer total_error = 0;
integer times = 0;
reg over = 0;
integer exp_num = 0;
wire [13:0] gray_addr;
wire [13:0] lbp_addr;
reg [7:0] gray_data;
reg gray_ready = 0;
integer i;

   TOP TOP( .clk(clk), .rst(rst),
            .gray_addr(gray_addr), .gray_req(gray_req), .gray_ready(gray_ready), .gray_data(gray_data),
			.lbp_addr(lbp_addr), .lbp_valid(lbp_valid), .lbp_data(lbp_data), .finish(finish));

   lbp_mem u_lbp_mem(.lbp_valid(lbp_valid), .lbp_data(lbp_data), .lbp_addr(lbp_addr), .clk(clk));

localparam SDFFILE = "../02_SYN/Netlist/top_syn.sdf";
`ifdef SDF
	initial $sdf_annotate(SDFFILE, TOP);
`endif

initial	$readmemh (`PAT, gray_mem);
initial	$readmemh (`EXP, exp_mem);

always begin #(`CYCLE/2) clk = ~clk; end

// initial begin
// 	$fsdbDumpfile("LBP.fsdb");
// 	$fsdbDumpvars;
// end

initial begin  // data input
   @(negedge clk)  rst = 1'b1;
   #(`CYCLE*2);    rst = 1'b0;
   @(negedge clk)  gray_ready = 1'b1;
    while (finish == 0) begin
      if( gray_req ) begin
         gray_data = gray_mem[gray_addr];
      end
      else begin
         gray_data = 'hz;
      end
      @(negedge clk);
    end
    gray_ready = 0; gray_data='hz;
	@(posedge clk) result_compare = 1;
end

initial begin // result compare
	$display("-----------------------------------------------------\n");
 	$display("START!!! Simulation Start .....\n");
 	$display("-----------------------------------------------------\n");
	#(`CYCLE*3);
	wait( finish ) ;
	@(posedge clk); @(posedge clk);
	for (i=0; i <N_PAT ; i=i+1) begin
			//@(posedge clk);  // TRY IT ! no comment this line for debugging !!
				exp_dbg = exp_mem[i]; LBP_dbg = u_lbp_mem.LBP_M[i];
				if (exp_mem[i] == u_lbp_mem.LBP_M[i]) begin
					total_error = total_error;
				end
				else begin
					//$display("pixel %d is FAIL !!", i);
					total_error = total_error+1;
					if (total_error <= 10) $display("Output pixel %d are wrong!", i);
					if (total_error == 11) begin $display("Find the wrong pixel reached a total of more than 10 !, Please check the code .....\n");  end
				end
				if( ((i%1000) === 0) || (i == 16383))begin
					if ( total_error === 0)
      					$display("Output pixel: 0 ~ %d are correct!\n", i);
					else
					$display("Output Pixel: 0 ~ %d are wrong ! The wrong pixel reached a total of %d or more ! \n", i, total_error);

  				end
				exp_num = exp_num + 1;
	end
	over = 1;
end

integer exe_cycle;
reg ooo;
initial begin
	ooo = 0;
	exe_cycle = 0;
	repeat(3) @(posedge clk);
	while(over != 1) begin
		exe_cycle = exe_cycle + 1;
		@(negedge clk);
	end
	ooo = 1;
end

initial begin
	$display(" Cycle Period = %0f ns", `CYCLE);
end
initial  begin
 #`End_CYCLE ;
 	$display("-----------------------------------------------------\n");
 	$display("Error!!! Somethings' wrong with your code ...!\n");
 	$display("-------------------------FAIL------------------------\n");
 	$display("-----------------------------------------------------\n");
 	$finish;
end

initial begin
      @(posedge ooo);
      if((ooo) && (exp_num!='d0)) begin
         $display("-----------------------------------------------------\n");
        if(total_error == 0) begin
            $display("------------------------------------------------");
            $display("----------------All tests PASS!-----------------");
            $display("------------total time: %0d cycles-----------------", exe_cycle);
            $display("------------------------------------------------");
        end else begin
            $display("------------------------------------------------");
            $display("-              Total Error: %0d               -", total_error);
            $display("------------------------------------------------");
        end
      end
      #(`CYCLE/2); $finish;
end

endmodule

module lbp_mem (lbp_valid, lbp_data, lbp_addr, clk);
input		lbp_valid;
input	[13:0] 	lbp_addr;
input	[7:0]	lbp_data;
input		clk;

reg [7:0] LBP_M [0:16383];
integer i;

initial begin
	for (i=0; i<=16383; i=i+1) LBP_M[i] = 0;
end

always@(negedge clk)
	if (lbp_valid) LBP_M[ lbp_addr ] <= lbp_data;

endmodule


---

# Human-Readable I/O-Only Spec — `systolic`

## 1) Module

* **Name**: `TOP`
* **Clock**: `clk`, rising-edge.
* **Reset**: `rst`, **Synchronous, active-high**.

  * While `rst=1`: internal state is cleared; `o_valid=0`;
  * On `rst` deassert (1→0): module is ready to accept a new tile per the rules below.

> All ports are **1-D flattened** (no multi-dimensional arrays on the port list).

## 2) Ports (I/O only)

### 2.1 Control & Clock

* `input  clk`
* `input  rst`
* `input  tile_en` — **load enable**; must be **1 for four consecutive cycles** to provide **one tile**.

### 2.2 Data Inputs (sampled only when `tile_en=1`)

* `input  [15:0] tileA_data_0`
* `input  [15:0] tileA_data_1`
* `input  [15:0] tileA_data_2`
* `input  [15:0] tileA_data_3`
* `input  [15:0] tileB_data_0`
* `input  [15:0] tileB_data_1`
* `input  [15:0] tileB_data_2`
* `input  [15:0] tileB_data_3`

**Sampling rule:** On each **posedge** with `tile_en=1`, sample all eight inputs above. **Exactly four consecutive** such cycles constitute one complete tile load (32 total 16-bit values).

### 2.3 Data Outputs (valid only when `o_valid=1`)

* `output reg [15:0] tileO_data_0`  … `tileO_data_15`

**Mapping:** `tileO_data_(4*r + c)` corresponds to output element at row `r`, column `c`, with `r,c ∈ {0..3}` (row-major).

### 2.4 Completion Pulse

* `output reg o_valid` — **one-cycle pulse**; when `o_valid=1`, **all** `tileO_data_*` are valid and stable in that same cycle.

## 3) Timing Contract (externally observable)

1. **Load phase**

   * One tile **must** be provided by **four consecutive** cycles with `tile_en=1`.
   * Inputs are sampled on each **posedge** of those four cycles.

2. **Output validity**
   * `o_valid` is **one clock** wide; all `tileO_data_*` are valid and stable in that cycle only.
   * `tileO_data_*` are considered valid **only** in the cycle where `o_valid=1`.
   * Outside that cycle, `tileO_data_*` may be don’t-care.

## 4) **Critical rule after completion**

* The **cycle immediately after** `o_valid` assert `tile_en=1`.
* **If** `tile_en=1` in that cycle, it **must be accepted** as the **first load cycle of the next tile**.

## 5) Interface assumptions

* No other ready/valid or back-pressure signals exist.
* Inputs during `rst=1` are ignored; outputs/`o_valid` have no meaning during `rst=1`.
* Internal implementation is unconstrained; only this **I/O and timing** contract will be verified.

---

// no multi-dimensional arrays
module TOP (
    input clk,
    input rst,
    input tile_en,
    input [15:0] tileA_data_0,
    input [15:0] tileA_data_1,
    input [15:0] tileA_data_2,
    input [15:0] tileA_data_3,
    input [15:0] tileB_data_0,
    input [15:0] tileB_data_1,
    input [15:0] tileB_data_2,
    input [15:0] tileB_data_3,
    output reg   o_valid,
    // output logic [15:0] tileO_data [0:3][0:3]
    // output reg [15:0] tileO_data [0:15]
    output reg [15:0] tileO_data_0,
    output reg [15:0] tileO_data_1,
    output reg [15:0] tileO_data_2,
    output reg [15:0] tileO_data_3,
    output reg [15:0] tileO_data_4,
    output reg [15:0] tileO_data_5,
    output reg [15:0] tileO_data_6,
    output reg [15:0] tileO_data_7,
    output reg [15:0] tileO_data_8,
    output reg [15:0] tileO_data_9,
    output reg [15:0] tileO_data_10,
    output reg [15:0] tileO_data_11,
    output reg [15:0] tileO_data_12,
    output reg [15:0] tileO_data_13,
    output reg [15:0] tileO_data_14,
    output reg [15:0] tileO_data_15
);
    // input buffers
    reg [15:0] tileA_w [0:27], tileA_r [0:27];
    reg [15:0] tileB_w [0:27], tileB_r [0:27];

    // state machine
    // typedef enum logic [1:0] {
    //     LOADING,
    //     COMPUTE,
    //     DONE
    // } state_t;
    // state_t state_w, state_r;
    localparam LOADING = 2'b00, COMPUTE = 2'b01, DONE = 2'b10;
    reg [1:0] state_w, state_r;

    reg [1:0] load_num_w, load_num_r;
    reg [4:0] propagate_num_w, propagate_num_r;

    always@(*) begin
        state_w = state_r;
        case (state_r)
            LOADING: begin
                if (tile_en && load_num_r == 3) begin
                    state_w = COMPUTE;
                end
            end
            COMPUTE: begin
                // Assuming some condition to go to DONE state
                if(propagate_num_r == 11) begin
                    state_w = DONE;
                end
            end
            DONE: begin
                state_w = LOADING; // Loop back to LOADING for next tile
            end
        endcase
    end

    // logic [15:0] next_a [0:3][0:3], next_b [0:3][0:3];
    reg [15:0] next_a [0:15], next_b [0:15];
    reg [15:0] tileA_in [0:3], tileB_in [0:3];
    reg PE_clear, PE_en, PE_out;
    wire  [15:0] o [0:15];
    wire PE_input_gate;
    assign PE_input_gate = (state_r == LOADING || state_r == COMPUTE) && PE_en;

    always@(*) begin
        tileO_data_0 = o[0];
        tileO_data_1 = o[1];
        tileO_data_2 = o[2];
        tileO_data_3 = o[3];
        tileO_data_4 = o[4];
        tileO_data_5 = o[5];
        tileO_data_6 = o[6];
        tileO_data_7 = o[7];
        tileO_data_8 = o[8];
        tileO_data_9 = o[9];
        tileO_data_10 = o[10];
        tileO_data_11 = o[11];
        tileO_data_12 = o[12];
        tileO_data_13 = o[13];
        tileO_data_14 = o[14];
        tileO_data_15 = o[15];
    end

    // systolic array

    //                 tileB_in[0]  tileB_in[1] tileB_in[2] tileB_in[3]
    //  tileA_in[0]    PE00         PE01        PE02        PE03
    //  tileA_in[1]    PE10         PE11        PE12        PE13
    //  tileA_in[2]    PE20         PE21        PE22        PE23
    //  tileA_in[3]    PE30         PE31        PE32        PE33

    PE pe00 (
        .*,
        .a(tileA_in[0]),
        .b(tileB_in[0]),
        .next_a(next_a[0]),
        .next_b(next_b[0]),
        .o(o[0])
    );
    PE pe01 (
        .*,
        .a(next_a[0]),
        .b(tileB_in[1]),
        .next_a(next_a[1]),
        .next_b(next_b[1]),
        .o(o[1])
    );
    PE pe02 (
        .*,
        .a(next_a[1]),
        .b(tileB_in[2]),
        .next_a(next_a[2]),
        .next_b(next_b[2]),
        .o(o[2])
    );
    PE pe03 (
        .*,
        .a(next_a[2]),
        .b(tileB_in[3]),
        .next_a(),
        .next_b(next_b[3]),
        .o(o[3])
    );
    PE pe10 (
        .*,
        .a(tileA_in[1]),
        .b(next_b[0]),
        .next_a(next_a[4]),
        .next_b(next_b[4]),
        .o(o[4])
    );
    PE pe11 (
        .*,
        .a(next_a[4]),
        .b(next_b[1]),
        .next_a(next_a[5]),
        .next_b(next_b[5]),
        .o(o[5])
    );
    PE pe12 (
        .*,
        .a(next_a[5]),
        .b(next_b[2]),
        .next_a(next_a[6]),
        .next_b(next_b[6]),
        .o(o[6])
    );
    PE pe13 (
        .*,
        .a(next_a[6]),
        .b(next_b[3]),
        .next_a(),
        .next_b(next_b[7]),
        .o(o[7])
    );
    PE pe20 (
        .*,
        .a(tileA_in[2]),
        .b(next_b[4]),
        .next_a(next_a[8]),
        .next_b(next_b[8]),
        .o(o[8])
    );
    PE pe21 (
        .*,
        .a(next_a[8]),
        .b(next_b[5]),
        .next_a(next_a[9]),
        .next_b(next_b[9]),
        .o(o[9])
    );
    PE pe22 (
        .*,
        .a(next_a[9]),
        .b(next_b[6]),
        .next_a(next_a[10]),
        .next_b(next_b[10]),
        .o(o[10])
    );
    PE pe23 (
        .*,
        .a(next_a[10]),
        .b(next_b[7]),
        .next_a(),
        .next_b(next_b[11]),
        .o(o[11])
    );
    PE pe30 (
        .*,
        .a(tileA_in[3]),
        .b(next_b[8]),
        .next_a(next_a[12]),
        .next_b(),
        .o(o[12])
    );
    PE pe31 (
        .*,
        .a(next_a[12]),
        .b(next_b[9]),
        .next_a(next_a[13]),
        .next_b(),
        .o(o[13])
    );
    PE pe32 (
        .*,
        .a(next_a[13]),
        .b(next_b[10]),
        .next_a(next_a[14]),
        .next_b(),
        .o(o[14])
    );
    PE pe33 (
        .*,
        .a(next_a[14]),
        .b(next_b[11]),
        .next_a(),
        .next_b(),
        .o(o[15])
    );

    always@(*) begin
        load_num_w = load_num_r;
        propagate_num_w = propagate_num_r;
        for(int i=0; i<28; i++) begin
            tileA_w[i] = tileA_r[i];
            tileB_w[i] = tileB_r[i];
        end
        PE_clear = 0;
        PE_en = 0;
        PE_out = 0;
        o_valid = 0;
        for(int i=0; i<4; i++) begin
            tileA_in[i] = 0;
            tileB_in[i] = 0;
        end
        case(state_r)
            LOADING: begin
                if(tile_en) begin
                    // tile
                    // 05 04 03 02 01 00
                    // 15 14 13 12 11 10
                    // 25 24 23 22 21 20
                    // 35 34 33 32 31 30
                    load_num_w = load_num_r + 1;
                    case(load_num_r)
                    0: begin
                        tileA_w[0] = tileA_data_0;
                        tileA_w[1] = tileA_data_1;
                        tileA_w[2] = tileA_data_2;
                        tileA_w[3] = tileA_data_3;
                        tileB_w[0] = tileB_data_0;
                        tileB_w[8] = tileB_data_1;
                        tileB_w[16] = tileB_data_2;
                        tileB_w[24] = tileB_data_3;
                    end
                    1: begin
                        tileA_w[8] = tileA_data_0;
                        tileA_w[9] = tileA_data_1;
                        tileA_w[10] = tileA_data_2;
                        tileA_w[11] = tileA_data_3;
                        tileB_w[1] = tileB_data_0;
                        tileB_w[9] = tileB_data_1;
                        tileB_w[17] = tileB_data_2;
                        tileB_w[25] = tileB_data_3;
                    end
                    2: begin
                        tileA_w[16] = tileA_data_0;
                        tileA_w[17] = tileA_data_1;
                        tileA_w[18] = tileA_data_2;
                        tileA_w[19] = tileA_data_3;
                        tileB_w[2] = tileB_data_0;
                        tileB_w[10] = tileB_data_1;
                        tileB_w[18] = tileB_data_2;
                        tileB_w[26] = tileB_data_3;
                    end
                    3: begin
                        load_num_w = 0;
                        tileA_w[24] = tileA_data_0;
                        tileA_w[25] = tileA_data_1;
                        tileA_w[26] = tileA_data_2;
                        tileA_w[27] = tileA_data_3;
                        tileB_w[3] = tileB_data_0;
                        tileB_w[11] = tileB_data_1;
                        tileB_w[19] = tileB_data_2;
                        tileB_w[27] = tileB_data_3;
                    end
                    endcase
                end
            end
            COMPUTE: begin
                propagate_num_w = propagate_num_r + 1;
                case(propagate_num_r)
                0,1,2,3,4,5,6: begin
                    for(int i=0; i<4; i++) begin
                        tileA_in[i] = tileA_r[i * 7 + propagate_num_r];
                        tileB_in[i] = tileB_r[i * 7 + propagate_num_r];
                    end
                    PE_en = 1;
                end
                11: begin // last cycle
                    PE_en = 1;
                    propagate_num_w = 0; // Reset for next tile
                end
                default: begin
                    PE_en = 1;
                end
                endcase
            end
            DONE: begin
                PE_out  = 1;
                o_valid = 1;
                PE_clear = 1;
            end
        endcase
    end

    // systolic array

    //                 tileB_in[0]  tileB_in[1] tileB_in[2] tileB_in[3]
    //  tileA_in[0]    PE00         PE01        PE02        PE03
    //  tileA_in[1]    PE10         PE11        PE12        PE13
    //  tileA_in[2]    PE20         PE21        PE22        PE23
    //  tileA_in[3]    PE30         PE31        PE32        PE33

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            for(int i = 0; i < 28; i++) begin
                tileA_r[i] <= 0;
                tileB_r[i] <= 0;
            end
        end
        else if(state_r == LOADING) begin
            // Load the tileA and tileB data
            for(int i = 0; i < 28; i++) begin
                tileA_r[i] <= tileA_w[i];
                tileB_r[i] <= tileB_w[i];
            end
        end
    end
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            // Reset logic
            state_r <= LOADING;
            load_num_r <= 0;
            propagate_num_r <= 0;
        end else begin
            // Write logic
            state_r <= state_w;
            load_num_r <= load_num_w;
            propagate_num_r <= propagate_num_w;
        end
    end

endmodule

module PE (
    input clk,
    input rst,
    input signed [15:0] a,
    input signed [15:0] b,
    input PE_clear,
    input PE_en,
    input PE_out,
    input PE_input_gate,
    output  signed [15:0] next_a,
    output  signed [15:0] next_b,
    output reg  signed [15:0] o
);
    reg signed [35:0] o_w, o_r;
    reg signed [15:0] a_r, b_r, a_w, b_w;

    assign a_w = a;
    assign b_w = b;
    assign next_a = a_r;
    assign next_b = b_r;

    localparam signed [35:0] NEG_MAX = -(1<<30);
    localparam signed [35:0] POS_MAX = (1<<30) - 1;

    always@(*) begin
        o = 0;
        if (PE_out) begin
            if(o_r > 0) begin
                if(o_r >= POS_MAX) begin // > 1
                    o = 16'h7FFF; // Saturate to max positive value
                end else begin
                    o = {1'b0, o_r[29-:15]}; // Take the upper 15 bits and sign extend
                end
            end
            else begin
                if(o_r <= NEG_MAX) begin // < -1
                    o = 16'h8000; // Saturate to max negative value

                end else begin
                    o = {1'b1, o_r[29-:15]}; // Take the upper 15 bits and sign extend
                end
            end
        end
    end
    always@(*) begin
        o_w = o_r;
        if (PE_clear) begin
            o_w = 0;
        end else if (PE_en) begin
            o_w = o_r + a * b;
        end
    end
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            o_r <= 0;
        end
        else if(PE_en || PE_clear)begin
            o_r <= o_w;
        end
    end
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            a_r <= 0;
            b_r <= 0;
        end
        else if(PE_input_gate) begin
            a_r <= a_w;
            b_r <= b_w;
        end
    end

endmodule

`timescale 1ns/10ps
`define CYCLE 	  4.4
`define MAX_CYCLE 5000
`define RST_DELAY `CYCLE/2
`define Matrix1_A_ref "./00_TB/data/matrix1_A.hex"
`define Matrix2_A_ref "./00_TB/data/matrix2_A.hex"
`define Matrix3_A_ref "./00_TB/data/matrix3_A.hex"
`define Matrix1_B_ref "./00_TB/data/matrix1_B.hex"
`define Matrix2_B_ref "./00_TB/data/matrix2_B.hex"
`define Matrix3_B_ref "./00_TB/data/matrix3_B.hex"
`define Matrix1_O_ref "./00_TB/data/matrix1_O.hex"
`define Matrix2_O_ref "./00_TB/data/matrix2_O.hex"
`define Matrix3_O_ref "./00_TB/data/matrix3_O.hex"
`define INST_ref      "./00_TB/data/inst.hex"

module test;

 // Ports
    wire            clk;
    wire            rst;
    wire            rst_n;
	logic           out_end;
	integer         correct, error, j, total_error;

	logic  [15:0]  matrixA1 [0:63], matrixA2 [0:63], matrixA3 [0:63];
    logic  [15:0]  matrixB1 [0:63], matrixB2 [0:63], matrixB3 [0:63];
    logic  [15:0]  matrixO1 [0:255], matrixO2 [0:255], matrixO3 [0:255];
	logic  [5:0]   inst_m  [0:3];

	// signal of top module
	logic [7:0] addr_A, addr_B, addr_I, addr_O;
	logic en_A, en_B, en_I, en_O;
	logic [15:0] data_A, data_B;
	logic [5:0]  data_I;
	logic [15:0] data_O;
    logic out_valid;
	logic ap_start, ap_done;

    logic [1:0] inst_length;

    integer s;

    initial begin
        $readmemh(`Matrix1_A_ref, matrixA1);
        $readmemh(`Matrix2_A_ref, matrixA2);
        $readmemh(`Matrix3_A_ref, matrixA3);
        $readmemh(`Matrix1_B_ref, matrixB1);
        $readmemh(`Matrix2_B_ref, matrixB2);
        $readmemh(`Matrix3_B_ref, matrixB3);
        $readmemh(`Matrix1_O_ref, matrixO1);
        $readmemh(`Matrix2_O_ref, matrixO2);
        $readmemh(`Matrix3_O_ref, matrixO3);
		$readmemh(`INST_ref, inst_m);
    end

    localparam SDFFILE = "../02_SYN/Netlist/top_syn.sdf";
    `ifdef SDF
        initial $sdf_annotate(SDFFILE, TOP);
    `endif

    // Modules
    clk_gen clk_gen_inst (
        .clk   (clk),
        .rst   (rst),
        .rst_n (rst_n)
    );
    TOP_Control TOP_Control (
        .clk 	  (clk),
		.rst 	  (rst),
		.addr_A  (addr_A),
		.en_A 	  (en_A),
		.data_A  (data_A),
		.addr_B  (addr_B),
		.en_B 	  (en_B),
		.data_B  (data_B),
		.addr_I  (addr_I),
		.en_I 	  (en_I),
		.data_I  (data_I),
		.addr_O  (addr_O),
		.data_O  (data_O),
        .en_O 	  (en_O),
        .out_valid(out_valid),
		.ap_start(ap_start),
		.ap_done (ap_done)

    );

    // initial begin
    //     $fsdbDumpfile("top.fsdb");
    //     $fsdbDumpvars(0, TOP_Control);
    // end
    initial begin
        $display(" Cycle Period = %0f ns", `CYCLE);
    end

    integer i, inst_i;
    // Input
    initial begin

        i = 0; inst_i = 0;
        addr_A = 0; addr_B = 0; addr_I = 0; addr_O = 0;
        en_A = 0; en_B = 0; en_I = 0;
        data_A = 0; data_B = 0; data_I = 0;
		ap_start = 0;

        out_end = 0;
        correct = 0;
        error   = 0;
        total_error = 0;
        en_O = 0;

        j = 0;

        // Waiting for reset to finish
        wait (rst_n === 1'b0);
        wait (rst_n === 1'b1);
        @(posedge clk);

        while(inst_m[inst_i] !== 0) begin
            $display("----------------------------------------------");
            $display("-             inst = %0d                      -", inst_m[inst_i]);
            @(negedge clk);
            addr_I = inst_i;
            en_I = 1;
            data_I = inst_m[inst_i];

            while(i < 64) begin
                @(negedge clk);
                en_I = 0;
                addr_A = i;             addr_B = i;
                en_A = 1;               en_B = 1;
                case(inst_i)
                0: begin
                    data_A = matrixA1[i]; data_B = matrixB1[i];
                end
                1: begin
                    data_A = matrixA2[i]; data_B = matrixB2[i];
                end
                2: begin
                    data_A = matrixA3[i]; data_B = matrixB3[i];
                end
                endcase

                i = i + 1;
            end
            i = 0;
            @(negedge clk);
            ap_start = 1;
            $display("-             START COMPUTE                  -");

            @(posedge ap_done);
            $display("-             CHECK ANSWER                   -");
            ap_start = 0;
            @(posedge clk);

            while (ap_done) begin
                @(negedge clk);
                addr_O = j;
                en_O = 1;
                @(negedge clk);
                en_O = 0;
                if(out_valid) begin
                    case(inst_i)
                    0: begin
                        if (data_O === matrixO1[j]) begin
                            correct = correct + 1;
                        end else begin
                            error = error + 1;
                            $display("Test[%d]: Error!, expected %h, got %h", j, matrixO1[j], data_O);
                        end
                    end
                    1: begin
                        if (data_O === matrixO2[j]) begin
                            correct = correct + 1;
                        end else begin
                            error = error + 1;
                            $display("Test[%d]: Error!, expected %h, got %h", j, matrixO2[j], data_O);
                        end
                    end
                    2: begin
                        if (data_O === matrixO3[j]) begin
                            correct = correct + 1;
                        end else begin
                            error = error + 1;
                            $display("Test[%d]: Error!, expected %h, got %h", j, matrixO3[j], data_O);
                        end
                    end
                    endcase
                end
                j = j + 1;
                if(j==256) begin
                    j = 0;
                    inst_i = inst_i + 1;
                    en_O = 0;
                    if(error == 0) begin
                        $display("----------------------------------------------");
                        $display("-              Test %0d PASS!                  -", inst_i);
                        $display("----------------------------------------------");
                    end
                    total_error = total_error + error;
                    error = 0;
                end
            end
        end
        out_end = 1;
    end

    // execution cycle
    integer exe_cycle;

    initial begin
        exe_cycle = 0;
        while(!out_end) begin
            while(ap_start) begin
                @(posedge clk);
                exe_cycle = exe_cycle + 1;
            end
            @(negedge clk);
        end
        $display("----------------------------------------------");
        $display("------------total time: %0d cycles-----------------", exe_cycle);
        $display("----------------------------------------------");
        if(total_error == 0) begin
            $display("------------------------------------------------");
            $display("----------------All tests PASS!-----------------");
            $display("------------------------------------------------");
        end else begin
            $display("------------------------------------------------");
            $display("-              Total Error: %0d               -", total_error);
            $display("------------------------------------------------");
        end

        $finish;
    end

endmodule

module clk_gen(
    output reg clk,
    output reg rst,
    output reg rst_n
);
    always #(`CYCLE/2.0) clk = ~clk;
    // initial begin
    //     clk = 1'b0;
    //     rst = 1'b0; rst_n = 1'b1; #(              0.25  * `CYCLE);
    //     rst = 1'b1; rst_n = 1'b0; #((`RST_DELAY - 0.25) * `CYCLE);
    //     rst = 1'b0; rst_n = 1'b1; #(         `MAX_CYCLE * `CYCLE);
    //     $display("Error! Time limit exceeded!");
    //     $finish;
    // end

   initial begin
        clk = 1'b1;
        rst = 1'b0;  rst_n = 1'b1; #(`CYCLE * 0.25);
        rst = 1'b1;  rst_n = 1'b0; #((`RST_DELAY)        * `CYCLE);
        rst = 1'b0; rst_n = 1'b1;

        #(`MAX_CYCLE * `CYCLE);
        $display("------------------------");
        $display("Error! Runtime exceeded!");
        $display("------------------------");
        $finish;
    end
endmodule

module TOP_Control (
    input clk,
    input rst,
    input  [7:0]  addr_A,
    input         en_A,
    input  [15:0] data_A,
    input  [7:0]  addr_B,
    input         en_B,
    input  [15:0] data_B,
    input  [7:0]  addr_I,
    input         en_I,
    input  [5:0]  data_I,
    input  [7:0]  addr_O,
    output [15:0] data_O,
    input         en_O,
    output        out_valid,
    input         ap_start,
    output        ap_done
);

    reg [15:0] matrixA_w[0:63], matrixA_r[0:63];
    reg [15:0] matrixB_w[0:63], matrixB_r[0:63];
    reg [15:0] matrixO1_w[0:255], matrixO1_r[0:255];
    reg [5:0]  inst_m_w  [0:5], inst_m_r  [0:5];

    reg tile_en;
    reg  [15:0] tileA_data [0:3], tileB_data [0:3];
    wire [15:0] tileO_data [0:15];
    wire o_valid;

    TOP TOP (
        .clk(clk),
        .rst(rst),
        .tile_en(tile_en),
        // .tileA_data(tileA_data),
        // .tileB_data(tileB_data),
        .tileA_data_0(tileA_data[0]),
        .tileA_data_1(tileA_data[1]),
        .tileA_data_2(tileA_data[2]),
        .tileA_data_3(tileA_data[3]),
        .tileB_data_0(tileB_data[0]),
        .tileB_data_1(tileB_data[1]),
        .tileB_data_2(tileB_data[2]),
        .tileB_data_3(tileB_data[3]),
        // .tileO_data(tileO_data),
        .tileO_data_0(tileO_data[0]),
        .tileO_data_1(tileO_data[1]),
        .tileO_data_2(tileO_data[2]),
        .tileO_data_3(tileO_data[3]),
        .tileO_data_4(tileO_data[4]),
        .tileO_data_5(tileO_data[5]),
        .tileO_data_6(tileO_data[6]),
        .tileO_data_7(tileO_data[7]),
        .tileO_data_8(tileO_data[8]),
        .tileO_data_9(tileO_data[9]),
        .tileO_data_10(tileO_data[10]),
        .tileO_data_11(tileO_data[11]),
        .tileO_data_12(tileO_data[12]),
        .tileO_data_13(tileO_data[13]),
        .tileO_data_14(tileO_data[14]),
        .tileO_data_15(tileO_data[15]),
        .o_valid(o_valid)
    );

    typedef enum logic [2:0] {
        IDLE,
        LOADING,
        FILLING,
        COMPUTE,
        DONE,
        FINISH
    } state_t;
    state_t state_w, state_r;

    reg [1:0] load_num_w, load_num_r;
    reg [2:0] inst_num_w, inst_num_r;
    reg [1:0] tile_row_num_w, tile_row_num_r;
    reg [1:0] tile_col_num_w, tile_col_num_r;

    reg [15:0] odata_w, odata_r;
    reg out_valid_w, out_valid_r;
    wire [2:0] inst_sel;

    assign ap_done   = (state_r == DONE);
    assign data_O    = odata_r;
    assign out_valid = out_valid_r;
    assign inst_sel = addr_I[2:0];

    always@(*)  begin
        state_w = state_r;
        case (state_r)
        IDLE: begin
            state_w = LOADING;
        end
        LOADING: begin
            if(ap_start) begin
                state_w = FILLING;
            end
            if(en_I && data_I==0) begin
                state_w = FINISH;
            end
        end
        FILLING: begin
            if(load_num_r == 3) begin
                state_w = COMPUTE;
            end
        end
        COMPUTE: begin
            if(o_valid) begin
                case(inst_m_r[inst_num_r])
                4: begin
                    state_w = DONE;
                end
                8: begin
                    if(tile_row_num_r == 1 && tile_col_num_r == 1) begin
                        state_w = DONE; // Move to DONE after filling first tile
                    end else begin
                        state_w = FILLING; // Continue filling next tile
                    end
                end
                16: begin
                    if(tile_row_num_r == 3 && tile_col_num_r == 3) begin
                        // state_w = DONE; // Move to DONE after filling second tile
                        state_w = DONE;
                    end else begin
                        state_w = FILLING; // Continue filling next tile
                    end
                end
                endcase
            end
        end
        DONE: begin
            if(en_O && addr_O == 255) begin
                state_w = LOADING; // Otherwise, go back to LOADING
            end
        end
        FINISH: begin
        end
        endcase
    end
    always @(posedge clk or posedge rst) begin
        if (rst) state_r <= IDLE;
        else state_r <= state_w;
    end

    always@(*)  begin
        for(int i=0; i<64; i++) begin
            matrixA_w[i] = matrixA_r[i];
            matrixB_w[i] = matrixB_r[i];
        end
        for(int i=0; i<256; i++) begin
            matrixO1_w[i] = matrixO1_r[i];
        end
        for(int i=0; i<6; i++) begin
            inst_m_w[i] = inst_m_r[i];
        end
        tile_en    = 0;
        load_num_w = load_num_r;
        inst_num_w = inst_num_r;
        tile_row_num_w = tile_row_num_r;
        tile_col_num_w = tile_col_num_r;
        for(int i=0; i<4; i++) begin
            tileA_data[i] = 0;
            tileB_data[i] = 0;
        end
        odata_w     = odata_r;
        out_valid_w = 0;

        case(state_r)
        IDLE: begin end
        LOADING: begin
            if(en_A) begin // and en_B
                matrixA_w[addr_A] = data_A;
                matrixB_w[addr_B] = data_B;
            end
            if(en_I && data_I!=0) begin
                inst_m_w[inst_sel] = data_I;
            end
        end
        FILLING: begin
            load_num_w = load_num_r + 1;
            tile_en = 1; // Enable tile for processing
            if(load_num_r == 3) begin
                load_num_w = 0;
            end
            // 0000 0001 0010 0011
            // 0100 0101 0110 0111
            // 1000 1001 1010 1011
            // 1100 1101 1110 1111
            case(load_num_r)
            0: begin
                for(int i=0;i<4;i++) begin
                    tileA_data[i] = matrixA_r[4*tile_row_num_r*4 + i];
                    tileB_data[i] = matrixB_r[4*tile_col_num_r + i];
                end
            end
            1: begin
                for(int i=0;i<4;i++) begin
                    tileA_data[i] = matrixA_r[(4*tile_row_num_r + 1)*4 + i];
                    tileB_data[i] = matrixB_r[16 + 4*tile_col_num_r + i];
                end
            end
            2: begin
                for(int i=0;i<4;i++) begin
                    tileA_data[i] = matrixA_r[(4*tile_row_num_r + 2)*4 + i];
                    tileB_data[i] = matrixB_r[32 + 4*tile_col_num_r + i];
                end
            end
            3: begin
                for(int i=0;i<4;i++) begin
                    tileA_data[i] = matrixA_r[(4*tile_row_num_r + 3)*4 + i];
                    tileB_data[i] = matrixB_r[48 + 4*tile_col_num_r + i];
                end
            end
            endcase
        end

        COMPUTE: begin
            if(o_valid) begin
                for(int i=0; i<4; i++) begin
                    for(int j=0; j<4; j++) begin
                        matrixO1_w[(4*tile_row_num_r + i)*16 + 4*tile_col_num_r + j] = tileO_data[4*i + j];

                    end
                end
                case(inst_m_r[inst_num_r])
                4: begin
                end
                8: begin
                    tile_col_num_w = tile_col_num_r + 1;
                    if(tile_col_num_r == 1) begin
                        tile_row_num_w = 1;
                        tile_col_num_w = 0; // Reset column for next row
                        if(tile_row_num_r == 1) begin
                            tile_row_num_w = 0;
                        end
                    end
                end
                16: begin
                    tile_col_num_w = tile_col_num_r + 1;
                    if(tile_col_num_r == 3) begin
                        tile_row_num_w = tile_row_num_r + 1;
                        tile_col_num_w = 0; // Reset column for next row
                        if(tile_row_num_r == 3) begin
                            tile_row_num_w = 0;
                        end
                    end
                end
                endcase
            end
        end
        DONE: begin
            if(en_O) begin
                out_valid_w = 1;
                // odata_w = matrixO1_r[addr_O[7:4]][addr_O[3:0]];
                odata_w = matrixO1_r[addr_O]; // Flattened access
                if(addr_O == 255) begin
                    inst_num_w = inst_num_r + 1;
                    for(int i = 0; i < 256; i++) begin
                        matrixO1_w[i] = 0; // Reset output matrix after reading
                    end
                end
            end

        end
        endcase
    end
    always @(posedge clk or posedge rst) begin
        if(rst) begin
            for(int i = 0; i < 256; i++) begin
                matrixO1_r[i] <= 0;
            end
        end
        else if(state_r == COMPUTE || state_r == DONE) begin
            for(int i = 0; i < 256; i++) begin
                matrixO1_r[i] <= matrixO1_w[i];
            end
        end
    end
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            for(int i = 0; i < 64; i++) begin
                matrixA_r[i] <= 0;
                matrixB_r[i] <= 0;
            end
            for (int k = 0; k < 6; k++) begin
                inst_m_r[k] <= 0;
            end
        end else if(state_r == LOADING) begin

            for(int i = 0; i < 64; i++) begin
                matrixA_r[i] <= matrixA_w[i];
                matrixB_r[i] <= matrixB_w[i];
            end
            for (int k = 0; k < 6; k++) begin
                inst_m_r[k] <= inst_m_w[k];
            end
        end
    end

    always @(posedge clk or posedge rst) begin
        if(rst) begin
            odata_r <= 0;
        end
        else if(state_r == DONE) begin
            odata_r <= odata_w;
        end
    end

    always @(posedge clk or posedge rst) begin
        if(rst) begin
            out_valid_r    <= 0;
            load_num_r     <= 0;
            inst_num_r     <= 0;
            tile_row_num_r <= 0;
            tile_col_num_r <= 0;
        end else begin
            out_valid_r    <= out_valid_w;
            load_num_r     <= load_num_w;
            inst_num_r     <= inst_num_w;
            tile_row_num_r <= tile_row_num_w;
            tile_col_num_r <= tile_col_num_w;
        end
    end

endmodule


---

# Version A — Human-Readable Spec (CONV)

## 1) Goal & Scope

Implement module **`TOP`** that:

* Reads a **64×64** grayscale image from the testfixture via the `iaddr/idata` interface. Pixel data width is **20 bits (Q4.16)**.
* Produces:

  1. **Layer 0**: **zero-padding(1) → 3×3 convolution (Kernel 0) → +bias → ReLU** ⇒ **64×64** result in Q4.16, written to **L0\_MEM0**.
  2. **Layer 1**: **2×2 max-pooling, stride 2** over Layer-0 output ⇒ **32×32** result in Q4.16, written to **L1\_MEM0**.

---

## 2) Top-Level Ports (names, widths, meaning)

| Signal     | Dir | Width | Description                                                                                |
| ---------- | --- | ----: | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `clk`      | I   |     1 | System clock, **posedge-synchronous**.                                                                                |
| `rst`    | I   |     1 | **Synchronous, active-high** rst.                                                                                |
| `ready`    | I   |     1 | Testfixture asserts when inputs are prepared; `TOP` may start only after seeing `ready=1`.                                                                 |
| `busy`     | O   |     1 | Set **High** once to start work after seeing `ready=1`; set **Low** once when all required writes finish. Exactly **one rise** and **one fall** per image.  |
| `iaddr`    | O   |    12 | Address for input image (row-major, 0..4095).                                                                                |
| `idata`    | I   |    20 | Input pixel at `iaddr`, **Q4.16** (20-bit).                                                                                |
| `crd`      | O   |     1 | Result memory **read enable** (see timing).                                                                                |
| `cdata_rd` | I   |    20 | Read data from selected result memory (Q4.16).                                                                                |
| `caddr_rd` | O   |    12 | Read address.                                                                                |
| `cwr`      | O   |     1 | Result memory **write enable** (see timing).                                                                                |
| `cdata_wr` | O   |    20 | Write data (Q4.16).                                                                                |
| `caddr_wr` | O   |    12 | Write address.                                                                                |
| `csel`     | O   |     3 | Memory select: `3’b001` = **L0\_MEM0**, `3’b011` = **L1\_MEM0**.                                                                                |

---

## 3) Handshake & Global Timing

1. **Start/End protocol**

   * After `rst` deasserts, testfixture sets `ready=1` when inputs (image & constants) are ready. On detecting `ready=1`, assert `busy=1` (start). When all mandated writes (L0 then L1) complete, deassert `busy` (end). **Exactly one** rising and **one** falling edge of `busy` per image.

2. **Image memory read timing (`iaddr`→`idata`)**

   * Drive `iaddr` on/after a **posedge**; the testfixture returns the addressed pixel on `idata` **after the following negedge**. Keep `iaddr` stable until that negedge. (You may pipeline one address per cycle.)

3. **Result memory timing (L0\_MEM0 & L1\_MEM0)**

   * **Read**: If `crd=1` at a **negedge**, `cdata_rd` immediately reflects the word at `caddr_rd` (for selected `csel`).
   * **Write**: If `cwr=1` at a **posedge**, the testfixture writes `cdata_wr` to `caddr_wr` (for selected `csel`).
   * **Select**: Use `csel=3’b001` to access **L0\_MEM0**; use `csel=3’b011` to access **L1\_MEM0**.

---

## 4) Memories & Addressing

* **Input image**: 64×64 = **4096** pixels, row-major (`addr = y*64 + x`). Data width **20 bits (Q4.16)**.
* **L0\_MEM0**: Layer-0 output, **64×64**, row-major, **20-bit Q4.16**. Access with `csel=3’b001`. Quantize per §5.
* **L1\_MEM0**: Layer-1 output, **32×32**, row-major, **20-bit Q4.16**. Access with `csel=3’b011`.

---

## 5) Numeric Format & Quantization

* All I/O and stored results are **20-bit Q4.16 two’s-complement** (4 integer bits incl. sign + 16 fractional bits).
* **Round-to-nearest** when writing to memories using the **17th fractional bit**.

---

## 6) Layer Algorithms

### 6.1 Layer 0 — Zero-padding → 3×3 Convolution → +Bias → ReLU

* **Zero-padding**: Pad the input image with **1-pixel zeros** on all sides so that 3×3 stride-1 convolution preserves 64×64 size.
* **Convolution** (stride 1):

  $$
  S(x,y)=\sum_{i=0}^{2}\sum_{j=0}^{2}K[i,j]\cdot I(x+i-1,\,y+j-1)
  $$

  where `I` is the padded image (Q4.16) and `K` is **Kernel 0** (Q4.16). After the sum, **add bias**, then **ReLU**: `S←max(S,0)`.
* **Kernel 0 (decimal, Q4.16 constants)**:

  ```
  [ [  0.426810,  0.573572,  0.658674 ],
    [ -0.569037, -0.439696,  0.0625617],
    [ -0.327755, -0.217964, -0.348290] ]

   =

   [ [ 0x0A89E, 0x092D5, 0x06D43],
     [ 0x01004, 0xF8F71, 0xF6E54],
     [ 0xFA6D7, 0xFC834, 0xFAC19] ]
  ```

  (Hex Q4.16 provided in the brief as well.)
* **Bias**: `+0.07446326` (decimal), **Q4.16** = `0x01310`.
* **Write-out**: Quantize to Q4.16 using §5, then write each (x,y) to **L0\_MEM0** at row-major address with `csel=3’b001` and `cwr=1` on the write **posedge**.

### 6.2 Layer 1 — Max-Pooling (2×2 window, stride 2)

* For each **2×2** window over the Layer-0 image, output the **maximum** of the four Q4.16 values. Scan left→right, top→bottom; output size is **32×32**.
* **Write-out**: Write each pooled value (unchanged Q4.16) to **L1\_MEM0** at row-major address with `csel=3’b011` and `cwr=1` on the write **posedge**.

---

## 7) Legality & Assumptions

* Only **one** start (`busy`↑ after `ready`=1) and **one** end (`busy`↓) per image. While `busy=1`, you may perform unlimited reads/writes to L0/L1.
* Respect the **edge timing**: `iaddr` valid until the following **negedge** when `idata` returns; `crd` read on **negedge**; `cwr` write on **posedge**; `csel` selects the target memory for both read/write.
* Internal micro-architecture is unconstrained; only the **I/O, timing, addressing, numeric**, and **algorithm** contracts are verified.

---

`timescale 1ns/10ps
`define CYCLE      10.0          	  // Modify your clock period here
`define End_CYCLE  100000000              // Modify cycle times once your design need more cycle times!

`define PAT            "./00_TB/dat_grad/cnn_sti.dat"                 // Modify your "dat" directory path
`define L0_EXP0        "./00_TB/dat_grad/cnn_layer0_exp0.dat"
`define L1_EXP0        "./00_TB/dat_grad/cnn_layer1_exp0.dat"

module test;

reg	[19:0]	PAT	[0:4095];

reg	[19:0]	L0_EXP0	[0:4095];
reg	[19:0]	L0_MEM0	[0:4095];

reg	[19:0]	L1_EXP0	[0:1023];
reg	[19:0]	L1_MEM0	[0:1023];

reg		rst = 0;
reg		clk = 0;
reg		ready = 0;

wire		cwr;
wire		crd;
wire	[19:0]	cdata_wr;
reg	[19:0]	cdata_rd;
wire	[2:0]	csel;
wire	[11:0]	caddr_rd;
wire	[11:0]	caddr_wr;

wire	[11:0]	iaddr;
reg	[19:0]	idata;

integer		p0, p1, p3, p4, p2;
integer		err00, err10;

integer		pat_num;
reg		check0=0, check1=0;

localparam SDFFILE = "../02_SYN/Netlist/top_syn.sdf";
`ifdef SDF
	initial $sdf_annotate(SDFFILE, TOP);
`endif

TOP TOP(
			.clk(clk),
			.rst(rst),
			.busy(busy),
			.ready(ready),
			.iaddr(iaddr),
			.idata(idata),
			.cwr(cwr),
			.caddr_wr(caddr_wr),
			.cdata_wr(cdata_wr),
			.crd(crd),
			.cdata_rd(cdata_rd),
			.caddr_rd(caddr_rd),
			.csel(csel)
			);

always begin #(`CYCLE/2) clk = ~clk; end

// initial begin
// 	$fsdbDumpfile("CONV.fsdb");
// 	$fsdbDumpvars(0, test);
// end
initial begin
	$display(" Cycle Period = %0f ns", `CYCLE);
end

// initial begin
// 	$dumpfile("CONV.vcd");
// 	$dumpvars(0, testfixture);
// end

initial begin  // global control
	$display("-----------------------------------------------------\n");
 	$display("START!!! Simulation Start .....\n");
 	$display("-----------------------------------------------------\n");
	@(negedge clk); #1; rst = 1'b1;  ready = 1'b1;
   	#(`CYCLE*3);  #1;   rst = 1'b0;
   	wait(busy == 1); #(`CYCLE/4); ready = 1'b0;
end

initial begin // initial pattern and expected result
	wait(rst==1);
	wait ((ready==1) && (busy ==0) ) begin
		$readmemh(`PAT, PAT);
		$readmemh(`L0_EXP0, L0_EXP0);
		$readmemh(`L1_EXP0, L1_EXP0);
	end

end

always@(negedge clk) begin // generate the stimulus input data
	#1;
	if ((ready == 0) & (busy == 1)) idata <= PAT[iaddr];
	else idata <= 'hx;
	end

always@(negedge clk) begin
	if (crd == 1) begin
		case(csel)
			3'b001:cdata_rd <= L0_MEM0[caddr_rd] ;
			3'b011:cdata_rd <= L1_MEM0[caddr_rd] ;
		endcase
	end
end

always@(posedge clk) begin
	if (cwr == 1) begin
		case(csel)
			3'b001: begin check0 <= 1; L0_MEM0[caddr_wr] <= cdata_wr; end
			3'b011: begin check1 <= 1; L1_MEM0[caddr_wr] <= cdata_wr; end
		endcase
	end
end

reg c1, c2;

//-------------------------------------------------------------------------------------------------------------------
initial begin  	// layer 0,  conv output
check0<= 0;
c1  = 0;
wait(busy==1); wait(busy==0);
if (check0 == 1) begin
	err00 = 0;
	for (p0=0; p0<=4095; p0=p0+1) begin
		if (L0_MEM0[p0] == L0_EXP0[p0]) begin
			// $display(err00);
		end
		else begin
			err00 = err00 + 1;
			// $display(err00);
			begin
				$display("WRONG! Layer 0 (Convolutional Output) with Kernel 0 , Pixel %d is wrong!", p0);
				$display("               The output data is %h, but the expected data is %h ", L0_MEM0[p0], L0_EXP0[p0]);
			end
		end
	end
	if (err00 == 0) $display("Layer 0 (Convolutional Output) with Kernel 0 is correct !");
	else		 $display("Layer 0 (Convolutional Output) with Kernel 0 be found %d error !", err00);
	c1 = 1;
end
end

//-------------------------------------------------------------------------------------------------------------------
initial begin  	// layer 1,  max-pooling output
check1<= 0;
c2 = 0;
wait(busy==1); wait(busy==0);
wait(c1 == 1);
if(check1 == 1) begin
	err10 = 0;
	for (p1=0; p1<=1023; p1=p1+1) begin
		if (L1_MEM0[p1] == L1_EXP0[p1]);// $display(err10);
		else begin
			err10 = err10 + 1;
			begin
				$display("WRONG! Layer 1 (Max-pooling Output) with Kernel 0 , Pixel %d is wrong!", p1);
				$display("               The output data is %h, but the expected data is %h ", L1_MEM0[p1], L1_EXP0[p1]);
			end
		end
	end
	if (err10 == 0) $display("Layer 1 (Max-pooling Output) with Kernel 0 is correct!");
	else		 $display("Layer 1 (Max-pooling Output) with Kernel 0 be found %d error !", err10);
	c2 = 1;
end
end

//-------------------------------------------------------------------------------------------------------------------
initial  begin
 #`End_CYCLE ;
 	$display("-----------------------------------------------------\n");
 	$display("Error!!! The simulation can't be terminated under normal operation!\n");
 	$display("-------------------------FAIL------------------------\n");
 	$display("-----------------------------------------------------\n");
 	$finish;
end

reg out_end;

initial begin
	out_end = 0;
      wait(busy == 1);
      wait(busy == 0);
	  wait(c1 == 1);
	  wait(c2 == 1);
    $display(" ");
	$display("-----------------------------------------------------\n");
	$display("--------------------- S U M M A R Y -----------------\n");
	if( (check0==1)&(err00==0) ) $display("Congratulations! Layer 0 data have been generated successfully! The result is PASS!!\n");
		else if (check0 == 0) $display("Layer 0 output was fail! \n");
		else $display("FAIL!!!  There are %d errors! in Layer 0 \n", err00);
	if( (check1==1)&(err10==0) ) $display("Congratulations! Layer 1 data have been generated successfully! The result is PASS!!\n");
		else if (check1 == 0) $display("Layer 1 output was fail! \n");
		else $display("FAIL!!!  There are %d errors! in Layer 1 \n", err10);
	if ((check0|check1) == 0) $display("FAIL!!! No output data was found!! \n");
	$display("-----------------------------------------------------\n");
    //   #(`CYCLE/2); $finish;
	out_end = 1;
end

integer exe_cycle;
integer total_error;

initial begin
	exe_cycle = 0;
	while(!out_end) begin
		exe_cycle = exe_cycle + 1;
		@(negedge clk);
	end
	total_error = err00 + err10;
	$display("----------------------------------------------");
  	$display("------------total time: %0d cycles-----------------", exe_cycle);
  	$display("----------------------------------------------");
	if(err00 == 0 && err10 == 0) begin
		$display("------------------------------------------------");
		$display("----------------All tests PASS!-----------------");
		$display("------------------------------------------------");
	end else begin
		$display("------------------------------------------------");
		$display("-              Total Error: %0d               -", total_error);
		$display("------------------------------------------------");
	end

	$finish;
end

endmodule


---

# 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.)

---

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

`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


---

# Human Version — Job Assignment Machine (JAM): Complete Design Specification

## 1) Problem Overview

Implement a hardware **Job Assignment Machine (JAM)** that, for **n = 8** workers and **8** jobs, **exhaustively enumerates all assignments** (permutations) to:

1. find the **minimum total cost**, and
2. report the **number of assignments** that achieve that minimum.

The per-worker per-job **costs are stored in a synchronous 8×8 cost ROM** accessed via index signals. JAM repeatedly queries this ROM while iterating through all permutations. When done, it outputs `MinCost`, `MatchCount`, and asserts `Valid` for one clock to indicate results are ready (the testbench ends on the next cycle).

---

## 2) Top-Level Module & I/O

**Module name:** `TOP`

**Clocking & reset:**

* `CLK`: rising-edge synchronous.
* `RST`: **active-high, Synchronous** reset; testbench holds high for \~2 cycles then deasserts. While `RST=1`, internal state is cleared and no valid result is presented.

**Ports (widths & meaning):**

* `input  CLK` (1): system clock, posedge trigger.
* `input  RST` (1): Synchronous active-high reset.
* `output reg [2:0] W` (3): worker index selector (**0..7**) into cost ROM row.
* `output reg [2:0] J` (3): job index selector (**0..7**) into cost ROM column.
* `input  [6:0] Cost` (7): **unsigned** cost returned by the ROM (range **0..100**).
* `output reg [3:0] MatchCount` (4): number of assignments achieving the minimum (0..15; guaranteed to fit).
* `output reg [9:0] MinCost` (10): **unsigned** minimum total cost; testbench guarantees the true minimum ≤ **1024**.
* `output reg Valid` (1): **1-cycle pulse** indicating `MinCost` and `MatchCount` are final and valid.

---

## 3) External Cost ROM Interface & Timing

* The 8×8 cost table is provided as a synchronous read memory (“`cost_rom`”).
* **Addressing:** Drive `(W,J)` with values in **0..7**.
* **Read latency:** The **Cost** value reflects the **(W,J)** that were presented **in the preceding cycle**; i.e., apply `W`/`J` during cycle **t**, sample the corresponding `Cost` at the **rising edge of cycle t+1** (typical synchronous read). Keep `W`/`J` stable through the driving cycle to meet setup/hold.
* **Reuse:** The same ROM entries may be read any number of times; there is no side effect.
* **Waveforms:** Input (W,J→Cost) and output (`MinCost/MatchCount` with `Valid`) timing follow the figures in the brief; here we formalize: `Valid` is asserted for **exactly one** clock when the final numbers are present; the testbench terminates on the following cycle.

---

## 4) Required Functionality

### 4.1 Exhaustive Enumeration

* Consider the set of job indices **\[0..7]**.
* An **assignment** is a **permutation P** of \[0..7] where worker **W=k** is assigned job **J=P\[k]**.
* There are **8!** assignments; JAM must **evaluate every one** (no pruning).

### 4.2 Total Cost of an Assignment

For a given permutation **P**, compute:

$$
\text{TotalCost}(P) = \sum_{k=0}^{7} \text{Cost}(W=k,\;J=P[k]).
$$

Each term is obtained by a ROM read at address `(W=k, J=P[k])`. Accumulate the 8 terms to get the assignment’s total.

### 4.3 Global Results

* **MinCost:** the minimum of `TotalCost(P)` over all permutations.
* **MatchCount:** how many distinct permutations achieve that **MinCost**.
* When the search completes, drive `MinCost`, `MatchCount`, and assert `Valid=1` for **one** clock.

---

## 5) Permutation Generation (Lexicographic “next-permutation”)

You may generate all permutations by any correct method. For determinism and simplicity, the brief describes the **lexicographic next-permutation** routine (not the only allowable method). One standard formulation:

1. **Find pivot:** Scan from the right to find the **first i** with `a[i] < a[i+1]`. If none, the current sequence is the last permutation.
2. **Find successor:** In the suffix `a[i+1..end]`, find the **smallest element > a\[i]**; call its position `j`.
3. **Swap & reverse:** Swap `a[i]` and `a[j]`, then **reverse** the suffix `a[i+1..end]`. The result is the **next** permutation in lexicographic order.

Start from the sorted sequence `[0,1,2,3,4,5,6,7]` and iterate until all permutations are covered. (Example reasoning and a 7-element demonstration are provided in the brief; the above steps capture the required behavior.)

---

## 6) Control & Output Protocol

1. **Reset phase:** With `RST=1`, clear internal state (counters, trackers, permutation registers, pipelines). No `Valid` pulse.
2. **Run phase:** After `RST` deasserts, begin exhaustive enumeration and ROM queries; accumulate and track the minimum and its multiplicity.
3. **Finalize:** Once all permutations are evaluated, present `MinCost`/`MatchCount` and assert `Valid=1` for a **single** clock. The testbench stops in the **next** cycle.

---

## 7) Data Ranges & Types

* **Cost:** `0..100` (unsigned 7-bit), provided by the ROM.
* **MinCost:** unsigned 10-bit; true minimum is guaranteed ≤ **1024**.
* **MatchCount:** unsigned 4-bit (0..15); wide enough for all supplied patterns.
* **Indices:** `W`, `J` are 3-bit unsigned (`0..7`).

---

## 8) Design Constraints & Notes

* **Must not** hard-code or special-case any known test patterns; solutions that detect pattern IDs or embed precomputed answers are disallowed.
* The lexicographic algorithm is **suggested** but **not mandatory**—any correct exhaustive enumeration is acceptable.
* The port names and widths are **fixed** as specified; do not change them.
* Synthesis, SDF, and tool command details belong to appendices and are **out of scope** here.

---

module TOP(clk, rst, gray_data, gray_valid, CNT_valid, CNT1, CNT2, CNT3, CNT4, CNT5, CNT6,
    code_valid, HC1, HC2, HC3, HC4, HC5, HC6, M1, M2, M3, M4, M5, M6);

input             clk;
input             rst;
input             gray_valid;
input       [7:0] gray_data;
output reg        CNT_valid;
output   [7:0] CNT1, CNT2, CNT3, CNT4, CNT5, CNT6;
output reg        code_valid;
output  [7:0] HC1, HC2, HC3, HC4, HC5, HC6;
output  [7:0] M1, M2, M3, M4, M5, M6;

integer i, j;
reg [1:0] state_w,state_r;
reg [7:0] CNT_array [6:1];
reg [7:0] HC_array  [6:1];
reg [7:0] M_array   [6:1];
reg [7:0] counter ;

reg [7:0] min1, min2;
reg [2:0] min1_index, min2_index;
reg [3:0] group1_index, group2_index;
reg [3:0] CNT_group [6:1];
reg [3:0] group_count;

assign CNT1 = CNT_array[1];
assign CNT2 = CNT_array[2];
assign CNT3 = CNT_array[3];
assign CNT4 = CNT_array[4];
assign CNT5 = CNT_array[5];
assign CNT6 = CNT_array[6];

assign M1 = 8'b1111_1111 >> (8-M_array[1]);
assign M2 = 8'b1111_1111 >> (8-M_array[2]);
assign M3 = 8'b1111_1111 >> (8-M_array[3]);
assign M4 = 8'b1111_1111 >> (8-M_array[4]);
assign M5 = 8'b1111_1111 >> (8-M_array[5]);
assign M6 = 8'b1111_1111 >> (8-M_array[6]);

assign HC1 = HC_array[1] >> (8-M_array[1]);
assign HC2 = HC_array[2] >> (8-M_array[2]);
assign HC3 = HC_array[3] >> (8-M_array[3]);
assign HC4 = HC_array[4] >> (8-M_array[4]);
assign HC5 = HC_array[5] >> (8-M_array[5]);
assign HC6 = HC_array[6] >> (8-M_array[6]);

localparam  ACCEPT = 0, FIND_MIN1 = 1, COMPARE = 2, FINAL = 3;

always@(posedge clk or posedge rst) begin
    if (rst) begin
        min1_index <= 0;
        min2_index <= 0;
        group1_index <= 0;
        group2_index <= 0;
        for(i = 1; i <= 6 ; i = i+1) begin
            HC_array[i] <= 0;
            M_array [i] <= 0;
            CNT_group[i] <= i;
            CNT_array[i] <= 0;
        end
        CNT_valid <= 0;
        code_valid <= 0;
        counter <= 0;
        min1    <= 255;
        min2    <= 255;
        group_count <= 7;
        state_r <= ACCEPT;
    end
    else begin
        state_r <= state_w;

        case(state_r)

            ACCEPT:begin
                counter <= (counter==2)? 2 : counter + 1;
		        if(gray_valid)
                	CNT_array[gray_data] <= CNT_array[gray_data] + 8'd1;
                if((!gray_valid && counter==2)) begin
                    CNT_valid    <= 1;
                    counter      <= 1;
                end
            end

            FIND_MIN1:begin   //bubble sort
                CNT_valid    <= 0    ;
                if(CNT_array[counter] < min1 || (CNT_array[counter] == min1) && (CNT_group[counter] == (group_count-1)) )begin
                    min1 <= CNT_array[counter];
                    min1_index <= counter;
                    group1_index <= CNT_group[counter];

                    min2 <= min1;
                    min2_index <= min1_index;
                    group2_index <= group1_index;
                end
                if(CNT_array[counter] <= min2 && CNT_array[counter] >= min1 )begin
                    min2 <= CNT_array[counter];
                    min2_index <= counter;
                    group2_index <= CNT_group[counter];
                end
                counter <= (counter==6)? 1 : counter+1;
            end

            COMPARE:begin
                for(i = 1; i <= 6 ; i = i+1) begin
                    if(CNT_group[i] == group1_index) begin
                        M_array[i] <= M_array[i] + 1;
                        HC_array[i] <= { 1'b1 , HC_array[i][7:1] };
                        CNT_group[i] <= group_count;
                    end
		        if(CNT_group[i] == group2_index) begin
                        M_array[i] <= M_array[i] + 1;
                        HC_array[i] <= { 1'b0 , HC_array[i][7:1] };
                        CNT_group[i] <= group_count;
                    end
                end

                CNT_array[min2_index] <= CNT_array[min1_index] + CNT_array[min2_index];
                CNT_array[min1_index] <= 255;
                group_count <= group_count + 1;
                min1 <= 255;
                min2 <= 255;
            end

            FINAL:begin
                code_valid <= 1;
            end

        endcase

    end
end

always@(*)begin
    case(state_r)
        ACCEPT: state_w = (!gray_valid && counter==2)? FIND_MIN1 : ACCEPT ;
        FIND_MIN1: state_w = (counter==6)? COMPARE : FIND_MIN1;
        COMPARE: state_w = (CNT_array[min1_index] + CNT_array[min2_index] == 100)? FINAL : FIND_MIN1;
        FINAL: state_w = FINAL;

    endcase

end

endmodule

`timescale 1ns/10ps
`define CYCLE 10               // clk period. DO NOT modify period
`define tb1

`ifdef tb1
  `define PAT "./00_TB/pattern1.dat"
  `define EXP "./00_TB/golden1.dat"
`endif

`ifdef tb2
  `define PAT "./00_TB/pattern2.dat"
  `define EXP "./00_TB/golden2.dat"
`endif

`ifdef tb3
  `define PAT "./00_TB/pattern3.dat"
  `define EXP "./00_TB/golden3.dat"
`endif

module test;
reg clk;
reg rst;
reg [7:0] pat_mem [0:99];
reg [7:0] exp_mem [0:17];
reg gray_valid;
reg [7:0] gray_data;
integer i;

wire CNT_valid;
wire [7:0] CNT [1:6];
wire code_valid;
wire [7:0] HC [1:6];
wire [7:0] M [1:6];

reg flag1; // CNT PASS or not
reg flag2; // HC PASS or not
reg flag3; // M PASS or not
reg done1;

wire [47:0] CNT_G, CNT_EXP;
wire [47:0] HC_G, HC_EXP;
wire [47:0] M_G, M_EXP;

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

localparam SDFFILE = "../02_SYN/Netlist/top_syn.sdf";
`ifdef SDF
	initial $sdf_annotate(SDFFILE, TOP);
`endif

TOP TOP(.clk(clk), .rst(rst), .gray_valid(gray_valid), .gray_data(gray_data),
    .CNT_valid(CNT_valid),
    .CNT1(CNT[1]),   // should compare with exp_mem[0]
    .CNT2(CNT[2]),   // should compare with exp_mem[1]
    .CNT3(CNT[3]),   // should compare with exp_mem[2]
    .CNT4(CNT[4]),   // should compare with exp_mem[3]
    .CNT5(CNT[5]),   // should compare with exp_mem[4]
    .CNT6(CNT[6]),   // should compare with exp_mem[5]
    .code_valid(code_valid),
    .HC1(HC[1]),   // should compare with exp_mem[6]
    .HC2(HC[2]),   // should compare with exp_mem[7]
    .HC3(HC[3]),   // should compare with exp_mem[8]
    .HC4(HC[4]),   // should compare with exp_mem[9]
    .HC5(HC[5]),   // should compare with exp_mem[10]
    .HC6(HC[6]),   // should compare with exp_mem[11]
    .M1(M[1]),   // should compare with exp_mem[12]
    .M2(M[2]),   // should compare with exp_mem[13]
    .M3(M[3]),   // should compare with exp_mem[14]
    .M4(M[4]),   // should compare with exp_mem[15]
    .M5(M[5]),   // should compare with exp_mem[16]
    .M6(M[6]) ); // should compare with exp_mem[17]

assign CNT_G = {CNT[1], CNT[2], CNT[3], CNT[4], CNT[5], CNT[6]};
assign CNT_EXP = {exp_mem[0], exp_mem[1], exp_mem[2], exp_mem[3], exp_mem[4], exp_mem[5]};
assign HC_G = {HC[1], HC[2], HC[3], HC[4], HC[5], HC[6]};
assign HC_EXP = {exp_mem[6], exp_mem[7], exp_mem[8], exp_mem[9], exp_mem[10], exp_mem[11]};
assign M_G = {M[1], M[2], M[3], M[4], M[5], M[6]};
assign M_EXP = {exp_mem[12], exp_mem[13], exp_mem[14], exp_mem[15], exp_mem[16], exp_mem[17]};

initial $readmemh(`PAT, pat_mem);
initial $readmemh(`EXP, exp_mem);
initial $display("%s and %s were used for this simulation.", `PAT, `EXP);   //

initial clk = 1'b0;

always begin #(`CYCLE/2) clk = ~clk; end

initial begin
  #0 rst = 1'b0;
  #`CYCLE rst = 1'b1;
  #(`CYCLE*2) rst = 1'b0;
end
initial begin
    $display(" Cycle Period = %0f ns", `CYCLE);
end
initial begin
  #0 gray_valid = 1'b0;
     i = 0;
  #(`CYCLE*5);
  @(negedge clk) gray_valid = 1'b1;
  gray_data = pat_mem[i];
  for (i=1;i<100;i=i+1)
    @(negedge clk) gray_data = pat_mem[i];
  @(negedge clk) gray_valid = 1'b0;
       gray_data = 8'b0;
end

reg out_end;
integer exe_cycle;
integer total_error;

always@(negedge clk) begin
  if (rst) begin
    done1 <= 1'b0;
    flag1 <= 1'b0;
    flag2 <= 1'b0;
    flag3 <= 1'b0;
    out_end <= 1'b0;
    total_error = 0;

  end else begin

    if(CNT_valid == 1'b1) begin
      if (CNT_G == CNT_EXP) begin     // flag1 1 means PASS, 0 means ERROR
        $display("Check CNT : PASS");
        flag1 <= 1'b1;
      end else begin
        $display("Check CNT : ERROR. Please fixed it first!");
        $display("Simulation stop here.");
        $finish;
      end
      done1 <= 1'b1;
    end

    if(code_valid == 1'b1) begin

      case ({(HC_G == HC_EXP),(M_G == M_EXP)})   // (HC_G == HC_EXP) true means HC PASS
        2'b00: begin                             // (M_G == M_EXP) true means M PASS
                 $display("Check HC : ERROR");
                 $display("Check M : ERROR");
                //  $display("Simulation stop here.");
                 total_error = 1;
                 out_end <= 1'b1;
                //  $finish;
               end
        2'b01: begin
                 $display("Check HC : ERROR");
                 $display("Check M : PASS");
                 total_error = 1;
                 out_end <= 1'b1;
                //  $display("Simulation stop here.");

                //  $finish;
               end
        2'b10: begin
                 $display("Check HC : PASS");
                 $display("Check M : ERRPR");
                 total_error = 1;
                 out_end <= 1'b1;
                //  $display("Simulation stop here.");
                //  $finish;
               end
        2'b11: begin
                 $display("Check HC : PASS");
                 $display("Check M : PASS");
                 if(flag1 == 1'b1)
                   $display("You PASS the contest now.");
                 else
                   $display("Where are those CNT output?");
                   out_end <= 1'b1;
                //  $finish;
                 //$stop;
               end
        endcase
    end

  end
end

initial begin
  repeat(5)@(negedge clk);
	exe_cycle = 0;
	while(!out_end) begin
		exe_cycle = exe_cycle + 1;
		@(negedge clk);
	end
  $display("----------------------------------------------");
  $display("------------total time: %0d cycles-----------------", exe_cycle);
  $display("----------------------------------------------");
	if(total_error == 0) begin
		$display("------------------------------------------------");
		$display("----------------All tests PASS!-----------------");
		$display("------------------------------------------------");
	end else begin
		$display("------------------------------------------------");
		$display("-              Total Error: %0d               -", total_error);
		$display("------------------------------------------------");
	end

	$finish;
end

/*
initial begin
  for (i=0; i<100; i=i+1) begin
    $display("%3d %h", i, pat_mem[i]);
  end
  $display("--------------------------------------");
  for( i=0; i<18; i=i+1) begin
    $display("%3d %h", i, exp_mem[i]);
  end
end
*/

endmodule