Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // bddram.v
- // Copyright (c) 2019 Alynna
- //
- //
- // This source file is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published
- // by the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This source file is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- // ------------------------------------------
- //
- module single_port_ram
- #(
- parameter DATA_WIDTH=64,
- parameter ADDR_WIDTH=7,
- parameter PAGE_WIDTH=7)
- (
- input [(DATA_WIDTH-1):0] data,
- input [(ADDR_WIDTH-1):0] addr,
- input [(PAGE_WIDTH-1):0] page,
- input we, clk,
- output [(DATA_WIDTH-1):0] q
- );
- // Declare the RAM variable
- reg [DATA_WIDTH-1:0] ram[(2**PAGE_WIDTH)-1:0][(2**ADDR_WIDTH)-1:0];
- // Variable to hold the registered read address
- reg [ADDR_WIDTH-1:0] addr_reg;
- reg [PAGE_WIDTH-1:0] page_reg;
- always @ (posedge clk)
- begin
- // Write
- if (we)
- ram[page][addr] <= data;
- page_reg <= page;
- addr_reg <= addr;
- end
- // Continuous assignment implies read returns NEW data.
- // This is the natural behavior of the TriMatrix memory
- // blocks in Single Port mode.
- assign q = ram[page_reg][addr_reg];
- endmodule
- module ddram #(
- parameter MODE = 0
- // MODE=0: 512M addressing space, risk to ASCAL (avoid using lowest 32M memory)
- // MODE=1: 256M addressing space at top of HPS RAM, use freely
- )
- (
- input DDRAM_CLK,
- inout [7:0] debug,
- input DDRAM_BUSY, // waitrequest
- output [7:0] DDRAM_BURSTCNT, // burstcount
- output [28:0] DDRAM_ADDR, // Exact HPS memory address
- input [63:0] DDRAM_DOUT, // readdata
- input DDRAM_DOUT_READY, // readdatavalid
- output DDRAM_RD, // read
- output [63:0] DDRAM_DIN, // writedata
- output [7:0] DDRAM_BE, // byteenable
- output DDRAM_WE, // write
- inout [1:0] cfg_req,
- input [31:0] wr_a,
- input [15:0] wr_d,
- input [7:0] wr_d8,
- input [1:0] wr_be,
- input wr_req,
- output wr_ack,
- input bus16,
- output [7:0] page,
- input [31:0] rd_a,
- output [15:0] rd_d,
- output [7:0] rd_d8,
- input rd_req,
- output rd_ack
- );
- localparam PAGES = 64; // I had to hardcode this..
- // Structure
- reg PAGE_SWAP [128-1:0]; // 1: Permitted to be swapped out
- reg [15:0] PAGE_AGE [128-1:0]; // Page ages
- reg PAGE_W [128-1:0]; // Set if a page has been written to
- reg [28:0] PAGE_ADDR [128-1:0]; // Page addresses in core - 1K boundaries
- wire BRAM_CLK;
- // Inferred BRAM
- single_port_ram #(
- .DATA_WIDTH(64), // Size of data bus, 64 is right
- .ADDR_WIDTH(7), // Size of burst length. 128 for now
- .PAGE_WIDTH(7) // 2**x = Number of pages (6=64)
- ) bram (
- .data(BIN),
- .addr(BADDR),
- .page(BPAGE),
- .we(BWE),
- .q(BOUT),
- .clk(BRAM_CLK)
- );
- wire [63:0] BIN, BOUT;
- wire [7:0] BPAGE;
- wire [6:0] BADDR;
- wire BWE;
- reg [7:0] ram_burst;
- reg [63:0] ram_data;
- reg [28:0] ram_address;
- reg ram_read = 0;
- reg ram_write = 0;
- reg rd_acki,wr_acki;
- assign DDRAM_ADDR = MODE ? {1'b0,ram_address[27:10],10'b0} : {ram_address[28:10],10'b0};
- assign DDRAM_BE = 8'b11111111;
- assign DDRAM_BURSTCNT = ram_burst;
- assign DDRAM_DIN = ram_data;
- assign DDRAM_RD = ram_read;
- assign DDRAM_WE = ram_write;
- assign rd_ack = rd_acki;
- assign wr_ack = wr_acki;
- reg [31:0] rd_addr, wr_addr;
- reg [15:0] rd_dat16, wr_dat16;
- reg [7:0] rd_dat8, wr_dat8;
- reg [1:0] wr_byteen;
- reg [7:0] rd_pend;
- reg [7:0] wr_pend;
- reg [7:0] sw_page; // Page being swapped
- reg [1:0] sw_pend;
- reg [1:0] phase;
- assign rd_d = rd_dat16;
- assign rd_d8 = rd_dat8;
- reg [7:0] x8, y8;
- reg [15:0] x16, y16;
- reg [7:0] signal;
- // 00: No errors
- // Bit 7: Any other errors
- // Bit 0: Page not found
- // 7: 1: Write / 0: Read
- // 6-5: phase;
- task age_pages;
- reg [7:0] p;
- begin
- for (p=0; p<128; p++) PAGE_AGE[p] <= (PAGE_AGE[p] == 16'hFFFF) ? 16'hFFFF : (PAGE_AGE[p] + 16'd1);
- end endtask
- task find_page_old;
- // Find the oldest page
- reg [7:0] p;
- reg [15:0] r;
- begin
- r <= 16'd0;
- for (p=127; p[7]; p--) begin
- if ((PAGE_SWAP[p]==1'b1) && (PAGE_AGE[p] > r)) begin
- r <= PAGE_AGE[p];
- page <= p;
- end
- end
- end endtask
- task find_page_a(reg [28:0] addr);
- // Find page matching the given address
- reg [7:0] p;
- begin
- signal[0] <= 1'b1;
- for (p=127; p[7]; p--) begin
- if (PAGE_ADDR[p][28:10]==addr[28:10]) begin
- signal[0] <= 1'b0;
- page <= p;
- end
- end
- end endtask
- task get16(reg [28:0] addr);
- // Get a 16 bit value if available in cache
- begin
- find_page_a(addr);
- if (!signal[0]) begin
- BWE <= 0;
- BPAGE <= page;
- BADDR <= addr[9:3];
- rd_dat16 <= BOUT[(addr[2:1] << 4) +:16];
- PAGE_AGE[page] <= 16'b0;
- rd_pend <= 8'hff;
- BRAM_CLK <= 1'b1;
- phase <= 2'b11;
- end
- end endtask
- task get8(reg [28:0] addr);
- // Get a 8 bit value if available in cache
- begin
- find_page_a(addr);
- if (!signal[0]) begin
- BWE <= 0;
- BPAGE <= page;
- BADDR <= addr[9:3];
- rd_dat8 <= BOUT[(addr[2:0] << 3) +:8];
- PAGE_AGE[page] <= 16'b0;
- rd_pend <= 8'hff;
- BRAM_CLK <= 1'b1;
- phase <= 2'b11;
- end
- end endtask
- task put16(reg [28:0] addr, reg [15:0] val);
- // Put a 16 bit value if its page is cached.
- begin
- find_page_a(addr);
- if (!signal[0]) begin
- BPAGE <= page;
- BADDR <= addr[9:3];
- BIN[(addr[2:1] << 4) +:16] <= val;
- BWE <= 1;
- PAGE_AGE[page] <= 16'b0;
- PAGE_W[page] <= 1'b1;
- wr_pend <= 8'hff;
- BRAM_CLK <= 1'b1;
- phase <= 2'b11;
- end else signal[0] <= 1'b1;
- end endtask
- task put8(reg [28:0] addr, reg [7:0] val);
- // Put an 8 bit value if its page is cached.
- begin
- find_page_a(addr);
- if (!signal[0]) begin
- BPAGE <= page;
- BADDR <= addr[9:3];
- BIN[(addr[2:1] << 3) +:8] <= val;
- BWE <= 1;
- PAGE_W[page] <= 1'b1;
- PAGE_AGE[page] <= 16'b0;
- wr_pend <= 8'hff;
- BRAM_CLK <= 1'b1;
- phase <= 2'b11;
- end else signal[0] <= 1'b1;
- end endtask
- task write_page_s(reg [6:0] p);
- // Begin process of sending a cache page to ddr3
- begin
- page <= p;
- BWE <= 0;
- BPAGE <= p;
- BADDR <= 0;
- ram_address <= PAGE_ADDR[page];
- ram_burst <= 8'd128;
- wr_pend <= 8'd127;
- BRAM_CLK <= 1;
- wr_acki <= 0;
- ram_write <= 0;
- end endtask
- task write_page_l(reg [6:0] p);
- // Continue write burst
- begin
- if (!DDRAM_BUSY && !wr_pend[7]) begin
- BADDR <= ~wr_pend[6:0];
- ram_data <= BOUT;
- BRAM_CLK <= 1'b0;
- ram_write <= 1'b1;
- end
- end endtask
- task write_page_h(reg [6:0] p);
- // Continue write burst
- begin
- if (!DDRAM_BUSY && !wr_pend[7]) begin
- wr_pend <= wr_pend - 8'd1;
- BRAM_CLK <= 1'b1;
- ram_write <= 1'b0;
- end
- end endtask
- task reset_page(reg [6:0] p, reg [15:0] addr, reg ptype=1'b1);
- // Reset the page and set a new address for it.
- begin
- page <= p;
- PAGE_ADDR[page] <= addr;
- PAGE_AGE[page] <= 16'b0;
- PAGE_SWAP[page] <= ptype;
- PAGE_W[page] <= 1'b0;
- end endtask
- task read_page_s(reg [6:0] p);
- // Begin process of getting a cache page from ddr3
- begin
- page <= p;
- BWE <= 1;
- BPAGE <= p;
- BADDR <= 0;
- ram_burst <= 8'd128;
- rd_pend <= 8'd127;
- BRAM_CLK <= 1'b0;
- ram_read <= 1'b1;
- rd_acki <= 0;
- end endtask
- task read_page_l(reg [6:0] p);
- // Continue read burst
- begin
- if (!DDRAM_BUSY && DDRAM_DOUT_READY && !rd_pend[7]) begin
- BADDR <= ~rd_pend[6:0];
- BIN <= DDRAM_DOUT;
- BRAM_CLK <= 1'b1;
- ram_read <= 1'b0;
- end
- end endtask
- task read_page_h(reg [6:0] p);
- // Continue read burst
- begin
- if (!DDRAM_BUSY && DDRAM_DOUT_READY && !rd_pend[7]) begin
- rd_pend <= rd_pend - 8'd1;
- BRAM_CLK <= 1'b0;
- ram_read <= 1'b1;
- end
- end endtask
- task page_sw_s;
- // Begin process of swapping a page out and bringing a new one in.
- // Page swapped out will be the least accessed page.
- reg [7:0] p;
- begin
- // We only have to write the page if its been updated
- find_page_old;
- sw_pend <= (PAGE_W[page] == 1'b1) ? 2'b01 : 2'b10;
- sw_page <= page;
- end endtask
- // CFG interface:
- // Use cfg_req:1 with rd_req:0 and wr_req:0 for the following tasks:
- // cfg_req:1 wr_d:16'd0 wr_d8:<page>: Make a page unswappable
- // cfg_req:1 wr_d:16'd1 wr_d8:<page>: Make a page swappable
- // cfg_req:1 wr_d:16'd2 Look up a page by address (returned in rd_d8)
- // cfg_req:1 wr_d:16'd3 wr_d8:<page> wr_a:<addr> Assign an address to a page
- // cfg_req:1 wr_d:16'd4 wr_d8:<page> Make a page young (age = 0)
- // cfg_req:1 wr_d:16'd5 wr_d8:<page> Make a page old (age = 65535)
- // cfg_req:1 wr_d:16'd7 wr_d8:<page> wr_a:<addr> Reset a page (does not commit it!)
- task cfg(reg [28:0] a, reg [15:0] f, reg [6:0] p);
- begin
- debug <= 8'b11100000;
- case (f)
- 16'd0: PAGE_SWAP[p] <= 1'b0;
- 16'd1: PAGE_SWAP[p] <= 1'b1;
- 16'd2: begin
- find_page_a(a);
- rd_dat8 <= page;
- end
- 16'd3: PAGE_ADDR[p] <= a;
- 16'd4: PAGE_AGE[p] <= 16'h0;
- 16'd5: PAGE_AGE[p] <= 16'hFFFF;
- 16'd7: reset_page(p, a, 1'b1);
- default: ;
- endcase
- end endtask
- // Phases:
- // 00: Ready for r/w request
- // 01: Initialize page swap
- // 02: Continue page swap
- // 03: Finalize transfer (wait for rd/wr req to go low
- reg [7:0] pg = 0;
- reg init = 0;
- always @(posedge DDRAM_CLK) begin
- if (!init) begin
- for (pg=0; pg < 128; pg++) begin // Cheap ass init block
- PAGE_ADDR[pg] <= 28'b0;
- PAGE_AGE[pg] <= 16'b0;
- PAGE_W[pg] <= 1'b0;
- PAGE_SWAP[pg] <= 1'b1;
- end
- rd_pend <= 8'hFF;
- wr_pend <= 8'hFF;
- phase <= 2'b00;
- init <= 1;
- end
- debug[6:5] <= phase;
- age_pages;
- if (phase == 2'b00) begin // Should be in phase 0 whenever we are ready to process requests.
- if (wr_req) begin
- debug[7] <= 1'b1;
- if (bus16)
- case (wr_be)
- 2'b00: ;
- 2'b01: put8(wr_a,wr_d[7:0]);
- 2'b10: put8(wr_a+1,wr_d[15:8]);
- 2'b11: put16(wr_a,wr_d);
- endcase
- else
- put8(wr_a, wr_d8);
- if (signal[0]) begin // Page not found
- page_sw_s;
- sw_page <= page;
- debug[4:0] <= {3'b001,sw_pend};
- case (sw_pend)
- 2'b01: write_page_s(sw_page);
- 2'b10: read_page_s(sw_page);
- default: ;
- endcase
- phase <= 2'b01;
- debug[4:0] <= {3'b001,sw_pend};
- end else begin
- phase <= 2'b11;
- end;
- end else if (rd_req) begin
- debug[7] <= 1'b0;
- if (bus16) get16(rd_a);
- else get8(rd_a);
- if (signal[0]) begin
- page_sw_s;
- sw_page <= page;
- case (sw_pend)
- 2'b01: write_page_s(sw_page);
- 2'b10: read_page_s(sw_page);
- default: ;
- endcase
- phase <= 2'b01;
- debug[4:0] <= {3'b001,sw_pend};
- end else phase <= 2'b11;
- end else if (!wr_req && !rd_req && cfg_req) begin
- debug <= 8'b11100111;
- cfg(wr_a, wr_d, wr_d8);
- cfg_req <= 1'b0;
- phase <= 2'b10;
- end
- end else if (phase == 2'b01) begin // Phase 1: Swap page
- case (sw_pend)
- 2'b01: write_page_l(sw_page);
- 2'b10: begin // Reset page and set address
- if (rd_req)
- reset_page(sw_page,rd_a);
- else
- reset_page(sw_page,wr_a);
- end
- 2'b11: begin // Read page from DDR3
- read_page_l(sw_page);
- end
- default: ;
- endcase
- phase <= 2'b10;
- debug <= {6'b101001,sw_pend};
- end else if (phase == 2'b10 || (!rd_req && !wr_req)) begin // Continue or end decision
- case (sw_pend)
- 2'b01: begin // Commit page to DDR3 (Skipped if no writes to the page)
- write_page_h(sw_page);
- if (wr_pend[7]) sw_pend <= 2'b10;
- end
- 2'b10: begin // Reset page and set address
- read_page_s(sw_page);
- sw_pend <= 2'b11;
- end
- 2'b11: begin // Read page from DDR3
- read_page_h(sw_page);
- if (rd_pend[7]) sw_pend <= 2'b00;
- end
- default: ;
- endcase
- BRAM_CLK <= 1'b0;
- if (rd_pend != 8'hFF || wr_pend != 8'hFF) begin
- phase <= 2'b01; // DDR3 burst continues
- end else begin
- phase <= 2'b00; // Retry RW
- end
- end else if (phase == 2'b11 || (!rd_req && !wr_req)) begin
- // Wait for the core to be ready
- // We also detect if theres no request being made
- // to allow the phase to be reset to 0.
- signal <= 8'b00000000;
- BWE <= 1'b0;
- BRAM_CLK <= 1'b0;
- if (rd_pend==8'hFF) rd_acki <= 1;
- if (wr_pend==8'hFF) wr_acki <= 1;
- end
- if (!wr_req) wr_acki <= 0;
- if (!rd_req) rd_acki <= 0;
- if (!wr_req && !rd_req) phase <= 2'b00;
- end
- endmodule
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement