FPA_module_test.sv 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. module floating_add #(parameter N=16, M=4)(input_1, input_2, sum, diff, clk, reset);
  2. input logic [N-1:0] input_1, input_2;
  3. input logic clk, reset;
  4. output logic [N-1:0] sum;
  5. output logic [M:0] diff;
  6. logic flag_a;
  7. logic flag_b;
  8. logic [M:0] abs;
  9. logic [N-3-M:0] res;
  10. logic [N-1:0] D0 [7:0];
  11. logic [N-1:0] Q0 [7:0];
  12. logic [N-1:0] Q1 [7:0];
  13. logic [N-1:0] Q2 [7:0];
  14. // sign_x = x[N-1]
  15. // exponent_x = x[N-2:N-2-M]
  16. // mantissa_x = x[N-3-M:0]
  17. //First pipeline stage
  18. always_comb
  19. begin
  20. D0[0] = input_1;
  21. D0[1] = input_2;
  22. D0[2] = 0; // sum
  23. D0[3] = 0; // diff
  24. D0[4] = 0; // flag_a
  25. D0[5] = 0; // flag_b
  26. D0[6] = 0; // abs
  27. D0[7] = 0; // res
  28. end
  29. pipe#(.N(N-1), .K(7)) pipe0(.clk(clk), .reset(reset), .D(D0), .Q(Q0));
  30. always_comb
  31. begin
  32. if (Q0[0][N-2:N-2-M] > Q0[1][N-2:N-2-M]) // If input 1 has the bigger exponent
  33. begin
  34. // Flags input a as larger and calculates the absolute difference
  35. Q0[4] = 1;
  36. Q0[5] = 0;
  37. Q0[6] = Q0[0][N-2:N-2-M] - Q0[1][N-2:N-2-M];
  38. // ASsigning overall sign of the output
  39. Q0[2][N-1] = Q0[0][N-1];
  40. // Sets output to have the same exponent
  41. Q0[2][N-2:N-2-M] = Q0[0][N-2:N-2-M];
  42. end
  43. else if (Q0[1][N-2:N-2-M] > Q0[0][N-2:N-2-M]) // If input 2 has the bigger exponent
  44. begin
  45. // Similarly flags input b as larger and calculates the absolute difference
  46. Q0[4] = 0;
  47. Q0[5] = 1;
  48. Q0[6] = Q0[1][N-2:N-2-M] - Q0[0][N-2:N-2-M];
  49. // ASsigning overall sign of the output
  50. Q0[2][N-1] = Q0[1][N-1];
  51. // Sets ouput to have the same exponent
  52. Q0[2][N-2:N-2-M] = Q0[1][N-2:N-2-M];
  53. end
  54. else
  55. begin
  56. // THe condition that both inputs have the same exponent
  57. Q0[4] = 1;
  58. Q0[5] = 1;
  59. Q0[6] = 0;
  60. // ASsigning overall sign of the output based on size of the mantissa
  61. if (Q0[0][N-3-M:0] >= Q0[1][N-3-M:0]) Q0[2][N-1] = Q0[0][N-1];
  62. else Q0[2][N-1] = Q0[1][N-1];
  63. Q0[2][N-2:N-2-M] = Q0[0][N-2:N-2-M];
  64. end
  65. Q0[3] = Q0[6];
  66. end
  67. //Second pipeline stage 1
  68. pipe#(.N(N-1), .K(7)) pipe1(.clk(clk), .reset(reset), .D(Q0), .Q(Q1));
  69. always_comb
  70. begin
  71. // Condition for overflow is that it sets the output to the larger input
  72. if (Q1[6] > N-2-M) // Because size of mantissa is 10 bits and shifting by 10 would give 0
  73. begin
  74. if (Q1[4] & ~Q1[5]) Q1[2] = Q1[0]; // input 1 is larger and is translated to output
  75. else if (~Q1[4] & Q1[5]) Q1[2] = Q1[1]; // input 2 is larger and is translated to output
  76. else // exponents are the same
  77. begin
  78. if (Q1[6][N-3-M:0] >= Q1[1][N-3-M:0]) Q1[2] = Q1[0];// input 1 has the bigger mantissa
  79. else Q1[2] = Q1[1]; // input 2 has the bigger mantissa
  80. end
  81. end
  82. else
  83. begin
  84. // Shifts the smaller input's mantissa to the right based on abs
  85. if (Q1[4] & ~Q1[5])// If input 1 has the larger exponent
  86. begin
  87. // If the signs of both inputs are the same you add, otherwise you subtract
  88. if (Q1[0][N-1] == Q1[1][N-1])
  89. begin
  90. Q1[7] = Q1[0][N-3-M:0] + (Q1[1][N-3-M:0] >> Q1[6]-1); // Sum the mantissa
  91. Q1[2][N-3-M:0] = Q1[7];
  92. end
  93. else
  94. begin
  95. Q1[7] = Q1[0][N-3-M:0] - (Q1[1][N-3-M:0] >> Q1[6]-1); // Subtract the mantissas
  96. sum[N-3-M:0] = res;
  97. end
  98. end
  99. else if (~Q1[4] & Q1[5])
  100. begin
  101. // If the signs of both inputs are the same you add, otherwise you subtract
  102. if (Q1[0][N-1] == Q1[1][N-1])
  103. begin
  104. Q1[7] = (Q1[0][N-3-M:0] >> Q1[6]-1) + Q1[1][N-3-M:0]; // Sum the mantissa
  105. Q1[2][N-3-M:0] = Q1[7];
  106. end
  107. else
  108. begin
  109. Q1[7] = Q1[1][N-3-M:0] - (Q1[0][N-3-M:0] >> Q1[6]-1); // Subtract the mantissas
  110. Q1[2][N-3-M:0] = Q1[7];
  111. end
  112. end
  113. else
  114. begin
  115. if (Q1[0][N-1] == Q1[1][N-1]) // If exponents and signs equal
  116. begin
  117. Q1[7] = Q1[0][N-3-M:0] + Q1[1][N-3-M:0]; // Sum the mantissa
  118. Q1[2][N-3-M:0] = Q1[7];
  119. end
  120. else // In this case it will be a subtraction
  121. begin
  122. if (Q1[0][N-3-M:0] > Q1[1][N-3-M:0]) // Which has the larger mantissa
  123. begin
  124. Q1[7] = Q1[0][N-3-M:0] - Q1[1][N-3-M:0]; // Subtract the mantissa
  125. Q1[2][N-3-M:0] = Q1[7];
  126. end
  127. else if (Q1[0][N-3-M:0] < Q1[1][N-3-M:0])
  128. begin
  129. Q1[7] = Q1[1][N-3-M:0] - Q1[0][N-3-M:0]; // Subtract the mantissa
  130. Q1[2][N-3-M:0] = Q1[7];
  131. end
  132. else Q1[7] = 0; // Both the exponent and the mantissa are equal so subtraction leads to 0
  133. Q1[2][N-3-M:0] = Q1[7];
  134. end
  135. end
  136. end
  137. end
  138. // Final pipeline stage
  139. pipe#(.N(N-1), .K(7)) pipe2(.clk(clk), .reset(reset), .D(Q1), .Q(Q2));
  140. assign sum = Q2[2];
  141. assign diff = Q2[3];
  142. endmodule : floating_add
  143. module floating_product #(parameter N=16, M=4)(input_1, input_2, product, clk, reset);
  144. input logic [N-1:0] input_1, input_2;
  145. input logic clk, reset;
  146. output logic [N-1:0] product;
  147. logic [2*N-1:0] D0 [7:0];
  148. logic [2*N-1:0] Q0 [7:0];
  149. logic [2*N-1:0] Q1 [7:0];
  150. logic [2*N-1:0] Q2 [7:0];
  151. always_comb
  152. begin
  153. D0[0][N-1:0] = input_1;
  154. D0[1][N-1:0] = input_2;
  155. D0[2] = 0; // product (output)
  156. D0[3] = 0; // multiple for multiplying the mantissa
  157. D0[4] = 0; // flag for return NaN
  158. D0[5] = 0; // flag for return infinity
  159. D0[6] = 0; // flag for return zero
  160. D0[7][N-3-M:0] = input_1[N-3-M:0]; // for storing the mantissa of input 1
  161. end
  162. // sign_x = x[N-1]
  163. // exponent_x = x[N-2:N-2-M]
  164. // mantissa_x = x[N-3-M:0]
  165. pipe #(.N(2*N-1), .K(7)) pipe0(.clk(clk), .reset(reset), .D(D0), .Q(Q0));
  166. always_comb
  167. begin
  168. // if input_1 or input_2 is NaN then return NaN
  169. if ((Q0[0][N-2:N-2-M] == (1<<M) && Q0[0][N-3-M:0] != 0) || (Q1[0][N-2:N-2-M] == (1<<M) && Q1[0][N-3-M:0] != 0))
  170. begin
  171. Q0[2][N-1] = 1;
  172. Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
  173. Q0[2][N-3-M] = 1;
  174. Q0[2][N-4-M:0] = 0;
  175. Q0[4][0] = 1;
  176. end
  177. // if input 1 is infinity then return infinity
  178. else if (Q0[0][N-2:N-2-M] == (1<<M))
  179. begin
  180. Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
  181. Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
  182. Q0[2][N-3-M:0] = 0;
  183. Q0[5] = 1;
  184. // if input 2 is zero then return NaN
  185. if (($signed(Q0[1][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[1][N-3-M:0] == 0))
  186. begin
  187. Q0[2][N-1] = 1;
  188. Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
  189. Q0[2][N-3-M] = 1;
  190. Q0[2][N-4-M:0] = 0;
  191. Q0[4][0] = 1;
  192. end
  193. end
  194. // if input 2 is infinity then return infinity
  195. else if (Q0[1][N-2:N-2-M] == (1<<M))
  196. begin
  197. Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
  198. Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
  199. Q0[2][N-3-M:0] = 0;
  200. Q0[5][0] = 1;
  201. // if input 1 is zero then return NaN
  202. if (($signed(Q0[0][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[0][N-3-M:0] == 0))
  203. begin
  204. Q0[2][N-1] = 1;
  205. Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
  206. Q0[2][N-3-M] = 1;
  207. Q0[2][N-4-M:0] = 0;
  208. Q0[4][0] = 1;
  209. end
  210. end
  211. // if input 1 is zero then return zero
  212. else if (($signed(Q0[0][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[0][N-3-M:0] == 0))
  213. begin
  214. Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
  215. Q0[2][N-2:N-2-M] = 0;
  216. Q0[2][N-3-M:0] = 0;
  217. Q0[6][0] = 1;
  218. end
  219. // if input 2 is zero then return zero
  220. else if (($signed(Q0[1][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[1][N-3-M:0] == 0))
  221. begin
  222. Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
  223. Q0[2][N-2:N-2-M] = 0;
  224. Q0[2][N-3-M:0] = 0;
  225. Q0[6][0] = 1;
  226. end
  227. end
  228. pipe #(.N(2*N-1), .K(7)) pipe1(.clk(clk), .reset(reset), .D(Q0), .Q(Q1));
  229. always_comb
  230. begin
  231. // If none of the return flags have been triggered
  232. if ((Q1[4][0] && Q1[5][0] && Q1[6][0]) != 1)
  233. begin
  234. // if msb of input 1 mantissa is not 1 then shift left by 1 and reduce exponent by 1
  235. if (Q1[0][N-3-M] != 1)
  236. begin
  237. Q1[0][N-3-M:0] = Q1[0][N-3-M:0] << 1;
  238. Q1[0][N-2:N-2-M] = Q1[0][N-2:N-2-M] - 1;
  239. end
  240. // if msb of input 2 mantissa is not 1 then shift left by 1 and reduce exponent by 1
  241. if (Q1[1][N-3-M] != 1)
  242. begin
  243. Q1[1][N-3-M:0] = Q1[1][N-3-M:0] << 1;
  244. Q1[1][N-2:N-2-M] = Q1[1][N-2:N-2-M] - 1;
  245. end
  246. Q1[2][N-1] = Q1[2][N-1] ^ Q1[2][N-1]; // ouput sign = input_1 sign xor input_2 sign
  247. Q1[2][N-2:N-2-M] = Q1[0][N-2:N-2-M] + Q1[1][N-2:N-2-M] - (1<<M); // out exp = in1 exp + in2 exp - 2**M
  248. // multiplying mantissa
  249. for (int i = 0; i<N-2-M; i++)
  250. begin
  251. // multiplying each digit of input 2 by all of input 1 shifting the bits left each time and adding result to the array
  252. if (Q1[1][i] == 1)
  253. begin
  254. Q1[3] = Q1[3] +(Q1[7]<<i);
  255. end
  256. else
  257. begin
  258. Q1[3] = Q1[3] + 0;
  259. end
  260. end
  261. // Assigning the top set of bits to the mantissa of the output
  262. Q1[2][N-3-M:0] = Q1[3][2*N-1:2*N-1-N-3-M];
  263. end
  264. end
  265. pipe #(.N(2*N-1), .K(7)) pipe2(.clk(clk), .reset(reset), .D(Q1), .Q(Q2));
  266. assign product = Q2[2][N-1:0];
  267. endmodule : floating_product
  268. module pipe #(parameter N, K)(clk, reset, Q, D);
  269. input logic clk, reset;
  270. input logic [N:0] D [K:0];
  271. output reg [N:0] Q [K:0];
  272. reg [N:0] in_pipe [K:0];
  273. always_ff @(posedge clk or negedge reset)
  274. begin
  275. if(reset)
  276. begin
  277. in_pipe <= '{default:0};
  278. Q <= '{default:0};
  279. end
  280. else
  281. begin
  282. in_pipe <= D;
  283. Q <= in_pipe;
  284. end
  285. end
  286. endmodule : pipe
  287. module floating_tb;
  288. reg reset, clk;
  289. logic [15:0] input_a, input_b, result_add, result_mult;
  290. logic [4:0] diff;
  291. logic [15:0] expected_add, expected_mult;
  292. floating_add adder1(.input_1(input_a), .input_2(input_b), .sum(result_add), .diff(diff), .clk(clk), .reset(reset));
  293. floating_product multiplier1(.input_1(input_a), .input_2(input_b), .product(result_mult), .clk(clk), .reset(reset));
  294. initial forever #5 clk = ~clk;
  295. localparam PIPELINES = 3;
  296. reg [15:0] test_mem [29:0][3:0];
  297. initial $readmemh("scripts/fp16_test.hex", test_mem);
  298. initial begin
  299. static int num_err = 0;
  300. static int num_tests = $size(test_mem) * 2;
  301. clk = 0;
  302. reset = 1;
  303. #15;
  304. reset = 0;
  305. expected_add = 0;
  306. expected_mult = 0;
  307. for (int i=0; i < $size(test_mem)+PIPELINES; i++) begin
  308. if(i >= PIPELINES) begin
  309. expected_add = test_mem[i-PIPELINES][2];
  310. expected_mult = test_mem[i-PIPELINES][3];
  311. end
  312. input_a = test_mem[i][0];
  313. input_b = test_mem[i][1];
  314. #10;
  315. if(result_add != test_mem[i][2]) begin
  316. if(num_err < 20)
  317. $display("FAIL ADD: %H + %H = %H, expected %H", input_a, input_b, result_add, test_mem[i][2]);
  318. num_err = num_err + 1;
  319. end
  320. if(result_mult != test_mem[i][3]) begin
  321. if(num_err < 20)
  322. $display("FAIL MULTIPLY: %H + %H = %H, expected %H", input_a, input_b, result_mult, test_mem[i][3]);
  323. num_err = num_err + 1;
  324. end
  325. end
  326. expected_add = 0;
  327. expected_mult = 0;
  328. #50;
  329. $display("Passed %d of %d tests", num_tests-num_err, num_tests);
  330. $finish();
  331. end
  332. endmodule : floating_tb
  333. module floating32_tb;
  334. reg reset, clk;
  335. logic [31:0] input_a, input_b, result_add, result_mult;
  336. floating_add#(.N(32), .M(8)) add0(
  337. .input_1(input_a), .input_2(input_b), .sum(result_add), .diff()
  338. );
  339. floating_product#(.N(32), .M(8)) mult0(
  340. .input_1(input_a), .input_2(input_b), .product(result_mult)
  341. );
  342. reg [31:0] test_mem [29:0][3:0];
  343. initial $readmemh("scripts/fp32_test.hex", test_mem);
  344. initial begin
  345. static int num_err = 0;
  346. static int num_tests = $size(test_mem) * 2;
  347. for (int i=0; i < $size(test_mem); i++) begin
  348. input_a = test_mem[i][0];
  349. input_b = test_mem[i][1];
  350. #10;
  351. if(result_add != test_mem[i][2]) begin
  352. if(num_err < 20)
  353. $display("FAIL ADD: %H + %H = %H, expected %H", input_a, input_b, result_add, test_mem[i][2]);
  354. num_err = num_err + 1;
  355. end
  356. if(result_mult != test_mem[i][3]) begin
  357. if(num_err < 20)
  358. $display("FAIL MULTIPLY: %H + %H = %H, expected %H", input_a, input_b, result_mult, test_mem[i][3]);
  359. num_err = num_err + 1;
  360. end
  361. end
  362. $display("Passed %d of %d tests", num_tests-num_err, num_tests);
  363. $finish();
  364. end
  365. endmodule : floating32_tb