tty.sv 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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 clk,
  14. input valid,
  15. input [3:0] wstrb,
  16. input [31:0] wdata,
  17. input [0:0] addr,
  18. output tty_txd
  19. );
  20. `include "functions.sv" // For ModelSim
  21. //
  22. // Baud rate generator; produces a clock enable synchronous
  23. // with clk. This is based on a numerically controlled oscillator
  24. // (NCO); the baudrate is given as a binary fraction of the input
  25. // clock rate divided by the oversampling rate (16); for practical
  26. // reasons represented minus one LSB so 0x0.ffffff -> 1
  27. // and 0 -> 0x0.000001.
  28. //
  29. // The term "divisor" here is probably misleading, since it is
  30. // actually a fixed-point *multiplier* which is <= 1.
  31. //
  32. parameter [31:0] BAUDRATE = 115200;
  33. parameter [31:0] TTY_CLK = 84000000;
  34. parameter NCO_BITS = 24;
  35. reg [NCO_BITS-1:0] divisor
  36. = round_div(BAUDRATE << NCO_BITS, TTY_CLK >> 4) - 1'b1;
  37. reg [NCO_BITS-1:0] nco_q;
  38. reg tty_clk_en; // tty clock tick (clock enable)
  39. always @(posedge clk)
  40. { tty_clk_en, nco_q } <= nco_q + divisor + 1'b1;
  41. //
  42. // Tx FIFO
  43. //
  44. reg tx_rdack;
  45. wire tx_wrreq;
  46. wire tx_rdempty;
  47. wire [7:0] tx_data;
  48. fifo txfifo (
  49. .aclr ( ~rst_n ),
  50. .clock ( clk ),
  51. .data ( wdata ),
  52. .rdreq ( tx_rdack ),
  53. .sclr ( 1'b0 ), // Flush FIFO command
  54. .wrreq ( tx_wrreq ),
  55. .empty ( tx_rdempty ),
  56. .full ( ),
  57. .q ( tx_data ),
  58. .usedw ( )
  59. );
  60. //
  61. // CPU -> transmitter data. No wait state is needed nor expected.
  62. //
  63. // Data mask (if/when needed)
  64. wire [31:0] wmask = {{8{wstrb[3]}}, {8{wstrb[2]}},
  65. {8{wstrb[1]}}, {8{wstrb[0]}}};
  66. // Data (FIFO) register; normally addressed as byte
  67. // Protect against long pulses (edge detect)
  68. reg old_wstrb;
  69. always @(posedge clk)
  70. old_wstrb <= wstrb[0];
  71. assign tx_wrreq = valid & wstrb[0] & ~old_wstrb & (addr == 0);
  72. // Divisor register
  73. always @(posedge clk)
  74. if (wstrb[0] & valid & (addr == 1))
  75. divisor <= wdata[NCO_BITS-1:0] & wmask;
  76. //
  77. // Transmitter
  78. //
  79. reg [3:0] tx_phase;
  80. reg [3:0] tx_bits;
  81. reg [9:0] tx_sr = ~10'b0; // Shift register
  82. assign tty_txd = tx_sr[0];
  83. always @(negedge rst_n or posedge clk)
  84. if (~rst_n)
  85. begin
  86. tx_phase <= 4'h0;
  87. tx_bits <= 4'd0;
  88. tx_sr <= ~10'b0; // Line idle
  89. tx_rdack <= 1'b0;
  90. end
  91. else
  92. begin
  93. tx_rdack <= 1'b0;
  94. if ( tty_clk_en )
  95. begin
  96. tx_phase <= tx_phase + 1'b1;
  97. if (tx_phase == 4'hF)
  98. begin
  99. tx_sr[8:0] <= tx_sr[9:1];
  100. tx_sr[9] <= 1'b1; // Stop bit/idle
  101. if (tx_bits == 4'd0)
  102. begin
  103. if ( ~tx_rdempty )
  104. begin
  105. tx_sr[9:2] <= tx_data;
  106. tx_sr[1] <= 1'b0; // Start bit
  107. // 10 = start bit + data + stop bit
  108. tx_bits <= 4'd10;
  109. tx_rdack <= 1'b1; // Remove from FIFO
  110. end
  111. end
  112. else
  113. begin
  114. tx_bits <= tx_bits - 1'b1;
  115. end // else: !if(tx_bits == 4'd0)
  116. end // if (tx_phase == 4'hF)
  117. end // if ( tty_clk_en )
  118. end // else: !if(~rst_n)
  119. endmodule // tty