hub75_bcm.v 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * hub75_bcm.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Copyright (C) 2019 Sylvain Munaut <tnt@246tNt.com>
  7. * All rights reserved.
  8. *
  9. * LGPL v3+, see LICENSE.lgpl3
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation; either
  14. * version 3 of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public License
  22. * along with this program; if not, write to the Free Software Foundation,
  23. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  24. */
  25. `default_nettype none
  26. module hub75_bcm #(
  27. parameter integer N_ROWS = 32,
  28. parameter integer N_PLANES = 8,
  29. // Auto-set
  30. parameter integer LOG_N_ROWS = $clog2(N_ROWS)
  31. )(
  32. // PHY
  33. output wire phy_addr_inc,
  34. output wire phy_addr_rst,
  35. output wire [LOG_N_ROWS-1:0] phy_addr,
  36. output wire phy_le,
  37. // Shifter interface
  38. output wire [N_PLANES-1:0] shift_plane,
  39. output wire shift_go,
  40. input wire shift_rdy,
  41. // Blanking interface
  42. output wire [N_PLANES-1:0] blank_plane,
  43. output wire blank_go,
  44. input wire blank_rdy,
  45. // Control
  46. input wire [LOG_N_ROWS-1:0] ctrl_row,
  47. input wire ctrl_row_first,
  48. input wire ctrl_go,
  49. output wire ctrl_rdy,
  50. // Config
  51. input wire [7:0] cfg_pre_latch_len,
  52. input wire [7:0] cfg_latch_len,
  53. input wire [7:0] cfg_post_latch_len,
  54. // Clock / Reset
  55. input wire clk,
  56. input wire rst
  57. );
  58. genvar i;
  59. // Signals
  60. // -------
  61. // FSM
  62. localparam
  63. ST_IDLE = 0,
  64. ST_SHIFT = 1,
  65. ST_WAIT_TO_LATCH = 2,
  66. ST_PRE_LATCH = 3,
  67. ST_DO_LATCH = 4,
  68. ST_POST_LATCH = 5,
  69. ST_ISSUE_BLANK = 6;
  70. reg [2:0] fsm_state;
  71. reg [2:0] fsm_state_next;
  72. reg [7:0] timer_val;
  73. wire timer_trig;
  74. reg [N_PLANES-1:0] plane;
  75. wire plane_last;
  76. reg [LOG_N_ROWS-1:0] addr;
  77. reg [LOG_N_ROWS-1:0] addr_out;
  78. reg addr_do_inc;
  79. reg addr_do_rst;
  80. wire le;
  81. // FSM
  82. // ---
  83. // State register
  84. always @(posedge clk or posedge rst)
  85. if (rst)
  86. fsm_state <= ST_IDLE;
  87. else
  88. fsm_state <= fsm_state_next;
  89. // Next-State logic
  90. always @(*)
  91. begin
  92. // Default is to not move
  93. fsm_state_next = fsm_state;
  94. // Transitions ?
  95. case (fsm_state)
  96. ST_IDLE:
  97. if (ctrl_go)
  98. fsm_state_next = ST_SHIFT;
  99. ST_SHIFT:
  100. fsm_state_next = ST_WAIT_TO_LATCH;
  101. ST_WAIT_TO_LATCH:
  102. if (shift_rdy & blank_rdy)
  103. fsm_state_next = ST_PRE_LATCH;
  104. ST_PRE_LATCH:
  105. if (timer_trig)
  106. fsm_state_next = ST_DO_LATCH;
  107. ST_DO_LATCH:
  108. if (timer_trig)
  109. fsm_state_next = ST_POST_LATCH;
  110. ST_POST_LATCH:
  111. if (timer_trig)
  112. fsm_state_next = ST_ISSUE_BLANK;
  113. ST_ISSUE_BLANK:
  114. fsm_state_next = plane_last ? ST_IDLE : ST_SHIFT;
  115. endcase
  116. end
  117. // Timer
  118. // -----
  119. always @(posedge clk)
  120. begin
  121. if (fsm_state != fsm_state_next) begin
  122. // Default is to trigger all the time
  123. timer_val <= 8'h80;
  124. // Preload for next state
  125. case (fsm_state_next)
  126. ST_PRE_LATCH: timer_val <= cfg_pre_latch_len;
  127. ST_DO_LATCH: timer_val <= cfg_latch_len;
  128. ST_POST_LATCH: timer_val <= cfg_post_latch_len;
  129. endcase
  130. end else begin
  131. timer_val <= timer_val - 1;
  132. end
  133. end
  134. assign timer_trig = timer_val[7];
  135. // Plane counter
  136. // -------------
  137. always @(posedge clk)
  138. if (fsm_state == ST_IDLE)
  139. plane <= { {(N_PLANES-1){1'b0}}, 1'b1 };
  140. else if (fsm_state == ST_ISSUE_BLANK)
  141. plane <= { plane[N_PLANES-2:0], 1'b0 };
  142. assign plane_last = plane[N_PLANES-1];
  143. // External Control
  144. // ----------------
  145. // Shifter
  146. assign shift_plane = plane;
  147. assign shift_go = (fsm_state == ST_SHIFT);
  148. // Blanking
  149. assign blank_plane = plane;
  150. assign blank_go = (fsm_state == ST_ISSUE_BLANK);
  151. // Address
  152. always @(posedge clk)
  153. if (ctrl_go)
  154. addr <= ctrl_row;
  155. always @(posedge clk)
  156. begin
  157. addr_do_inc <= (addr_do_inc | (ctrl_go & ~ctrl_row_first)) & ~(fsm_state == ST_POST_LATCH);
  158. addr_do_rst <= (addr_do_rst | (ctrl_go & ctrl_row_first)) & ~(fsm_state == ST_POST_LATCH);
  159. end
  160. always @(posedge clk)
  161. if (fsm_state == ST_DO_LATCH)
  162. addr_out <= addr;
  163. // Latch
  164. assign le = (fsm_state == ST_DO_LATCH);
  165. // Ready ?
  166. assign ctrl_rdy = (fsm_state == ST_IDLE);
  167. // PHY
  168. // ---
  169. assign phy_addr = addr_out;
  170. assign phy_le = le;
  171. assign phy_addr_inc = (fsm_state == ST_DO_LATCH) ? addr_do_inc : 1'b0;
  172. assign phy_addr_rst = (fsm_state == ST_DO_LATCH) ? addr_do_rst : 1'b0;
  173. endmodule // hub75_bcm