Index: trunk/modules/vci_spi/caba/metadata/vci_spi.sd
===================================================================
--- trunk/modules/vci_spi/caba/metadata/vci_spi.sd	(revision 551)
+++ trunk/modules/vci_spi/caba/metadata/vci_spi.sd	(revision 551)
@@ -0,0 +1,52 @@
+
+# -*- python -*-
+
+Module('caba:vci_spi',
+	   classname = 'soclib::caba::VciSpi',
+
+        tmpl_parameters = [ 
+           parameter.Module('vci_param',  default = 'caba:vci_param'), 
+        ],
+
+        header_files = [
+            '../source/include/vci_spi.h', 
+        ],
+
+        interface_files = [
+            '../../include/soclib/vcispi.h', 
+        ],
+
+        implementation_files = [
+            '../source/src/vci_spi.cpp',
+        ],
+
+        ports = [
+		    Port('caba:vci_target', 'p_vci_target'),
+		    Port('caba:vci_initiator', 'p_vci_initiator'),
+		    Port('caba:bit_out', 'p_irq'),
+		    Port('caba:bit_out', 'p_spi_clk'),
+		    Port('caba:bit_out', 'p_spi_ss'),
+		    Port('caba:bit_out', 'p_spi_mosi'),
+		    Port('caba:bit_in',  'p_spi_miso'),
+		    Port('caba:bit_in',   'p_resetn', auto = 'resetn'),
+		    Port('caba:clock_in', 'p_clk', auto = 'clock'), 
+		],
+
+        uses = [
+		    Uses('caba:base_module'),
+            Uses('common:mapping_table'),
+		],
+
+        instance_parameters = [
+        	parameter.Module('mt', typename = 'common:mapping_table', auto = 'env:mapping_table'),
+        	parameter.IntTab('srcid'),
+        	parameter.IntTab('tgtid'),
+		parameter.Int('burst_size'),
+        ],
+
+	    extensions = [
+		    'dsx:addressable=tgtid',
+		    'dsx:max_segments=1',
+		    'dsx:get_ident=tgtid:p_vci_target:mt,srcid:p_vci_initiator:mt',
+		],
+)
Index: trunk/modules/vci_spi/caba/source/include/vci_spi.h
===================================================================
--- trunk/modules/vci_spi/caba/source/include/vci_spi.h	(revision 551)
+++ trunk/modules/vci_spi/caba/source/include/vci_spi.h	(revision 551)
@@ -0,0 +1,234 @@
+
+/* -*- c++ -*-
+ *
+ * SOCLIB_LGPL_HEADER_BEGIN
+ * 
+ * This file is part of SoCLib, GNU LGPLv2.1.
+ * 
+ * SoCLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 of the License.
+ * 
+ * SoCLib is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with SoCLib; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ * 
+ * SOCLIB_LGPL_HEADER_END
+ *
+ * Copyright (c) UPMC, Lip6, SoC
+ *         manuel.bouyer@lip6.fr october 2013
+ *
+ * Maintainers: bouyer
+ */
+
+//////////////////////////////////////////////////////////////////////////////////////
+// This component is a SPI controller with a VCI interface
+// It supports only 32 or 64 bits VCI DATA width, but all addressable registers
+// contain 32 bits words. It supports VCI addresss lartger than 32 bits.
+//
+// This component can perform data transfers between one single file belonging 
+// to the host system and a buffer in the memory of the virtual prototype.
+// The file name is an argument of the constructor.
+// This component has a DMA capability, and is both a target and an initiator.
+// The burst size (bytes) must be power of 2.
+// The burst size is typically a cache line. 
+// The memory buffer must be aligned to a a burst boundary.
+// Both read and write transfers are supported. An IRQ is optionally
+// asserted when the transfer is completed. 
+//
+
+#ifndef SOCLIB_VCI_SPI_H
+#define SOCLIB_VCI_SPI_H
+
+#include <stdint.h>
+#include <systemc>
+#include <unistd.h>
+#include "caba_base_module.h"
+#include "mapping_table.h"
+#include "vci_initiator.h"
+#include "vci_target.h"
+
+namespace soclib {
+namespace caba {
+
+using namespace sc_core;
+
+template<typename vci_param>
+class VciSpi
+	: public caba::BaseModule
+{
+private:
+
+    // Registers
+    sc_signal<int>            	       r_target_fsm;   	   // target fsm state register
+    sc_signal<int>                     r_initiator_fsm;    // initiator fsm state register
+    sc_signal<int>		       r_spi_fsm;	   // spi engine state
+    sc_signal<uint64_t>                r_txrx[2];      	   // data in/out
+    sc_signal<uint32_t>                r_divider;      	   // SPI clk divider
+    sc_signal<uint8_t>                 r_ss;      	   // SPI slave select
+    sc_signal<bool>                    r_ctrl_cpol;	// clock polarity
+    sc_signal<bool>                    r_ctrl_cpha;	// clock phase
+    sc_signal<bool>                    r_ctrl_ass;	// auto slave select
+    sc_signal<bool>                    r_ctrl_ie;	// interrupt enable
+    sc_signal<bool>                    r_ctrl_go_bsy;
+    sc_signal<uint8_t>                 r_ctrl_char_len; // number of bits in xfer
+
+    sc_signal<uint8_t>                 r_txrx_addr;
+
+    sc_signal<uint32_t>		       r_bit_count;
+    sc_signal<uint32_t>		       r_clk_counter;
+    sc_signal<bool>		       r_spi_clk;
+    sc_signal<bool>		       r_spi_clk_previous;
+    sc_signal<bool>		       r_spi_clk_ignore;
+    sc_signal<bool>		       r_spi_out;
+    sc_signal<bool>		       r_irq;
+
+    sc_signal<bool>		       r_read;
+    sc_signal<uint32_t>                r_nblocks;      	   // number of blocks in transfer
+    sc_signal<uint64_t>                r_buf_address;  	   // memory buffer address 
+    sc_signal<uint32_t>                r_index;        	   // word index in local buffer
+    sc_signal<uint32_t>                r_latency_count;    // latency counter 
+    sc_signal<uint32_t>                r_words_count;      // word counter (in a burst)
+    sc_signal<uint32_t>                r_burst_count;      // burst counter (in a block)
+    sc_signal<uint32_t>                r_block_count;  	   // block counter (in a transfer)
+    sc_signal<uint32_t>                r_burst_offset;     // number of non aligned words
+    sc_signal<uint32_t>                r_burst_nwords;     // number of words in a burst
+    sc_signal<bool>                    r_go;           	   // command from T_FSM to M_FSM
+
+    sc_signal<typename vci_param::srcid_t >	r_srcid;   // save srcid
+    sc_signal<typename vci_param::trdid_t >	r_trdid;   // save trdid
+    sc_signal<typename vci_param::pktid_t >	r_pktid;   // save pktid
+    sc_signal<typename vci_param::data_t >	r_tdata;   // save wdata
+
+    uint32_t*                          r_local_buffer; 	   // capacity is one block 
+
+    // structural parameters
+    std::list<soclib::common::Segment> m_seglist;
+    uint32_t                           m_srcid;        	   // initiator index
+    const uint32_t		       m_words_per_block;  // block size 
+    const uint32_t                     m_words_per_burst;  // number of words in a burst
+    const uint32_t                     m_bursts_per_block; // number of bursts in a block
+
+    // methods
+    void transition();
+    void genMoore();
+
+    //  Master FSM states
+    enum {
+    M_IDLE              = 0,
+
+    M_READ_BLOCK        = 1,
+    M_READ_BURST        = 2,
+    M_READ_CMD          = 3,
+    M_READ_RSP          = 4,
+    M_READ_SUCCESS      = 5,
+    M_READ_ERROR        = 6,
+
+    M_WRITE_BURST       = 7,
+    M_WRITE_CMD         = 8,
+    M_WRITE_RSP         = 9,
+    M_WRITE_BLOCK       = 10,
+    M_WRITE_SUCCESS     = 11,
+    M_WRITE_ERROR       = 12,
+    };
+
+    // Target FSM states
+    enum {
+    T_IDLE              = 0,
+    T_WRITE_TXRX        = 1,
+    T_READ_TXRX         = 2,
+    T_WRITE_CTRL        = 3,
+    T_READ_CTRL         = 4,
+    T_WRITE_DIVIDER     = 5,
+    T_READ_DIVIDER      = 6,
+    T_WRITE_SS          = 7,
+    T_READ_SS           = 8,
+    T_WRITE_ERROR       = 9,
+    T_READ_ERROR        = 10,
+    };
+
+    // SPI FSM states
+    enum {
+    S_IDLE		= 0,
+    S_XMIT		= 1,
+    };
+
+    // Error codes values
+    enum {
+    VCI_READ_OK		= 0,
+    VCI_READ_ERROR	= 1,
+    VCI_WRITE_OK	= 2,
+    VCI_WRITE_ERROR	= 3,
+    };
+
+    /* transaction type, pktid field */
+    enum transaction_type_e
+    {
+      // b3 unused
+      // b2 READ / NOT READ
+      // Si READ
+      //  b1 DATA / INS
+      //  b0 UNC / MISS
+      // Si NOT READ
+      //  b1 accÃšs table llsc type SW / other
+      //  b2 WRITE/CAS/LL/SC
+      TYPE_READ_DATA_UNC          = 0x0,
+      TYPE_READ_DATA_MISS         = 0x1,
+      TYPE_READ_INS_UNC           = 0x2,
+      TYPE_READ_INS_MISS          = 0x3,
+      TYPE_WRITE                  = 0x4,
+      TYPE_CAS                    = 0x5,
+      TYPE_LL                     = 0x6,
+      TYPE_SC                     = 0x7
+    };
+
+protected:
+
+    SC_HAS_PROCESS(VciSpi);
+
+public:
+
+    // ports
+    sc_in<bool> 					      p_clk;
+    sc_in<bool> 					      p_resetn;
+    sc_out<bool> 					      p_irq;
+    soclib::caba::VciInitiator<vci_param> p_vci_initiator;
+    soclib::caba::VciTarget<vci_param>    p_vci_target;
+    sc_out<bool> 					      p_spi_ss;
+    sc_out<bool> 					      p_spi_clk;
+    sc_out<bool> 					      p_spi_mosi;
+    sc_in<bool> 					      p_spi_miso;
+
+    void print_trace();
+
+    // Constructor   
+    VciSpi(
+	sc_module_name                      name,
+	const soclib::common::MappingTable  &mt,
+	const soclib::common::IntTab 	    &srcid,
+	const soclib::common::IntTab 	    &tgtid,
+        const uint32_t 	                    burst_size = 64);
+
+    ~VciSpi();
+
+};
+
+}}
+
+#endif /* SOCLIB_VCI_SPI_H */
+
+// Local Variables:
+// tab-width: 4
+// c-basic-offset: 4
+// c-file-offsets:((innamespace . 0)(inline-open . 0))
+// indent-tabs-mode: nil
+// End:
+
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: trunk/modules/vci_spi/caba/source/src/vci_spi.cpp
===================================================================
--- trunk/modules/vci_spi/caba/source/src/vci_spi.cpp	(revision 551)
+++ trunk/modules/vci_spi/caba/source/src/vci_spi.cpp	(revision 551)
@@ -0,0 +1,890 @@
+/* -*- c++ -*-
+ *
+ * SOCLIB_LGPL_HEADER_BEGIN
+ * 
+ * This file is part of SoCLib, GNU LGPLv2.1.
+ * 
+ * SoCLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 of the License.
+ * 
+ * SoCLib is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with SoCLib; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ * 
+ * SOCLIB_LGPL_HEADER_END
+ *
+ * Copyright (c) UPMC, Lip6, SoC
+ *         manuel.bouyer@lip6.fr october 2013
+ *
+ * Maintainers: bouyer
+ */
+
+#include <stdint.h>
+#include <iostream>
+#include <fcntl.h>
+#include "vci_spi.h"
+#include "vcispi.h"
+
+namespace soclib { namespace caba {
+
+#define tmpl(t) template<typename vci_param> t VciSpi<vci_param>
+
+using namespace soclib::caba;
+using namespace soclib::common;
+
+////////////////////////
+tmpl(void)::transition()
+{
+    if(p_resetn.read() == false) 
+    {
+        r_initiator_fsm   = M_IDLE;
+        r_target_fsm      = T_IDLE;
+	r_spi_fsm         = S_IDLE;
+        r_ss              = 0;
+        r_divider         = 0xffff;
+        r_ctrl_char_len   = 0;
+        r_ctrl_ass        = false;
+        r_ctrl_ie         = false;
+        r_ctrl_cpol       = false;
+        r_ctrl_cpha       = false;
+        r_ctrl_go_bsy     = false;
+	r_clk_counter     = 0xffff;
+	r_spi_clk         = 0;
+
+	r_irq		  = false;
+	r_read		  = false;
+
+        return;
+    } 
+
+    //////////////////////////////////////////////////////////////////////////////
+    // The Target FSM controls the following registers:
+    // r_target_fsm, r_irq_enable, r_nblocks, r_buf adress, r_lba, r_go, r_read
+    //////////////////////////////////////////////////////////////////////////////
+
+    switch(r_target_fsm) {
+    ////////////
+    case T_IDLE:
+    {
+        if ( p_vci_target.cmdval.read() ) 
+        { 
+            r_srcid = p_vci_target.srcid.read();
+            r_trdid = p_vci_target.trdid.read();
+            r_pktid = p_vci_target.pktid.read();
+	    r_tdata = p_vci_target.wdata.read();
+            sc_dt::sc_uint<vci_param::N> address = p_vci_target.address.read();
+
+            bool found = false;
+            std::list<soclib::common::Segment>::iterator seg;
+            for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) 
+            {
+                if ( seg->contains(address) ) found = true;
+            }
+ 
+            bool                  read    = (p_vci_target.cmd.read() == vci_param::CMD_READ);
+            uint32_t              cell    = (uint32_t)((address & 0x3F)>>2);
+
+	    if (read) {
+		if (not found) {
+            		r_target_fsm = T_READ_ERROR;
+		} else {
+			switch(cell) {
+			case SPI_DATA_TXRX0:
+			case SPI_DATA_TXRX1:
+			case SPI_DATA_TXRX2:
+			case SPI_DATA_TXRX3:
+				r_target_fsm = T_READ_TXRX;
+				r_txrx_addr = cell;
+				break;
+			case SPI_CTRL:
+				r_target_fsm = T_READ_CTRL;
+				break;
+			case SPI_DIVIDER:
+				r_target_fsm = T_READ_DIVIDER;
+				break;
+			case SPI_SS:
+				r_target_fsm = T_READ_SS;
+				break;
+			default:
+				r_target_fsm = T_READ_ERROR;
+				break;
+			}
+		}
+	    } else { // write
+		if (not found) {
+            		r_target_fsm = T_WRITE_ERROR;
+		} else {
+			switch(cell) {
+			case SPI_DATA_TXRX0:
+			case SPI_DATA_TXRX1:
+			case SPI_DATA_TXRX2:
+			case SPI_DATA_TXRX3:
+				r_target_fsm = T_WRITE_TXRX;
+				r_txrx_addr = cell;
+				break;
+			case SPI_CTRL:
+				r_target_fsm = T_WRITE_CTRL;
+				break;
+			case SPI_DIVIDER:
+				r_target_fsm = T_WRITE_DIVIDER;
+				break;
+			case SPI_SS:
+				r_target_fsm = T_WRITE_SS;
+				break;
+			default:
+				r_target_fsm = T_WRITE_ERROR;
+				break;
+			}
+		}
+	    }
+			
+        }
+        break;
+    }
+    ////////////////////
+    case T_WRITE_TXRX:
+    {
+	if (p_vci_target.rspack.read() ) {
+            if (r_ctrl_go_bsy.read() == false)
+            {
+		switch(r_txrx_addr.read()) {
+		case 0:
+                    r_txrx[0]     = (r_txrx[0] & 0xffffffff00000000) |
+		        ((uint64_t)r_tdata.read() & 0x00000000ffffffff);
+		    break;
+		case 1:
+                    r_txrx[0]     = (r_txrx[0] & 0x00000000ffffffff) |
+			((uint64_t)r_tdata.read() << 32);
+		    break;
+		case 2:
+                    r_txrx[1]     = (r_txrx[1] & 0xffffffff00000000) |
+		        ((uint64_t)r_tdata.read() & 0x00000000ffffffff);
+		    break;
+		case 3:
+                    r_txrx[1]     = (r_txrx[1] & 0x00000000ffffffff) |
+			((uint64_t)r_tdata.read() << 32);
+		    break;
+	    }
+            r_target_fsm  = T_IDLE;
+        }
+        break;
+    }
+    ////////////////////////
+    case T_WRITE_CTRL:
+    {
+	if (p_vci_target.rspack.read() ) {
+            if (r_ctrl_go_bsy.read() == false)
+            {
+                r_ctrl_cpol = ((r_tdata.read() & SPI_CTRL_CPOL) != 0);
+                r_ctrl_cpha = ((r_tdata.read() & SPI_CTRL_CPHA) != 0);
+                r_ctrl_ass = ((r_tdata.read() & SPI_CTRL_ASS_EN) != 0);
+                r_ctrl_ie  = ((r_tdata.read() & SPI_CTRL_IE_EN) != 0);
+                r_ctrl_go_bsy = ((r_tdata.read() & SPI_CTRL_GO_BSY) != 0);
+		r_ctrl_char_len = (r_tdata.read() & SPI_CTRL_CHAR_LEN_MASK);
+#ifdef SOCLIB_MODULE_DEBUG
+		if ((r_tdata.read() & SPI_CTRL_GO_BSY) != 0) {
+		    std::cout << name() << " start xfer " << std::dec << (int)r_ctrl_char_len.read() << " data " << std::hex << r_txrx[1] << " " << r_txrx[0] << std::endl;
+		}
+#endif
+	    }
+            r_target_fsm  = T_IDLE;
+        }
+        break;
+    }
+    ///////////////////
+    case T_WRITE_DIVIDER:
+    {
+	if (p_vci_target.rspack.read() ) {
+            if (r_ctrl_go_bsy.read() == false)
+            {
+                r_divider    = (uint32_t)r_tdata.read();
+#ifdef SOCLIB_MODULE_DEBUG
+		std::cout << name() << " divider set to " << std::dec << (uint32_t)r_tdata.read() << std::endl;
+#endif
+            }
+            r_target_fsm = T_IDLE;
+	}
+        break;
+    }
+    /////////////////
+    case T_WRITE_SS:
+    {
+	if (p_vci_target.rspack.read() ) {
+            if (r_ctrl_go_bsy.read() == false)
+                r_ss         = (uint32_t)r_tdata.read();
+            }
+            r_target_fsm = T_IDLE;
+	}
+        break;
+    }
+    ///////////////////
+    case T_READ_TXRX:
+    case T_READ_DIVIDER:
+    case T_READ_SS:
+    case T_WRITE_ERROR:
+    case T_READ_ERROR:
+    {
+        if ( p_vci_target.rspack.read() ) r_target_fsm = T_IDLE;
+        break;
+    }
+    ///////////////////
+    case T_READ_CTRL:
+    {
+        if ( p_vci_target.rspack.read() ) 
+        {
+            r_target_fsm = T_IDLE;
+	    r_irq = r_irq & r_ctrl_go_bsy;
+        }
+        break;
+    }
+    } // end switch target fsm
+
+
+	
+
+    //////////////////////////////////////////////////////////////////////////////
+    // the SPI FSM controls SPI signals
+    //////////////////////////////////////////////////////////////////////////////
+    switch (r_spi_fsm) {
+    case S_IDLE:
+	r_clk_counter = r_divider.read();
+	r_spi_clk = 0;
+	r_spi_clk_previous = r_ctrl_cpha;
+	r_spi_clk_ignore = r_ctrl_cpha;
+	r_bit_count = r_ctrl_char_len;
+	r_spi_out = (r_txrx[(r_ctrl_char_len -1)/ 64] >> ((r_ctrl_char_len - 1) % 64)) & 0x0000000000000001;
+	if (r_ctrl_go_bsy.read())
+		r_spi_fsm = S_XMIT;
+	break;
+    case S_XMIT:
+      {
+	bool s_clk_sample;
+	// on clock transition, sample input line, and shift data
+	s_clk_sample = r_spi_clk ^ r_ctrl_cpha;
+	if (!r_spi_clk_ignore) {
+	    if (r_spi_clk_previous == 0 && s_clk_sample == 1) {
+	        // low to high transition: shift and sample
+	        r_txrx[1] = (r_txrx[1] << 1) | (r_txrx[0] >> 63);
+	        r_txrx[0] = (r_txrx[0] << 1) | p_spi_miso;
+	        r_bit_count = r_bit_count - 1;
+	    } else if (r_spi_clk_previous == 1 && s_clk_sample == 0) {
+	        // high to low transition: change output, or stop
+	        if (r_bit_count == 0) {
+		    r_spi_fsm = S_IDLE;
+		    r_irq = r_ctrl_ie;
+		    r_ctrl_go_bsy = false;
+#ifdef SOCLIB_MODULE_DEBUG
+		    std::cout << name() << " end xfer " << std::dec << (int)r_ctrl_char_len.read() << " data " << std::hex << r_txrx[1] << " " << r_txrx[0] << std::endl;
+#endif
+		} else {
+		    r_spi_out = (r_txrx[(r_ctrl_char_len -1)/ 64] >> ((r_ctrl_char_len - 1) % 64)) & 0x0000000000000001;
+		}
+	    }
+	}
+	r_spi_clk_previous = s_clk_sample;
+        // generate the SPI clock
+	if (r_clk_counter.read() == 0) {
+	    r_clk_counter = r_divider.read();
+	    r_spi_clk = !r_spi_clk.read();
+	    r_spi_clk_ignore = false;
+	} else {
+	    r_clk_counter = r_clk_counter.read() - 1;
+	}
+	break;
+      }
+    }
+    //////////////////////////////////////////////////////////////////////////////
+    // The initiator FSM executes a loop, transfering one block per iteration.
+    // Each block is split in bursts, and the number of bursts depends
+    // on the memory buffer alignment on a burst boundary:
+    // - If buffer aligned, all burst have the same length (m_words_per burst)
+    //   and the number of bursts is (m_bursts_per_block).
+    // - If buffer not aligned, the number of bursts is (m_bursts_per_block + 1)
+    //   and first and last burst are shorter, because all words in a burst 
+    //   must be contained in a single cache line.
+    //   first burst => nwords = m_words_per_burst - offset
+    //   last  burst => nwords = offset
+    //   other burst => nwords = m_words_per_burst
+    //////////////////////////////////////////////////////////////////////////////
+
+    switch( r_initiator_fsm.read() ) {
+    ////////////
+    case M_IDLE: 	// check buffer alignment to compute the number of bursts
+    {
+        if ( false )  // XXX
+        {
+            r_index         = 0;
+            r_block_count   = 0;
+            r_burst_count   = 0;
+            r_words_count   = 0;
+
+            // compute r_burst_offset (zero when buffer aligned)
+            r_burst_offset = (uint32_t)((r_buf_address.read()>>2) % m_words_per_burst);
+
+            // start tranfer
+            if ( r_read.read() ) 	r_initiator_fsm = M_READ_BLOCK;
+            else                    r_initiator_fsm = M_WRITE_BURST;
+        }
+        break;
+    } 
+    //////////////////
+    case M_READ_BLOCK:  // read one block from disk after waiting m_latency cycles
+    {
+        r_burst_count   = 0;
+        r_words_count    = 0;
+        r_initiator_fsm = M_READ_BURST;
+        break;
+    }
+    //////////////////
+    case M_READ_BURST:  // Compute the number of words and the number of flits in the burst
+                        // The number of flits can be smaller than the number of words 
+                        // in case of 8 bytes flits...
+    {
+        uint32_t nwords;
+        uint32_t offset = r_burst_offset.read();
+
+        if ( offset )                  // buffer not aligned
+        {
+            if ( r_burst_count.read() == 0 ) nwords = m_words_per_burst - offset;
+            else if ( r_burst_count.read() == m_bursts_per_block ) nwords = offset;
+            else nwords = m_words_per_burst;
+        }
+        else                           // buffer aligned
+        {
+            nwords = m_words_per_burst;
+        }
+
+        r_burst_nwords  = nwords;
+        r_initiator_fsm = M_READ_CMD;
+        break;
+    }
+    ////////////////
+    case M_READ_CMD:	// Send a multi-flits VCI WRITE command
+    {
+        if ( p_vci_initiator.cmdack.read() )
+        {
+            uint32_t nwords = r_burst_nwords.read() - r_words_count.read();
+
+            if ( vci_param::B == 4 )    // one word per flit 
+            {
+                if ( nwords <= 1 )      // last flit
+                {
+                    r_initiator_fsm = M_READ_RSP;
+                    r_words_count = 0;
+                }
+                else                    // not the last flit
+                {
+                    r_words_count = r_words_count.read() + 1;
+                }
+
+                // compute next word address and next local buffer index
+                r_buf_address = r_buf_address.read() + 4;
+                r_index       = r_index.read() + 1;
+            }
+            else                        // 2 words per flit
+            {
+                if ( nwords <= 2 )      // last flit
+                {
+                    r_initiator_fsm = M_READ_RSP;
+                    r_words_count = 0;
+                }
+                else                    // not the last flit
+                {
+                    r_words_count = r_words_count.read() + 2;
+                }
+                    
+                // compute next word address and next local buffer index
+                if ( nwords == 1 )
+                {
+                    r_buf_address = r_buf_address.read() + 4;
+                    r_index       = r_index.read() + 1;
+                }
+                else
+                {
+                    r_buf_address = r_buf_address.read() + 8;
+                    r_index       = r_index.read() + 2;
+                }
+            }
+        }
+        break;
+    }
+    ////////////////
+    case M_READ_RSP: 	// Wait a single flit VCI WRITE response
+    {
+        if ( p_vci_initiator.rspval.read() )
+        {
+            bool aligned = (r_burst_offset.read() == 0);
+
+            if ( (p_vci_initiator.rerror.read()&0x1) != 0 ) 
+            {
+                r_initiator_fsm = M_READ_ERROR;
+#ifdef SOCLIB_MODULE_DEBUG
+		std::cout << "vci_bd M_READ_ERROR" << std::endl;
+#endif
+            }
+            else if ( (not aligned and (r_burst_count.read() == m_bursts_per_block)) or 
+                      (aligned and (r_burst_count.read() == (m_bursts_per_block-1))) )
+            {
+                if ( r_block_count.read() == (r_nblocks.read()-1) ) // last burst of last block 
+                {
+                    r_initiator_fsm = M_READ_SUCCESS;
+#ifdef SOCLIB_MODULE_DEBUG
+		    std::cout << "vci_bd M_READ_SUCCESS" << std::endl;
+#endif
+                }
+                else                                              // last burst not last block
+                {
+                    r_index          = 0;
+                    r_burst_count    = 0;
+                    r_block_count    = r_block_count.read() + 1;
+                    r_initiator_fsm  = M_READ_BLOCK;
+                }
+            }
+            else                                                // not the last burst
+            {
+                r_burst_count = r_burst_count.read() + 1;
+                r_initiator_fsm = M_READ_BURST;
+            }
+        }
+        break;
+    }
+    ///////////////////
+    case M_READ_SUCCESS:
+    case M_READ_ERROR:
+    {
+        if( !r_go ) r_initiator_fsm = M_IDLE;
+        break;
+    }
+    ///////////////////
+    case M_WRITE_BURST:  // Compute the number of words in the burst
+    {
+        uint32_t nwords;
+        uint32_t offset = r_burst_offset.read();
+
+        if ( offset )                  // buffer not aligned
+        {
+            if ( r_burst_count.read() == 0 ) nwords = m_words_per_burst - offset;
+            else if ( r_burst_count.read() == m_bursts_per_block ) nwords = offset;
+            else nwords = m_words_per_burst;
+        }
+        else                           // buffer aligned
+        {
+            nwords = m_words_per_burst;
+        }
+
+        r_burst_nwords  = nwords;
+        r_initiator_fsm =  M_WRITE_CMD;
+        break;
+    }
+    /////////////////
+    case M_WRITE_CMD:	// This is actually a single flit VCI READ command
+    {
+	    if ( p_vci_initiator.cmdack.read() ) r_initiator_fsm = M_WRITE_RSP;
+        break;
+    }
+    /////////////////
+    case M_WRITE_RSP:	// This is actually a multi-words VCI READ response
+    {
+        if ( p_vci_initiator.rspval.read() )
+        {
+            bool aligned = (r_burst_offset.read() == 0);
+
+            if ( (vci_param::B == 8) and (r_burst_nwords.read() > 1) )
+            {
+                r_local_buffer[r_index.read()]   = (uint32_t)p_vci_initiator.rdata.read();
+                r_local_buffer[r_index.read()+1] = (uint32_t)(p_vci_initiator.rdata.read()>>32);
+                r_index = r_index.read() + 2;
+            }
+            else
+            {
+                r_local_buffer[r_index.read()]   = (uint32_t)p_vci_initiator.rdata.read();
+                r_index = r_index.read() + 1;
+            }
+
+            if ( p_vci_initiator.reop.read() )  // last flit of the burst
+            {
+	            r_words_count  = 0;
+                r_buf_address = r_buf_address.read() + (r_burst_nwords.read()<<2); 
+
+	            if( (p_vci_initiator.rerror.read()&0x1) != 0 ) 
+                {
+                    r_initiator_fsm = M_WRITE_ERROR;
+#ifdef SOCLIB_MODULE_DEBUG
+		    std::cout << "vci_bd M_WRITE_ERROR" << std::endl;
+#endif
+                }
+                else if ( (not aligned and (r_burst_count.read() == m_bursts_per_block)) or 
+                     (aligned and (r_burst_count.read() == (m_bursts_per_block-1))) ) // last burst
+                {
+                    r_initiator_fsm  = M_WRITE_BLOCK;
+                }
+                else                                          // not the last burst
+                {
+                    r_burst_count = r_burst_count.read() + 1;
+                    r_initiator_fsm = M_WRITE_BURST;
+                }
+            }
+            else
+            {
+	            r_words_count = r_words_count.read() + 1;
+            }
+        }
+        break;
+    }
+    ///////////////////
+    case M_WRITE_BLOCK:		// write a block to disk after waiting m_latency cycles
+    {
+        if ( r_block_count.read() == r_nblocks.read() - 1 ) 
+        {
+            r_initiator_fsm = M_WRITE_SUCCESS; 
+#ifdef SOCLIB_MODULE_DEBUG
+	    std::cout << "vci_bd M_WRITE_SUCCESS" << std::endl;
+#endif
+        }
+        else
+        {
+            r_burst_count    = 0;
+            r_index          = 0;
+            r_block_count    = r_block_count.read() + 1;
+            r_initiator_fsm  = M_WRITE_BURST;
+        }
+        break;
+    }
+    /////////////////////
+    case M_WRITE_SUCCESS:
+    case M_WRITE_ERROR:
+    {
+        r_initiator_fsm = M_IDLE;
+        break;
+    }
+    } // end switch r_initiator_fsm
+}  // end transition
+
+//////////////////////
+tmpl(void)::genMoore()
+{
+    // p_vci_target port   
+    p_vci_target.rsrcid = (sc_dt::sc_uint<vci_param::S>)r_srcid.read();
+    p_vci_target.rtrdid = (sc_dt::sc_uint<vci_param::T>)r_trdid.read();
+    p_vci_target.rpktid = (sc_dt::sc_uint<vci_param::P>)r_pktid.read();
+    p_vci_target.reop   = true;
+
+    switch(r_target_fsm) {
+    case T_IDLE:
+        p_vci_target.cmdack = true;
+        p_vci_target.rspval = false;
+        p_vci_target.rdata  = 0;
+        break;
+    case T_READ_TXRX:
+        p_vci_target.cmdack = false;
+        p_vci_target.rspval = true;
+	switch(r_txrx_addr.read()) {
+	case 0:
+		p_vci_target.rdata = r_txrx[0] & 0x00000000ffffffff;
+		break;
+	case 1:
+		p_vci_target.rdata = r_txrx[0] >> 32;
+		break;
+	case 2:
+		p_vci_target.rdata = r_txrx[1] & 0x00000000ffffffff;
+		break;
+	case 3:
+		p_vci_target.rdata = r_txrx[1] >> 32;
+		break;
+	}
+        p_vci_target.rerror = VCI_READ_OK;
+        break;
+    case T_READ_CTRL:
+    {
+	uint32_t data = 0;
+	if (r_ctrl_cpol.read()) 
+		data |= SPI_CTRL_CPOL;
+	if (r_ctrl_cpha.read()) 
+		data |= SPI_CTRL_CPHA;
+	if (r_ctrl_ass.read()) 
+		data |= SPI_CTRL_ASS_EN;
+	if (r_ctrl_ie.read()) 
+		data |= SPI_CTRL_IE_EN;
+	if (r_ctrl_go_bsy.read()) 
+		data |= SPI_CTRL_GO_BSY;
+	data |= (uint32_t)r_ctrl_char_len.read();
+
+        p_vci_target.cmdack = false;
+        p_vci_target.rspval = true;
+        p_vci_target.rdata  = data;
+        p_vci_target.rerror = VCI_READ_OK;
+        break;
+    }
+    case T_READ_DIVIDER:
+        p_vci_target.cmdack = false;
+        p_vci_target.rspval = true;
+        p_vci_target.rdata  = r_divider.read();
+        p_vci_target.rerror = VCI_READ_OK;
+        break;
+    case T_READ_SS:
+        p_vci_target.cmdack = false;
+        p_vci_target.rspval = true;
+        p_vci_target.rdata  = r_ss.read();
+        p_vci_target.rerror = VCI_READ_OK;
+        break;
+    case T_READ_ERROR:
+        p_vci_target.cmdack = false;
+        p_vci_target.rspval = true;
+        p_vci_target.rdata  = 0;
+        p_vci_target.rerror = VCI_READ_ERROR;
+        break;
+    case T_WRITE_ERROR:
+        p_vci_target.cmdack = false;
+        p_vci_target.rspval = true;
+        p_vci_target.rdata  = 0;
+        p_vci_target.rerror = VCI_WRITE_ERROR;
+        break;
+    default:
+        p_vci_target.cmdack = false;
+        p_vci_target.rspval = true;
+        p_vci_target.rdata  = 0;
+        p_vci_target.rerror = VCI_WRITE_OK;
+        break;
+    } // end switch target fsm
+
+    // p_vci_initiator port
+    p_vci_initiator.srcid  = (sc_dt::sc_uint<vci_param::S>)m_srcid;
+    p_vci_initiator.trdid  = 0;
+    p_vci_initiator.contig = true;
+    p_vci_initiator.cons   = false;
+    p_vci_initiator.wrap   = false;
+    p_vci_initiator.cfixed = false;
+    p_vci_initiator.clen   = 0;
+
+    switch (r_initiator_fsm) {
+    case M_WRITE_CMD:		// It is actually a single flit VCI read command
+        p_vci_initiator.rspack  = false;
+        p_vci_initiator.cmdval  = true;
+        p_vci_initiator.address = (sc_dt::sc_uint<vci_param::N>)r_buf_address.read();
+        p_vci_initiator.cmd     = vci_param::CMD_READ;
+        p_vci_initiator.pktid   = TYPE_READ_DATA_UNC; 
+        p_vci_initiator.wdata   = 0;
+        p_vci_initiator.be      = 0;
+        p_vci_initiator.plen    = (sc_dt::sc_uint<vci_param::K>)(r_burst_nwords.read()<<2);
+        p_vci_initiator.eop     = true;
+        break;
+    case M_READ_CMD:		// It is actually a multi-words VCI WRITE command 
+        p_vci_initiator.rspack  = false;
+        p_vci_initiator.cmdval  = true;
+        p_vci_initiator.address = (sc_dt::sc_uint<vci_param::N>)r_buf_address.read(); 
+        p_vci_initiator.cmd     = vci_param::CMD_WRITE;
+        p_vci_initiator.pktid   = TYPE_WRITE;
+        p_vci_initiator.plen    = (sc_dt::sc_uint<vci_param::K>)(r_burst_nwords.read()<<2);
+        if ( (vci_param::B == 8) and ((r_burst_nwords.read() - r_words_count.read()) > 1) )  
+        {
+            p_vci_initiator.wdata = ((uint64_t)r_local_buffer[r_index.read()  ]) +
+                                   (((uint64_t)r_local_buffer[r_index.read()+1]) << 32); 
+            p_vci_initiator.be    = 0xFF;
+            p_vci_initiator.eop   = ( (r_burst_nwords.read() - r_words_count.read()) <= 2 );
+        }
+        else
+        {
+            p_vci_initiator.wdata = r_local_buffer[r_index.read()];
+            p_vci_initiator.be    = 0xF;
+            p_vci_initiator.eop   = ( r_words_count.read() == (r_burst_nwords.read() - 1) );
+        }
+        break;
+    case M_READ_RSP:
+    case M_WRITE_RSP:
+        p_vci_initiator.rspack  = true;
+        p_vci_initiator.cmdval  = false;
+        break;
+    default:
+        p_vci_initiator.rspack  = false;
+        p_vci_initiator.cmdval  = false;
+        break;
+    }
+
+    // SPI signals
+    p_spi_ss = ((r_ss & 0x1) == 0);
+    switch(r_spi_fsm) {
+    case S_IDLE:
+	p_spi_mosi = 0;
+	p_spi_clk = 0;
+	break;
+    case S_XMIT:
+	p_spi_clk = r_spi_clk ^ r_ctrl_cpol;
+	p_spi_mosi = r_spi_out;
+	break;
+    }
+
+    // IRQ signal
+    p_irq = r_irq;
+} // end GenMoore()
+
+//////////////////////////////////////////////////////////////////////////////
+tmpl(/**/)::VciSpi( sc_core::sc_module_name              name, 
+                                const soclib::common::MappingTable   &mt,
+                                const soclib::common::IntTab         &srcid,
+                                const soclib::common::IntTab         &tgtid,
+                                const uint32_t                       burst_size)
+
+: caba::BaseModule(name),
+	m_seglist(mt.getSegmentList(tgtid)),
+	m_srcid(mt.indexForId(srcid)),
+	m_words_per_block(512/4),
+	m_words_per_burst(burst_size/4),
+	m_bursts_per_block(512/burst_size),
+	p_clk("p_clk"),
+	p_resetn("p_resetn"),
+	p_vci_initiator("p_vci_initiator"),
+	p_vci_target("p_vci_target"),
+	p_irq("p_irq"),
+	p_spi_ss("p_spi_ss"),
+	p_spi_clk("p_spi_clk"),
+	p_spi_mosi("p_spi_mosi"),
+	p_spi_miso("p_spi_miso")
+{
+    std::cout << "  - Building VciSpi " << name << std::endl;
+
+	SC_METHOD(transition);
+    dont_initialize();
+    sensitive << p_clk.pos();
+
+	SC_METHOD(genMoore);
+    dont_initialize();
+    sensitive << p_clk.neg();
+
+    size_t nbsegs = 0;
+    std::list<soclib::common::Segment>::iterator seg;
+    for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) 
+    {
+        nbsegs++;
+        
+	    if ( (seg->baseAddress() & 0x0000003F) != 0 ) 
+	    {
+		    std::cout << "Error in component VciSpi : " << name 
+		              << "The base address of segment " << seg->name()
+                      << " must be multiple of 64 bytes" << std::endl;
+		    exit(1);
+	    }
+	    if ( seg->size() < 64 ) 
+	    {
+		    std::cout << "Error in component VciSpi : " << name 
+	                  << "The size of segment " << seg->name()
+                      << " cannot be smaller than 64 bytes" << std::endl;
+		    exit(1);
+	    }
+        std::cout << "    => segment " << seg->name()
+                  << " / base = " << std::hex << seg->baseAddress()
+                  << " / size = " << seg->size() << std::endl; 
+    }
+
+    if( nbsegs == 0 )
+    {
+		std::cout << "Error in component VciSpi : " << name
+		          << " No segment allocated" << std::endl;
+		exit(1);
+    }
+
+    if( (burst_size != 8 ) && 
+		(burst_size != 16) && 
+		(burst_size != 32) && 
+		(burst_size != 64) )
+	{
+		std::cout << "Error in component VciSpi : " << name 
+		          << " The burst size must be 8, 16, 32 or 64 bytes" << std::endl;
+		exit(1);
+	}
+
+	if ( (vci_param::B != 4) and (vci_param::B != 8) )
+	{
+		std::cout << "Error in component VciSpi : " << name              
+		          << " The VCI data fields must have 32 bits or 64 bits" << std::endl;
+		exit(1);
+	}
+
+	r_local_buffer = new uint32_t[m_words_per_block];
+
+} // end constructor
+
+tmpl(/**/)::~VciSpi()
+{
+    delete [] r_local_buffer;
+}
+
+
+//////////////////////////
+tmpl(void)::print_trace()
+{
+	const char* initiator_str[] = 
+    {
+		"M_IDLE",
+
+		"M_READ_BLOCK",
+		"M_READ_BURST",
+		"M_READ_CMD",
+		"M_READ_RSP",
+		"M_READ_SUCCESS",
+		"M_READ_ERROR",
+
+		"M_WRITE_BURST",
+		"M_WRITE_CMD",
+		"M_WRITE_RSP",
+		"M_WRITE_BLOCK",
+		"M_WRITE_SUCCESS",
+		"M_WRITE_ERROR",
+	};
+	const char* target_str[] = 
+    {
+		"T_IDLE",
+		"T_WRITE_TXRX",
+		"T_READ_TXRX",
+		"T_WRITE_CTRL",
+		"T_READ_CTRL",
+		"T_WRITE_DIVIDER",
+		"T_READ_DIVIDER",
+		"T_WRITE_SS",
+		"T_READ_SS",
+		"T_WRITE_ERROR",
+		"T_READ_ERROR",
+	};
+	const char* spi_str[] = 
+    {
+		"S_IDLE",
+		"S_XMIT",
+	};
+
+	std::cout << name() << " _TGT : " << target_str[r_target_fsm.read()] 
+	    << std::endl;
+	std::cout << name() << " _SPI : " << spi_str[r_spi_fsm.read()] 
+	    << " clk_counter " << r_clk_counter.read()
+	    << " r_bit_count " << r_bit_count.read() << std::endl;
+	std::cout << name() << " _SPI : "
+	    << " r_spi_clk " << r_spi_clk.read()
+	    << " cpol " << r_ctrl_cpol.read()
+	    << " cpha " << r_ctrl_cpha.read()
+	    << " r_spi_clk_ignore " << r_spi_clk_ignore.read()
+	    << " r_txrx 0x" << std::hex
+	    << r_txrx[1].read() << " " << r_txrx[0].read()
+	    << std::endl;
+	std::cout << name() << "  _INI : " << initiator_str[r_initiator_fsm.read()] 
+          << "  buf = " << std::hex << r_buf_address.read()
+	  << "  block = " << std::dec << r_block_count.read() 
+	  << "  burst = " << r_burst_count.read() 
+	  << "  word  = " << r_words_count.read() <<std::endl; 
+}
+
+}} // end namespace
+
+// Local Variables:
+// tab-width: 4
+// c-basic-offset: 4
+// c-file-offsets:((innamespace . 0)(inline-open . 0))
+// indent-tabs-mode: nil
+// End:
+
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: trunk/modules/vci_spi/include/soclib/vcispi.h
===================================================================
--- trunk/modules/vci_spi/include/soclib/vcispi.h	(revision 551)
+++ trunk/modules/vci_spi/include/soclib/vcispi.h	(revision 551)
@@ -0,0 +1,58 @@
+/*
+ * SOCLIB_LGPL_HEADER_BEGIN
+ * 
+ * This file is part of SoCLib, GNU LGPLv2.1.
+ * 
+ * SoCLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 of the License.
+ * 
+ * SoCLib is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with SoCLib; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ * 
+ * SOCLIB_LGPL_HEADER_END
+ *
+ * Copyright (c) UPMC, Lip6, Asim
+ *         alain greiner
+ *
+ * Maintainers: alain
+ */
+#ifndef SPISD_H
+#define SPISD_H
+
+enum SoclibBlockDeviceRegisters {
+    SPI_DATA_TXRX0,
+    SPI_DATA_TXRX1,
+    SPI_DATA_TXRX2,
+    SPI_DATA_TXRX3,
+    SPI_CTRL,
+    SPI_DIVIDER,
+    SPI_SS
+};
+
+#define SPI_CTRL_CPOL		(1 << 15) /* Clock polarity                */
+#define SPI_CTRL_CPHA		(1 << 14) /* Clock phase                   */
+#define SPI_CTRL_ASS_EN		(1 << 13) /* Auto Slave Sel Assertion      */
+#define SPI_CTRL_IE_EN		(1 << 12) /* Interrupt Enable              */
+// 9-11 reserved
+#define SPI_CTRL_GO_BSY		(1 << 8 ) /* Start the transfer            */
+#define SPI_CTRL_CHAR_LEN_MASK	(0xFF   ) /* Bits transmited in 1 transfer */
+
+#endif /* SPISD_H */
+
+// Local Variables:
+// tab-width: 4
+// c-basic-offset: 4
+// c-file-offsets:((innamespace . 0)(inline-open . 0))
+// indent-tabs-mode: nil
+// End:
+
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
