3signal.v 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /*
  2. * 3signal.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Copyright (C) 2025 Krzysztof Skrzynecki, Jakub Duchniewicz <j.duchniewicz@gmail.com>
  7. * SPDX-License-Identifier: TODO:
  8. */
  9. `default_nettype none
  10. module compare_eq#(
  11. parameter WIDTH = 16
  12. )(
  13. input wire clk,
  14. input wire [WIDTH-1:0] A,
  15. input wire [WIDTH-1:0] B,
  16. output reg [0:0] was_eq //1 if A and B were equal 2 ticks ago
  17. );
  18. parameter WIDTH_DIV4 = (WIDTH+3)/4;
  19. parameter WIDTH_REM = WIDTH - WIDTH_DIV4*3;
  20. wire [WIDTH_DIV4-1:0] A0_pt0, A0_pt1, A0_pt2;
  21. wire [WIDTH_REM-1:0] A0_pt3;
  22. wire [WIDTH_DIV4-1:0] B0_pt0, B0_pt1, B0_pt2;
  23. wire [WIDTH_REM-1:0] B0_pt3;
  24. assign {A0_pt3, A0_pt2, A0_pt1, A0_pt0} = A;
  25. assign {B0_pt3, B0_pt2, B0_pt1, B0_pt0} = B;
  26. reg pt0_eq, pt1_eq, pt2_eq, pt3_eq;
  27. always @(posedge clk) begin
  28. pt0_eq <= A0_pt0==B0_pt0;
  29. pt1_eq <= A0_pt1==B0_pt1;
  30. pt2_eq <= A0_pt2==B0_pt2;
  31. pt3_eq <= A0_pt3==B0_pt3;
  32. was_eq <= pt0_eq & pt1_eq & pt2_eq & pt3_eq;
  33. end
  34. endmodule
  35. module add#(
  36. parameter WIDTH = 16
  37. )(
  38. input wire clk,
  39. input wire [WIDTH-1:0] A,
  40. input wire [WIDTH-1:0] B,
  41. output reg [WIDTH-1:0] sum
  42. );
  43. parameter WIDTH_DIV2 = (WIDTH+1)/2;
  44. parameter WIDTH_REM = WIDTH - WIDTH_DIV2;
  45. wire [WIDTH_DIV2-1:0] A0_pt0;
  46. wire [WIDTH_REM-1:0] A0_pt1;
  47. wire [WIDTH_DIV2-1:0] B0_pt0;
  48. wire [WIDTH_REM-1:0] B0_pt1;
  49. assign {A0_pt1, A0_pt0} = A;
  50. assign {B0_pt1, B0_pt0} = B;
  51. reg [WIDTH_DIV2:0] C0_pt0;
  52. reg [WIDTH_REM-1:0] C0_pt1;
  53. always @(posedge clk) begin
  54. C0_pt0 <= {1'b0, A0_pt0} + {1'b0, B0_pt0};
  55. C0_pt1 <= A0_pt1 + B0_pt1;
  56. sum <= {C0_pt1+{6'b0, C0_pt0[WIDTH_DIV2]}, C0_pt0[WIDTH_DIV2-1:0]};
  57. end
  58. endmodule
  59. module compare_gt#(
  60. parameter WIDTH = 16
  61. )(
  62. input wire clk,
  63. input wire [WIDTH-1:0] A,
  64. input wire [WIDTH-1:0] B,
  65. output reg [0:0] was_gt //1 if A was greater than B 3 ticks ago
  66. );
  67. parameter WIDTH_DIV4 = (WIDTH+3)/4;
  68. parameter WIDTH_REM = WIDTH - WIDTH_DIV4*3;
  69. wire [WIDTH_DIV4-1:0] A0_pt0, A0_pt1, A0_pt2;
  70. wire [WIDTH_REM-1:0] A0_pt3;
  71. wire [WIDTH_DIV4-1:0] B0_pt0, B0_pt1, B0_pt2;
  72. wire [WIDTH_REM-1:0] B0_pt3;
  73. assign {A0_pt3, A0_pt2, A0_pt1, A0_pt0} = Ab;
  74. assign {B0_pt3, B0_pt2, B0_pt1, B0_pt0} = Bb;
  75. reg pt0_gt, pt1_gt, pt2_gt, pt3_gt;
  76. reg pt0_eq, pt1_eq, pt2_eq, pt3_eq;
  77. reg pt01_eq, pt23_eq;
  78. reg pt01_gt, pt23_gt;
  79. reg [WIDTH-1:0] Ab, Bb; // buffer regs for shorter wires
  80. always @(posedge clk) begin
  81. Ab <= A;
  82. Bb <= B;
  83. pt0_gt <= A0_pt0>B0_pt0;
  84. pt1_gt <= A0_pt1>B0_pt1;
  85. pt2_gt <= A0_pt2>B0_pt2;
  86. pt3_gt <= A0_pt3>B0_pt3;
  87. pt0_eq <= A0_pt0==B0_pt0;
  88. pt1_eq <= A0_pt1==B0_pt1;
  89. pt2_eq <= A0_pt2==B0_pt2;
  90. pt3_eq <= A0_pt3==B0_pt3;
  91. pt01_eq <= pt0_eq & pt1_eq;
  92. pt01_gt <= pt1_gt | (pt1_eq & pt0_gt);
  93. pt23_eq <= pt2_eq & pt3_eq;
  94. pt23_gt <= pt3_gt | (pt3_eq & pt2_gt);
  95. was_gt <= pt23_gt | (pt23_eq & pt01_gt);
  96. end
  97. endmodule
  98. module cycle_trigger#(
  99. parameter WIDTH = 16
  100. ) (
  101. input wire /*nrst,*/ clk,
  102. input wire [WIDTH-1:0] period,
  103. output reg [0:0] start_cycle,
  104. output reg [0:0] half_cycle,
  105. output reg [2:0] trig_out
  106. );
  107. reg [WIDTH-1:0] counter;
  108. reg [WIDTH-1:0] counter_delayed;// just to make placement easier - less branches from counter
  109. reg [WIDTH-1:0] period_div2;
  110. reg [WIDTH-1:0] period_shadow;
  111. wire zero;
  112. always @(posedge clk /*or negedge nrst*/) begin
  113. /*if (!nrst) begin
  114. counter <= 0;
  115. //period_div2 <= 16'h0;
  116. high_match_a <= 0;
  117. high_match_b <= 0;
  118. half_match_a <= 0;
  119. half_match_b <= 0;
  120. start_cycle <= 0;
  121. half_cycle <= 0;
  122. trig_out <= 0;
  123. end else begin*/
  124. if(zero) begin
  125. start_cycle <= 1;
  126. period_div2 <= period>>1;
  127. period_shadow <= period;
  128. end else begin
  129. start_cycle <= 0;
  130. end
  131. if (start_cycle) begin
  132. counter <= period_shadow;
  133. end else begin
  134. counter <= counter-1;
  135. end
  136. counter_delayed <= counter;
  137. //end //nrst
  138. end
  139. compare_eq#(.WIDTH(WIDTH))cmp_zero(
  140. .clk(clk),
  141. .A(counter_delayed),
  142. .B(0),
  143. .was_eq(zero)
  144. );
  145. compare_eq#(.WIDTH(WIDTH))cmp_half(
  146. .clk(clk),
  147. .A(counter_delayed),
  148. .B(period_div2),
  149. .was_eq(half_cycle)
  150. );
  151. compare_eq#(.WIDTH(WIDTH))cmp0(
  152. .clk(clk),
  153. .A(counter_delayed),
  154. .B(3),
  155. .was_eq(trig_out[0])
  156. );
  157. compare_eq#(.WIDTH(WIDTH))cmp1(
  158. .clk(clk),
  159. .A(counter_delayed),
  160. .B(3),
  161. .was_eq(trig_out[1])
  162. );
  163. compare_eq#(.WIDTH(WIDTH))cmp2(
  164. .clk(clk),
  165. .A(counter_delayed),
  166. .B(9),
  167. .was_eq(trig_out[2])
  168. );
  169. endmodule
  170. /*module continous_pwm_gen#(
  171. parameter WIDTH = 16
  172. ) (
  173. input wire nrst, clk,
  174. input wire [WIDTH-1:0] period,
  175. input wire [WIDTH-1:0] delay,
  176. output reg [0:0] pwm_out
  177. );
  178. reg [WIDTH-1:0] counter;
  179. reg [WIDTH-1:0] _period;
  180. reg [WIDTH-1:0] _delay;
  181. reg [0:0] next_out;
  182. reg [0:0] is_last_tick;
  183. reg [0:0] is_last_tickA;
  184. reg [0:0] is_last_tickB;
  185. reg [0:0] is_mid_tick;
  186. // Counter logic
  187. always @(posedge clk or negedge nrst) begin
  188. if (!nrst) begin
  189. counter <= 0;
  190. pwm_out <= 0;
  191. next_out <= 0;
  192. _period <= 0;
  193. _delay <= 0;
  194. is_last_tick <= 0;
  195. is_last_tickA <= 0;
  196. is_last_tickB <= 0;
  197. end else begin
  198. _period <= period;
  199. _delay <= delay;
  200. is_last_tickA <= counter[WIDTH-1:8]==0;
  201. is_last_tickB <= counter[7:0]==2;
  202. is_last_tick <= is_last_tickA&is_last_tickB;
  203. if (is_last_tick) begin
  204. counter <= _period;
  205. end else begin
  206. counter <= counter-1;
  207. end
  208. next_out <= is_last_tick;
  209. pwm_out <= next_out;
  210. end
  211. end
  212. endmodule*/
  213. module single_shot_gen#(
  214. parameter WIDTH = 16
  215. )(
  216. input wire nrst,clk,
  217. input wire trigger,
  218. input [WIDTH-1:0] delay,
  219. input [WIDTH-1:0] period,
  220. output reg pwm_out
  221. );
  222. reg [WIDTH-1:0] counter;
  223. reg [WIDTH-1:0] counter2; // Buffer register for better timing
  224. wire pwm_gt;
  225. always @(posedge clk) begin
  226. if (trigger) begin
  227. counter <= period; //########TODO WARNING: counter will underflow which may trigger unwanted pulses. Add logic to fix that.
  228. end else begin
  229. counter <= counter - 1;
  230. end
  231. // Buffer register to reduce timing pressure
  232. counter2 <= counter;
  233. // Output register to reduce delay
  234. pwm_out <= pwm_gt;
  235. end
  236. // Parallel comparison with buffered counter
  237. compare_gt #(.WIDTH(WIDTH)) cmp_out (
  238. .clk(clk),
  239. .A(delay),
  240. .B(counter2),
  241. .was_gt(pwm_gt)
  242. );
  243. endmodule
  244. /*module phase_delay#(
  245. parameter WIDTH = 16,
  246. parameter FORWARD_DATA_WIDTH = 16
  247. )(
  248. input wire nrst, clk,
  249. input wire in_trig,
  250. input [WIDTH-1:0] delay,
  251. input [FORWARD_DATA_WIDTH-1:0] in_data_fwd,
  252. output wire out_trig,
  253. output reg [FORWARD_DATA_WIDTH-1:0] out_data_fwd
  254. );
  255. reg [WIDTH-1:0] counter;
  256. reg [0:0] is_counting;
  257. reg [WIDTH-1:0] delay_latched;
  258. always @(posedge clk or negedge nrst) begin
  259. if (!nrst) begin
  260. counter <= 0;
  261. is_counting <=0;
  262. delay_latched <=0;
  263. end else begin
  264. if (is_counting) begin
  265. if ((counter+1) >= delay_latched) begin
  266. counter <= 0;
  267. is_counting <= 0;
  268. end else begin
  269. counter <= counter+1;
  270. end
  271. end else begin
  272. if (in_trig) begin
  273. is_counting <= 1;
  274. out_data_fwd <= in_data_fwd;
  275. delay_latched <= delay;
  276. end
  277. end
  278. end
  279. end
  280. assign out_trig=((counter+1)>=delay) && is_counting;
  281. endmodule*/
  282. module simple_counter#(
  283. parameter WIDTH = 14
  284. )(
  285. input wire clk,
  286. input wire trigger,
  287. input wire if_counting,
  288. output reg [WIDTH-1:0] cnt_out
  289. );
  290. parameter HALF_WIDTH=7;
  291. reg [HALF_WIDTH-1:0] cnt1, cnt0;
  292. reg cnt0f;
  293. always @(posedge clk /*or negedge nrst*/) begin
  294. if (trigger) begin
  295. cnt1 <= 0;
  296. cnt0 <= 0;
  297. cnt0f <= 0;
  298. end else begin
  299. //cnt1f <= &cnt1;
  300. cnt0f <= &cnt0;
  301. if(if_counting) begin
  302. cnt0 <= cnt0+1;
  303. if(cnt0f) begin
  304. cnt1 <= cnt1+1;
  305. end
  306. end
  307. cnt_out <= {cnt1, cnt0};
  308. end
  309. end
  310. endmodule
  311. module pulse_train_gen#(
  312. parameter TOTAL_PERIOD_WIDTH = 14,
  313. parameter SINGLE_CYCLE_WIDTH = 8,
  314. parameter PULSE_COUNTER_WIDTH = 8
  315. )(
  316. input wire nrst, clk,
  317. input wire trigger,
  318. input [PULSE_COUNTER_WIDTH-1:0] npuls,
  319. input [SINGLE_CYCLE_WIDTH-1:0] period,
  320. input [SINGLE_CYCLE_WIDTH-1:0] duty,
  321. output reg [0:0] pwm_out
  322. );
  323. reg [TOTAL_PERIOD_WIDTH-1:0] counter;//total waveform counter
  324. reg [TOTAL_PERIOD_WIDTH-1:0] counter2;
  325. reg [TOTAL_PERIOD_WIDTH-1:0] cycle_threshold;
  326. reg [TOTAL_PERIOD_WIDTH-1:0] cycle_threshold2;
  327. reg [TOTAL_PERIOD_WIDTH-1:0] next_cycle_threshold;
  328. reg [PULSE_COUNTER_WIDTH-1:0] cycle_counter;
  329. reg [PULSE_COUNTER_WIDTH-1:0] next_cycle_counter;
  330. reg [SINGLE_CYCLE_WIDTH-1:0] _period;
  331. reg if_next_cycle;
  332. reg is_counting;
  333. reg is_counting2;
  334. always @(posedge clk /*or negedge nrst*/) begin
  335. /*if (!nrst) begin
  336. is_counting <= 0;
  337. end else begin*/
  338. if(trigger) begin
  339. //counter <= 0;
  340. cycle_threshold <= {6'b0, _period};
  341. cycle_counter <= npuls;
  342. end else begin
  343. //counter <= counter + is_counting2;
  344. end
  345. counter2 <= counter;
  346. _period <= period;
  347. if(if_next_cycle & is_counting2) begin
  348. cycle_counter <= next_cycle_counter;
  349. cycle_threshold <= next_cycle_threshold;
  350. end
  351. next_cycle_counter <= cycle_counter-1;
  352. is_counting <= |next_cycle_counter;
  353. is_counting2 <= is_counting;
  354. pwm_out <= if_next_cycle;
  355. cycle_threshold2 <= cycle_threshold;
  356. //end
  357. end
  358. simple_counter cnt(
  359. .clk(clk),
  360. .trigger(trigger),
  361. .if_counting(is_counting2),
  362. .cnt_out(counter)
  363. );
  364. compare_eq#(.WIDTH(TOTAL_PERIOD_WIDTH))cmp_cycle(
  365. .clk(clk),
  366. .A(counter2),
  367. .B(cycle_threshold2),
  368. .was_eq(if_next_cycle)
  369. );
  370. /*add#(
  371. .WIDTH(TOTAL_PERIOD_WIDTH)
  372. )cycle_th(
  373. .clk(clk),
  374. .A(cycle_threshold2),
  375. .B({6'b0, _period}),
  376. .sum(next_cycle_threshold)
  377. );*/
  378. endmodule
  379. parameter [1:0] ODD_TRAIN_FORCE_OFF = 2'b00;
  380. parameter [1:0] ODD_TRAIN_ENA_CONTROL = 2'b01;
  381. parameter [1:0] ODD_TRAIN_FORCE_ON = 2'b10;
  382. module three_signal#(
  383. parameter FAST_PWM_WIDTH=8,
  384. parameter PULSE_COUNTER_WIDTH=8,
  385. parameter SLOW_PWM_WIDTH=14
  386. )(
  387. input wire nrst, clk,
  388. input [SLOW_PWM_WIDTH-1:0] period1,
  389. input [SLOW_PWM_WIDTH-1:0] delay1,
  390. input [SLOW_PWM_WIDTH-1:0] period2,
  391. input [SLOW_PWM_WIDTH-1:0] delay2,
  392. input [FAST_PWM_WIDTH-1:0] period3,
  393. input [FAST_PWM_WIDTH-1:0] duty3,
  394. input [SLOW_PWM_WIDTH-1:0] delay3,//delay is wrt slow pwm, thus longer bit length
  395. input [PULSE_COUNTER_WIDTH-1:0] npuls3,
  396. input /*odd_train_flag_t*/ wire [1:0] odd_train_flag,
  397. input wire ena_odd_out3,
  398. output reg Out1,
  399. output reg Out2,
  400. output reg Out3
  401. );
  402. reg [SLOW_PWM_WIDTH-1:0] _period1;
  403. reg [SLOW_PWM_WIDTH-1:0] _delay1;
  404. reg [SLOW_PWM_WIDTH-1:0] _duty1;
  405. reg [SLOW_PWM_WIDTH-1:0] _period2;
  406. reg [SLOW_PWM_WIDTH-1:0] _delay2;
  407. reg [FAST_PWM_WIDTH-1:0] _period3;
  408. reg [FAST_PWM_WIDTH-1:0] _duty3;
  409. reg [SLOW_PWM_WIDTH-1:0] _delay3;//delay is wrt slow pwm, thus longer bit length
  410. reg [PULSE_COUNTER_WIDTH-1:0] _npuls3;
  411. reg /*odd_train_flag_t*/ [1:0] _odd_train_flag;
  412. reg _ena_odd_out3;
  413. wire _Out1;
  414. wire _Out2;
  415. wire _Out3;
  416. always @(posedge clk) begin
  417. _period1 <= period1 ;
  418. _delay1 <= delay1 ;
  419. _period2 <= period2 ;
  420. _delay2 <= delay2 ;
  421. _period3 <= period3 ;
  422. _duty3 <= duty3 ;
  423. _delay3 <= delay3 ;
  424. _npuls3 <= npuls3 ;
  425. _odd_train_flag <= odd_train_flag;
  426. _ena_odd_out3 <= ena_odd_out3 ;
  427. //TODO - output already as reg; no additional latency needed?
  428. Out1 <= _Out1;
  429. Out2 <= _Out2;
  430. Out3 <= _Out3;
  431. end
  432. //wire trigger_next_cycle;
  433. //wire trigger_even_cycle;
  434. //wire trigger_odd_cycle;
  435. wire [SLOW_PWM_WIDTH-1:0] delay3_part1;
  436. wire [SLOW_PWM_WIDTH-1:0] delay3_part234;
  437. assign delay3_part234 = delay3>>2;
  438. assign delay3_part1 = (delay3<4) ? 0 : (delay3 - (delay3_part234*3));
  439. wire [0:0] start_cycle;
  440. wire [0:0] half_cycle;
  441. wire [2:0] trig_out;
  442. cycle_trigger #(.WIDTH(SLOW_PWM_WIDTH)) cyc_trig(
  443. //.nrst(nrst),
  444. .clk(clk),
  445. .period(period1),
  446. .start_cycle(start_cycle),
  447. .half_cycle(half_cycle),
  448. .trig_out(trig_out)
  449. );
  450. single_shot_gen #(.WIDTH(SLOW_PWM_WIDTH)) pwm1(
  451. .nrst(nrst),
  452. .clk(clk),
  453. .trigger(trig_out[0]),
  454. .delay(_delay1),
  455. .period(_period1),
  456. .pwm_out(_Out1)
  457. );
  458. single_shot_gen #(.WIDTH(SLOW_PWM_WIDTH)) pwm2(
  459. .nrst(nrst),
  460. .clk(clk),
  461. .trigger(trig_out[1]),
  462. .delay(_delay2),
  463. .period(_period2),
  464. .pwm_out(_Out2)
  465. );
  466. pulse_train_gen#(
  467. .TOTAL_PERIOD_WIDTH(SLOW_PWM_WIDTH),
  468. .SINGLE_CYCLE_WIDTH(FAST_PWM_WIDTH),
  469. .PULSE_COUNTER_WIDTH(PULSE_COUNTER_WIDTH)
  470. )pwm3(
  471. .nrst(nrst),
  472. .clk(clk),
  473. .trigger(trig_out[2]),
  474. .npuls(_npuls3),
  475. .period(_period3),
  476. .duty(_duty3),
  477. .pwm_out(_Out3)
  478. );
  479. /*wire trigger_delay_1_to_2;
  480. wire trigger_delay_2_to_3;
  481. wire trigger_delay_3_to_4;
  482. wire trigger_delay_4_to_pulse_train;
  483. localparam FORWARD_DATA_WIDTH = SLOW_PWM_WIDTH + PULSE_COUNTER_WIDTH + FAST_PWM_WIDTH + FAST_PWM_WIDTH;
  484. localparam DELAY_BITS_POS = PULSE_COUNTER_WIDTH + FAST_PWM_WIDTH + FAST_PWM_WIDTH;
  485. wire [FORWARD_DATA_WIDTH-1:0] data_1_to_2;
  486. wire [FORWARD_DATA_WIDTH-1:0] data_2_to_3;
  487. wire [FORWARD_DATA_WIDTH-1:0] data_3_to_4;
  488. wire [FORWARD_DATA_WIDTH-1:0] data_4_to_gen;
  489. assign trigger_odd_cycle =
  490. (odd_train_flag == ODD_TRAIN_ENA_CONTROL) ? trigger_next_cycle && ena_odd_out3 :
  491. (odd_train_flag == ODD_TRAIN_FORCE_ON) ? trigger_next_cycle :
  492. 0;
  493. wire [FAST_PWM_WIDTH-1:0] period3_gen;
  494. wire [FAST_PWM_WIDTH-1:0] duty3_gen;
  495. wire [PULSE_COUNTER_WIDTH-1:0] npuls3_gen;
  496. assign duty3_gen = data_4_to_gen[FAST_PWM_WIDTH-1:0];
  497. assign period3_gen = data_4_to_gen[FAST_PWM_WIDTH+FAST_PWM_WIDTH-1:FAST_PWM_WIDTH];
  498. assign npuls3_gen = data_4_to_gen[FAST_PWM_WIDTH+FAST_PWM_WIDTH+PULSE_COUNTER_WIDTH-1:FAST_PWM_WIDTH+FAST_PWM_WIDTH];*/
  499. endmodule