esp.sv 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. //
  2. // Communication interface with ESP32-S2
  3. //
  4. // This is a DIO (2-bit, including command) SPI slave interface which
  5. // allows direct access to content in SDRAM. Additionally, each
  6. // direction has three interrupt flags (3-1); the FPGA CPU additionally
  7. // has a fourth interrupt condition (0) which indicates DRAM timing
  8. // overrun/underrun.
  9. //
  10. // The SPI command byte is:
  11. // Bit [7:5] - reserved, must be 0
  12. // Bit 4 - read/write#
  13. // Bit [3:2] - clear upstream (FPGA->ESP) interrupt flag if nonzero
  14. // Bit [1:0] - set downstream (ESP->FPGA) interrupt flag if nonzero
  15. //
  16. // CPU downstream interrupts are set after the transaction completes
  17. // (CS# goes high.)
  18. //
  19. // A 32-bit address follows; for a read, the following 16 cycles
  20. // contains dummy/status data:
  21. //
  22. // Bit [31:16] = adjusted memory address
  23. // Bit [15:14] = 2'b10
  24. // Bit [13: 8] = 0 reserved
  25. // Bit [ 7: 5] = upstream interrupt status
  26. // Bit 4 = 0 reserved
  27. // Bit [ 3: 1] = downstream interrupt status
  28. // Bit 0 = underrun error
  29. //
  30. module esp #(
  31. parameter dram_bits = 25,
  32. parameter [31:0] dram_base = 32'h40000000
  33. ) (
  34. input rst_n,
  35. input sys_clk,
  36. input sdram_clk,
  37. input cpu_valid,
  38. input [4:0] cpu_addr,
  39. input [3:0] cpu_wstrb,
  40. input [31:0] cpu_wdata,
  41. output [31:0] cpu_rdata,
  42. output reg irq,
  43. dram_bus.dstr dram,
  44. output reg esp_int,
  45. input spi_clk,
  46. inout [1:0] spi_io,
  47. input spi_cs_n
  48. );
  49. reg [31:0] mem_addr = 'b0;
  50. wire [31:0] mem_addr_mask = (1'b1 << dram_bits) - 3'd4;
  51. wire [31:0] mem_addr_out = (mem_addr & mem_addr_mask)
  52. | dram_base;
  53. reg mem_valid;
  54. reg [31:0] mem_wdata;
  55. wire mem_write;
  56. reg [ 3:0] mem_wstrb;
  57. wire mem_ready;
  58. wire [31:0] mem_rdata;
  59. dram_port #(32) mem
  60. (
  61. .bus ( dram ),
  62. .prio ( 2'd2 ),
  63. .addr ( mem_addr[dram_bits-1:0] ),
  64. .valid ( mem_valid ),
  65. .wd ( mem_wdata ),
  66. .wstrb ( mem_wstrb ),
  67. .ready ( mem_ready ),
  68. .rd ( mem_rdata )
  69. );
  70. reg [1:0] spi_clk_q;
  71. reg spi_cs_n_q;
  72. reg [1:0] spi_io_q;
  73. always @(posedge sdram_clk)
  74. begin
  75. spi_clk_q <= { spi_clk_q[0], spi_clk };
  76. spi_cs_n_q <= spi_cs_n;
  77. spi_io_q <= spi_io;
  78. end
  79. typedef enum logic [1:0] {
  80. st_cmd, // Reading command
  81. st_addr, // Reading address
  82. st_io // I/O (including read dummy bits)
  83. } state_t;
  84. state_t spi_state;
  85. reg [ 4:0] spi_cmd;
  86. reg [31:0] spi_shr;
  87. reg [ 3:0] spi_ctr;
  88. reg [ 3:0] cpu_irq;
  89. reg [ 3:1] cpu_set_irq; // CPU IRQs to set once idle
  90. reg [ 3:1] spi_irq;
  91. reg [ 3:1] latched_spi_irq; // SPI IRQ as of transition start
  92. reg [ 1:0] spi_out;
  93. reg spi_oe;
  94. reg [ 2:0] spi_wbe; // Partial word write byte enables
  95. reg [23:0] spi_wdata; // Partial word write data
  96. assign spi_io = spi_oe ? spi_out : 2'bzz;
  97. assign mem_write = ~spi_cmd[4];
  98. wire [31:0] spi_indata = { spi_shr[29:0], spi_io_q };
  99. reg cpu_valid_q;
  100. always @(negedge rst_n or posedge sdram_clk)
  101. if (~rst_n)
  102. begin
  103. spi_state <= st_cmd;
  104. spi_cmd <= 'b0;
  105. spi_ctr <= 4'd3; // 8 bits needed for this state
  106. cpu_irq <= 'b0;
  107. cpu_set_irq <= 'b0;
  108. spi_irq <= 'b0;
  109. latched_spi_irq <= 'b0;
  110. spi_oe <= 1'b0;
  111. spi_wbe <= 3'b0;
  112. mem_addr <= 'b0;
  113. mem_wstrb <= 4'b0;
  114. mem_valid <= 1'b0;
  115. end
  116. else
  117. begin
  118. esp_int <= ~|spi_irq;
  119. if (spi_cs_n_q)
  120. begin
  121. spi_state <= st_cmd;
  122. spi_ctr <= 4'd3;
  123. spi_oe <= 1'b0;
  124. if (~mem_valid)
  125. begin
  126. cpu_irq <= cpu_irq | { cpu_set_irq, 1'b0 };
  127. cpu_set_irq <= 'b0;
  128. end
  129. end
  130. else if (spi_clk_q == 2'b01)
  131. begin
  132. spi_ctr <= spi_ctr - 1'b1;
  133. spi_shr <= spi_indata;
  134. case (spi_ctr)
  135. 4'b1100:
  136. if (spi_state == st_io && mem_write)
  137. begin
  138. spi_wbe[0] <= 1'b1;
  139. spi_wdata[7:0] <= spi_indata[7:0];
  140. end
  141. 4'b1000:
  142. if (spi_state == st_io && mem_write)
  143. begin
  144. spi_wbe[1] <= 1'b1;
  145. spi_wdata[15:8] <= spi_indata[7:0];
  146. end
  147. 4'b0100:
  148. if (spi_state == st_io && mem_write)
  149. begin
  150. spi_wbe[2] <= 1'b1;
  151. spi_wdata[23:16] <= spi_indata[7:0];
  152. end
  153. 4'b0000: begin
  154. // Transfer data to/from memory controller, but
  155. // we have to shuffle endianness...
  156. if (spi_state == st_io)
  157. begin
  158. // Memory output
  159. spi_shr[31:24] <= mem_rdata[ 7: 0];
  160. spi_shr[23:16] <= mem_rdata[15: 8];
  161. spi_shr[15: 8] <= mem_rdata[23:16];
  162. spi_shr[ 7: 0] <= mem_rdata[31:24];
  163. end
  164. else
  165. begin
  166. // Status output
  167. spi_shr[31:16] <= mem_addr_out[31:16];
  168. spi_shr[15: 8] <= 8'h80;
  169. spi_shr[ 7: 4] <= { latched_spi_irq, 1'b0 };
  170. spi_shr[ 3: 0] <= cpu_irq;
  171. end // else: !if(spi_state == st_io)
  172. if (mem_valid && spi_state != st_cmd)
  173. cpu_irq[0] <= 1'b1; // Overrun/underrun
  174. case (spi_state)
  175. st_cmd: begin
  176. spi_cmd <= spi_indata[5:0];
  177. spi_state <= st_addr;
  178. latched_spi_irq <= spi_irq;
  179. for (int i = 1; i < 4; i++)
  180. begin
  181. if (spi_indata[3:2] == i)
  182. spi_irq[i] <= 1'b0;
  183. if (spi_indata[1:0] == i)
  184. cpu_set_irq[i] <= 1'b1;
  185. end
  186. end
  187. st_addr: begin
  188. mem_addr <= spi_indata & mem_addr_mask;
  189. spi_state <= st_io;
  190. mem_valid <= ~mem_write;
  191. mem_wstrb <= 4'b0;
  192. spi_wbe <= 3'b000;
  193. // If the first word is partial, skip ahead
  194. if (mem_write)
  195. spi_ctr[3:2] <= ~spi_indata[1:0];
  196. end
  197. st_io: begin
  198. if (mem_write)
  199. begin
  200. mem_wdata[23: 0] <= spi_wdata[23:0];
  201. mem_wdata[31:24] <= spi_indata[7:0];
  202. mem_wstrb <= { 1'b1, spi_wbe };
  203. end
  204. else
  205. begin
  206. mem_wstrb <= 4'b0000;
  207. end // else: !if(mem_write)
  208. mem_valid <= 1'b1;
  209. spi_wbe <= 3'b000;
  210. end
  211. endcase
  212. end // case: 4'b0000
  213. default:
  214. ; // Nothing
  215. endcase // case (spi_ctr)
  216. end // if (spi_clk_q == 2'b01)
  217. else if (spi_clk_q == 2'b10)
  218. begin
  219. spi_out <= spi_shr[31:30];
  220. spi_oe <= (spi_state == st_io) & ~mem_write;
  221. end
  222. if (mem_valid & mem_ready)
  223. begin
  224. mem_addr <= mem_addr + 3'd4;
  225. mem_valid <= 1'b0;
  226. end
  227. if (spi_state != st_io & ~mem_valid & |spi_wbe)
  228. begin
  229. // Complete a partial write terminated by CS#
  230. mem_valid <= 1'b1;
  231. mem_wstrb <= { 1'b0, spi_wbe };
  232. mem_wdata[23:0] <= spi_wdata[23:0];
  233. mem_wdata[31:24] <= 8'hxx;
  234. spi_wbe <= 3'b000;
  235. end
  236. cpu_valid_q <= cpu_valid;
  237. if (cpu_valid & ~cpu_valid_q & cpu_wstrb[0])
  238. case (cpu_addr[1:0])
  239. 2'b00:
  240. cpu_irq <= cpu_wdata[3:0];
  241. 2'b01:
  242. for (int i = 0; i < 4; i++)
  243. if (cpu_wdata[i])
  244. cpu_irq[i] <= 1'b0;
  245. 2'b10:
  246. spi_irq <= cpu_wdata[3:1];
  247. 2'b11:
  248. for (int i = 1; i < 4; i++)
  249. if (cpu_wdata[i])
  250. spi_irq[i] <= 1'b1;
  251. endcase // case (cpu_addr[1:0])
  252. end // else: !if(~rst_n)
  253. always @(posedge sys_clk)
  254. irq <= |cpu_irq;
  255. always @(*)
  256. casez (cpu_addr[1:0])
  257. 2'b0?:
  258. cpu_rdata = { 28'b0, cpu_irq };
  259. 2'b1?:
  260. cpu_rdata = { 28'b0, spi_irq, 1'b0 };
  261. endcase // casez (cpu_addr[1:0])
  262. endmodule // esp