---
# System prepended metadata

title: Perancangan Deep Q-Learning Accelerator

---

# Perancangan Deep Q-Learning Accelerator
Pengerjanaan dilakukan secara modular dengan memecah verilog per-sub-sistem dari keseluruhan arsitektur.

Rancangan Q-Learning Accelerator yang akan diimplementasikan adalah sebagai berikut.



[TOC]
:::warning
Perancangan ini masih dikerjakan 
:::
*** 

## Pemodelan Sistem
Sistem dimodelkan oleh Satrio PL dengan penjelasan sebagai berikut. Bentuk layer yang ada di matlab Okinawa: 
![](https://i.imgur.com/tK7wF6A.png)
Fungsi fungsi yang dibawah ini berdasarkan yang ada di matlab Okinawa:
Parameter awal:
-	Jumlah episode maks = 10000
-	Jumlah step maks = 10
-	Lingkungan maze dan reward yang ada
-	Inisialisasi state awal agen
-	Jumlah hidden layer awal = 5, aktivasi fungsi sigmoid
Persamaan fungsinya:
![](https://i.imgur.com/0aZy8Wx.png)
Bentuk grafiknya:
![](https://i.imgur.com/FNDhrvn.png)
-	Aktivasi fungsi output layer : linear
Ya kayak fungsi linear biasa.
-	Learning param:
Alpha : 0.001
Gamma : 0.9
Buat weight dan bias untuk tiap panah pada layer:
-	w12 : artinya besar suatu nilai dari input ke hidden layer (di inisialisasi awal dengan nilai random (0-1))
-	b2 : artinya besar suatu bias dari input layer ke hidden layer (dibuat nilai -1)

-	w23 : artinya besar suatu nilai dari hidden layer ke output layer (di inisialisasi awal dengan nilai random (0-1))
-	b3 : artinya besar suatu bias dari hidden layer ke output (dibuat nilai -1)

Proses learning :
-	inisiasi epsilon
-	for episode 1 sampe max eps:
-	st1 = 1
-	decrease epsilon
-	for step = 1 sampe max step:
-	random data (nilai ini dipake untuk nentuin milih aksi random atau dari nilai Q)
-	Pake fungsi forward prop (dijelasin dibawah, nama fungsinya sw_move_state), keluaran dari fungs ini : next_state_num, action, Qt(dalam bentuk array 4 index))
-	St1= next_state_num, at = action
-	Ada penalty (dijelasin dibawah)
-	Peroleh reward dari lingkungan
-	Update w12, b2, w23, b3 (pake fungsi yang dijelasin dibawah)
-	Kalo sudah sampe goal, for loop ini berhenti (break)
-	Kalo sudah learning sampe max episode, learning selesai.

Fungsi – fungsi yang dijelaskan diatas:
Forward prop : perkalian matriks 
Simbol input layer I, hidden layer H, output layer O
Dari input layer ke hidden layer 
![](https://i.imgur.com/MehDL3s.png)

Dari hidden layer ke output 
![](https://i.imgur.com/TWbPR0Z.png)

Update weight and bias
Di fungsi update ini pada awalnya pake fungsi forward prop pada next_state yang dipake sebelumnya.
Terus ada fungsi back prop : (fungsi ini dipake untuk memperbaharui nilai weight and bias yang ada pada network) intinya di back prop ini ada persamaan derivative. Tapi derivative yang ada gak susah, Cuma perkalian doang.
Untuk derivative dari fungsi sigmoid = 
 ![](https://i.imgur.com/aCTUeB4.png)

Terus nanti akhirnya Cuma penjumlahan matriks doang.
Jadi intinya untuk DQN coba dibuat dulu proses perkalian matriks, penjumlahan matriks, fungsi transpose matriks, dan element wise multiplication matriks.

Contoh perkalian matriks yang dipake di forward prop :
![](https://i.imgur.com/SPkgqf3.png)

Contoh element wise multip matriks: (dipake untuk derivative di back propagation)
![](https://i.imgur.com/r3aKkZ5.png)



## Perancangan PL (Verilog) 
### Matrix Pada Verilog
Untuk dapat melakukan operasi matriks maka perlu diketahui deklarasi matriks pada Verilog. Sayangnya, ==Verilog belum mendukung tipe data matriks sebagai port input==. Untuk itu perlu digunakan sedikit modifikasi menggunakan Verilog Generate Blocks dengan Packed Arrays dan Unpacked Arrays. 

#### Packed Arrays
Array jenis ini adalah array yang deklarasi dimensi nya dilakukan sebelum nama objek sehingga seperti Vector. Tipe data yang dapat digunakan hanyalah data 1-bit sehingga merupakan sekumpulan bit yang contiguous. Contoh nya:
```
reg [31:0] temp;

// Concatenation (for Initialization)
wire [7:0] a = {4'd7, 4'd14};
// Nested Concatenation
wire [7:0] b = {{1'b0,1'b1,1'b1,1'b1},{1'b1,1'b1,1'b1,1'b0}};
```
#### Unpacked Arrays
Berbeda dengan packed, jenis ini melakukan deklarasi setelah nama objek. Tipe data yang digunakan dapat berupa apa saja. Contoh nya:
```
reg temp [0:1023];

// Array Assignment
integer c [0:3] = '{0, 1, 2, 3};
// Nested Array Assignment
integer d [0:3][0:2] = '{'{0,1,2,3},'{4,5,6,7},'{8,9,10,11}};
```
#### Multi-dimensional Arrays
Array ini merupakan gabungan dari packed dan unpacked. Array pada verilog hanya dapat diakses satu data pada satu waktu. Pada array contiguous, maka data dapat diambil per element atau sekelompok elemen satu dimensi yang dinamakan dengan slice. Contoh nya :
```
car B = car A [7:6];     // select a 2-vector slice from car A  
car B = car A [6+:2];    // equivalent to car A[7:6]

// Concatenation and Array Assignment
wire [7:0] e [0:3] = '{{4'd7, 4'd14}, 8'd1, {4'd5, 4'd3}, 8'd3};
```
#### Packed Arrays Assignment
Berikut operasi assignment yang dapat dilakukan pada packed arrays.
```
logic [1:0][1:0][7:0] packed_3d_array;  
   
always_ff @(posedge clk, negedge rst_n)  
  if (!rst_n) begin  
    packed_3d_array <= '0;                             // assign 0 to all elements of array  
  end  
    
  else begin  
    packed_3d_array[0][0][0]   <= 1'b0;                    // assign one bit  
    packed_3d_array[0][0]      <= A0a;                    // assign one element  
    packed_3d_array[0][0][3:0] <= 4'ha;                   // assign part select  
    packed_3d_array[0]         <= 16'habcd;                // assign slice  
    packed_3d_array            <= 32'h01234567;         // assign entire array as vector  
  end  
``````

#### Unpacked Arrays Assignment
Berikut operasi assignment yang dapat dilakukan pada unpacked arrays.
```
logic [7:0] a, b, c;  
logic [7:0] d_array[0:3];  
logic [7:0] e_array[3:0];                // note index of unpacked dimension is reversed  
                            
logic [7:0] mult_array_a[3:0][3:0];  
logic [7:0] mult_array_b[3:0][3:0];  
   
always_ff @(posedge clk, negedge rst_n)  
  if (!rst_n) begin  
    d_array <= '{default:0};                                  // assign 0 to all elements of array  
  end  
    
  else begin  
    d_array        <= '{A00, c, b, a};                    // d_array[0]=A00, d_array[1]=c,      
                                                                             d_array[2]=b, d_array[3]=a  
  
    e_array        <= '{A00, c, b, a};                    // e_array[3]=A00, e_array[2]=c,     
                                                                             e_array[1]=b, d_array[0]=a  
  
    mult_array_a   <= '{'{A00, A01, A02, A03}, '{A04, A05, A06, A07},  
                                    '{A08, A09, A0a, A0b},  
                                    '{A0c, A0d, A0e, A0f}};               // assign to full array  
    mult_array_b[3] <= '{A00, A01, A02, A03};        // assign to slice of array  
  end  
``````

#### Packed and Unpacked Arrays Assignment
``````
wire [383:0] array = {{0,1,2,3},{4,5,6,7},{8,9,10,11}}; //Valid
integer array [0:3][0:2] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}}; //Invalid
integer array [0:3][0:2] = '{'{0,1,2,3},'{4,5,6,7},'{8,9,10,11}}; //Valid
``````

### Blok Generate Pada Verilog
Memiliki dua buah kegunaan :
1. Untuk menginisiasi modul yang sama secara berulang-kali
2. Melakukan instantinasi kondisional dari sebuah modul

Blok ini tidak dapat mengandung port, parameter, specparam, atau specify. Namun modul lainnya diperbolehkan. Semua blok generate terdapat di dalam module dengan keywords generate dan endgenerate.

Modul yang dibuat (diinstantinasi) dapat berupa continuos assignments, always / initial blok, dan user defined priimitives. ==Genvar dan Generate hanya merupakan directive yang akan diterjemahkan oleh Synthesizer== sehinga meng-unroll loop menjadi, sebagai contoh : 

``````
genvar i;

generate 
    for(i = 0; i< 2; i = i + 1) begin
         assign x[i] = i; end
endgenerate
``````         
ekuivalen dengan
``````
assign x[0] = 0;
assign x[1] = 1;
``````

#### Generate "for Loop"
``````
module ha (input a,b,
           output sum,cout);
    assign sum = a ^ b;
    assign cout = a&b;
endmodule

// N instance of half adder
module my_design
    #(parameter N=4)
        (    input [N-1:0] a, b,
             output [N-1:0] sum, cout);

// Temporary loop variable, won't be seen during 
// simulation
genvar i;

// For loop
generate
    for(i = 0; i < N; i = i +1) begin
        ha u0 (a[i], b[i], sum[i], cout[i]);
    end
endgenerate
endmodule

``````
#### Testbench untuk Generate "for Loop"
``````
module tb;
        parameter N = 2;
    reg [N-1:0] a, b;
    wire [N-1:0] sum, cout;
    
    my_design #(.N(N)) md( .a(a), .b(b), .sum(sum),     .cout(cout));
    
    initial begin
        a <= 0;
        b <= 0;
        
        $monitor ("a=0x%0h b=0x%0h sum=0x%0h                 cout=0x%0h, a, b, sum, cout");
        
        #10 a <= 'h2;
            b <= 'h3;
        #20 b <= 'h4;
        #10 a <= 'h5;
    end
endmodule
``````

#### Blok RTL
![](https://i.imgur.com/vr7PfZn.png)

#### Contoh lain
``````
Example of parameterized gray to binary code converter

module gray2bin
#(parameter SIZE = 8)
(
  input [SIZE-1:0] gray,
  output [SIZE-1:0] bin
)

Genvar gi;
// generate and endgenerate is optional
// generate (optional)
  for (gi=0; gi&lt;SIZE; gi=gi+1) begin : genbit
    assign bin[gi] = ^gray[SIZE-1:gi]; // Thanks Dhruvkumar!
  end
// endgenerate (optional)
endmodule
``````
``````
module addergen1
#(parameter SIZE = 4)
(
  input  logic [SIZE-1:0] a, b,
  input  logic            ci,
  output logic            co,
  output logic [SIZE-1:0] sum
);

wire [SIZE :0] c;
genvar i;

assign c[0] = ci;

// Hierarchical gate instance names are:
// xor gates: bitnum[0].g1 bitnum[1].g1 bitnum[2].g1 bitnum[3].g1
// bitnum[0].g2 bitnum[1].g2 bitnum[2].g2 bitnum[3].g2
// and gates: bitnum[0].g3 bitnum[1].g3 bitnum[2].g3 bitnum[3].g3
// bitnum[0].g4 bitnum[1].g4 bitnum[2].g4 bitnum[3].g4
// or gates: bitnum[0].g5 bitnum[1].g5 bitnum[2].g5 bitnum[3].g5
// Gate instances are connected with nets named:
// bitnum[0].t1 bitnum[1].t1 bitnum[2].t1 bitnum[3].t1
// bitnum[0].t2 bitnum[1].t2 bitnum[2].t2 bitnum[3].t2
// bitnum[0].t3 bitnum[1].t3 bitnum[2].t3 bitnum[3].t3

for(i=0; i&lt;SIZE; i=i+1) begin:bitnum
  wire t1, t2, t3;
  xor g1 ( t1, a[i], b[i]);
  xor g2 ( sum[i], t1, c[i]);
  and g3 ( t2, a[i], b[i]);
  and g4 ( t3, t1, c[i]);
  or g5 ( c[i+1], t2, t3);
end

assign co = c[SIZE];

endmodule
``````

#### Macros
Saat menggunakan macros berikut : 
``````
`define PACK_ARRAY(PK_WIDTH,PK_LEN,PK_SRC,PK_DEST)    genvar pk_idx; generate for (pk_idx=0; pk_idx<(PK_LEN); pk_idx=pk_idx+1) begin; assign PK_DEST[((PK_WIDTH)*pk_idx+((PK_WIDTH)-1)):((PK_WIDTH)*pk_idx)] = PK_SRC[pk_idx][((PK_WIDTH)-1):0]; end; endgenerate

`define UNPACK_ARRAY(PK_WIDTH,PK_LEN,PK_DEST,PK_SRC)  genvar unpk_idx; generate for (unpk_idx=0; unpk_idx<(PK_LEN); unpk_idx=unpk_idx+1) begin; assign PK_DEST[unpk_idx][((PK_WIDTH)-1):0] = PK_SRC[((PK_WIDTH)*unpk_idx+(PK_WIDTH-1)):((PK_WIDTH)*unpk_idx)]; end; endgenerate


module pack_unpack (
    input  [63:0] pack_4_16_in,
    output [31:0] pack_16_2_out
    );

wire [3:0] in [0:15];
`UNPACK_ARRAY(4,16,in,pack_4_16_in)

wire [15:0] out [0:1];
`PACK_ARRAY(16,2,in,pack_16_2_out)


// useful code goes here

endmodule // example

``````
Terdapat error karena saat macros diterjemahkan, tedapat semicolon yang tidak seharusnya pada setelah begin (;) dan end (;), sehingga setelah dihapus, warning nya hilang. ==Macros tersebut perlu dirubah karena matrix yang digunakan merupakan array 2 Dimensi==, sehingga dibentuk Macros baru dengan definisi sebagai berikut.

``````
`define PACK_ARRAY_2D(PK_WIDTH,PK_LEN,PK_DIMS,PK_SRC,PK_DEST)  genvar pk_idx; genvar pk_dims; generate for (pk_idx=0; pk_idx<(PK_LEN); pk_idx=pk_idx+1) begin for (pk_dims=0; pk_dims<(PK_DIMS); pk_dims=pk_dims+1) begin  assign PK_DEST[((PK_WIDTH)*pk_idx*pk_dims+((PK_WIDTH)-1)):((PK_WIDTH)*pk_idx*pk_dims)] = PK_SRC[pk_idx][pk_dims][((PK_WIDTH)-1):0]; end end endgenerate


`define UNPACK_ARRAY_2D(PK_WIDTH,PK_LEN,PK_DIMS,PK_DEST,PK_SRC)  genvar unpk_idx; genvar unpk_dims; generate for (unpk_idx=0; unpk_idx<(PK_LEN); unpk_idx=unpk_idx+1)  begin for (unpk_dims=0; unpk_dims<(PK_DIMS); unpk_dims=unpk_dims+1) begin  assign PK_DEST[unpk_idx][unpk_dims][((PK_WIDTH)-1):0] = PK_SRC[((PK_WIDTH)*unpk_idx*unpk_dims+(PK_WIDTH-1)):((PK_WIDTH)*unpk_idx*unpk_dims)];  end end endgenerate

``````

### Blok Transpose Matrix Weight
==Terdapat tiga bagian utama blok ini, pertama adalah unpack array 2D, kemudian mentranspose matriks tersebut, dan mempack kembali sebagai output.== Setelah beberapa kali debugging, didapatkan hasil simulasi telah sesuai. Meski begitu, blok ini kedepannya tidak digunakan karena hanya untuk menguji pack_unpack saja.
``````
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Xirka
// Engineer: Adnan
// 
// Create Date: 04/01/2022 13:15:00 AM
// Design Name: DQN
// Module Name: matrix_weight_transpose
// Project Name: DQN
// Target Devices: Zybo Zynq-7000
// Tool Versions: 2020.1
// Description: Program Matrix Weight Transpose
//
// Dependencies: 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

// Macros for Matrix
`include "pack_unpack.v"

module matrix_weight_transpose#(parameter BIT_LGTH = 32, COLM = 9, ROWS = 5, OFFS1 = 4, OFFS2 = 8)
(
    input signed [(COLM)*(ROWS)*(BIT_LGTH)-1:0] weight,               // 5 columns, 9 rows, 32 bit data length
    
    output signed [(ROWS)*(COLM)*(BIT_LGTH)-1:0] weight_transposed    // 9 columns, 5 rows, 32 bit data length
);
 
 wire [(BIT_LGTH-1):0] weight_in [(COLM-1):0][(ROWS-1):0];
`UNPACK_ARRAY_2D(BIT_LGTH,COLM,ROWS,weight_in,weight,OFFS1)

 wire [(BIT_LGTH-1):0] weight_out [(ROWS-1):0][(COLM-1):0];
 `PACK_ARRAY_2D(BIT_LGTH,ROWS,COLM,weight_out,weight_transposed,OFFS2)
 
 generate                                           // Computing the transpose
    genvar i;
    for (i = 0; i < COLM; i = i + 1)
     begin     : columns              
     genvar j;
         for (j = 0; j < ROWS; j = j + 1)
         begin   : rows
            assign weight_out[j][i] = weight_in[i][j];
         end
    end
 endgenerate

endmodule
``````
testbench nya :
``````
module matrix_weight_transpose_sim();

reg [9*5*32-1:0] in;
wire [9*5*32-1:0] out;

matrix_weight_transpose MWT(.weight(in),
                            .weight_transposed(out));
                            
initial
    begin
        in = {{5{32'hAAAAAAAA}} , {5{32'hBBBBBBBB}} , {5{32'hCCCCCCCC}}, {5{32'hDDDDDDDD}} ,
             {5{32'hEEEEEEEE}}, {5{32'hFFFFFFFF}}, {5{32'hAAAAAAAA}} , {5{32'hBBBBBBBB}} , {5{32'hCCCCCCCC}}} ;
        #30;
    end
endmodule
``````
### Blok Dot Product Matrix Weight dengan Matrix Input Layer
Modul ini masih menggunakan full-pararel multiplier untuk perkalian setiap elemen matrix. Hal tersebut sangat boros area sehingga akan digantikan dengan arsitektur Systolic.
``````
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Xirka
// Engineer: Adnan
// 
// Create Date: 04/01/2022 13:15:00 AM
// Design Name: DQN
// Module Name: matrix_W_dot_I
// Project Name: DQN
// Target Devices: Zybo Zynq-7000
// Tool Versions: 2020.1
// Description: Program Matrix Weight Dot Product Input Layer
//
// Dependencies: 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


// Macros for Matrix
`include "pack_unpack.v"

module matrix_w_dot_i#(parameter BIT_LGTH = 32, COLM = 9, ROWS = 5)
(
    input signed [(COLM)*(ROWS)*(BIT_LGTH)-1:0] weight_TRPS,     // Transposed Weight
    input signed [(COLM)*(BIT_LGTH)-1:0] input_layer,            // Input Layer
    input clk,
    
    output signed [(ROWS)*(BIT_LGTH)-1:0] w_dot_i                // Weight dot product Input
);
 
 wire [(BIT_LGTH-1):0] weight_TRPS_in [(ROWS-1):0][(COLM-1):0];
`UNPACK_ARRAY_2D((BIT_LGTH),(ROWS),(COLM),weight_TRPS_in,weight_TRPS,8)

 wire [(BIT_LGTH-1):0] input_layer_in [(COLM-1):0];
`UNPACK_ARRAY((BIT_LGTH),(COLM),input_layer_in,input_layer)

 wire [(BIT_LGTH-1):0] w_dot_i_out [(ROWS-1):0];
 `PACK_ARRAY((BIT_LGTH),(ROWS),w_dot_i_out,w_dot_i)

 reg [(BIT_LGTH-1):0] result [(ROWS-1):0];
 generate                                           // Computing the dot product
    genvar i;
    for (i = 0; i < (ROWS); i = i + 1)
     begin     : columns              
     genvar j;
         for (j = 0; j < (COLM); j = j + 1)
         begin   : rows
         always@(posedge clk)
             begin 
                if (j==0) result[j] <= weight_TRPS_in[i][j]* input_layer_in[j];
                else result[j] <= result[j-1] + weight_TRPS_in[i][j]* input_layer_in[j];
             end
         end
     assign w_dot_i_out[i] = result[i];   
    end
 endgenerate

endmodule

``````
testbench nya :
``````
module matrix_w_dot_i_sim();

reg [9*5*32-1:0] weight_in;
reg [9*32-1:0] layer_in;
reg clk = 1'b0;

wire [9*5*32-1:0] out;

matrix_w_dot_i MWDI(.weight_TRPS(weight_in),
                    .input_layer(layer_in),
                    .clk(clk),
                    .w_dot_i(out));
                            
initial 
    begin
        weight_in = {{9{32'hAAAAAAAA}} , {9{32'hBBBBBBBB}} , {9{32'hCCCCCCCC}}, {9{32'hDDDDDDDD}} , {9{32'hEEEEEEEE}}} ;
        layer_in = {{{32'hAAAAAAAA}} , {{32'hBBBBBBBB}} , {{32'hCCCCCCCC}} , {{32'hDDDDDDDD}} ,
                    {{32'hEEEEEEEE}} , {{32'hFFFFFFFF}} , {{32'hAAAAAAAA}} , {{32'hBBBBBBBB}} , {5{32'hCCCCCCCC}}} ;
        #30;
    end
    
 always
    begin
        clk = ~clk;
        #10;
    end
endmodule
``````
### Blok Penjumlahan Matrix dari Input Layer ke Hidden Layer
``````
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Xirka
// Engineer: Adnan
// 
// Create Date: 04/01/2022 13:15:00 AM
// Design Name: DQN
// Module Name: matrix_addition_IH
// Project Name: DQN
// Target Devices: Zybo Zynq-7000
// Tool Versions: 2020.1
// Description: Program Matrix Addition from Input Layer to Hidden Layer 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

// Macros for Matrix

`include "pack_unpack.v"

module matrix_addition_IH #(parameter BIT_LGTH = 32, COLM = 1, ROWS = 5)
(
    input signed [(ROWS)*(BIT_LGTH)-1:0] w_dot_i,                    // 5 rows
    input signed [(ROWS)*(BIT_LGTH)-1:0] bias,                       // 5 rows
    input clk,
    
    output signed [(ROWS)*(BIT_LGTH)-1:0] IH                         // 5 rows
);

 wire [31:0] w_dot_i_in [4:0];
`UNPACK_ARRAY((BIT_LGTH),(ROWS),w_dot_i_in,w_dot_i)

 wire [31:0] bias_in [4:0];
`UNPACK_ARRAY2((BIT_LGTH),(ROWS),bias_in,bias)

 wire [31:0] IH_out [4:0];
 `PACK_ARRAY((BIT_LGTH),(ROWS),IH_out,IH)
 
  generate                                           // Computing the matrix addition
    genvar i;
    for (i = 0; i < (ROWS); i = i + 1)
     begin     : rows  
        assign IH_out[i] = w_dot_i_in[i] + bias_in[i];
     end
  endgenerate
  
endmodule
``````
testbench nya:
``````
module matrix_addition_IH_sim #(parameter BIT_LGTH = 32, COLM = 1, ROWS = 5)();

reg [(ROWS)*(BIT_LGTH)-1:0] w_dot_i_in;
reg [(ROWS)*(BIT_LGTH)-1:0] bias_in;
reg clk = 1'b0;

wire [(ROWS)*(BIT_LGTH)-1:0] IH_out;

matrix_addition_IH MAIH(.w_dot_i(w_dot_i_in),
                    .bias(bias_in),
                    .clk(clk),
                    .IH(IH_out));
                            
initial 
    begin
        w_dot_i_in = {{32'hAAAAAAAA} , {32'hBBBBBBBB} , {32'hCCCCCCCC}, {32'hDDDDDDDD} , {32'hEEEEEEEE}} ;
        bias_in = {{32'hEEEEEEEE} , {32'hDDDDDDDD} , {32'hCCCCCCCC}, {32'hBBBBBBBB} , {32'hAAAAAAAA}} ;
        #30;
    end
    
 always
    begin
        clk = ~clk;
        #10;
    end
endmodule

``````

### Blok Activation Function (Sigmoid)
Modul ini dibuat menggunakan aproksimasi dari fungsi sigmoid dengan gradien 1/4 dan 1/8 yang ditunjukan dalam bentuk grafik :
![](https://i.imgur.com/K2xdLPW.png)
Arsitektur yang digunakan adalah sebagai berikut.
![](https://i.imgur.com/DppiW44.png)


``````
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Xirka
// Engineer: Adnan
// 
// Create Date: 04/01/2022 13:15:00 AM
// Design Name: DQN
// Module Name: matrix_sigmoid
// Project Name: DQN
// Target Devices: Zybo Zynq-7000
// Tool Versions: 2020.1
// Description: Program Sigmoid Function
//
// Dependencies: 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

// Macros for Matrix
`include "pack_unpack.v"

module matrix_sigmoid#(parameter BIT_LGTH = 16, COLM = 1, ROWS = 5)
(
    input signed [(ROWS)*(BIT_LGTH)-1:0] IH,              // Weight dot Input(1) 
    input signed [(ROWS)*(BIT_LGTH)-1:0] bias,            // Bias 2 => Input to Hidden Layer
    input clk,
    
    output   [(ROWS)*(BIT_LGTH)-1:0] IH_sigmoid      // Weight dot product Input
);
 
 wire [(BIT_LGTH-1):0] IH_in [(ROWS-1):0];
`UNPACK_ARRAY((BIT_LGTH),(ROWS),IH_in,IH)

 wire [(BIT_LGTH-1):0] bias_in [(ROWS-1):0];
`UNPACK_ARRAY2((BIT_LGTH),(ROWS),bias_in,bias)

 wire [(BIT_LGTH-1):0] IH_sigmoid_out [(ROWS-1):0];
 `PACK_ARRAY((BIT_LGTH),(ROWS),IH_sigmoid_out,IH_sigmoid)

 wire [(BIT_LGTH-1):0] IH_in_temp [(ROWS-1):0];
 generate                                                 // Computing the sigmoid function
    genvar i;
    for (i = 0; i < (ROWS); i = i + 1)
     begin     : rows
         assign IH_in_temp[i] = IH_in[i] + bias_in[i];
         sigmoid #(.BIT_LGTH(BIT_LGTH)) a0 (.in(IH_in_temp[i]), .out(IH_sigmoid_out[i]));
     end
 endgenerate

endmodule

module sigmoid#(parameter BIT_LGTH = 16)(
   //input  : signed fractional 4 decimal, 20 fractional
  input signed [(BIT_LGTH-1):0] in,
  //output : unsigned fractional 0 decimal, 15 fractional
  output signed [(BIT_LGTH-1):0] out
);
    localparam signed border1 = 16'hFC00;
    localparam signed border2 = 16'h0400;
    localparam signed border3 = 16'hF400;
    localparam signed border4 = 16'h0C00;

    wire temp1, temp2, temp3, temp4;

    wire signed [15:0] outmux0, outmux1, outmux2, outmux3;
    wire signed [15:0] result;
    
    wire signed [15:0] inshift2 = in >>> 3;
    wire signed [15:0] inshift1 = in >>> 2;
    wire slc0, slc1, slc4;                                 //slc2=slc1 ; slc3 = slc4
    
    //Temporary wire for signed arithmetic
    assign temp1 = (in < border1);                         // Less than -1
    assign temp2 = (in >= border2);                        // More than 1
    assign temp3 = (in < border3);                         // Less than -3
    assign temp4 = (in >= border4);                        // More than 3
        
    //Select wire assignment
    assign slc0 = in[15];                                  // slc0 : 1 if negative
    assign slc1 = temp1 || temp2;                          // slc1 = (in<-1.0)||(in>1.0)
    assign slc4 = temp3 || temp4;                          // slc4 = (in<-3.0)||(in>3.0)
    
    //Linear region
    assign outmux0 = slc0 ? 16'h180 : 16'h0280;            //mux0 : Constant selector  y1 = 0.375 or y3 = 0.625
    assign outmux1 = slc1 ? outmux0 : 16'h0200;            //mux1 : Constant selector outmux1 = c (outmux0 or 0.5) 
    assign outmux2 = slc1 ? inshift2 : inshift1;           //mux2 : Gradien selector mx (x/8) or (x/4)
    assign result = outmux2 + outmux1;                     //adder to calculate output function mx + c
    
    //Saturation
    assign outmux3 = slc0 ? 16'h0000 : 16'h03FF;           //mux3 : Saturation selector (0 or 0.999(approximately 1))
    
    //Output
    assign out = slc4 ? outmux3 : result;

endmodule
``````
testbench nya:
``````
module matrix_sigmoid_sim#(parameter BIT_LGTH = 16, COLM = 1, ROWS = 5)();

reg [(ROWS)*(BIT_LGTH)-1:0] IH_in;
reg [(ROWS)*(BIT_LGTH)-1:0] bias_in;

reg clk = 1'b0;

wire [(ROWS)*(BIT_LGTH)-1:0] IH_sigmoid_out;

matrix_sigmoid MS(.IH(IH_in),
                    .bias(bias_in),
                    .clk(clk),
                    .IH_sigmoid(IH_sigmoid_out));
                            
initial 
    begin
        IH_in = {{16'hF400} , {16'hF800} , {16'h0400}, {16'h1000} , {16'h2000}} ;
        bias_in = {{16'hFC00} , {16'hFC00} , {16'hFC00}, {16'hFC00} , {16'hFC00}} ;
        #30;
        IH_in = {{16'hF500} , {16'hF900} , {16'h0500}, {16'h0BFF} , {16'h2800}} ;
    end
    
 always
    begin
        clk = ~clk;
        #10;
    end
endmodule

``````

### Blok Maximum Q-Value
Modul ini akan memilih antara 4 pilihan Action yang dapat diambil dengan mempertimbangkan action mana yang memiliki nilai Q-Value paling maksimum. Arsitektur yang digunakan adalah binary-tree-comparators sebagai gambar berikut.
![](https://i.imgur.com/gZet3Ge.png)
``````
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Xirka
// Engineer: Adnan
// 
// Create Date: 10/13/2021 13:15:00 AM
// Design Name: DQN
// Module Name: MAX
// Project Name: DQN
// Target Devices: Zybo Zynq-7000
// Tool Versions: 2020.1
// Description: Comparation for Maximum Q value 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module MAX#(parameter BIT_LGTH = 16)(
        input signed [(BIT_LGTH-1):0] Q_next_state_1, 
        input signed [(BIT_LGTH-1):0] Q_next_state_2,
        input signed [(BIT_LGTH-1):0] Q_next_state_3,
        input signed [(BIT_LGTH-1):0] Q_next_state_4,
        output reg signed [(BIT_LGTH-1):0] Qmax
    );
    
    reg [(BIT_LGTH-1):0] maximum_1_and_2;
    reg [(BIT_LGTH-1):0] maximum_3_and_4;
    
    always @(Q_next_state_1 or Q_next_state_2)
        begin
            if (Q_next_state_1 > Q_next_state_2)
                maximum_1_and_2 = Q_next_state_1;
            else 
                maximum_1_and_2 = Q_next_state_2;
        end
        
     always @(Q_next_state_3 or Q_next_state_4)
        begin
            if (Q_next_state_3 > Q_next_state_4)
                maximum_3_and_4 = Q_next_state_3;
            else 
                maximum_3_and_4 = Q_next_state_4;
        end
    
     wire [(BIT_LGTH-1):0] difference = maximum_1_and_2 - maximum_3_and_4;  
    
     always @(difference)
        begin
            if (difference[(BIT_LGTH-1)] == 0)
                Qmax = maximum_1_and_2;
            else 
                Qmax = maximum_3_and_4;
        end 
     
endmodule

``````
test bench :
``````
module MAX_sim#(parameter BIT_LGTH = 16)();
reg [(BIT_LGTH-1):0] Q_next_state_1_in;
reg [(BIT_LGTH-1):0] Q_next_state_2_in;
reg [(BIT_LGTH-1):0] Q_next_state_3_in;
reg [(BIT_LGTH-1):0] Q_next_state_4_in;

wire [(BIT_LGTH-1):0] Qmax_out;

MAX MX( .Q_next_state_1(Q_next_state_1_in),
        .Q_next_state_2(Q_next_state_2_in),
        .Q_next_state_3(Q_next_state_3_in),
        .Q_next_state_4(Q_next_state_4_in),
        .Qmax(Qmax_out));
                            
initial 
    begin
        #20
        Q_next_state_1_in = {16'h10F0}; 
        Q_next_state_2_in = {16'h100F}; 
        Q_next_state_3_in = {16'hF400}; 
        Q_next_state_4_in = {16'h0400};
    end
    
endmodule

``````

### Blok Step Counter dan Episode Counter
Modul ini akan mengakumulasi setiap kalo satu step selesai diambil (dalam waktu 15 clock). Setiap jumlah step terakumulasi mencapai batas tertentu (maximum step) atau menemukan goal (reward positif) maka episode counter akan bertambah. Terakhir, saat episode counter mencapai jumlah maksimal episode yang diinginkan, learning telah selesai. 

==Dua hal== yang perlu diperhatikan adalah ==pertama== bahwa karena format representasi angka yang digunakan adalah Q6.10 maka untuk persamaan dengan jumlah episode perlu direpresentasikan dalam heksa yang bersesuaian. ==Kedua==, karena modul step counter akan menghitung setiap satu step selesai diambil, maka dari itu trigger untuk menambah nilai step counter bukan berasal berasal dari clock melainkan dari Control Unit yang memberitahu bahwa telah sampai pada state selesai satu step. S untuk Episode counter.l step_done dari step counter ataipun dari modul reward.
``````
``````
Pada simulasi terdapat sedikit anomali yaitu setelah jumlah maksimum episode sampai, siklus berikutnya menghitung dari state 1 dan loncat ke state 3 tanpa melalui state 2. testbench nya :
``````
``````


### Blok Derivatif C terhadap Action 3 (Bagian 1)
Modul ini menghitung sesuai fungsi berikut. Apabila maxQ bernilai kurang dari nol, maka operasi aritmatik akan salah. Namun karena nilai maxQ terbatas antara 0<maxQ<1 maka hal tersebut tidak akan terjadi.
![](https://i.imgur.com/BRfdcyQ.png)
``````
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 01/26/2022 03:22:12 AM
// Design Name: 
// Module Name: dC3da
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
// Macros for Matrix
`include "pack_unpack.v"

module back_addrightmulti_dC3da#(parameter BIT_LGTH = 16, COLM = 1, ROWS = 4, DISC_FCT = 8)
(
    input signed [(ROWS)*(BIT_LGTH)-1:0] maxQ,
    input signed [(BIT_LGTH)-1:0] dCdatemp,            // Input Layer
    input [1:0] action,
    input clk,
    
    output signed [(BIT_LGTH)-1:0] dCda                // Weight dot product Input
);

wire [(BIT_LGTH-1):0] maxQ_in [(ROWS-1):0];
`UNPACK_ARRAY((BIT_LGTH),(ROWS),maxQ_in,maxQ)

 reg [(BIT_LGTH-1):0] result;
 generate                                              // Calculating 
    genvar i;
    for (i = 0; i < (ROWS); i = i + 1)
     begin     : rows              
     always@(posedge clk)
         begin
            if (i == action)  result <= dCdatemp + (maxQ_in[i] >>> DISC_FCT);
         end
         assign dCda = result;
    end
 endgenerate

endmodule
``````
testbench
``````
module back_addrightmulti_dC3da_sim();

reg [4*16-1:0] maxQ_in;
reg [16-1:0] dc_in;
reg [1:0] act_in;
reg [3:0] gamma_in;
reg clk = 1'b0;

wire [16-1:0] out;

back_addrightmulti_dC3da BAD (.maxQ(maxQ_in),
                    .dCdatemp(dc_in),
                    .action(act_in),
                    .clk(clk),
                    .dCda(out));
                            
initial 
    begin
        maxQ_in = {{16'h0F00} , {16'h0FF0}, {16'h0F0F} , {16'h00FF}} ;
        gamma_in = 4'b1000;
        act_in = 2'b10;
        dc_in = 16'hFF00;
    end
    
 always
    begin
        clk = ~clk;
        #1;
    end
endmodule
``````

## Simulasi 
### Simulasi Blok Transpose Matrix Weight
Model program serupa telah dibuat pada bahasa C dan telah jalan dengan baik.

dari ![](https://i.imgur.com/KMPePu9.png) sampai dengan![](https://i.imgur.com/qZMiTIU.png)
Namun hasil pada Verilog belum benar karena unpacking dan packing binary masih memiliki kesalahan pada akses array.
![](https://i.imgur.com/YlkPEwg.png)
*Matriks 5x9 (bawah) ditranspose menjadi 9x5 (atas)*

Setelah debugging yang cukup panjang didapatkan hasil yang sesuai. Input sepanjang 1440 bit diolah kedalam bentuk matriks 9x5, kemudian ditransposes menjadi 5x9, dan di keluarkan sebagai output 1440 bit dengan bentuk matriks yang baru.
![](https://i.imgur.com/yiRML4I.png)
*Matriks 9x5 (bawah) ditranspose menjadi 5x9 (atas)*

### Simulasi Blok Dot Product Matrix Weight dengan Matrix Input Layer
Triger masih dilakukan melalui clock karena apabila auto sensitivity list, hasil tepat namun tidak muncul bentuk sinyal.
![](https://i.imgur.com/uBOJ6Ts.png)
*Matriks Weight (.) Input Layer, hasil pada sinyal paling atas*

### Simulasi Blok Penjumlahan Matrix dari Input Layer ke Hidden Layer
![](https://i.imgur.com/tBvdmt8.png)
*Matriks W (.) I + IL, hasil pada sinyal paling bawah*

### Simulasi Blok Activation Function
![](https://i.imgur.com/EPsVqNB.png)
*sinyal IH_in_temp merupakan input yang telah dijumlahkan dengan bias, sedangkan IH_sigmoid_out hasil activation function nya*

### Simulasi Blok Maximum Value
![](https://i.imgur.com/LGCjwsO.png)
*Empat sinyal masukan dapat dipilih dengan baik mana nilai maksimum nya*

### Simulasi Blok Derivatif C terhadap Action 3
![](https://i.imgur.com/GdJYCgb.png)
*Sinyal keluaran merupakan aproksimasi yang baik dari operasi yang dilakukan*
Sinyal akhir : 
![](https://i.imgur.com/dMhBbBs.png)



## FAQ
#### Q : Simulasi Jalan, hasil keluar tapi waveform tidak muncul
#### A : Restart Simulator / Re-open Project

#### Q : Multiplication salah, kenapa ?
#### A : COBA KASIH SIGNED !

#### Q : Multiplication salah, kenapa ?
#### A : Jangan lupa ( ) karena bisa jadi dia <<< dulu baru +