Advertisement
alynna

Untitled

Feb 1st, 2019
171
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.69 KB | None | 0 0
  1. //
  2. // ddram.v
  3. // Copyright (c) 2017 Sorgelig
  4. // Copyright (c) 2018 Alynna
  5. //
  6. // This source file is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published
  8. // by the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // This source file is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. //
  19. // ------------------------------------------
  20. //
  21.  
  22. // 8/16-bit version
  23. // Thank you @Sorgelig and the users on Smokemonster Discord for LOTS of ideas
  24. // Rysha, Grabulosaure, BrNX :) :)
  25. // Features:
  26. //
  27. // * 24 bytes of readahead cache
  28. // * 8 bytes of writeback cache
  29. // * Pauses only when it needs to commit a cache
  30. // * Leaves time for ascal to update the screen
  31. // * 8 or 16 bit write bus switchable dynamically
  32. // * Read 8 or 16 bit wide address anytime
  33. //
  34. // Caveats:
  35. // This module lets you access all 512m of the HPS DDR3.
  36. // $20000000-$3FFFFFFF
  37. // At the very least, ASCAL uses $20000000-$21FFFFFF
  38. // It is smart to reserve $20000000-$27FFFFFF for MiSTer functionality.
  39. // I recommend working your way down from the top of memory ($3FFFFFFF).
  40.  
  41. module ddram
  42. (
  43. input DDRAM_CLK,
  44. input RESET,
  45. inout [7:0] debug,
  46.  
  47. input DDRAM_BUSY, // waitrequest
  48. output [7:0] DDRAM_BURSTCNT, // burstcount
  49. output [28:0] DDRAM_ADDR, // address (in HPS reserved memory $20000000-$3FFFFFFF)
  50. input [63:0] DDRAM_DOUT, // readdata
  51. input DDRAM_DOUT_READY, // readdatavalid
  52. output DDRAM_RD, // read
  53. output [63:0] DDRAM_DIN, // readdata
  54. output [7:0] DDRAM_BE, // byteenable
  55. output DDRAM_WE, // write
  56.  
  57. input bus16, // 0 = 8bit access through _d8, 1 = 16bit access through _d
  58. input [28:0] wr_a,
  59. input [15:0] wr_d,
  60. input [7:0] wr_d8,
  61. input [1:0] wr_be, // NOTE: Byte enable not used for d8 access!
  62. input wr_req,
  63. output wr_ack,
  64.  
  65. input [28:0] rd_a,
  66. output [15:0] rd_d,
  67. output [7:0] rd_d8,
  68. input rd_req,
  69. output rd_ack
  70. );
  71.  
  72. // I will probably be implementing a write cache.
  73. // Some of these new regs are for this.
  74. reg [7:0] ram_burst;
  75. reg [63:0] cache, wq, wq2, rq, rq2;
  76. reg [63:0] ram_data;
  77. reg [28:0] ram_address, cache_addr, w_addr, w2_a, t_a;
  78. reg ram_read = 0;
  79. reg ram_write = 0;
  80. reg [7:0] ram_be = 8'b11111111;
  81. reg [7:0] cache_wbe = 8'b00000000;
  82. reg [7:0] w_be = 8'b00000000;
  83. reg [7:0] w2_be = 8'b00000000;
  84. reg [15:0] t_d = 16'b0000000000000000;
  85. reg [7:0] t_d8 = 8'b00000000;
  86. reg [1:0] t_be = 0;
  87. reg wr_pend = 0;
  88. reg [1:0] rd_pend = 0;
  89. reg [1:0] rc_valid = 0;
  90. reg [1:0] w2_commit = 0;
  91. reg [3:0] ddr_wait = 0;
  92.  
  93. reg rd_acki,wr_acki;
  94. assign rd_ack=rd_acki;
  95. assign wr_ack=wr_acki;
  96.  
  97. // Constrain assignments to $20xxxxxx-$3Fxxxxxx. Lower addresses will echo to upper ones.
  98. // Addresses sent to this module represent their exact address in HPS RAM.
  99. assign DDRAM_ADDR = {ram_address[28:3],3'b000};
  100. assign DDRAM_BURSTCNT = ram_burst;
  101. assign DDRAM_BE = ram_be;
  102. assign DDRAM_RD = ram_read;
  103. assign DDRAM_DIN = ram_data;
  104. assign DDRAM_WE = ram_write;
  105.  
  106. assign rd_d = cache[{rd_a[2:1], 4'b0000} +:16];
  107. assign rd_d8 = cache[{rd_a[2:0], 3'b000} +:8];
  108.  
  109. always @(posedge DDRAM_CLK) begin
  110. ddr_wait <= DDRAM_BUSY ? 4'b0010 : (ddr_wait ? (ddr_wait - 4'b0001) : 4'b0000);
  111. debug[7] <= {(ddr_wait ? 1'b1:1'b0),7'b0000000}; // Bit 7 DDR_WAIT
  112. if (RESET) begin // Sane startup defaults
  113. rd_acki <= 0;
  114. wr_acki <= 0;
  115. wr_pend <= 0;
  116. ddr_wait <= 0;
  117. w2_commit <= 0;
  118. rc_valid <= 2'b00; // Ensure first read fills new cache
  119. cache_wbe <= 8'b00000000;
  120. cache <= {64{1'b0}};
  121. w_addr <= 29'h1FFFFFFF;
  122. cache_addr <= 29'h1FFFFFFF;
  123. end else begin
  124. if (rd_req) begin // Read requests
  125. // Stuff we can do any time.
  126. if (rc_valid == 2'b00) begin
  127. // Immediately deal with the condition of cache being invalid
  128. debug[3:0] <= 4'b0111; // $7: Invalid read cache
  129. cache_addr <= ({rd_a[28:3],3'b000});
  130. rd_acki <= 0;
  131. end else if ((cache_addr[28:3] == rd_a[28:3]) && (rc_valid >= 1)) begin
  132. // Read from read cache requires no action
  133. debug[3:0] <= 4'b0001; // $1: Cache hit
  134. rd_acki <= 1;
  135. end else if (((cache_addr[28:3]+1'd1) == rd_a[28:3]) && (rc_valid >= 2)) begin
  136. debug[3:0] <= 4'b0010; // $2: Cache+1 hit
  137. // Shift all caches down 1 and invalidate cache 3
  138. w_addr <= {cache_addr[28:3],3'b000};
  139. w_be <= cache_wbe;
  140. wq <= cache;
  141. cache <= rq;
  142. rq <= rq2;
  143. cache_addr <= {rd_a[28:3],3'b000};
  144. cache_wbe <= 8'b00000000;
  145. rc_valid <= 2;
  146. rd_acki <= 1;
  147. end else if (((cache_addr[28:3]+2'd2) == rd_a[28:3]) && (rc_valid == 3)) begin
  148. debug[3:0] <= 4'b0011; // $3: Cache+2 hit
  149. // Shift all caches down 2 invalidate cache 2 and 3
  150. w_addr <= {cache_addr[28:3],3'b000};
  151. w_be <= cache_wbe;
  152. wq <= cache;
  153. cache <= rq2;
  154. cache_addr <= {rd_a[28:3],3'b000};
  155. cache_wbe <= 8'b00000000;
  156. rc_valid <= 1;
  157. rd_acki <= 1;
  158. end else if (w_addr || (w2_commit!=2'b00) || wr_pend || (rd_pend != 2'b00)) begin
  159. debug[3:0] <= 4'b0110; // $6: Cache miss, in wait
  160. // If a read cannot be satisfied by cache we must pause
  161. rd_acki <= 0;
  162. rc_valid <= 0;
  163. end else debug[3:0] <= 4'b0000; // $0: Read request, nothing happened
  164.  
  165. end
  166. if (wr_req) begin // Write requests
  167. debug[7] <= 0;
  168. // Stuff that can be done right away
  169. if (cache_addr[28:3] == wr_a[28:3]) begin
  170. // Write to read cache
  171. debug[3:0] <= 4'b1001; // $9: Read cache hit
  172. if (bus16) begin
  173. if (wr_be == 2'b00)
  174. cache_wbe <= cache_wbe | (8'b00000011 << (wr_a[2:1] << 1));
  175. else
  176. cache_wbe <= cache_wbe | ({6'b000000,wr_be} << (wr_a[2:1] << 1));
  177. cache[(wr_a[2:1] << 4) +:16] <= wr_d;
  178. end else begin
  179. cache_wbe[wr_a[2:0]] <= 1'b1;
  180. cache[(wr_a[2:0] << 3) +:8] <= wr_d8;
  181. end
  182. wr_acki <= 1;
  183. end else if (w2_a[28:3] == wr_a[28:3]) begin
  184. debug[3:0] <= 4'b1010; // $A: Write cache hit
  185. // Write to write cache
  186. if (bus16) begin
  187. if (wr_be == 2'b00)
  188. w2_be <= w2_be | (8'b00000011 << (wr_a[2:1] << 1));
  189. else
  190. w2_be <= w2_be | ({6'b000000,wr_be} << (wr_a[2:1] << 1));
  191. wq2[(wr_a[2:1] << 4) +:16] <= wr_d;
  192. end else begin
  193. w2_be[wr_a[2:0]] <= 1'b1;
  194. wq2[(wr_a[2:0] << 3) +:8] <= wr_d8;
  195. end
  196. wr_acki <= 1;
  197. end else if (!w2_commit) begin
  198. debug[3:0] <= 4'b1011; // $B: Write cache commit stage 1
  199. // Save the current transaction and commit write buffer
  200. t_d <= wr_d;
  201. t_d8 <= wr_d8;
  202. t_a <= wr_a;
  203. t_be <= wr_be;
  204. w2_commit <= 2;
  205. wr_acki <= 0;
  206. end else if (rd_pend || wr_pend || w_addr || w2_commit) begin
  207. debug[3:0] <= 4'b1100; // $C: Read/write cache miss
  208. // If a read or write is pending and we can't use the cache, we must pause.
  209. wr_acki <= 0;
  210. end else debug[3:0] <= 4'b1000; // $8: Write request, nothing happened
  211. end
  212. if (!ddr_wait) begin // Things we should do when the DDRAM is not busy
  213. // Signal end of read/write
  214. if (ram_write || ram_read) begin
  215. if (ram_write) begin
  216. ram_write <= 0;
  217. wr_pend <= 0;
  218. wr_acki <= 1;
  219. end
  220. if (ram_read) begin
  221. ram_read <= 0;
  222. end
  223. end
  224. if (!ram_write && w_addr) begin
  225. debug[6:4] <= 3'b010; // $2: Pipeline write commit
  226. // Commit the write pipeline cache
  227. ram_address <= w_addr;
  228. ram_be <= w_be;
  229. ram_data <= wq;
  230. ram_write <= 1;
  231. ram_burst <= 1;
  232. w_addr <= {29{1'b0}};
  233. wr_pend <= 1;
  234. end else if (!ram_read && rc_valid < 2'd3) begin
  235. debug[6:4] <= 1'b001; // $1 : Cache refill
  236. // Refill the cache when not busy
  237. ram_address <= {cache_addr[28:3]+rc_valid,3'b000};
  238. ram_be <= {8{1'b1}};
  239. ram_read <= 1;
  240. ram_burst <= (2'd3-rc_valid);
  241. rd_pend <= (2'd3-rc_valid);
  242. end else if (!ram_write && (w2_commit==2)) begin
  243. debug[6:4] <= 3'b011; // $3: Write cache commit stage 2
  244. // Commit the write buffer
  245. ram_address <= w2_a;
  246. ram_be <= w2_be;
  247. ram_data <= wq2;
  248. ram_write <= 1;
  249. ram_burst <= 1;
  250. w2_commit <= 1;
  251. wr_pend <= 1;
  252. end
  253. end else debug[6:4]=3'b000; // $0: DDR_WAIT | DDRAM_BUSY asserted
  254. end
  255. if (DDRAM_DOUT_READY) begin
  256. debug[6:4] <= 3'b100; // $4: DDRAM_DOUT_READY
  257. // Read data ready -- Refill cache
  258. rd_pend <= rd_pend - 1'b1;
  259. case (rc_valid)
  260. 0: cache <= DDRAM_DOUT;
  261. 1: rq <= DDRAM_DOUT;
  262. 2: rq2 <= DDRAM_DOUT;
  263. default: cache <= DDRAM_DOUT;
  264. endcase
  265. rc_valid <= rc_valid + 1'b1;
  266. rd_acki <= 1;
  267. end
  268. if (w2_commit==1) begin
  269. debug[6:4] <= 3'b101; // $5: New write cache
  270. // If Write buffer committed, make a new one.
  271. w2_a <= {t_a[28:3],3'b000};
  272. if (bus16) begin
  273. if (w2_be == 2'b00)
  274. w2_be <= (8'b00000011 << {t_a[2:1],1'b0});
  275. else
  276. w2_be <= ({6'b000000,t_be} << {t_a[2:1],1'b0});
  277. wq2 <= ({{48{1'b0}},t_d} << {t_a[2:1],4'b0000});
  278. end else begin
  279. w2_be <= 8'b00000001 << t_a[2:0];
  280. wq2 <= ({{56{1'b0}},t_d8} << {t_a[2:0],3'b000});
  281. end
  282. w2_commit <= 0;
  283. wr_acki <= 1;
  284. end
  285. if (!wr_req) wr_acki <= 0; // Drop my ack lines when
  286. if (!rd_req) rd_acki <= 0; // they drop their request
  287. end
  288. endmodule
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement