1 |
3 |
ojosynariz |
/*
|
2 |
|
|
* ann.h
|
3 |
|
|
*
|
4 |
|
|
* Description: This header file helps programmers to access correctly to ANN IP core weight and bias memories.
|
5 |
|
|
* User must edit ANN_BASEADDRESS, NLAYER, and definitions of layer inputs and neurons.
|
6 |
|
|
* MAX_MUL macro can be calculated manually, or relay on automated calculation if NLAYER<=4.
|
7 |
|
|
* A Wyb(x) macro must be declared on the code per layer of the ANN IP core.
|
8 |
|
|
* Those macro declare the 2D weight arrays and 1D bias arrays needed to access ANN IP core memories.
|
9 |
|
|
*
|
10 |
|
|
* Created on: 17/05/2016
|
11 |
|
|
* Author: David A
|
12 |
|
|
*/
|
13 |
|
|
|
14 |
|
|
#ifndef ANN_H
|
15 |
|
|
#define ANN_H
|
16 |
|
|
|
17 |
|
|
/* Base address of weight and bias memories of the ANN IP core */
|
18 |
|
|
// Example for Xilinx's SDK using the example wrapper for Vivado. Correct user base address must be defined here:
|
19 |
|
|
#define ANN_BASEADDRESS XPAR_ANN_0_WYB_S_AXI_BASEADDR
|
20 |
|
|
|
21 |
|
|
/* Number of layers */
|
22 |
|
|
#define NLAYER 4
|
23 |
|
|
|
24 |
|
|
/* Number of inputs and neurons of each layer */
|
25 |
|
|
// Add or remove as many layers as needed:
|
26 |
|
|
#define NumIn0 16
|
27 |
|
|
#define NumN0 13
|
28 |
|
|
#define NumIn1 NumN0
|
29 |
|
|
#define NumN1 6
|
30 |
|
|
#define NumIn2 NumN1
|
31 |
|
|
#define NumN2 13
|
32 |
|
|
#define NumIn3 NumN2
|
33 |
|
|
#define NumN3 16
|
34 |
|
|
|
35 |
|
|
/* (optional) Redefine number of neurons in the last layer as number of outputs */
|
36 |
|
|
#define NumOut NumN3
|
37 |
|
|
|
38 |
|
|
/* Next-power-of-two of inputs and neurons of each layer */
|
39 |
|
|
// Define a next-power-of-two macro per parameter in the number of inputs and neurons of each layer list:
|
40 |
|
|
// NOTE: next_2power(x) macro function calculates the next-power-of-two of x for x<=256. If x>256 it still returns 256.
|
41 |
|
|
#define NumN0_b2 next_2power(NumN0)
|
42 |
|
|
#define NumIn0_b2 next_2power(NumIn0)
|
43 |
|
|
#define NumN1_b2 next_2power(NumN1)
|
44 |
|
|
#define NumIn1_b2 next_2power(NumIn1)
|
45 |
|
|
#define NumN2_b2 next_2power(NumN2)
|
46 |
|
|
#define NumIn2_b2 next_2power(NumIn2)
|
47 |
|
|
#define NumN3_b2 next_2power(NumN3)
|
48 |
|
|
#define NumIn3_b2 next_2power(NumIn3)
|
49 |
|
|
|
50 |
|
|
/* Maximum multiplication of the next-power-of-two of inputs by the next-power-of-two of neurons */
|
51 |
|
|
// MAX_MUL macro can be defined manually, or automatically if NLAYER<=4.
|
52 |
|
|
// To define it manually user must determine which layer has the maximum of these products, and edit MAX_MUL definition:
|
53 |
|
|
// In the example is layer 0 (or layer 3 with same MAX_MUL), 256 > 128
|
54 |
|
|
// NumIn0 = 16 ==> NumIn0_b2 = 16
|
55 |
|
|
// NumN0 = 13 ==> NumN0_b2 = 16
|
56 |
|
|
// NumN0_b2*NumIn0_b2=16*16=256
|
57 |
|
|
// NumIn1 = 13 ==> NumIn1_b2 = 16
|
58 |
|
|
// NumN1 = 6 ==> NumN1_b2 = 8
|
59 |
|
|
// NumN1_b2*NumIn1_b2=16*8=128
|
60 |
|
|
// NumIn2 = 6 ==> NumIn2_b2 = 8
|
61 |
|
|
// NumN2 = 13 ==> NumN2_b2 = 16
|
62 |
|
|
// NumN2_b2*NumIn2_b2=8*16=128
|
63 |
|
|
// NumIn3 = 13 ==> NumIn3_b2 = 16
|
64 |
|
|
// NumN3 = 16 ==> NumN3_b2 = 16
|
65 |
|
|
// NumN3_b2*NumIn3_b2=16*16=256
|
66 |
|
|
|
67 |
|
|
//#define MAX_MUL (NumN0_b2*NumIn0_b2) //Uncomment and edit this manual definition of MAX_MUL for manual definition of MAX_MUL
|
68 |
|
|
|
69 |
|
|
// Automated calculation of MAX_MUL for NLAYER<=4:
|
70 |
|
|
#ifndef MAX_MUL
|
71 |
|
|
#if NLAYER > 4
|
72 |
|
|
#error MAX_MUL cannot be automatically calculated if NLAYER>4. Define MAX_MUL manually or complete the automaed calculation of MAX_MUL preprocessor code.
|
73 |
|
|
#endif
|
74 |
|
|
#define max2(x,y) ( ((x) < (y)) ? y : x )
|
75 |
|
|
#define MAX_0 (NumN0_b2*NumIn0_b2)
|
76 |
|
|
#if NLAYER > 1
|
77 |
|
|
#define MAX_1 max2((NumN1_b2*NumIn1_b2),MAX_0)
|
78 |
|
|
#if NLAYER > 2
|
79 |
|
|
#define MAX_2 max2((NumN2_b2*NumIn2_b2),MAX_1)
|
80 |
|
|
#if NLAYER == 4
|
81 |
|
|
#define MAX_MUL max2((NumN3_b2*NumIn3_b2),MAX_2)
|
82 |
|
|
#elif NLAYER == 3
|
83 |
|
|
#define MAX_MUL MAX_2
|
84 |
|
|
#endif //NLAYER == 4
|
85 |
|
|
#elif NLAYER == 2
|
86 |
|
|
#define MAX_MUL MAX_1
|
87 |
|
|
#endif //NLAYER > 2
|
88 |
|
|
#else //NLAYER == 1
|
89 |
|
|
#define MAX_MUL MAX_0
|
90 |
|
|
#endif //NLAYER > 1
|
91 |
|
|
#endif
|
92 |
|
|
|
93 |
|
|
/* Definition of the macro function next_2power(x) */
|
94 |
|
|
// It calculates the next-power-of-two of x for x<=256. If x>256 it still returns 256.
|
95 |
|
|
#define next_2power(x) ( ((x) > 128) ? 256 : ((x) > 64) ? 128 : ((x) > 32) ? 64 : ((x) > 16) ? 32 : ((x) > 8) ? 16 : ((x) > 4) ? 8 : ((x) > 2) ? 4 : ((x) > 1) ? 2 : 1 )
|
96 |
|
|
|
97 |
|
|
/* When this macro is expanded for a particular layer x, it declares pointers to the weight 2D array, bias 1D array, and unused spaces; and initializes them with a proper address */
|
98 |
|
|
// Declare a Wvb(x) macro per layer on the user's ANN, each time with a different layer number x, from 0 to NLAYER-1.
|
99 |
|
|
// Example: For a two layer ANN (NLAYER 2)
|
100 |
|
|
// Wvb(0) // declares and initializes int (*W0)[NumN0][NumIn0_b2], (*b0)[NumN0];
|
101 |
|
|
// Wyb(1) // declares and initializes int (*W1)[NumN1][NumIn1_b2], (*b1)[NumN1];
|
102 |
|
|
// The unused spaces (*NOT_EXISTx0) and (*NOT_EXISTx1) are declared in order to prevent the use of these space address for other proposes. Although it does not assure it will not be used.
|
103 |
|
|
#define Wyb(x) volatile int (*W##x)[NumN##x][NumIn##x##_b2] = (void *) ANN_BASEADDRESS + MAX_MUL*2*x*sizeof(int), \
|
104 |
|
|
(*NOT_EXIST##x##0)[MAX_MUL-NumN##x*NumIn##x##_b2] = (void *) ANN_BASEADDRESS + (NumN##x*NumIn##x##_b2 + MAX_MUL*2*x)*sizeof(int), \
|
105 |
|
|
(*b##x)[NumN##x] = (void *) ANN_BASEADDRESS + MAX_MUL*(2*x+1)*sizeof(int), \
|
106 |
|
|
(*NOT_EXIST##x##1)[MAX_MUL-NumN##x] = (void *) ANN_BASEADDRESS + (NumN##x + MAX_MUL*(2*x+1))*sizeof(int);
|
107 |
|
|
|
108 |
|
|
#endif // ANN_H
|