tty.sv 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. //
  2. // Very simple asynchronous tty. Not really a "UART" since it isn't
  3. // very "universal". It doesn't have to be.
  4. //
  5. // Currently only transmit is supported, 8-N-1, at a fixed speed.
  6. // The baud rate is tty_clk/((divisor+1)*16).
  7. //
  8. // Currently there is no overrun checking or interrupt support, but that
  9. // can come later. A large FIFO makes that less of an issue anyway...
  10. //
  11. module tty (
  12. input rst_n,
  13. input sys_clk,
  14. input tty_clk,
  15. input valid,
  16. input [3:0] wstrb,
  17. input [31:0] wdata,
  18. input [0:0] addr,
  19. output tty_txd
  20. );
  21. `include "functions.sv" // For ModelSim
  22. //
  23. // Baud rate generator; produces a clock enable synchronous
  24. // with tty_clk
  25. //
  26. parameter [31:0] BAUDRATE = 115200;
  27. parameter [31:0] TTY_CLK = 48000000;
  28. localparam divisor_bits = 16;
  29. reg [divisor_bits-1:0] divisor_q = round_div(TTY_CLK, BAUDRATE << 4) - 1;
  30. wire [divisor_bits-1:0] divisor;
  31. reg [divisor_bits-1:0] clk_div;
  32. reg tty_clk_en; // tty clock tick (clock enable)
  33. always @(negedge rst_n or posedge tty_clk)
  34. if (~rst_n)
  35. begin
  36. clk_div <= 16; // Give enough time for synchronizer
  37. tty_clk_en <= 1'b0;
  38. end
  39. else
  40. begin
  41. if (~|clk_div)
  42. begin
  43. clk_div <= divisor;
  44. tty_clk_en <= 1'b1;
  45. end
  46. else
  47. begin
  48. clk_div <= clk_div - 1'b1;
  49. tty_clk_en <= 1'b0;
  50. end
  51. end // else: !if(~rst_n)
  52. //
  53. // Tx FIFO
  54. //
  55. reg tx_rdack;
  56. wire tx_wrreq;
  57. wire tx_rdempty;
  58. wire [7:0] tx_data;
  59. fifo txfifo (
  60. .aclr ( ~rst_n ),
  61. .data ( wdata ),
  62. .q ( tx_data ),
  63. .rdclk ( tty_clk ),
  64. .rdreq ( tx_rdack ),
  65. .wrclk ( sys_clk ),
  66. .wrreq ( tx_wrreq ),
  67. .rdempty ( tx_rdempty ),
  68. .rdusedw ( ),
  69. .wrfull ( ),
  70. .wrusedw ( )
  71. );
  72. //
  73. // CPU -> transmitter data. No wait state is needed nor expected.
  74. //
  75. // Data mask (if/when needed)
  76. wire [31:0] wmask = {{8{wstrb[3]}}, {8{wstrb[2]}},
  77. {8{wstrb[1]}}, {8{wstrb[0]}}};
  78. // Data (FIFO) register; normally addressed as byte
  79. // Protect against long pulses (edge detect)
  80. reg old_wstrb;
  81. always @(posedge sys_clk)
  82. old_wstrb <= wstrb[0];
  83. assign tx_wrreq = valid & wstrb[0] & ~old_wstrb & (addr == 0);
  84. // Divisor register
  85. always @(posedge sys_clk)
  86. if (wstrb[0] & valid & (addr == 1))
  87. divisor_q <= wdata[divisor_bits-1:0] & wmask;
  88. synchronizer #(.width(divisor_bits), .stages(2)) sync_divisor
  89. (
  90. .rst_n ( rst_n ),
  91. .clk ( tty_clk ),
  92. .d ( divisor_q ),
  93. .q ( divisor )
  94. );
  95. //
  96. // Transmitter
  97. //
  98. reg [3:0] tx_phase;
  99. reg [3:0] tx_bits;
  100. reg [9:0] tx_sr = ~10'b0; // Shift register
  101. assign tty_txd = tx_sr[0];
  102. always @(negedge rst_n or posedge tty_clk)
  103. if (~rst_n)
  104. begin
  105. tx_phase <= 4'h0;
  106. tx_bits <= 4'd0;
  107. tx_sr <= ~10'b0; // Line idle
  108. tx_rdack <= 1'b0;
  109. end
  110. else
  111. begin
  112. tx_rdack <= 1'b0;
  113. if ( tty_clk_en )
  114. begin
  115. tx_phase <= tx_phase + 1'b1;
  116. if (tx_phase == 4'hF)
  117. begin
  118. tx_sr[8:0] <= tx_sr[9:1];
  119. tx_sr[9] <= 1'b1; // Stop bit/idle
  120. if (tx_bits == 4'd0)
  121. begin
  122. if ( ~tx_rdempty )
  123. begin
  124. tx_sr[9:2] <= tx_data;
  125. tx_sr[1] <= 1'b0; // Start bit
  126. // 10 = start bit + data + stop bit
  127. tx_bits <= 4'd10;
  128. tx_rdack <= 1'b1; // Remove from FIFO
  129. end
  130. end
  131. else
  132. begin
  133. tx_bits <= tx_bits - 1'b1;
  134. end // else: !if(tx_bits == 4'd0)
  135. end // if (tx_phase == 4'hF)
  136. end // if ( tty_clk_en )
  137. end // else: !if(~rst_n)
  138. endmodule // tty