www.pudn.com > noc.rar > bram8k.cpp


/*
 *  TU Eindhoven
 *  Eindhoven, The Netherlands
 *
 *  Name            :   bram8k.cpp
 *
 *  Author          :   A.S.Slusarczyk@tue.nl
 *
 *  Date            :   
 *
 *  Function        :   RAM based on VirtexII 16kb BlockRAMs
 *
 *
 */
 
#include "bram8k.h"

#ifdef MEM_DBG
#include "dbg_mem.h"
#endif

void BRAM8KCONV::reg()
{
  
  sc_bv<2> ar = addr.read().range(1,0);

#ifdef MEM_DBG
  sc_uint<2> _r = r.read(), _w = w.read();
  extern void hack_pc();
  if( (_r == 1 || _w == 1) && ar != 0 ){
    cout << "WARNING: Non-aligned word access address=" << addr.read().to_uint() << " r=" << _r << " w=" << _w << endl;
    cout << "\t" << name() << " PCs:"; 
    hack_pc();
  }
  if( dbg_mem_hit( addr.read().to_uint() ) ){
    cout << "MEMORY ACCESS " 
         << " addr=0x" << hex << addr.read().to_uint() << dec << " "
         << (_r==2 ? "read byte " : (_r==1 ? "read word " : "") ) 
         << (_w==2 ? "write byte " : (_w==1 ? "write word " : "") )
         << "data=0x" << hex << din.read().to_uint() << dec << endl;
    cout << "\t" << name() << " PCs:"; 
    hack_pc();
  }
#endif

  
  if( en.read()[0]!=0 )
    {
      // register r and w inputs
      r_reg.write(r.read());
      w_reg.write(w.read());
      byte_reg.write(ar);
    }
}

void BRAM8KCONV::in()
{  
  // read/write request
  sc_uint<2> iw=w.read(), ir=r.read();

  sc_bv a = addr.read();
  
  // discard two least significant bits of the address
  // they are only used in byte mode -- 
  // for that purpose they are registered in byte_reg
  sc_bv<11> a_12_2 = a.range(12,2);
  sc_uint<11> addr11 = a_12_2;
  
  ADDR1.write(addr11); ADDR0.write(addr11); ADDR2.write(addr11); ADDR3.write(addr11); 
  
  sc_bv dwr = din.read();

  // if w == 2, we're writing the LSByte of the input word to the appropriate address
  sc_bv<2> byteb = a.range(1,0);
  sc_uint<2> byteno = byteb;
  sc_bv<8> byte = dwr.range(7,0);

  bool byte_to_0 = (iw==2 && byteno==0),
	byte_to_1 = (iw==2 && byteno==1),
	byte_to_2 = (iw==2 && byteno==2),
	byte_to_3 = (iw==2 && byteno==3);


  // split the input data between the two memory blocks
#ifdef MIPS_BIG_ENDIAN
  sc_bv dwr0 = dwr.range(31,24), dwr1 = dwr.range(23,16), dwr2 = dwr.range(15,8), dwr3 = dwr.range(7,0);
#else
  sc_bv dwr3 = dwr.range(31,24), dwr2 = dwr.range(23,16), dwr1 = dwr.range(15,8), dwr0 = dwr.range(7,0);
#endif
  
  DI0.write(byte_to_0 ? byte : dwr0); 
  DI1.write(byte_to_1 ? byte : dwr1); 
  DI2.write(byte_to_2 ? byte : dwr2); 
  DI3.write(byte_to_3 ? byte : dwr3); 
  
  // BlockRAM enable needs to be active for both read and write
  bool e = ((en.read()[0]!=0) && ((ir!=0)||(iw!=0)));
  EN0.write(e);  EN1.write(e); EN2.write(e);  EN3.write(e);
  WE0.write(iw==1 || iw==2 && byte_to_0);  
  WE1.write(iw==1 || iw==2 && byte_to_1); 
  WE2.write(iw==1 || iw==2 && byte_to_2);  
  WE3.write(iw==1 || iw==2 && byte_to_3);
  SSR0.write(0); SSR1.write(0); SSR2.write(0); SSR3.write(0);
  CLK0.write(clk.read()); CLK1.write(clk.read()); CLK2.write(clk.read()); CLK3.write(clk.read()); 
  // Xilinx advises to tie unused data inputs HIGH
  DIP0.write(1); DIP1.write(1); DIP2.write(1); DIP3.write(1); 
}

void BRAM8KCONV::out()
{
  sc_bv<24> data24;
  sc_bv<8> d0, d1, d2, d3, msbyte;
  

  // gather bytes of the word from memory blocks
  d0 = DO0.read();
  d1 = DO1.read();
  d2 = DO2.read();
  d3 = DO3.read();

  // check byte/word mode
  sc_uint<2> iw=w_reg.read(), ir=r_reg.read();
  bool byte_mode = (iw==2 || ir==2);
  
  // 3 LS bytes go straight to the output, regardless of mode
#ifdef MIPS_BIG_ENDIAN
  data24 = (d1, d2, d3);
#else
  data24 = (d2, d1, d0);
#endif

  // depending on mode (byte/word) select the most significant byte
  if( byte_mode )
	{
	  // in byte mode take one of the bytes, 
	  // depending on the last two bits of the address
	  sc_uint<2> byteno = byte_reg.read();
	  
	  switch( byteno ){
	  case 0: msbyte = d0; break;
	  case 1: msbyte = d1; break;
	  case 2: msbyte = d2; break;
	  case 3: msbyte = d3; break;
	  }	  
	}
  else 
	{
	  // word mode
#ifdef MIPS_BIG_ENDIAN
	  msbyte = d0;
#else
	  msbyte = d3;
#endif
	}
  
  dout.write( (msbyte, data24) );
  memwait.write( false );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void DBGBRAM8KCONV::in()
{  

  bool clk = CLK.read();
  
  CLK0.write(clk); CLK1.write(clk); CLK2.write(clk); CLK3.write(clk);
  
  // discard two least significant bits of the address
  sc_uint<11> addr = ADDR.read().range(12,2);  
  ADDR1.write(addr); ADDR0.write(addr); ADDR2.write(addr); ADDR3.write(addr); 
  
  // split the input data between the memory blocks
  sc_int<32> dwr = DI.read();
#ifdef MIPS_BIG_ENDIAN
  sc_int<8> dwr0 = dwr.range(31,24), dwr1 = dwr.range(23,16), dwr2 = dwr.range(15,8), dwr3 = dwr.range(7,0);
#else
  sc_int<8> dwr3 = dwr.range(31,24), dwr2 = dwr.range(23,16), dwr1 = dwr.range(15,8), dwr0 = dwr.range(7,0);
#endif
  DI0.write(dwr0); DI1.write(dwr1); DI2.write(dwr2); DI3.write(dwr3); 

  bool en = EN.read(), we = WE.read();
  EN0.write(en); EN1.write(en); EN2.write(en); EN3.write(en);
  WE0.write(we); WE1.write(we); WE2.write(we); WE3.write(we);
  SSR0.write(0); SSR1.write(0); SSR2.write(0); SSR3.write(0);
  DIP0.write(1); DIP1.write(1); DIP2.write(1); DIP3.write(1); 
}

void DBGBRAM8KCONV::out()
{
  sc_int<32> data;
  sc_int<8> d0, d1, d2, d3;
  
  // gather bytes of the word from memory blocks
  d0 = DO0.read();
  d1 = DO1.read();
  d2 = DO2.read();
  d3 = DO3.read();

#ifdef MIPS_BIG_ENDIAN
  data = (d0, d1, d2, d3);
#else
  data = (d3, d2, d1, d0);
#endif
  
  DO.write( data );
}

#ifndef VERILOG

void BRAM8K::mem_init(const char *filename, int size){
  vector* > v;
  v.push_back(bram0->memory);
  v.push_back(bram1->memory);
  v.push_back(bram2->memory);
  v.push_back(bram3->memory);
  init_memory(&v,size,filename);
}
void BRAM8K::mem_dump(const char *filename, int size){
  vector* > v;
  v.push_back(bram0->memory);
  v.push_back(bram1->memory);
  v.push_back(bram2->memory);
  v.push_back(bram3->memory);
  dump_memory(&v,size,filename);
}

#endif