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

Subversion Repositories video_stream_scaler

[/] [video_stream_scaler/] [trunk/] [rtl/] [verilog/] [scaler.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 tesla500
/*-----------------------------------------------------------------------------
2
 
3
                                                                Video Stream Scaler
4
 
5
                                                        Author: David Kronstein
6
 
7
 
8
 
9
Copyright 2011, David Kronstein, and individual contributors as indicated
10
by the @authors tag.
11
 
12
This is free software; you can redistribute it and/or modify it
13
under the terms of the GNU Lesser General Public License as
14
published by the Free Software Foundation; either version 2.1 of
15
the License, or (at your option) any later version.
16
 
17
This software is distributed in the hope that it will be useful,
18
but WITHOUT ANY WARRANTY; without even the implied warranty of
19
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
Lesser General Public License for more details.
21
 
22
You should have received a copy of the GNU Lesser General Public
23
License along with this software; if not, write to the Free
24
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25
02110-1301 USA, or see the FSF site: http://www.fsf.org.
26
 
27
 
28
-------------------------------------------------------------------------------
29
 
30
Scales streaming video up or down in resolution. Bilinear and nearest neighbor
31
modes are supported.
32
 
33
Run-time adjustment of input and output resolution, scaling factors, and scale
34
type.
35
 
36
-------------------------------------------------------------------------------
37
 
38
Revisions
39
 
40
V1.0.0  Feb 21 2011             Initial Release         David Kronstein
41
Known bugs:
42
Very slight numerical errors (+0/-2 LSb) in output data due to coefficient arithmetic.
43
Impossible to notice without adjustment in video levels. Attempted to fix by setting
44
coeff11 to 1.0 - other coefficients, but this caused timing issues.
45
 
46
*/
47
`default_nettype none
48
 
49
module streamScaler #(
50
//---------------------------Parameters----------------------------------------
51
parameter       DATA_WIDTH =                    8,              //Width of input/output data
52
parameter       CHANNELS =                              1,              //Number of channels of DATA_WIDTH, for color images
53
parameter       DISCARD_CNT_WIDTH =             8,              //Width of inputDiscardCnt
54
parameter       INPUT_X_RES_WIDTH =             11,             //Widths of input/output resolution control signals
55
parameter       INPUT_Y_RES_WIDTH =             11,
56
parameter       OUTPUT_X_RES_WIDTH =    11,
57
parameter       OUTPUT_Y_RES_WIDTH =    11,
58
parameter       FRACTION_BITS =                 8,              //Number of bits for fractional component of coefficients.
59
 
60
parameter       SCALE_INT_BITS =                4,              //Width of integer component of scaling factor. The maximum input data width to
61
                                                                                        //multipliers created will be SCALE_INT_BITS + SCALE_FRAC_BITS. Typically these
62
                                                                                        //values will sum to 18 to match multipliers available in FPGAs.
63
parameter       SCALE_FRAC_BITS =               14,             //Width of fractional component of scaling factor
64
parameter       BUFFER_SIZE =                   4,              //Depth of RFIFO
65
//---------------------Non-user-definable parameters----------------------------
66
parameter       COEFF_WIDTH =                   FRACTION_BITS + 1,
67
parameter       SCALE_BITS =                    SCALE_INT_BITS + SCALE_FRAC_BITS,
68
parameter       BUFFER_SIZE_WIDTH =             ((BUFFER_SIZE+1) <= 2) ? 1 :    //wide enough to hold value BUFFER_SIZE + 1
69
                                                                        ((BUFFER_SIZE+1) <= 4) ? 2 :
70
                                                                        ((BUFFER_SIZE+1) <= 8) ? 3 :
71
                                                                        ((BUFFER_SIZE+1) <= 16) ? 4 :
72
                                                                        ((BUFFER_SIZE+1) <= 32) ? 5 :
73
                                                                        ((BUFFER_SIZE+1) <= 64) ? 6 : 7
74
)(
75
//---------------------------Module IO-----------------------------------------
76
//Clock and reset
77
input wire                                                      clk,
78
input wire                                                      rst,
79
 
80
//User interface
81
//Input
82
input wire [DATA_WIDTH*CHANNELS-1:0]dIn,
83
input wire                                                      dInValid,
84
output wire                                                     nextDin,
85
input wire                                                      start,
86
 
87
//Output
88
output reg [DATA_WIDTH*CHANNELS-1:0]
89
                                                                        dOut,
90
output reg                                                      dOutValid,                      //latency of 4 clock cycles after nextDout is asserted
91
input wire                                                      nextDout,
92
 
93
//Control
94
input wire [DISCARD_CNT_WIDTH-1:0]       inputDiscardCnt,        //Number of input pixels to discard before processing data. Used for clipping
95
input wire [INPUT_X_RES_WIDTH-1:0]       inputXRes,                      //Resolution of input data minus 1
96
input wire [INPUT_Y_RES_WIDTH-1:0]       inputYRes,
97
input wire [OUTPUT_X_RES_WIDTH-1:0]      outputXRes,                     //Resolution of output data minus 1
98
input wire [OUTPUT_Y_RES_WIDTH-1:0]      outputYRes,
99
input wire [SCALE_BITS-1:0]                      xScale,                         //Scaling factors. Input resolution scaled up by 1/xScale. Format Q SCALE_INT_BITS.SCALE_FRAC_BITS
100
input wire [SCALE_BITS-1:0]                      yScale,                         //Scaling factors. Input resolution scaled up by 1/yScale. Format Q SCALE_INT_BITS.SCALE_FRAC_BITS
101
 
102
input wire [OUTPUT_X_RES_WIDTH-1+SCALE_FRAC_BITS:0]
103
                                                                        leftOffset,                     //Integer/fraction of input pixel to offset output data horizontally right. Format Q OUTPUT_X_RES_WIDTH.SCALE_FRAC_BITS
104
input wire [SCALE_FRAC_BITS-1:0] topFracOffset,          //Fraction of input pixel to offset data vertically down. Format Q0.SCALE_FRAC_BITS
105
input wire                                                      nearestNeighbor         //Use nearest neighbor resize instead of bilinear
106
);
107
//-----------------------Internal signals and registers------------------------
108
reg                                                             advanceRead1;
109
reg                                                             advanceRead2;
110
 
111
wire [DATA_WIDTH*CHANNELS-1:0]   readData00;
112
wire [DATA_WIDTH*CHANNELS-1:0]   readData01;
113
wire [DATA_WIDTH*CHANNELS-1:0]   readData10;
114
wire [DATA_WIDTH*CHANNELS-1:0]   readData11;
115
reg [DATA_WIDTH*CHANNELS-1:0]    readData00Reg;
116
reg [DATA_WIDTH*CHANNELS-1:0]    readData01Reg;
117
reg [DATA_WIDTH*CHANNELS-1:0]    readData10Reg;
118
reg [DATA_WIDTH*CHANNELS-1:0]    readData11Reg;
119
 
120
wire [INPUT_X_RES_WIDTH-1:0]     readAddress;
121
 
122
reg                                                     readyForRead;           //Indicates two full lines have been put into the buffer
123
reg [OUTPUT_Y_RES_WIDTH-1:0]     outputLine;                     //which output video line we're on
124
reg [OUTPUT_X_RES_WIDTH-1:0]     outputColumn;           //which output video column we're on
125
reg [INPUT_X_RES_WIDTH-1+SCALE_FRAC_BITS:0]
126
                                                                xScaleAmount;           //Fractional and integer components of input pixel select (multiply result)
127
reg [INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:0]
128
                                                                yScaleAmount;           //Fractional and integer components of input pixel select (multiply result)
129
reg [INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:0]
130
                                                                yScaleAmountNext;       //Fractional and integer components of input pixel select (multiply result)
131
wire [BUFFER_SIZE_WIDTH-1:0]     fillCount;                      //Numbers used rams in the ram fifo
132
reg                                     lineSwitchOutputDisable; //On the end of an output line, disable the output for one cycle to let the RAM data become valid
133
reg                                                             dOutValidInt;
134
 
135
reg [COEFF_WIDTH-1:0]                    xBlend;
136
wire [COEFF_WIDTH-1:0]                   yBlend = {1'b0, yScaleAmount[SCALE_FRAC_BITS-1:SCALE_FRAC_BITS-FRACTION_BITS]};
137
 
138
wire [INPUT_X_RES_WIDTH-1:0]     xPixLow = xScaleAmount[INPUT_X_RES_WIDTH-1+SCALE_FRAC_BITS:SCALE_FRAC_BITS];
139
wire [INPUT_Y_RES_WIDTH-1:0]     yPixLow = yScaleAmount[INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:SCALE_FRAC_BITS];
140
wire [INPUT_Y_RES_WIDTH-1:0]     yPixLowNext = yScaleAmountNext[INPUT_Y_RES_WIDTH-1+SCALE_FRAC_BITS:SCALE_FRAC_BITS];
141
 
142
wire                                                    allDataWritten;         //Indicates that all data from input has been read in
143
reg                                                     readState;
144
 
145
//States for read state machine
146
parameter RS_START = 0;
147
parameter RS_READ_LINE = 1;
148
 
149
//Read state machine
150
//Controls the RFIFO(ram FIFO) readout and generates output data valid signals
151
always @ (posedge clk or posedge rst or posedge start)
152
begin
153
        if(rst | start)
154
        begin
155
                outputLine <= 0;
156
                outputColumn <= 0;
157
                xScaleAmount <= 0;
158
                yScaleAmount <= 0;
159
                readState <= RS_START;
160
                dOutValidInt <= 0;
161
                lineSwitchOutputDisable <= 0;
162
                advanceRead1 <= 0;
163
                advanceRead2 <= 0;
164
                yScaleAmountNext <= 0;
165
        end
166
        else
167
        begin
168
                case (readState)
169
 
170
                        RS_START:
171
                        begin
172
                                xScaleAmount <= leftOffset;
173
                                yScaleAmount <= {{INPUT_Y_RES_WIDTH{1'b0}}, topFracOffset};
174
                                if(readyForRead)
175
                                begin
176
                                        readState <= RS_READ_LINE;
177
                                        dOutValidInt <= 1;
178
                                end
179
                        end
180
 
181
                        RS_READ_LINE:
182
                        begin
183
 
184
                                //outputLine goes through all output lines, and the logic determines which input lines to read into the RRB and which ones to discard.
185
                                if(nextDout && dOutValidInt)
186
                                begin
187
                                        if(outputColumn == outputXRes)
188
                                        begin //On the last input pixel of the line
189
                                                if(yPixLowNext == (yPixLow + 1))    //If the next input line is only one greater, advance the RRB by one only
190
                                                begin
191
                                                        advanceRead1 <= 1;
192
                                                        if(fillCount < 3)               //If the RRB doesn't have enough data, stop reading it out
193
                                                                dOutValidInt <= 0;
194
                                                end
195
                                                else if(yPixLowNext > (yPixLow + 1))  //If the next input line is two or more greater, advance the read by two
196
                                                begin
197
                                                        advanceRead2 <= 1;
198
                                                        if(fillCount < 4)               //If the RRB doesn't have enough data, stop reading it out
199
                                                                dOutValidInt <= 0;
200
                                                end
201
 
202
                                                outputColumn <= 0;
203
                                                xScaleAmount <= leftOffset;
204
                                                outputLine <= outputLine + 1;
205
                                                yScaleAmount <= yScaleAmountNext;
206
                                                lineSwitchOutputDisable <= 1;
207
                                        end
208
                                        else
209
                                        begin
210
                                                //Advance the output pixel selection values except when waiting for the ram data to become valid
211
                                                if(lineSwitchOutputDisable == 0)
212
                                                begin
213
                                                        outputColumn <= outputColumn + 1;
214
                                                        xScaleAmount <= (outputColumn + 1) * xScale + leftOffset;
215
                                                end
216
                                                advanceRead1 <= 0;
217
                                                advanceRead2 <= 0;
218
                                                lineSwitchOutputDisable <= 0;
219
                                        end
220
                                end
221
                                else //else from if(nextDout && dOutValidInt)
222
                                begin
223
                                        advanceRead1 <= 0;
224
                                        advanceRead2 <= 0;
225
                                        lineSwitchOutputDisable <= 0;
226
                                end
227
 
228
                                //Once the RRB has enough data, let data be read from it. If all input data has been written, always allow read
229
                                if(fillCount >= 2 && dOutValidInt == 0 || allDataWritten)
230
                                begin
231
                                        if((!advanceRead1 && !advanceRead2))
232
                                        begin
233
                                                dOutValidInt <= 1;
234
                                                lineSwitchOutputDisable <= 0;
235
                                        end
236
                                end
237
                        end//state RS_READ_LINE:
238
                endcase
239
 
240
                //yScaleAmountNext is used to determine which input lines are valid.
241
                yScaleAmountNext <= (outputLine + 1) * yScale + {{OUTPUT_Y_RES_WIDTH{1'b0}}, topFracOffset};
242
        end
243
end
244
 
245
assign readAddress = xPixLow;
246
 
247
//Generate dOutValid signal, delayed to account for delays in data path
248
reg dOutValid_1;
249
reg dOutValid_2;
250
reg dOutValid_3;
251
 
252
always @(posedge clk or posedge rst)
253
begin
254
        if(rst)
255
        begin
256
                dOutValid_1 <= 0;
257
                dOutValid_2 <= 0;
258
                dOutValid_3 <= 0;
259
                dOutValid <= 0;
260
        end
261
        else
262
        begin
263
                dOutValid_1 <= nextDout && dOutValidInt && !lineSwitchOutputDisable;
264
                dOutValid_2 <= dOutValid_1;
265
                dOutValid_3 <= dOutValid_2;
266
                dOutValid <= dOutValid_3;
267
        end
268
end
269
 
270
//-----------------------Output data generation-----------------------------
271
//Scale amount values are used to generate coefficients for the four pixels coming out of the RRB to be multiplied with.
272
 
273
//Coefficients for each of the four pixels
274
//Format Q1.FRACTION_BITS
275
//                         yx
276
reg [COEFF_WIDTH-1:0]    coeff00;                //Top left
277
reg [COEFF_WIDTH-1:0]    coeff01;                //Top right
278
reg [COEFF_WIDTH-1:0]    coeff10;                //Bottom left
279
reg [COEFF_WIDTH-1:0]    coeff11;                //Bottom right
280
 
281
//Coefficient value of one, format Q1.COEFF_WIDTH-1
282
wire [COEFF_WIDTH-1:0]   coeffOne = {1'b1, {(COEFF_WIDTH-1){1'b0}}};     //One in MSb, zeros elsewhere
283
//Coefficient value of one half, format Q1.COEFF_WIDTH-1
284
wire [COEFF_WIDTH-1:0]   coeffHalf = {2'b01, {(COEFF_WIDTH-2){1'b0}}};
285
 
286
//Compute bilinear interpolation coefficinets. Done here because these pre-registerd values are used twice.
287
//Adding coeffHalf to get the nearest value.
288
wire [COEFF_WIDTH-1:0]   preCoeff00 = (((coeffOne - xBlend) * (coeffOne - yBlend) + (coeffHalf - 1)) >> FRACTION_BITS) &         {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}};
289
wire [COEFF_WIDTH-1:0]   preCoeff01 = ((xBlend * (coeffOne - yBlend) + (coeffHalf - 1)) >> FRACTION_BITS) &                              {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}};
290
wire [COEFF_WIDTH-1:0]   preCoeff10 = (((coeffOne - xBlend) * yBlend + (coeffHalf - 1)) >> FRACTION_BITS) &                              {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}};
291
 
292
//Compute the coefficients
293
always @(posedge clk or posedge rst)
294
begin
295
        if(rst)
296
        begin
297
                coeff00 <= 0;
298
                coeff01 <= 0;
299
                coeff10 <= 0;
300
                coeff11 <= 0;
301
                xBlend <= 0;
302
        end
303
        else
304
        begin
305
                xBlend <= {1'b0, xScaleAmount[SCALE_FRAC_BITS-1:SCALE_FRAC_BITS-FRACTION_BITS]};        //Changed to registered to improve timing
306
 
307
                if(nearestNeighbor == 1'b0)
308
                begin
309
                        //Normal bilinear interpolation
310
                        coeff00 <= preCoeff00;
311
                        coeff01 <= preCoeff01;
312
                        coeff10 <= preCoeff10;
313
                        coeff11 <= ((xBlend * yBlend + (coeffHalf - 1)) >> FRACTION_BITS) &                                                             {{COEFF_WIDTH{1'b0}}, {COEFF_WIDTH{1'b1}}};
314
                        //coeff11 <= coeffOne - preCoeff00 - preCoeff01 - preCoeff10;           //Guarantee that all coefficients sum to coeffOne. Saves a multiply too. Reverted to previous method due to timing issues.
315
                end
316
                else
317
                begin
318
                        //Nearest neighbor interploation, set one coefficient to 1.0, the rest to zero based on the fractions
319
                        coeff00 <= xBlend < coeffHalf && yBlend < coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}};
320
                        coeff01 <= xBlend >= coeffHalf && yBlend < coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}};
321
                        coeff10 <= xBlend < coeffHalf && yBlend >= coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}};
322
                        coeff11 <= xBlend >= coeffHalf && yBlend >= coeffHalf ? coeffOne : {COEFF_WIDTH{1'b0}};
323
                end
324
        end
325
end
326
 
327
 
328
//Generate the blending multipliers
329
reg [(DATA_WIDTH+COEFF_WIDTH)*CHANNELS-1:0]      product00, product01, product10, product11;
330
 
331
generate
332
genvar channel;
333
        for(channel = 0; channel < CHANNELS; channel = channel + 1)
334
                begin : blend_mult_generate
335
                        always @(posedge clk or posedge rst)
336
                        begin
337
                                if(rst)
338
                                begin
339
                                        //productxx[channel] <= 0;
340
                                        product00[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0;
341
                                        product01[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0;
342
                                        product10[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0;
343
                                        product11[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= 0;
344
 
345
                                        //readDataxxReg[channel] <= 0;
346
                                        readData00Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0;
347
                                        readData01Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0;
348
                                        readData10Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0;
349
                                        readData11Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0;
350
 
351
                                        //dOut[channel] <= 0;
352
                                        dOut[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= 0;
353
                                end
354
                                else
355
                                begin
356
                                        //readDataxxReg[channel] <= readDataxx[channel];
357
                                        readData00Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData00[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ];
358
                                        readData01Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData01[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ];
359
                                        readData10Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData10[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ];
360
                                        readData11Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <= readData11[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ];
361
 
362
                                        //productxx[channel] <= readDataxxReg[channel] * coeffxx
363
                                        product00[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData00Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff00;
364
                                        product01[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData01Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff01;
365
                                        product10[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData10Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff10;
366
                                        product11[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel] <= readData11Reg[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] * coeff11;
367
 
368
                                        //dOut[channel] <= (((product00[channel]) + 
369
                                        //                                      (product01[channel]) +
370
                                        //                                      (product10[channel]) +
371
                                        //                                      (product11[channel])) >> FRACTION_BITS) & ({ {COEFF_WIDTH{1'b0}}, {DATA_WIDTH{1'b1}} });
372
                                        dOut[ DATA_WIDTH*(channel+1)-1 : DATA_WIDTH*channel ] <=
373
                                                        (((product00[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel]) +
374
                                                        (product01[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel]) +
375
                                                        (product10[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel]) +
376
                                                        (product11[ (DATA_WIDTH+COEFF_WIDTH)*(channel+1)-1 : (DATA_WIDTH+COEFF_WIDTH)*channel])) >> FRACTION_BITS) & ({ {COEFF_WIDTH{1'b0}}, {DATA_WIDTH{1'b1}} });
377
                                end
378
                        end
379
                end
380
endgenerate
381
 
382
 
383
//---------------------------Data write logic----------------------------------
384
//Places input data into the correct ram in the RFIFO (ram FIFO)
385
//Controls writing to the RFIFO, and discards lines that arn't used
386
 
387
reg [INPUT_Y_RES_WIDTH-1:0]              writeNextValidLine;     //Which line greater than writeRowCount is the next one that must be read in
388
reg [INPUT_Y_RES_WIDTH-1:0]              writeNextPlusOne;       //One greater than writeNextValidLine, because we must always read in two adjacent lines
389
reg [INPUT_Y_RES_WIDTH-1:0]              writeRowCount;          //Which line we're reading from dIn
390
reg [OUTPUT_Y_RES_WIDTH-1:0]     writeOutputLine;        //The output line that corresponds to the input line. This is incremented until writeNextValidLine is greater than writeRowCount
391
reg                                                             getNextPlusOne;         //Flag so that writeNextPlusOne is captured only once after writeRowCount >= writeNextValidLine. This is in case multiple cycles are requred until writeNextValidLine changes.
392
 
393
//Determine which lines to read out and which to discard.
394
//writeNextValidLine is the next valid line number that needs to be read out above current value writeRowCount
395
//writeNextPlusOne also needs to be read out (to do interpolation), this may or may not be equal to writeNextValidLine
396
always @(posedge clk or posedge rst or posedge start)
397
begin
398
        if(rst | start)
399
        begin
400
                writeOutputLine <= 0;
401
                writeNextValidLine <= 0;
402
                writeNextPlusOne <= 1;
403
                getNextPlusOne <= 1;
404
        end
405
        else
406
        begin
407
                if(writeRowCount >= writeNextValidLine) //When writeRowCount becomes higher than the next valid line to read out, comptue the next valid line.
408
                begin
409
                        if(getNextPlusOne)                      //Keep writeNextPlusOne
410
                        begin
411
                                writeNextPlusOne <= writeNextValidLine + 1;
412
                        end
413
                        getNextPlusOne <= 0;
414
                        writeOutputLine <= writeOutputLine + 1;
415
                        writeNextValidLine <= ((writeOutputLine*yScale + {{(OUTPUT_Y_RES_WIDTH + SCALE_INT_BITS){1'b0}}, topFracOffset}) >> SCALE_FRAC_BITS) & {{SCALE_BITS{1'b0}}, {OUTPUT_Y_RES_WIDTH{1'b1}}};
416
                end
417
                else
418
                begin
419
                        getNextPlusOne <= 1;
420
                end
421
        end
422
end
423
 
424
reg                     discardInput;
425
reg [DISCARD_CNT_WIDTH-1:0] discardCountReg;
426
wire            advanceWrite;
427
 
428
reg [1:0]        writeState;
429
 
430
reg [INPUT_X_RES_WIDTH-1:0] writeColCount;
431
reg                     enableNextDin;
432
reg                     forceRead;
433
 
434
//Write state machine
435
//Controls writing scaler input data into the RRB
436
 
437
parameter       WS_START = 0;
438
parameter       WS_DISCARD = 1;
439
parameter       WS_READ = 2;
440
parameter       WS_DONE = 3;
441
 
442
//Control write and address signals to write data into ram FIFO
443
always @ (posedge clk or posedge rst or posedge start)
444
begin
445
        if(rst | start)
446
        begin
447
                writeState <= WS_START;
448
                enableNextDin <= 0;
449
                discardInput <= 0;
450
                readyForRead <= 0;
451
                writeRowCount <= 0;
452
                writeColCount <= 0;
453
                discardCountReg <= 0;
454
                forceRead <= 0;
455
        end
456
        else
457
        begin
458
                case (writeState)
459
 
460
                        WS_START:
461
                        begin
462
                                discardCountReg <= inputDiscardCnt;
463
                                if(inputDiscardCnt > 0)
464
                                begin
465
                                        discardInput <= 1;
466
                                        enableNextDin <= 1;
467
                                        writeState <= WS_DISCARD;
468
                                end
469
                                else
470
                                begin
471
                                        discardInput <= 0;
472
                                        enableNextDin <= 1;
473
                                        writeState <= WS_READ;
474
                                end
475
                                discardInput <= (inputDiscardCnt > 0) ? 1'b1 : 1'b0;
476
                        end
477
 
478
                        WS_DISCARD:     //Discard pixels from input data
479
                        begin
480
                                if(dInValid)
481
                                begin
482
                                        discardCountReg <= discardCountReg - 1;
483
                                        if((discardCountReg - 1) == 0)
484
                                        begin
485
                                                discardInput <= 0;
486
                                                writeState <= WS_READ;
487
                                        end
488
                                end
489
                        end
490
 
491
                        WS_READ:
492
                        begin
493
                                if(dInValid & nextDin)
494
                                begin
495
                                        if(writeColCount == inputXRes)
496
                                        begin   //Occurs on the last pixel in the line
497
                                                if((writeNextValidLine == writeRowCount + 1) ||
498
                                                        (writeNextPlusOne == writeRowCount + 1))
499
                                                begin //Next line is valid, write into buffer
500
                                                        discardInput <= 0;
501
                                                end
502
                                                else
503
                                                begin   //Next line is not valid, discard
504
                                                        discardInput <= 1;
505
                                                end
506
 
507
                                                //Once writeRowCount is >= 2, data is ready to start being output.
508
                                                if(writeRowCount[1])
509
                                                        readyForRead <= 1;
510
 
511
                                                if(writeRowCount == inputYRes)  //When all data has been read in, stop reading.
512
                                                begin
513
                                                        writeState <= WS_DONE;
514
                                                        enableNextDin <= 0;
515
                                                        forceRead <= 1;
516
                                                end
517
 
518
                                                writeColCount <= 0;
519
                                                writeRowCount <= writeRowCount + 1;
520
                                        end
521
                                        else
522
                                        begin
523
                                                writeColCount <= writeColCount + 1;
524
                                        end
525
                                end
526
                        end
527
 
528
                        WS_DONE:
529
                        begin
530
                                //do nothing, wait for reset
531
                        end
532
 
533
                endcase
534
        end
535
end
536
 
537
 
538
//Advance write whenever we have just written a valid line (discardInput == 0)
539
//Generate this signal one earlier than discardInput above that uses the same conditions, to advance the buffer at the right time.
540
assign advanceWrite =   (writeColCount == inputXRes) & (discardInput == 0) & dInValid & nextDin;
541
assign allDataWritten = writeState == WS_DONE;
542
assign nextDin = (fillCount < BUFFER_SIZE) & enableNextDin;
543
 
544
ramFifo #(
545
        .DATA_WIDTH( DATA_WIDTH*CHANNELS ),
546
        .ADDRESS_WIDTH( INPUT_X_RES_WIDTH ),    //Controls width of RAMs
547
        .BUFFER_SIZE( BUFFER_SIZE )             //Number of RAMs
548
) ramRB (
549
        .clk( clk ),
550
        .rst( rst | start ),
551
        .advanceRead1( advanceRead1 ),
552
        .advanceRead2( advanceRead2 ),
553
        .advanceWrite( advanceWrite ),
554
        .forceRead( forceRead ),
555
 
556
        .writeData( dIn ),
557
        .writeAddress( writeColCount ),
558
        .writeEnable( dInValid & nextDin & enableNextDin & ~discardInput ),
559
        .fillCount( fillCount ),
560
 
561
        .readData00( readData00 ),
562
        .readData01( readData01 ),
563
        .readData10( readData10 ),
564
        .readData11( readData11 ),
565
        .readAddress( readAddress )
566
);
567
 
568
endmodule       //scaler
569
 
570
 
571
 
572
//---------------------------Ram FIFO (RFIFO)-----------------------------
573
//FIFO buffer with rams as the elements, instead of data
574
//One ram is filled, while two others are simultaneously read out.
575
//Four neighboring pixels are read out at once, at the selected RAM and one line down, and at readAddress and readAddress + 1
576
module ramFifo #(
577
        parameter DATA_WIDTH = 8,
578
        parameter ADDRESS_WIDTH = 8,
579
        parameter BUFFER_SIZE = 2,
580
        parameter BUFFER_SIZE_WIDTH =   ((BUFFER_SIZE+1) <= 2) ? 1 :    //wide enough to hold value BUFFER_SIZE + 1
581
                                                                        ((BUFFER_SIZE+1) <= 4) ? 2 :
582
                                                                        ((BUFFER_SIZE+1) <= 8) ? 3 :
583
                                                                        ((BUFFER_SIZE+1) <= 16) ? 4 :
584
                                                                        ((BUFFER_SIZE+1) <= 32) ? 5 :
585
                                                                        ((BUFFER_SIZE+1) <= 64) ? 6 : 7
586
)(
587
        input wire                                              clk,
588
        input wire                                              rst,
589
        input wire                                              advanceRead1,   //Advance selected read RAM by one
590
        input wire                                              advanceRead2,   //Advance selected read RAM by two
591
        input wire                                              advanceWrite,   //Advance selected write RAM by one
592
        input wire                                              forceRead,              //Disables writing to allow all data to be read out (RAM being written to cannot be read from normally)         
593
 
594
        input wire [DATA_WIDTH-1:0]              writeData,
595
        input wire [ADDRESS_WIDTH-1:0]   writeAddress,
596
        input wire                                              writeEnable,
597
        output reg [BUFFER_SIZE_WIDTH-1:0]
598
                                                                        fillCount,
599
 
600
        //                                                                              yx
601
        output wire [DATA_WIDTH-1:0]     readData00,             //Read from deepest RAM (earliest data), at readAddress
602
        output wire [DATA_WIDTH-1:0]     readData01,             //Read from deepest RAM (earliest data), at readAddress + 1
603
        output wire [DATA_WIDTH-1:0]     readData10,             //Read from second deepest RAM (second earliest data), at readAddress
604
        output wire [DATA_WIDTH-1:0]     readData11,             //Read from second deepest RAM (second earliest data), at readAddress + 1
605
        input wire [ADDRESS_WIDTH-1:0]   readAddress
606
);
607
 
608
reg [BUFFER_SIZE-1:0]            writeSelect;
609
reg [BUFFER_SIZE-1:0]            readSelect;
610
 
611
//Read select ring register
612
always @(posedge clk or posedge rst)
613
begin
614
        if(rst)
615
                readSelect <= 1;
616
        else
617
        begin
618
                if(advanceRead1)
619
                begin
620
                        readSelect <= {readSelect[BUFFER_SIZE-2 : 0], readSelect[BUFFER_SIZE-1]};
621
                end
622
                else if(advanceRead2)
623
                begin
624
                        readSelect <= {readSelect[BUFFER_SIZE-3 : 0], readSelect[BUFFER_SIZE-1:BUFFER_SIZE-2]};
625
                end
626
        end
627
end
628
 
629
//Write select ring register
630
always @(posedge clk or posedge rst)
631
begin
632
        if(rst)
633
                writeSelect <= 1;
634
        else
635
        begin
636
                if(advanceWrite)
637
                begin
638
                        writeSelect <= {writeSelect[BUFFER_SIZE-2 : 0], writeSelect[BUFFER_SIZE-1]};
639
                end
640
        end
641
end
642
 
643
wire [DATA_WIDTH-1:0] ramDataOutA [2**BUFFER_SIZE-1:0];
644
wire [DATA_WIDTH-1:0] ramDataOutB [2**BUFFER_SIZE-1:0];
645
 
646
//Generate to instantiate the RAMs
647
generate
648
genvar i;
649
        for(i = 0; i < BUFFER_SIZE; i = i + 1)
650
                begin : ram_generate
651
 
652
                        ramDualPort #(
653
                                .DATA_WIDTH( DATA_WIDTH ),
654
                                .ADDRESS_WIDTH( ADDRESS_WIDTH )
655
                        ) ram_inst_i(
656
                                .clk( clk ),
657
 
658
                                //Port A is written to as well as read from. When writing, this port cannot be read from.
659
                                //As long as the buffer is large enough, this will not cause any problem.
660
                                .addrA( ((writeSelect[i] == 1'b1) && !forceRead && writeEnable) ? writeAddress : readAddress ), //&& writeEnable is 
661
                                //to allow the full buffer to be used. After the buffer is filled, write is advanced, so writeSelect
662
                                //and readSelect are the same. The full buffer isn't written to, so this allows the read to work properly.
663
                                .dataA( writeData ),
664
                                .weA( ((writeSelect[i] == 1'b1) && !forceRead) ? writeEnable : 1'b0 ),
665
                                .qA( ramDataOutA[2**i] ),
666
 
667
                                .addrB( readAddress + 1 ),
668
                                .dataB( 0 ),
669
                                .weB( 1'b0 ),
670
                                .qB( ramDataOutB[2**i] )
671
                        );
672
                end
673
endgenerate
674
 
675
//Select which ram to read from
676
wire [BUFFER_SIZE-1:0]   readSelect0 = readSelect;
677
wire [BUFFER_SIZE-1:0]   readSelect1 = (readSelect << 1) | readSelect[BUFFER_SIZE-1];
678
 
679
//Steer the output data to the right ports
680
assign readData00 = ramDataOutA[readSelect0];
681
assign readData10 = ramDataOutA[readSelect1];
682
assign readData01 = ramDataOutB[readSelect0];
683
assign readData11 = ramDataOutB[readSelect1];
684
 
685
//Keep track of fill level
686
always @(posedge clk or posedge rst)
687
begin
688
        if(rst)
689
        begin
690
                fillCount <= 0;
691
        end
692
        else
693
        begin
694
                if(advanceWrite)
695
                begin
696
                        if(advanceRead1)
697
                                fillCount <= fillCount;
698
                        else if(advanceRead2)
699
                                fillCount <= fillCount - 1;
700
                        else
701
                                fillCount <= fillCount + 1;
702
                end
703
                else
704
                begin
705
                        if(advanceRead1)
706
                                fillCount <= fillCount - 1;
707
                        else if(advanceRead2)
708
                                fillCount <= fillCount - 2;
709
                        else
710
                                fillCount <= fillCount;
711
                end
712
        end
713
end
714
 
715
endmodule //ramFifo
716
 
717
 
718
//Dual port RAM
719
module ramDualPort #(
720
        parameter DATA_WIDTH = 8,
721
        parameter ADDRESS_WIDTH = 8
722
)(
723
        input wire [(DATA_WIDTH-1):0] dataA, dataB,
724
        input wire [(ADDRESS_WIDTH-1):0] addrA, addrB,
725
        input wire weA, weB, clk,
726
        output reg [(DATA_WIDTH-1):0] qA, qB
727
);
728
 
729
        // Declare the RAM variable
730
        reg [DATA_WIDTH-1:0] ram[2**ADDRESS_WIDTH-1:0];
731
 
732
        //Port A
733
        always @ (posedge clk)
734
        begin
735
                if (weA)
736
                begin
737
                        ram[addrA] <= dataA;
738
                        qA <= dataA;
739
                end
740
                else
741
                begin
742
                        qA <= ram[addrA];
743
                end
744
        end
745
 
746
        //Port B
747
        always @ (posedge clk)
748
        begin
749
                if (weB)
750
                begin
751
                        ram[addrB] <= dataB;
752
                        qB <= dataB;
753
                end
754
                else
755
                begin
756
                        qB <= ram[addrB];
757
                end
758
        end
759
 
760
endmodule //ramDualPort

powered by: WebSVN 2.1.0

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