// 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. //********************************************************************** // Buffer Controller //---------------------------------------------------------------------- // // package mkBufferControl; import H264Types::*; import IBufferControl::*; import FIFO::*; import Vector::*; import Connectable::*; import GetPut::*; import ClientServer::*; //----------------------------------------------------------- // Local Datatypes //----------------------------------------------------------- typedef union tagged { void Idle; //not working on anything in particular void Y; void U; void V; } Outprocess deriving(Eq,Bits); //----------------------------------------------------------- // Short term pic list submodule //----------------------------------------------------------- typedef union tagged { void Idle; //not working on anything in particular void Remove; void RemoveOutput; void RemoveFound; void InsertGap; void Search; void ListAll; } ShortTermPicListState deriving(Eq,Bits); interface ShortTermPicList; method Action clear(); method Action insert( Bit#(16) frameNum, Bit#(5) slot, Bit#(5) maxAllowed ); method Action insert_gap( Bit#(16) frameNum, Bit#(5) slot, Bit#(5) maxAllowed, Bit#(16) gap, Bit#(5) log2_max_frame_num ); method Action remove( Bit#(16) frameNum, Bool removeOutputFlag ); method Action search( Bit#(16) frameNum ); method Action listAll(); method Action deq(); method Maybe#(Bit#(5)) resultSlot(); method Bit#(5) numPics(); endinterface module mkShortTermPicList( ShortTermPicList ); function Bit#(5) shortTermPicListNext( Bit#(5) addrFunc ); if(addrFunc=picCount) $display( "ERROR BufferControl: ShortTermPicList removing not found"); end else begin Bit#(5) tempPrev = shortTermPicListPrev(tempPic); rfile.upd(tempPrev,rfile.sub(tempPic)); if(tempCount==picCount) begin picCount <= picCount-1; nextPic <= tempPrev; state <= Idle; end end tempCount <= tempCount+1; tempPic <= shortTermPicListNext(tempPic); endrule rule insertingGap ( state matches tagged InsertGap ); if(tempCount>0) begin if(tempCount>1) rfile.upd(nextPic,tuple2(tempNum,31)); else rfile.upd(nextPic,tuple2(tempNum,tempPic)); nextPic <= shortTermPicListNext(nextPic); end else state <= Idle; Bit#(17) tempOne = 1; Bit#(17) maxPicNum = tempOne << log2_mfn; if(zeroExtend(tempNum) == maxPicNum-1) tempNum <= 0; else tempNum <= tempNum+1; tempCount <= tempCount-1; endrule rule searching ( state matches tagged Search ); if(tempCountpicCount) picCount <= picCount+1; endmethod method Action insert_gap( Bit#(16) frameNum, Bit#(5) slot, Bit#(5) maxAllowed, Bit#(16) gap, Bit#(5) log2_max_frame_num ) if(state matches tagged Idle); state <= InsertGap; log2_mfn <= log2_max_frame_num; if(zeroExtend(picCount)+gap+1 >= zeroExtend(maxAllowed)) picCount <= maxAllowed; else picCount <= truncate(zeroExtend(picCount)+gap+1); Bit#(5) temp; if(gap+1 >= zeroExtend(maxAllowed)) temp = maxAllowed; else temp = truncate(gap+1); tempCount <= temp; Bit#(17) tempOne = 1; Bit#(17) maxPicNum = tempOne << log2_max_frame_num; Bit#(17) tempFrameNum = zeroExtend(frameNum); if(tempFrameNum+1 > zeroExtend(temp)) tempNum <= truncate(tempFrameNum+1-zeroExtend(temp)); else tempNum <= truncate(maxPicNum+tempFrameNum+1-zeroExtend(temp)); tempPic <= slot; endmethod method Action remove( Bit#(16) frameNum, Bool removeOutputFlag ) if(state matches tagged Idle); if(removeOutputFlag) state <= RemoveOutput; else state <= Remove; tempCount <= 0; Bit#(5) temp = (maxRefFrames-picCount)+nextPic; if(temp>maxRefFrames-1) tempPic <= temp-maxRefFrames; else tempPic <= temp; tempNum <= frameNum; endmethod method Action search( Bit#(16) frameNum ) if(state matches tagged Idle); state <= Search; tempCount <= 0; tempPic <= shortTermPicListPrev(nextPic); tempNum <= frameNum; endmethod method Action listAll() if(state matches tagged Idle); state <= ListAll; tempCount <= 0; tempPic <= shortTermPicListPrev(nextPic); endmethod method Action deq(); returnList.deq(); endmethod method Maybe#(Bit#(5)) resultSlot(); return returnList.first(); endmethod method Bit#(5) numPics() if(state matches tagged Idle); return picCount; endmethod endmodule //----------------------------------------------------------- // Long term pic list submodule //----------------------------------------------------------- typedef union tagged { void Idle; //not working on anything in particular void Clear; void ListAll; } LongTermPicListState deriving(Eq,Bits); interface LongTermPicList; method Action clear(); method Action insert( Bit#(5) frameNum, Bit#(5) slot ); method Action remove( Bit#(5) frameNum ); method Action maxIndexPlus1( Bit#(5) maxAllowed ); method Action search( Bit#(5) frameNum ); method Action listAll(); method Action deq(); method Maybe#(Bit#(5)) resultSlot(); method Bit#(5) numPics(); endinterface module mkLongTermPicList( LongTermPicList ); // RegFile#(Bit#(5),Maybe#(Bit#(5))) rfile <- mkRegFile(0,maxRefFrames-1); RFile1#(Bit#(5),Maybe#(Bit#(5))) rfile <- mkRFile1Full(); Reg#(LongTermPicListState) state <- mkReg(Idle); Reg#(Bit#(5)) picCount <- mkReg(0); Reg#(Bit#(5)) tempPic <- mkReg(0); FIFO#(Maybe#(Bit#(5))) returnList <- mkFIFO(); rule clearing ( state matches tagged Clear ); if(tempPic= maxRefFrames+2) $display( "ERROR BufferControl: FreeSlots add out of bounds"); endmethod method Action remove( Bit#(5) slot ); Vector#(18,Bit#(1)) tempSlots = slots; if(slot != 31) begin tempSlots[slot] = 1; slots <= tempSlots; if(slot >= maxRefFrames+2) $display( "ERROR BufferControl: FreeSlots remove out of bounds"); end endmethod method Bit#(5) first( Bit#(5) exception ); Bit#(5) tempout = 31; for(Integer ii=17; ii>=0; ii=ii-1) begin if(slots[fromInteger(ii)]==1'b0 && fromInteger(ii)!=exception) tempout = fromInteger(ii); end return tempout; endmethod endmodule //----------------------------------------------------------- // Helper functions //----------------------------------------------------------- // Buffer Controller Module //----------------------------------------------------------- (* synthesize *) module mkBufferControl( IBufferControl ); FIFO#(DeblockFilterOT) infifo <- mkSizedFIFO(bufferControl_infifo_size); FIFO#(BufferControlOT) outfifo <- mkFIFO(); FIFO#(FrameBufferLoadReq) loadReqQ1 <- mkFIFO(); FIFO#(FrameBufferLoadResp) loadRespQ1 <- mkFIFO(); FIFO#(FrameBufferLoadReq) loadReqQ2 <- mkFIFO(); FIFO#(FrameBufferLoadResp) loadRespQ2 <- mkFIFO(); FIFO#(FrameBufferStoreReq) storeReqQ <- mkFIFO(); FIFO#(InterpolatorLoadReq) inLoadReqQ <- mkFIFO(); FIFO#(InterpolatorLoadResp) inLoadRespQ <- mkFIFO(); FIFO#(Bit#(2)) inLoadOutOfBounds <- mkSizedFIFO(64); Reg#(Bit#(5)) log2_max_frame_num <- mkReg(0); Reg#(Bit#(5)) num_ref_frames <- mkReg(0); Reg#(Bit#(1)) gaps_in_frame_num_allowed_flag <- mkReg(0); Reg#(Bit#(PicWidthSz)) picWidth <- mkReg(maxPicWidthInMB); Reg#(Bit#(PicHeightSz)) picHeight <- mkReg(0); Reg#(Bit#(PicAreaSz)) frameinmb <- mkReg(0); Reg#(Bit#(5)) ppsnum_ref_idx_l0_active <- mkReg(0); Reg#(Bit#(16)) frame_num <- mkReg(0); Reg#(Bit#(16)) prevRefFrameNum <- mkReg(0); Reg#(Bit#(5)) num_ref_idx_l0_active <- mkReg(0); Reg#(Bit#(2)) reordering_of_pic_nums_idc <- mkReg(0); Reg#(Bit#(16)) picNumLXPred <- mkReg(0); Reg#(Bit#(3)) memory_management_control_operation <- mkReg(0); Reg#(Bool) newInputFrame <- mkReg(True); Reg#(Bool) noMoreInput <- mkReg(False); Reg#(Bool) inputframedone <- mkReg(False); Reg#(Outprocess) outprocess <- mkReg(Idle); Reg#(Bool) outputframedone <- mkReg(True); Reg#(Bit#(5)) inSlot <- mkReg(0); Reg#(Bit#(FrameBufferSz)) inAddrBase <- mkReg(0); Reg#(Bit#(5)) outSlot <- mkReg(31); Reg#(Bit#(FrameBufferSz)) outAddrBase <- mkReg(0); Reg#(Bit#(TAdd#(PicAreaSz,7))) outReqCount <- mkReg(0); Reg#(Bit#(TAdd#(PicAreaSz,7))) outRespCount <- mkReg(0); FreeSlots freeSlots <- mkFreeSlots();//may include outSlot (have to make sure it's not used) ShortTermPicList shortTermPicList <- mkShortTermPicList(); LongTermPicList longTermPicList <- mkLongTermPicList(); RFile1#(Bit#(5),Bit#(5)) refPicList <- mkRFile1(0,maxRefFrames-1); Reg#(Bit#(5)) refPicListCount <- mkReg(0); Reg#(Bool) initRefPicList <- mkReg(False); Reg#(Bool) reorderRefPicList <- mkReg(False); Reg#(Bit#(5)) refIdx <- mkReg(0); Reg#(Bit#(5)) tempSlot <- mkReg(0); Reg#(Bit#(5)) tempSlot2 <- mkReg(0); Reg#(Bit#(2)) adjustFreeSlots <- mkReg(0); Reg#(Bool) refPicListDone <- mkReg(False); Reg#(Bool) lockInterLoads <- mkReg(True); DoNotFire donotfire <- mkDoNotFire(); //----------------------------------------------------------- // Rules rule inputing ( !noMoreInput && !inputframedone ); //$display( "Trace Buffer Control: passing infifo packed %h", pack(infifo.first())); case (infifo.first()) matches tagged EDOT .indata : begin case (indata) matches tagged SPSlog2_max_frame_num .xdata : begin if(adjustFreeSlots == 0) begin infifo.deq(); log2_max_frame_num <= xdata; freeSlots.init(); shortTermPicList.clear(); longTermPicList.clear(); end else donotfire.doNotFire(); end tagged SPSnum_ref_frames .xdata : begin infifo.deq(); num_ref_frames <= xdata; end tagged SPSgaps_in_frame_num_allowed_flag .xdata : begin infifo.deq(); gaps_in_frame_num_allowed_flag <= xdata; end tagged SPSpic_width_in_mbs .xdata : begin infifo.deq(); picWidth <= xdata; end tagged SPSpic_height_in_map_units .xdata : begin infifo.deq(); picHeight <= xdata; frameinmb <= zeroExtend(picWidth)*zeroExtend(xdata); end tagged PPSnum_ref_idx_l0_active .xdata : begin infifo.deq(); ppsnum_ref_idx_l0_active <= xdata; end tagged SHfirst_mb_in_slice .xdata : begin if(adjustFreeSlots == 0) begin infifo.deq(); newInputFrame <= False; shortTermPicList.listAll(); longTermPicList.listAll(); initRefPicList <= True; refPicListCount <= 0; if(newInputFrame) begin inSlot <= freeSlots.first(outSlot); inAddrBase <= (zeroExtend(freeSlots.first(outSlot))*zeroExtend(frameinmb)*3)<<5; end $display( "Trace BufferControl: passing SHfirst_mb_in_slice %h %h %0d", freeSlots.first(outSlot), outSlot, (newInputFrame ? 1 : 0)); end else donotfire.doNotFire(); end tagged SHframe_num .xdata : begin infifo.deq(); frame_num <= xdata; picNumLXPred <= frame_num; end tagged SHnum_ref_idx_active_override_flag .xdata : begin infifo.deq(); num_ref_idx_l0_active <= ppsnum_ref_idx_l0_active; end tagged SHnum_ref_idx_l0_active .xdata : begin infifo.deq(); num_ref_idx_l0_active <= xdata; end tagged SHRref_pic_list_reordering_flag_l0 .xdata : begin if(!initRefPicList) begin infifo.deq(); if(xdata==0) refPicListDone <= True; end else donotfire.doNotFire(); refIdx <= 0; end tagged SHRreordering_of_pic_nums_idc .xdata : begin if(!reorderRefPicList) begin infifo.deq(); reordering_of_pic_nums_idc <= xdata; if(xdata==3) refPicListDone <= True; end else donotfire.doNotFire(); end tagged SHRabs_diff_pic_num .xdata : begin if(!reorderRefPicList) begin infifo.deq(); Bit#(16) picNumLXNoWrap; Bit#(17) tempOne = 1; Bit#(17) maxPicNum = tempOne << log2_max_frame_num; if(reordering_of_pic_nums_idc==0) begin if(picNumLXPred < truncate(xdata)) picNumLXNoWrap = truncate(zeroExtend(picNumLXPred)-xdata+maxPicNum); else picNumLXNoWrap = truncate(zeroExtend(picNumLXPred)-xdata); end else begin if(zeroExtend(picNumLXPred)+xdata >= maxPicNum) picNumLXNoWrap = truncate(zeroExtend(picNumLXPred)+xdata-maxPicNum); else picNumLXNoWrap = truncate(zeroExtend(picNumLXPred)+xdata); end picNumLXPred <= picNumLXNoWrap; shortTermPicList.search(picNumLXNoWrap); reorderRefPicList <= True; refPicListCount <= 0; end else donotfire.doNotFire(); end tagged SHRlong_term_pic_num .xdata : begin if(!reorderRefPicList) begin infifo.deq(); longTermPicList.search(xdata); reorderRefPicList <= True; refPicListCount <= 0; end else donotfire.doNotFire(); end tagged SHDlong_term_reference_flag .xdata : begin infifo.deq(); if(xdata==0) shortTermPicList.insert(frame_num,inSlot,num_ref_frames); else longTermPicList.insert(0,inSlot); adjustFreeSlots <= 1; end tagged SHDadaptive_ref_pic_marking_mode_flag .xdata : begin infifo.deq(); Bit#(17) tempFrameNum = zeroExtend(frame_num); Bit#(17) tempOne = 1; Bit#(17) maxPicNum = tempOne << log2_max_frame_num; Bit#(16) tempGap = 0; if(frame_num < prevRefFrameNum) tempFrameNum = tempFrameNum + maxPicNum; if(tempFrameNum-zeroExtend(prevRefFrameNum) > 1) tempGap = truncate(tempFrameNum-zeroExtend(prevRefFrameNum)-1); if(xdata==0) begin if(tempGap==0) shortTermPicList.insert(frame_num,inSlot,(num_ref_frames-longTermPicList.numPics())); else shortTermPicList.insert_gap(frame_num,inSlot,(num_ref_frames-longTermPicList.numPics()),tempGap,log2_max_frame_num); adjustFreeSlots <= 1; end prevRefFrameNum <= frame_num; end tagged SHDmemory_management_control_operation .xdata : begin infifo.deq(); memory_management_control_operation <= xdata; if(xdata==0) adjustFreeSlots <= 1; else if(xdata==5) begin shortTermPicList.clear(); longTermPicList.clear(); end end tagged SHDdifference_of_pic_nums .xdata : begin infifo.deq(); Bit#(16) picNumXNoWrap; Bit#(17) tempOne = 1; Bit#(17) maxPicNum = tempOne << log2_max_frame_num; if(frame_num < truncate(xdata)) picNumXNoWrap = truncate(zeroExtend(frame_num)-xdata+maxPicNum); else picNumXNoWrap = truncate(zeroExtend(frame_num)-xdata); if(memory_management_control_operation == 1) shortTermPicList.remove(picNumXNoWrap,False); else shortTermPicList.remove(picNumXNoWrap,True); end tagged SHDlong_term_pic_num .xdata : begin infifo.deq(); longTermPicList.remove(xdata); end tagged SHDlong_term_frame_idx .xdata : begin infifo.deq(); if(memory_management_control_operation == 3) begin if(shortTermPicList.resultSlot() matches tagged Valid .validdata) longTermPicList.insert(xdata,validdata); else $display( "ERROR BufferControl: SHDlong_term_frame_idx Invalid output from shortTermPicList"); shortTermPicList.deq(); end else longTermPicList.insert(xdata,inSlot); end tagged SHDmax_long_term_frame_idx_plus1 .xdata : begin infifo.deq(); longTermPicList.maxIndexPlus1(xdata); end tagged EndOfFile : begin infifo.deq(); $display( "INFO Buffer Control: EndOfFile reached"); noMoreInput <= True; //$finish(0); //outfifo.enq(EndOfFile); end default: begin $display("WARNING: Why are we in this clause"); infifo.deq(); end endcase end tagged DFBLuma .indata : begin infifo.deq(); //$display( "TRACE Buffer Control: input Luma %0d %h %h", indata.mb, indata.pixel, indata.data); Bit#(TAdd#(PicAreaSz,6)) addr = {(zeroExtend(indata.ver)*zeroExtend(picWidth)),2'b00}+zeroExtend(indata.hor); storeReqQ.enq(tagged FBStoreReq {addr:inAddrBase+zeroExtend(addr),data:indata.data}); end tagged DFBChroma .indata : begin infifo.deq(); Bit#(TAdd#(PicAreaSz,4)) addr = {(zeroExtend(indata.ver)*zeroExtend(picWidth)),1'b0}+zeroExtend(indata.hor); Bit#(TAdd#(PicAreaSz,6)) chromaOffset = {frameinmb,6'b000000}; Bit#(TAdd#(PicAreaSz,4)) vOffset = 0; if(indata.uv == 1) vOffset = {frameinmb,4'b0000}; storeReqQ.enq(tagged FBStoreReq {addr:(inAddrBase+zeroExtend(chromaOffset)+zeroExtend(vOffset)+zeroExtend(addr)),data:indata.data}); //$display( "TRACE Buffer Control: input Chroma %0d %0h %h %h %h %h", indata.uv, indata.ver, indata.hor, indata.data, addr, (inAddrBase+zeroExtend(chromaOffset)+zeroExtend(vOffset)+zeroExtend(addr))); end tagged EndOfFrame : begin infifo.deq(); $display( "INFO Buffer Control: EndOfFrame reached"); inputframedone <= True; newInputFrame <= True; refPicListDone <= False; end default: infifo.deq(); endcase endrule rule initingRefPicList ( initRefPicList ); if(shortTermPicList.resultSlot() matches tagged Valid .xdata) begin shortTermPicList.deq(); refPicList.upd(refPicListCount,xdata); refPicListCount <= refPicListCount+1; $display( "Trace BufferControl: initingRefPicList shortTermPicList %h", xdata); end else if(longTermPicList.resultSlot() matches tagged Valid .xdata) begin longTermPicList.deq(); refPicList.upd(refPicListCount,xdata); refPicListCount <= refPicListCount+1; $display( "Trace BufferControl: initingRefPicList longTermPicList %h", xdata); end else begin shortTermPicList.deq(); longTermPicList.deq(); initRefPicList <= False; refPicListCount <= 0; $display( "Trace BufferControl: initingRefPicList end"); end endrule rule reorderingRefPicList ( reorderRefPicList ); $display( "Trace BufferControl: reorderingRefPicList"); if(shortTermPicList.resultSlot() matches tagged Valid .xdata)////////////////////////////////////////////////////////////////////////////////////////// begin shortTermPicList.deq(); tempSlot <= refPicList.sub(refIdx); refPicList.upd(refIdx,xdata); refPicListCount <= refIdx+1; tempSlot2 <= xdata; end else if(longTermPicList.resultSlot() matches tagged Valid .xdata)/////////////////////////////////////////////////////////////////////////////////////may get stuck? begin longTermPicList.deq(); tempSlot <= refPicList.sub(refIdx); refPicList.upd(refIdx,xdata); refPicListCount <= refIdx+1; tempSlot2 <= xdata; end else begin if(refPicListCount