2
0

tty.sv 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. // The registers are as follows:
  9. //
  10. // 0 - WO - data register (will be RW)
  11. // 1 - RW - baud rate register (binary fraction of TTY_CLK/16 - 1)
  12. // 2 - RO - status register
  13. // 0 - transmitter idle (FIFO and shift register empty)
  14. // 1 - transmit FIFO 3/4 empty
  15. // 2 - transmit FIFO 1/2 empty
  16. // 3 - transmit FIFO 1/2 full (inverse of bit 2)
  17. // 4 - transmit FIFO 3/4 full
  18. // 3 - RW - interrupt enable register (status register mask)
  19. module tty (
  20. input rst_n,
  21. input clk,
  22. input valid,
  23. input [3:0] wstrb,
  24. input [31:0] wdata,
  25. input [1:0] addr,
  26. output reg [31:0] rdata,
  27. output reg irq,
  28. output tty_txd
  29. );
  30. `include "functions.sv" // For ModelSim
  31. //
  32. // Baud rate generator; produces a clock enable synchronous
  33. // with clk. This is based on a numerically controlled oscillator
  34. // (NCO); the baudrate is given as a binary fraction of the input
  35. // clock rate divided by the oversampling rate (16); for practical
  36. // reasons represented minus one LSB so 0x0.ffffff -> 1
  37. // and 0 -> 0x0.000001.
  38. //
  39. // The term "divisor" here is probably misleading, since it is
  40. // actually a fixed-point *multiplier* which is <= 1.
  41. //
  42. parameter [31:0] BAUDRATE = 115200;
  43. parameter [31:0] TTY_CLK = 84000000;
  44. parameter NCO_BITS = 24;
  45. reg [NCO_BITS-1:0] divisor
  46. = round_div(BAUDRATE << NCO_BITS, TTY_CLK >> 4) - 1'b1;
  47. reg [NCO_BITS-1:0] nco_q;
  48. reg tty_clk_en; // tty clock tick (clock enable)
  49. always @(posedge clk)
  50. { tty_clk_en, nco_q } <= nco_q + divisor + 1'b1;
  51. //
  52. // Tx FIFO
  53. //
  54. reg tx_rdack;
  55. wire tx_wrreq;
  56. wire tx_rdempty;
  57. wire [7:0] tx_data;
  58. wire [8:0] tx_usedw;
  59. fifo txfifo (
  60. .aclr ( ~rst_n ),
  61. .clock ( clk ),
  62. .data ( wdata ),
  63. .rdreq ( tx_rdack ),
  64. .sclr ( 1'b0 ), // Flush FIFO command
  65. .wrreq ( tx_wrreq ),
  66. .empty ( tx_rdempty ),
  67. .full ( ),
  68. .q ( tx_data ),
  69. .usedw ( tx_usedw )
  70. );
  71. //
  72. // Transmitter
  73. //
  74. reg [3:0] tx_phase;
  75. reg [3:0] tx_bits;
  76. reg [9:0] tx_sr = ~10'b0; // Shift register
  77. assign tty_txd = tx_sr[0];
  78. always @(negedge rst_n or posedge clk)
  79. if (~rst_n)
  80. begin
  81. tx_phase <= 4'h0;
  82. tx_bits <= 4'd0;
  83. tx_sr <= ~10'b0; // Line idle
  84. tx_rdack <= 1'b0;
  85. end
  86. else
  87. begin
  88. tx_rdack <= 1'b0;
  89. if ( tty_clk_en )
  90. begin
  91. tx_phase <= tx_phase + 1'b1;
  92. if (tx_phase == 4'hF)
  93. begin
  94. tx_sr[8:0] <= tx_sr[9:1];
  95. tx_sr[9] <= 1'b1; // Stop bit/idle
  96. if (tx_bits == 4'd0)
  97. begin
  98. if ( ~tx_rdempty )
  99. begin
  100. tx_sr[9:2] <= tx_data;
  101. tx_sr[1] <= 1'b0; // Start bit
  102. // 10 = start bit + data + stop bit
  103. tx_bits <= 4'd10;
  104. tx_rdack <= 1'b1; // Remove from FIFO
  105. end
  106. end
  107. else
  108. begin
  109. tx_bits <= tx_bits - 1'b1;
  110. end // else: !if(tx_bits == 4'd0)
  111. end // if (tx_phase == 4'hF)
  112. end // if ( tty_clk_en )
  113. end // else: !if(~rst_n)
  114. //
  115. // CPU interface
  116. //
  117. // Data (FIFO) register; normally addressed as byte
  118. // Protect against long pulses (edge detect)
  119. reg old_wstrb;
  120. always @(posedge clk)
  121. old_wstrb <= wstrb[0];
  122. assign tx_wrreq = valid & wstrb[0] & ~old_wstrb & (addr == 2'b00);
  123. // Status register definition
  124. localparam status_bits = 5;
  125. wire [status_bits-1:0] status;
  126. assign status[0] = tx_rdempty & (tx_bits == 4'd0);
  127. assign status[1] = tx_usedw[8:7] == 2'b00;
  128. assign status[2] = ~tx_usedw[8];
  129. assign status[3] = tx_usedw[8];
  130. assign status[4] = tx_usedw[8:7] == 2'b11;
  131. reg [status_bits-1:0] irq_en;
  132. //
  133. // Control register writes.
  134. // Only full word writes are supported.
  135. //
  136. always @(negedge rst_n or posedge clk)
  137. if (~rst_n)
  138. begin
  139. irq_en <= 5'b0;
  140. end
  141. else if (valid & (&wstrb))
  142. case (addr)
  143. 2'b01: divisor <= wdata[NCO_BITS-1:0];
  144. 2'b11: irq_en <= wdata[status_bits-1:0];
  145. endcase // case (addr)
  146. // Read MUX
  147. always @(*)
  148. begin
  149. rdata = 32'b0;
  150. case (addr)
  151. 2'b01: rdata[NCO_BITS-1:0] = divisor;
  152. 2'b10: rdata[status_bits-1:0] = status;
  153. 2'b11: rdata[status_bits-1:0] = irq_en;
  154. default: rdata = 32'b0;
  155. endcase // case (addr)
  156. end
  157. // Interrupt
  158. always @(negedge rst_n or posedge clk)
  159. if (~rst_n)
  160. irq <= 1'b0;
  161. else
  162. irq <= |(status & irq_en);
  163. endmodule // tty