OpenCores
URL https://opencores.org/ocsvn/bluespec-h264/bluespec-h264/trunk

Subversion Repositories bluespec-h264

[/] [bluespec-h264/] [trunk/] [src_fpga/] [mkVgaController.bsv] - Rev 100

Compare with Previous | Blame | View Log


// The MIT License

// Copyright (c) 2006-2007 Massachusetts Institute of Technology

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package mkVgaController;

import BRAM::*;
import RegFile::*;
import FIFOF::*;
import IVgaController::*;
import IMemClient::*;

`define COLUMNS 640
`define ROWS    480

`define   L_HSYNC_TIME 96
`define   L_BACK_PORCH_TIME 48
`define   L_DATA_TIME 640
`define   L_FRONT_PORCH_TIME 16

typedef enum
{
   L_HSYNC = 96, 
   L_BACK_PORCH = 48,
   L_DATA = 640,
   L_FRONT_PORCH = 16
}
   LineState
            deriving (Eq, Bits);

`define   F_VSYNC_TIME  2
`define   F_BACK_PORCH_TIME 29
`define   F_DATA_TIME 480
`define   F_FRONT_PORCH_TIME 9

typedef enum
{
   F_VSYNC = 2, 
   F_BACK_PORCH = 29,
   F_DATA = 480,
   F_FRONT_PORCH = 9
}
   FrameState
            deriving (Eq, Bits);

typedef enum
{
   U_BRAM,
   Y_BRAM,
   V_BRAM
}
   TargetBuffer
            deriving (Eq, Bits);

`define Y0_OFFSET   20'b0
`define U0_OFFSET   `ROWS*`COLUMNS +  20'b0
`define V0_OFFSET   `U0_OFFSET + `ROWS/2*`COLUMNS/2 + 20'b0 
`define Y1_OFFSET   `V0_OFFSET + `ROWS/2*`COLUMNS/2 + 20'b0
`define U1_OFFSET   `Y1_OFFSET + `ROWS*`COLUMNS +  20'b0
`define V1_OFFSET   `U1_OFFSET + `ROWS/2*`COLUMNS/2 + 20'b0
`define HIGH_ADDR  `V1_OFFSET + `ROWS/2*`COLUMNS/2 - 1 

(* always_ready, always_enabled *)
interface BRAMFrontend;
  method Action   data_input(Bit#(64) data);
  method Bit#(64) data_output();
  method Bit#(32) addr_output();
  method Bit#(1)  enable();
  method Bit#(4)  wenable();
  method Bit#(1)  vsync();
  method Bit#(1)  hsync();
  method Bit#(1)  blank();
  method Bit#(1)  sync_on_green();
  method Bit#(8)  red();
  method Bit#(8)  blue();
  method Bit#(8)  green();
endinterface




//(* synthesize *)
module mkVgaController#(IMemClient#(Bit#(18), Bit#(32)) bram_Y, 
                        IMemClient#(Bit#(18), Bit#(32)) bram_U, 
                        IMemClient#(Bit#(18), Bit#(32)) bram_V) (IVgaController);

  Reg#(Bit#(8)) red_reg <- mkReg(0);
  Reg#(Bit#(8)) blue_reg <- mkReg(0);
  Reg#(Bit#(8)) green_reg <- mkReg(0);
  Reg#(Bit#(1)) target_buffer <- mkReg(0);
  Reg#(Bit#(TLog#(`ROWS))) bram_address_row <- mkReg(0);
  Reg#(Bit#(TLog#(`COLUMNS))) bram_address_col <- mkReg(0);
  Reg#(Bit#(TLog#(`COLUMNS))) bram_resp_col <- mkReg(0);       
  Reg#(FrameState) frame_state <- mkReg(F_VSYNC);
  Reg#(LineState) line_state <- mkReg(L_HSYNC);
  Reg#(Bit#(11)) line_counter <- mkReg(0);
  Reg#(Bit#(11)) tick_counter <- mkReg(0);
  Reg#(Bit#(1)) hsync_buffer <- mkReg(0);
  Reg#(Bit#(1)) vsync_buffer <- mkReg(0);
  Reg#(Bit#(1)) blank_buffer <- mkReg(0);
  Reg#(Bit#(1)) sync_on_green_buffer <- mkReg(0);
  Reg#(Bit#(3)) bram_line_offset <- mkReg(0);
  Reg#(Bool) frame_switch_seen <- mkReg(True);
  Reg#(Bit#(32)) counter <- mkReg(0);
  Reg#(Bit#(32)) y_word_buffer <- mkReg(0);
  Reg#(Bit#(32)) u_word_buffer <- mkReg(0);
  Reg#(Bit#(32)) v_word_buffer <- mkReg(0);   


  function Bit#(8) ybyte (Bit#(32) word);
     return case (bram_line_offset[1:0])
         2'b11: word[31:24];     
         2'b10: word[23:16];  
         2'b01: word[15:8];
         2'b00: word[7:0];
       endcase;
  endfunction: ybyte

  function Bit#(8) uvbyte (Bit#(32) word);
     return case (bram_line_offset[2:1])
         2'b11: word[31:24];     
         2'b10: word[23:16];  
         2'b01: word[15:8];
         2'b00: word[7:0];
       endcase;
  endfunction: uvbyte

// Fix the stupidity here.
  rule black_rgb((line_state == L_DATA) && (bram_resp_col == `COLUMNS));
   red_reg <= 0;
   blue_reg <= 0;
   green_reg <= 0;
  endrule

  rule translate_rgb(line_state == L_DATA);
    Bit#(8) y_wire;
    Bit#(8) u_wire;
    Bit#(8) v_wire;  

    counter <= counter + 1;
    bram_line_offset <= bram_line_offset + 1;
    bram_resp_col <= bram_resp_col + 1;

    if(bram_line_offset[1:0] == 0) 
      begin
        Bit#(32) y_word;
        y_word <- bram_Y.read_resp();
        y_word_buffer <= y_word;
        y_wire = ybyte(y_word);
      end
    else
      begin
        y_wire = ybyte(y_word_buffer);
      end

    if(bram_line_offset[2:0] == 0)
      begin
        Bit#(32)u_word;
        Bit#(32)v_word;
        u_word <- bram_U.read_resp();
        u_word_buffer <= u_word;
        u_wire = uvbyte(u_word);
        v_word <- bram_V.read_resp();
        v_word_buffer <= v_word;
        v_wire = uvbyte(v_word);
      end
    else
      begin
        u_wire = uvbyte(u_word_buffer);
        v_wire = uvbyte(v_word_buffer);
      end

    Int#(18) y_value = unpack(zeroExtend(y_wire));
    Int#(18) u_value = unpack(signExtend(u_wire-128));
    Int#(18) v_value = unpack(signExtend(v_wire-128));
 
    //YRB
    Int#(18) red_reg_next = (( 298 * y_value + 409 * v_value + 128) >> 8);
    Int#(18) green_reg_next = (( 298 * y_value -  100 *  u_value - 209 * v_value + 128) >> 8);
    Int#(18) blue_reg_next = (( 298 * y_value +  516* u_value +128) >> 8);

    Bit#(8) test_red = (red_reg_next < 0) ? 0 : ((red_reg_next >255) ? 255 : truncate(pack(red_reg_next))); 
    Bit#(8) test_blue = (blue_reg_next < 0) ? 0 : ((blue_reg_next >255) ? 255 : truncate(pack(blue_reg_next)));     
    Bit#(8) test_green = (green_reg_next < 0) ? 0 : ((green_reg_next >255) ? 255 : truncate(pack(green_reg_next)));

    red_reg <= (red_reg_next < 0) ? 0 : ((red_reg_next >255) ? 255 : truncate(pack(red_reg_next)));
    blue_reg <= (blue_reg_next < 0) ? 0 : ((blue_reg_next > 255) ? 255 : truncate(pack(blue_reg_next)));
    green_reg <= (green_reg_next < 0) ? 0 : ((green_reg_next > 255) ? 255 : truncate(pack(green_reg_next)));


    $display("RGB %d %d %d", test_red, test_green, test_blue);
  endrule

  rule tick_update(tick_counter > 0); 
    tick_counter <= tick_counter - 1;
  endrule

  rule line_update((line_counter > 0) && (tick_counter == 1) && (line_state == L_HSYNC));
    line_counter <= line_counter - 1; 
  endrule
   
  rule send_req_to_bram((frame_state == F_DATA) && ((line_state == L_BACK_PORCH) || (line_state == L_DATA)) && !(bram_address_col == `COLUMNS) && !(bram_address_row == `ROWS) );
    Bit#(TLog#(`COLUMNS)) adjusted_col_addr = (bram_address_col == `COLUMNS) ? 0 : bram_address_col;
    if(target_buffer == 0)
      begin
        bram_Y.read_req(truncate((`Y0_OFFSET +  `COLUMNS*zeroExtend(bram_address_row) + zeroExtend(adjusted_col_addr))>>2));
       if(bram_address_col[2:0] == 0)
         begin        
           bram_U.read_req(truncate((`U0_OFFSET +  (`COLUMNS/2)*zeroExtend(bram_address_row/2) + zeroExtend(adjusted_col_addr/2))>>2));
           bram_V.read_req(truncate((`V0_OFFSET +  (`COLUMNS/2)*zeroExtend(bram_address_row/2) + zeroExtend(adjusted_col_addr/2))>>2));
         end
      end      
    else
      begin
        bram_Y.read_req(truncate((`Y1_OFFSET +  `COLUMNS*zeroExtend(bram_address_row) + zeroExtend(adjusted_col_addr))>>2));
       if(bram_address_col[2:0] == 0)
         begin
           bram_U.read_req(truncate((`U1_OFFSET +  (`COLUMNS/2)*zeroExtend(bram_address_row/2) + zeroExtend(adjusted_col_addr/2))>>2));
           bram_V.read_req(truncate((`V1_OFFSET +  (`COLUMNS/2)*zeroExtend(bram_address_row/2) + zeroExtend(adjusted_col_addr/2))>>2));
         end
      end       
    bram_address_col <= bram_address_col + 4;
  endrule

  rule line_HSYNC_to_BP ((tick_counter == 0) && (line_state == L_HSYNC));
    tick_counter <= `L_BACK_PORCH_TIME;
    line_state <= L_BACK_PORCH;
    //$display("Back Porch\n");
  endrule

  rule line_BP_to_DATA ((tick_counter == 0) && (line_state == L_BACK_PORCH));
    tick_counter <= `L_DATA_TIME;
    line_state <= L_DATA;
    //$display("Data\n");
    // Need to do something with addressing here
  endrule

  rule line_data_to_FP ((tick_counter == 0) && (line_state == L_DATA));
    tick_counter <= `L_FRONT_PORCH_TIME;
    line_state <= L_FRONT_PORCH;
    //$display("Front Porch\n");
  endrule

  rule line_FP_to_HSYNC_no_deq ((tick_counter == 0) && (line_state == L_FRONT_PORCH));
    if(frame_state == F_DATA && (bram_address_row < `ROWS)) 
      begin 
        bram_address_row <=  bram_address_row + 1; 
      end
    else if (frame_state==F_BACK_PORCH)
      begin
        bram_address_row <=  0;
      end
    else
      begin
        bram_address_row <=  bram_address_row;
      end
    bram_resp_col <= 0;
    bram_address_col <= 0;
    bram_line_offset <=0;
    tick_counter <= `L_HSYNC_TIME;
    line_state <= L_HSYNC;
    //$display("HSYNC\n");
  endrule

  rule frame_HSYNC_to_BP ((line_counter == 0) && (frame_state == F_VSYNC));
    line_counter <= `F_BACK_PORCH_TIME;
    frame_state <= F_BACK_PORCH;
  endrule

  rule frame_BP_to_DATA ((line_counter == 0) && (frame_state == F_BACK_PORCH));
    line_counter <= `F_DATA_TIME;
    frame_state <= F_DATA;
  endrule

  rule frame_data_to_FP ((line_counter == 0) && (frame_state == F_DATA));
    frame_switch_seen <= False;     
    $display("bufferswitch: setdown");
    line_counter <= `F_FRONT_PORCH_TIME;
    frame_state <= F_FRONT_PORCH;
  endrule

  rule frame_FP_to_VSYNC ((line_counter == 0) && (frame_state == F_FRONT_PORCH));
    line_counter <= `F_VSYNC_TIME;
    frame_state <= F_VSYNC;
  endrule

  // hsync and vsync are asserted low.
  rule hsync_delay;
    hsync_buffer <= (line_state == L_HSYNC)? 1 : 0;
  endrule

  rule vsync_delay;
    vsync_buffer <= (frame_state == F_VSYNC)? 1 : 0;
  endrule

  rule blank_delay;
    blank_buffer <= ((frame_state == F_DATA) && (line_state == L_DATA))? 1 : 0;
  endrule

  method  red;
    return red_reg;
  endmethod

  method  blue;
    return blue_reg;
  endmethod

  method  green;
    return green_reg;
  endmethod


  method  sync_on_green;
    return ((hsync_buffer == 0) || (vsync_buffer == 0))? 0 : 1;
  endmethod

  // hsync and vsync are asserted low.
  method  hsync;
    return hsync_buffer;
  endmethod  

  method  vsync;
    return vsync_buffer;
  endmethod

  method blank;
   return blank_buffer;
  endmethod

   method Action  switch_buffer(Bit#(1) buffer) if((frame_state != F_DATA) && (!frame_switch_seen));
    frame_switch_seen <= True;
    $display("bufferswitch: %d", buffer);
    target_buffer <= buffer;
  endmethod

endmodule

endpackage

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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