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

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:

Bentuk grafiknya:

- 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

Dari hidden layer ke output

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 =

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 :

Contoh element wise multip matriks: (dipake untuk derivative di back propagation)

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

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

Arsitektur yang digunakan adalah sebagai berikut.

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

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

``````
`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  sampai dengan
Namun hasil pada Verilog belum benar karena unpacking dan packing binary masih memiliki kesalahan pada akses array.

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

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

*Matriks Weight (.) Input Layer, hasil pada sinyal paling atas*
### Simulasi Blok Penjumlahan Matrix dari Input Layer ke Hidden Layer

*Matriks W (.) I + IL, hasil pada sinyal paling bawah*
### Simulasi Blok Activation Function

*sinyal IH_in_temp merupakan input yang telah dijumlahkan dengan bias, sedangkan IH_sigmoid_out hasil activation function nya*
### Simulasi Blok Maximum Value

*Empat sinyal masukan dapat dipilih dengan baik mana nilai maksimum nya*
### Simulasi Blok Derivatif C terhadap Action 3

*Sinyal keluaran merupakan aproksimasi yang baik dari operasi yang dilakukan*
Sinyal akhir :

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