Task: Q5_JAM


---

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

---


## Reference RTL Implementation


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


## Testbench


`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