Line 1... |
Line 1... |
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: wbucompress.v
|
// Filename: wbucompress.v
|
//
|
//
|
// Project: XuLA2 board
|
// Project: FPGA library
|
//
|
//
|
// Purpose: When reading many words that are identical, it makes no sense
|
// Purpose: When reading many words that are identical, it makes no sense
|
// to spend the time transmitting the same thing over and over
|
// to spend the time transmitting the same thing over and over
|
// again, especially on a slow channel. Hence this routine uses a table
|
// again, especially on a slow channel. Hence this routine uses a table
|
// lookup to see if the word to be transmitted was one from the recent
|
// lookup to see if the word to be transmitted was one from the recent
|
Line 24... |
Line 24... |
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// 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
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
Line 131... |
Line 131... |
// table. And the first part of that is keeping track of what address
|
// table. And the first part of that is keeping track of what address
|
// to write into the compression table, and whether or not the entire
|
// to write into the compression table, and whether or not the entire
|
// table is full or not. This logic follows:
|
// table is full or not. This logic follows:
|
//
|
//
|
reg [(TBITS-1):0] tbl_addr;
|
reg [(TBITS-1):0] tbl_addr;
|
reg r_compressed, tbl_filled;
|
reg tbl_filled;
|
// First part, write the compression table
|
// First part, write the compression table
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
// If we send a new address, then reset the table to empty
|
// If we send a new address, then reset the table to empty
|
if (w_accepted)
|
if (w_accepted)
|
begin
|
begin
|
Line 173... |
Line 173... |
// Now that we have a working table, can we use it?
|
// Now that we have a working table, can we use it?
|
// On any new word, we'll start looking through our codewords.
|
// On any new word, we'll start looking through our codewords.
|
// If we find any that matches, we're there. We might (or might not)
|
// If we find any that matches, we're there. We might (or might not)
|
// make it through the table first. That's irrelevant. We just look
|
// make it through the table first. That's irrelevant. We just look
|
// while we can.
|
// while we can.
|
|
reg tbl_match, nxt_match; // <= (nxt_rd_addr == tbl_addr);
|
reg [(TBITS-1):0] rd_addr;
|
reg [(TBITS-1):0] rd_addr;
|
wire [(TBITS-1):0] nxt_rd_addr;
|
reg [(TBITS-1):0] nxt_rd_addr;
|
assign nxt_rd_addr = rd_addr - { {(TBITS-1){1'b0}}, 1'b1 };
|
|
initial rd_addr = 0;
|
initial rd_addr = 0;
|
|
initial tbl_match = 0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
|
begin
|
|
nxt_match <= ((nxt_rd_addr-tbl_addr)=={{(TBITS-1){1'b0}},1'b1});
|
if ((w_accepted)||(~a_stb))
|
if ((w_accepted)||(~a_stb))
|
|
begin
|
// Keep in mind, if a write was just accepted, then
|
// Keep in mind, if a write was just accepted, then
|
// rd_addr will need to be reset on the next clock
|
// rd_addr will need to be reset on the next clock
|
// when (~a_stb). Hence this must be a two clock
|
// when (~a_stb). Hence this must be a two clock
|
// update
|
// update
|
rd_addr <= tbl_addr + {(TBITS){1'b1}};
|
rd_addr <= tbl_addr + {(TBITS){1'b1}};
|
else if ((nxt_rd_addr != tbl_addr)&&(~match)
|
nxt_rd_addr = tbl_addr + { {(TBITS-1){1'b1}}, 1'b0 };
|
|
tbl_match <= 1'b0;
|
|
end else if ((~tbl_match)&&(~match)
|
&&((~nxt_rd_addr[TBITS-1])||(tbl_filled)))
|
&&((~nxt_rd_addr[TBITS-1])||(tbl_filled)))
|
|
begin
|
rd_addr <= nxt_rd_addr;
|
rd_addr <= nxt_rd_addr;
|
|
nxt_rd_addr = nxt_rd_addr - { {(TBITS-1){1'b0}}, 1'b1 };
|
|
tbl_match <= nxt_match;
|
|
end
|
|
end
|
|
|
|
reg [1:0] pmatch;
|
|
reg dmatch, // Match, on clock 'd'
|
|
vaddr; // Was the address valid then?
|
reg [(DW-1):0] cword;
|
reg [(DW-1):0] cword;
|
reg [(TBITS-1):0] caddr;
|
reg [(TBITS-1):0] caddr, daddr, maddr;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
begin
|
begin
|
cword <= compression_tbl[rd_addr];
|
cword <= compression_tbl[rd_addr];
|
caddr <= rd_addr;
|
caddr <= rd_addr;
|
|
|
|
dmatch <= (cword == { r_word[32:31], r_word[29:0] });
|
|
daddr <= caddr;
|
|
maddr <= tbl_addr - caddr;
|
|
|
|
vaddr <= ( {1'b0, caddr} < {tbl_filled, tbl_addr} )
|
|
&&(caddr != tbl_addr);
|
end
|
end
|
|
|
|
always @(posedge i_clk)
|
|
if ((w_accepted)||(~a_stb))
|
|
pmatch <= 0; // rd_addr is set on this clock
|
|
else
|
|
// cword is set on the next clock, pmatch = 3'b001
|
|
// dmatch is set on the next clock, pmatch = 3'b011
|
|
pmatch <= { pmatch[0], 1'b1 };
|
|
|
reg match;
|
reg match;
|
reg [9:0] matchaddr;
|
reg [9:0] matchaddr;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if((w_accepted)||(~a_stb)||(~r_stb))// Reset upon any write
|
if((w_accepted)||(~a_stb)||(~r_stb))// Reset upon any write
|
match <= 1'b0;
|
match <= 1'b0;
|
else if (~match)
|
else if (~match)
|
begin
|
begin
|
// To be a match, the table must not be empty,
|
// To be a match, the table must not be empty,
|
match <= (({1'b0, caddr } < {tbl_filled, tbl_addr}))
|
match <= (vaddr)&&(dmatch)&&(r_word[35:33]==3'b111)
|
// the word we are matching to must be
|
&&(pmatch == 2'b11);
|
// in the form of a read command
|
end
|
&&(r_word[35:33] == 3'b111)
|
|
// And the word in the table must be
|
reg zmatch, hmatch, fmatch;
|
// identical to the word we are about
|
always @(posedge i_clk)
|
// to send.
|
if (~match)
|
&&(cword == { r_word[32:31], r_word[29:0] });
|
begin
|
matchaddr <= tbl_addr-caddr;
|
matchaddr <= maddr;
|
|
fmatch <= (maddr < 10'h521);
|
|
zmatch <= (maddr == 10'h1);
|
|
hmatch <= (maddr < 10'd10);
|
end
|
end
|
|
|
// Did we find something?
|
// Did we find something?
|
wire [(TBITS-1):0] adr_diff;
|
wire [(TBITS-1):0] adr_diff;
|
wire [9:0] adr_dbld;
|
wire [9:0] adr_dbld;
|
wire [2:0] adr_hlfd;
|
wire [2:0] adr_hlfd;
|
assign adr_diff = matchaddr;
|
assign adr_diff = matchaddr;
|
assign adr_hlfd = matchaddr[2:0]- 3'd2;
|
assign adr_hlfd = matchaddr[2:0]- 3'd2;
|
assign adr_dbld = matchaddr- 10'd10;
|
assign adr_dbld = matchaddr- 10'd10;
|
initial r_compressed = 1'b0;
|
|
reg [(CW-1):0] r_cword; // Record our result
|
reg [(CW-1):0] r_cword; // Record our result
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
begin
|
begin
|
if ((~a_stb)||(~r_stb)||(w_accepted))//Reset whenever word gets written
|
if ((~a_stb)||(~r_stb)||(w_accepted))//Reset whenever word gets written
|
r_compressed <= 1'b0; // to our output
|
|
else if (r_compressed)//Already compressed, wait 'til sent
|
|
;
|
|
else if ((match)&&(matchaddr < 10'd521)) // &&(r_word == a_addrword))
|
|
begin
|
begin
|
if (matchaddr == 10'h1)
|
r_cword <= r_word;
|
|
end else if ((match)&&(fmatch)) // &&(r_word == a_addrword))
|
|
begin
|
|
r_cword <= r_word;
|
|
if (zmatch) // matchaddr == 1
|
r_cword[35:30] <= { 5'h3, r_word[30] };
|
r_cword[35:30] <= { 5'h3, r_word[30] };
|
else if (adr_diff < 10'd10)
|
else if (hmatch) // 2 <= matchaddr <= 9
|
r_cword[35:30] <= { 2'b10, adr_hlfd, r_word[30] };
|
r_cword[35:30] <= { 2'b10, adr_hlfd, r_word[30] };
|
else // if (adr_diff < 10'd521)
|
else // if (adr_diff < 10'd521)
|
r_cword[35:24] <= { 2'b01, adr_dbld[8:6],
|
r_cword[35:24] <= { 2'b01, adr_dbld[8:6],
|
r_word[30], adr_dbld[5:0] };
|
r_word[30], adr_dbld[5:0] };
|
r_compressed <= 1'b1;
|
|
end else
|
end else
|
r_cword <= r_word;
|
r_cword <= r_word;
|
end
|
end
|
|
|
// Can we do this without a clock delay?
|
// Can we do this without a clock delay?
|
assign o_stb = a_stb;
|
assign o_stb = a_stb;
|
assign o_cword = (r_compressed)?(r_cword):(a_addrword);
|
assign o_cword = (r_stb)?(r_cword):(a_addrword);
|
endmodule
|
endmodule
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|