OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

[/] [openarty/] [trunk/] [rtl/] [wbucompress.v] - Blame information for rev 4

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    wbucompress.v
4
//
5
// Project:     FPGA library
6
//
7
// Purpose:     When reading many words that are identical, it makes no sense
8
//              to spend the time transmitting the same thing over and over
9
//      again, especially on a slow channel.  Hence this routine uses a table
10
//      lookup to see if the word to be transmitted was one from the recent
11
//      past.  If so, the word is replaced with an address of the recently
12
//      transmitted word.  Mind you, the table lookup takes one clock per table
13
//      entry, so even if a word is in the table it might not be found in time.
14
//      If the word is not in the table, or if it isn't found due to a lack of
15
//      time, the word is placed into the table while incrementing every other
16
//      table address.
17
//
18
//      Oh, and on a new address--the table is reset and starts over.  This way,
19
//      any time the host software changes, the host software will always start
20
//      by issuing a new address--hence the table is reset for every new piece
21
//      of software that may wish to communicate.
22
//
23
//
24
// Creator:     Dan Gisselquist, Ph.D.
25
//              Gisselquist Technology, LLC
26
//
27
////////////////////////////////////////////////////////////////////////////////
28
//
29
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
30
//
31
// This program is free software (firmware): you can redistribute it and/or
32
// modify it under the terms of  the GNU General Public License as published
33
// by the Free Software Foundation, either version 3 of the License, or (at
34
// your option) any later version.
35
//
36
// This program is distributed in the hope that it will be useful, but WITHOUT
37
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
38
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
39
// for more details.
40
//
41
// License:     GPL, v3, as defined and found on www.gnu.org,
42
//              http://www.gnu.org/licenses/gpl.html
43
//
44
//
45
////////////////////////////////////////////////////////////////////////////////
46
//
47
//
48
// All input words are valid codewords.  If we can, we make them
49
// better here.
50
module  wbucompress(i_clk, i_stb, i_codword, o_stb, o_cword, i_busy);
51
        parameter       DW=32, CW=36, TBITS=10;
52
        input                           i_clk, i_stb;
53
        input           [(CW-1):0]       i_codword;
54
        output  wire                    o_stb;
55
        output  wire    [(CW-1):0]       o_cword;
56
        input                           i_busy;
57
 
58
        //
59
        //
60
        // First stage is to compress the address.
61
        // This stage requires one clock.
62
        //
63
        //      ISTB,ICODWORD
64
        //      ISTB2,IWRD2     ASTB,AWORD
65
        //      ISTB3,IWRD3     ASTB2,AWRD2     I_BUSY(1)
66
        //      ISTB3,IWRD3     ASTB2,AWRD2     I_BUSY(1)
67
        //      ISTB3,IWRD3     ASTB2,AWRD2     I_BUSY(1)
68
        //      ISTB3,IWRD3     ASTB2,AWRD2     
69
        //      ISTB4,IWRD4     ASTB3,AWRD3     I_BUSY(2)
70
        //      ISTB4,IWRD4     ASTB3,AWRD3     I_BUSY(2)
71
        //      ISTB4,IWRD4     ASTB3,AWRD3     I_BUSY(2)
72
        reg             a_stb;
73
        reg     [35:0]   a_addrword;
74
        wire    [31:0]   w_addr;
75
        assign  w_addr = i_codword[31:0];
76
        always @(posedge i_clk)
77
                if ((i_stb)&&(~a_stb))
78
                begin
79
                        if (i_codword[35:32] != 4'h2)
80
                        begin
81
                                a_addrword <= i_codword;
82
                        end else if (w_addr[31:6] == 26'h00)
83
                                a_addrword <= { 6'hc, w_addr[ 5:0], 24'h00 };
84
                        else if (w_addr[31:12] == 20'h00)
85
                                a_addrword <= { 6'hd, w_addr[11:0], 18'h00 };
86
                        else if (w_addr[31:18] == 14'h00)
87
                                a_addrword <= { 6'he, w_addr[17:0], 12'h00 };
88
                        else if (w_addr[31:24] == 8'h00)
89
                                a_addrword <= { 6'hf, w_addr[23:0],  6'h00 };
90
                        else begin
91
                                a_addrword <= i_codword;
92
                        end
93
                end
94
        initial a_stb = 1'b0;
95
        always @(posedge i_clk)
96
                if ((i_stb)&&(~a_stb))
97
                        a_stb <= i_stb;
98
                else if (~i_busy)
99
                        a_stb <= 1'b0;
100
 
101
 
102
        //
103
        //
104
        // The next stage attempts to replace data codewords with previous
105
        // codewords that may have been sent.  The memory is only allowed
106
        // to be as old as the last new address command.  In this fashion,
107
        // any program that wishes to talk to the device can start with a
108
        // known compression table by simply setting the address and then
109
        // reading from the device.
110
        //
111
 
112
        // We start over any time a new value shows up, and 
113
        // the follow-on isn't busy and can take it.  Likewise,
114
        // we reset the writer on the compression any time a
115
        // i_clr value comes through (i.e., ~i_cyc or new
116
        // address)
117
 
118
        wire    w_accepted;
119
        assign  w_accepted = (a_stb)&&(~i_busy);
120
 
121
        reg             r_stb;
122
        always @(posedge i_clk)
123
                r_stb <= a_stb;
124
 
125
        wire    [35:0]   r_word;
126
        assign  r_word = a_addrword;
127
 
128
 
129
        //
130
        // First step of the compression is keeping track of a compression
131
        // table.  And the first part of that is keeping track of what address
132
        // to write into the compression table, and whether or not the entire
133
        // table is full or not.  This logic follows:
134
        //
135
        reg     [(TBITS-1):0]    tbl_addr;
136
        reg                     tbl_filled;
137
        // First part, write the compression table
138
        always @(posedge i_clk)
139
                // If we send a new address, then reset the table to empty
140
                if (w_accepted)
141
                begin
142
                        // Reset on new address (0010xx) and on new compressed
143
                        // addresses (0011ll).
144
                        if (o_cword[35:33]==3'h1)
145
                                tbl_addr <= 0;
146
                        // Otherwise, on any valid return result that wasn't
147
                        // from our table, for whatever reason (such as didn't
148
                        // have the clocks to find it, etc.), increment the
149
                        // address to add another value into our table
150
                        else if (o_cword[35:33] == 3'b111)
151
                                tbl_addr <= tbl_addr + {{(TBITS-1){1'b0}},1'b1};
152
                end
153
        always @(posedge i_clk)
154
                if ((w_accepted)&&(o_cword[35:33]==3'h1)) // on new address
155
                        tbl_filled <= 1'b0;
156
                else if (tbl_addr == 10'h3ff)
157
                        tbl_filled <= 1'b1;
158
 
159
        // Now that we know where we are writing into the table, and what
160
        // values of the table are valid, we need to actually write into
161
        // the table.
162
        //
163
        // We can keep this logic really simple by writing on every clock
164
        // and writing junk on many of those clocks, but we'll need to remember
165
        // that the value of the table at tbl_addr is unreliable until tbl_addr
166
        // changes.
167
        //
168
        reg     [31:0]   compression_tbl [0:((1<<TBITS)-1)];
169
        // Write new values into the table
170
        always @(posedge i_clk)
171
                compression_tbl[tbl_addr] <= { r_word[32:31], r_word[29:0] };
172
 
173
        // Now that we have a working table, can we use it?
174
        // On any new word, we'll start looking through our codewords.
175
        // If we find any that matches, we're there.  We might (or might not)
176
        // make it through the table first.  That's irrelevant.  We just look
177
        // while we can.
178
        reg                     tbl_match, nxt_match; // <= (nxt_rd_addr == tbl_addr);
179
        reg     [(TBITS-1):0]    rd_addr;
180
        reg     [(TBITS-1):0]    nxt_rd_addr;
181
        initial rd_addr = 0;
182
        initial tbl_match = 0;
183
        always @(posedge i_clk)
184
        begin
185
                nxt_match <= ((nxt_rd_addr-tbl_addr)=={{(TBITS-1){1'b0}},1'b1});
186
                if ((w_accepted)||(~a_stb))
187
                begin
188
                        // Keep in mind, if a write was just accepted, then
189
                        // rd_addr will need to be reset on the next clock
190
                        // when (~a_stb).  Hence this must be a two clock
191
                        // update
192
                        rd_addr <= tbl_addr + {(TBITS){1'b1}};
193
                        nxt_rd_addr = tbl_addr + { {(TBITS-1){1'b1}}, 1'b0 };
194
                        tbl_match <= 1'b0;
195
                end else if ((~tbl_match)&&(~match)
196
                                &&((~nxt_rd_addr[TBITS-1])||(tbl_filled)))
197
                begin
198
                        rd_addr <= nxt_rd_addr;
199
                        nxt_rd_addr = nxt_rd_addr - { {(TBITS-1){1'b0}}, 1'b1 };
200
                        tbl_match <= nxt_match;
201
                end
202
        end
203
 
204
        reg     [1:0]            pmatch;
205
        reg                     dmatch, // Match, on clock 'd'
206
                                vaddr;  // Was the address valid then?
207
        reg     [(DW-1):0]       cword;
208
        reg     [(TBITS-1):0]    caddr, daddr, maddr;
209
        always @(posedge i_clk)
210
        begin
211
                cword <= compression_tbl[rd_addr];
212
                caddr <= rd_addr;
213
 
214
                dmatch <= (cword == { r_word[32:31], r_word[29:0] });
215
                daddr  <= caddr;
216
                maddr  <= tbl_addr - caddr;
217
 
218
                vaddr <= ( {1'b0, caddr} < {tbl_filled, tbl_addr} )
219
                        &&(caddr != tbl_addr);
220
        end
221
 
222
        always @(posedge i_clk)
223
                if ((w_accepted)||(~a_stb))
224
                        pmatch <= 0; // rd_addr is set on this clock
225
                else
226
                        // cword is set on the next clock, pmatch = 3'b001
227
                        // dmatch is set on the next clock, pmatch = 3'b011
228
                        pmatch <= { pmatch[0], 1'b1 };
229
 
230
        reg             match;
231
        reg     [(TBITS-1):0]    matchaddr;
232
        always @(posedge i_clk)
233
                if((w_accepted)||(~a_stb)||(~r_stb))// Reset upon any write
234
                        match <= 1'b0;
235
                else if (~match)
236
                begin
237
                        // To be a match, the table must not be empty,
238
                        match <= (vaddr)&&(dmatch)&&(r_word[35:33]==3'b111)
239
                                        &&(pmatch == 2'b11);
240
                end
241
 
242
        reg     zmatch, hmatch, fmatch;
243
        always @(posedge i_clk)
244
                if (~match)
245
                begin
246
                        matchaddr <= maddr;
247
                        fmatch    <= (maddr < 10'h521);
248
                        zmatch    <= (maddr == 10'h1);
249
                        hmatch    <= (maddr < 10'd10);
250
                end
251
 
252
        // Did we find something?
253
        wire    [(TBITS-1):0]    adr_diff;
254
        wire    [9:0]            adr_dbld;
255
        wire    [2:0]            adr_hlfd;
256
        assign  adr_diff = matchaddr;
257
        assign  adr_hlfd = matchaddr[2:0]- 3'd2;
258
        assign  adr_dbld = matchaddr- 10'd10;
259
        reg     [(CW-1):0]       r_cword; // Record our result
260
        always @(posedge i_clk)
261
        begin
262
                if ((~a_stb)||(~r_stb)||(w_accepted))//Reset whenever word gets written
263
                begin
264
                        r_cword <= r_word;
265
                end else if ((match)&&(fmatch)) // &&(r_word == a_addrword))
266
                begin
267
                        r_cword <= r_word;
268
                        if (zmatch) // matchaddr == 1
269
                                r_cword[35:30] <= { 5'h3, r_word[30] };
270
                        else if (hmatch) // 2 <= matchaddr <= 9
271
                                r_cword[35:30] <= { 2'b10, adr_hlfd, r_word[30] };
272
                        else // if (adr_diff < 10'd521)
273
                                r_cword[35:24] <= { 2'b01, adr_dbld[8:6],
274
                                                r_word[30], adr_dbld[5:0] };
275
                end else
276
                        r_cword <= r_word;
277
        end
278
 
279
        // Can we do this without a clock delay?
280
        assign  o_stb = a_stb;
281
        assign  o_cword = (r_stb)?(r_cword):(a_addrword);
282
endmodule
283
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.