Index: trunk/modules/sdmmc/caba/metadata/sdmmc.sd
===================================================================
--- trunk/modules/sdmmc/caba/metadata/sdmmc.sd	(revision 552)
+++ trunk/modules/sdmmc/caba/metadata/sdmmc.sd	(revision 552)
@@ -0,0 +1,33 @@
+
+# -*- python -*-
+
+Module('caba:sdmmc',
+	classname = 'soclib::caba::SdMMC',
+
+        header_files = [
+            '../source/include/sdmmc.h', 
+        ],
+
+        implementation_files = [
+            '../source/src/sdmmc.cpp',
+        ],
+
+        ports = [
+		    Port('caba:bit_in', 'p_spi_clk'),
+		    Port('caba:bit_in', 'p_spi_ss'),
+		    Port('caba:bit_in', 'p_spi_mosi'),
+		    Port('caba:bit_out', 'p_spi_miso'),
+		    Port('caba:bit_in',   'p_resetn', auto = 'resetn'),
+		    Port('caba:clock_in', 'p_clk', auto = 'clock'), 
+		],
+
+        uses = [
+		    Uses('caba:base_module'),
+		],
+
+        instance_parameters = [
+        	parameter.String('filename'),
+		parameter.Int('latency'),
+        ],
+
+)
Index: trunk/modules/sdmmc/caba/source/include/sdmmc.h
===================================================================
--- trunk/modules/sdmmc/caba/source/include/sdmmc.h	(revision 552)
+++ trunk/modules/sdmmc/caba/source/include/sdmmc.h	(revision 552)
@@ -0,0 +1,139 @@
+
+/* -*- 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 SD/MMC block device.
+//
+// This component can perform data transfers between one single file belonging 
+// to the host system and a SPI controller.
+// The file name is an argument of the constructor.
+//
+
+#ifndef SOCLIB_SDMMC_H
+#define SOCLIB_SDMMC_H
+
+#include <stdint.h>
+#include <systemc>
+#include <unistd.h>
+#include "caba_base_module.h"
+
+namespace soclib {
+namespace caba {
+
+using namespace sc_core;
+
+class SdMMC
+	: public caba::BaseModule
+{
+private:
+
+    // Registers
+    sc_signal<int>            	      r_spi_fsm;   	 // SPI state register
+    sc_signal<uint8_t>		      r_spi_shiftreg;	// data shift in/out
+    sc_signal<uint8_t>		      r_spi_bitcount;
+    sc_signal<bool>		      r_spi_clk;
+
+    sc_signal<uint8_t>		      r_command;
+    sc_signal<uint32_t>		      r_args;
+    sc_signal<uint8_t>		      r_cmdcrc;
+    int                               m_fd;           	 // File descriptor
+    uint64_t                          m_device_size;  	 // Total number of blocks
+    const uint32_t                    m_latency;      	 // device latency
+
+    uint8_t			      m_databuf[1 /* reponse */ + 1 /* data tocken */ + 512 /* data block */ + 2 /* CRC */ ];
+    uint32_t			      m_datalen_snd; // data size to be sent to host
+    uint32_t                          m_datalen_rcv; // data size expected from host
+    uint32_t			      m_data_idx;
+    bool			      m_acmd; // next command will be acmd
+    int				      m_sdstate; // sdcard internal state
+
+    // sd states
+    enum {
+	SD_IDLE = 0,
+	SD_READY = 1,
+    };
+
+    // methods
+    void transition();
+    void genMoore();
+
+    void handle_sdmmc_cmd(uint8_t, uint32_t);
+    void handle_sdmmc_write();
+
+    //  Master FSM states
+    enum {
+    S_IDLE               = 0,
+    S_RECEIVE_CMD        = 1,
+    S_RECEIVE_ARGS_START = 2,
+    S_RECEIVE_ARGS       = 3,
+    S_RECEIVE_CRC        = 4,
+    S_RECEIVE_DATA       = 5,
+    S_RECEIVE_DATA_END   = 6,
+    S_SEND_DATA      	 = 7,
+    S_NOP		 = 8,
+    };
+
+protected:
+
+    SC_HAS_PROCESS(SdMMC);
+
+public:
+
+    // ports
+    sc_in<bool> 					      p_clk;
+    sc_in<bool> 					      p_resetn;
+    sc_in<bool> 					      p_spi_ss;
+    sc_in<bool> 					      p_spi_clk;
+    sc_in<bool> 					      p_spi_mosi;
+    sc_out<bool> 					      p_spi_miso;
+
+    void print_trace();
+
+    // Constructor   
+    SdMMC(
+	sc_module_name                      name,
+        const std::string                   &filename,
+        const uint32_t	                    latency = 0);
+
+    ~SdMMC();
+
+};
+
+}}
+
+#endif /* SOCLIB_SDMMC_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/sdmmc/caba/source/src/sdmmc.cpp
===================================================================
--- trunk/modules/sdmmc/caba/source/src/sdmmc.cpp	(revision 552)
+++ trunk/modules/sdmmc/caba/source/src/sdmmc.cpp	(revision 552)
@@ -0,0 +1,429 @@
+/* -*- 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 <errno.h>
+#include <iostream>
+#include <fcntl.h>
+#include <cassert>
+#include "sdmmc.h"
+
+namespace soclib { namespace caba {
+
+using namespace soclib::caba;
+
+////////////////////////
+void SdMMC::transition()
+{
+    if(p_resetn.read() == false) 
+    {
+        r_spi_fsm  = S_IDLE;
+	m_acmd	   = false;	 
+	m_sdstate  = SD_IDLE;
+        return;
+    } 
+    if (p_spi_ss.read()) {
+	r_spi_fsm  = S_IDLE;
+	return;
+    }
+
+    r_spi_clk = p_spi_clk;
+
+    switch(r_spi_fsm) {
+    case S_IDLE:
+	if (p_spi_clk.read() == 1 && r_spi_clk.read() == 0) {
+		// rising edge
+		r_command = (r_command << 1) | p_spi_mosi;
+		r_spi_bitcount = 6;
+		r_spi_fsm = S_RECEIVE_CMD;
+	}
+        break;
+    case S_RECEIVE_CMD:
+	if (p_spi_clk.read() == 1 && r_spi_clk.read() == 0) {
+		// rising edge
+		r_command = (r_command << 1) | p_spi_mosi;
+		r_spi_bitcount = r_spi_bitcount - 1;
+		if (r_spi_bitcount == 0) {
+			if (((r_command << 1) & 0x80) == 0) {
+				r_spi_fsm = S_RECEIVE_ARGS_START;
+			} else {
+#ifdef SOCLIB_MODULE_DEBUG
+				std::cout << name() << " S_RECEIVE_CMD " << std::hex << ((int)((r_command << 1) | p_spi_mosi) & 0xff) << std::endl;
+#endif
+				r_spi_fsm = S_IDLE;
+			}
+		}
+	}
+	break;
+    case S_RECEIVE_ARGS_START:
+	if (p_spi_clk.read() == 1 && r_spi_clk.read() == 0) {
+		// rising edge
+		r_args = (r_args << 1) | p_spi_mosi;
+		r_spi_bitcount = 30;
+		r_spi_fsm = S_RECEIVE_ARGS;
+	}
+        break;
+    case S_RECEIVE_ARGS:
+	if (p_spi_clk.read() == 1 && r_spi_clk.read() == 0) {
+		// rising edge
+		r_args = (r_args << 1) | p_spi_mosi;
+		r_spi_bitcount = r_spi_bitcount - 1;
+		if (r_spi_bitcount == 0) {
+			r_spi_bitcount = 7;
+			r_spi_fsm = S_RECEIVE_CRC;
+		}
+	}
+        break;
+    case S_RECEIVE_CRC:
+	if (p_spi_clk.read() == 1 && r_spi_clk.read() == 0) {
+		// rising edge
+		uint8_t crc = (r_cmdcrc << 1) | p_spi_mosi;
+		r_cmdcrc = crc;
+		if (r_spi_bitcount == 0) {
+			handle_sdmmc_cmd(r_command.read(), r_args.read());
+			r_spi_bitcount = 0; // SEND_DATA will reset it
+			r_spi_fsm = S_SEND_DATA;
+			m_data_idx = 0;
+		} else {
+			r_spi_bitcount = r_spi_bitcount - 1;
+		}
+	}
+	break;
+	
+    case S_SEND_DATA:
+	if (p_spi_clk.read() == 0 && r_spi_clk.read() == 1) {
+		// falling edge
+		if (r_spi_bitcount == 0) {
+			if (m_data_idx != m_datalen_snd) {	
+				r_spi_shiftreg = m_databuf[m_data_idx];
+				r_spi_bitcount = 7;
+				r_spi_fsm = S_SEND_DATA;
+				m_data_idx++;
+#ifdef SOCLIB_MODULE_DEBUG
+		        std::cout << name() << " S_SEND_DATA " << std::dec << m_datalen_snd << " idx " << m_data_idx << " " << std::hex << (uint32_t)m_databuf[m_data_idx] << std::endl;
+#endif
+			} else if (m_datalen_rcv != 0) {
+				r_spi_fsm = S_RECEIVE_DATA;
+				r_spi_bitcount = 7;
+				m_data_idx = 0;
+			} else {
+				r_spi_fsm = S_IDLE;
+			}
+		} else {
+			r_spi_bitcount = r_spi_bitcount - 1;
+			r_spi_shiftreg = r_spi_shiftreg << 1;
+		}
+	}
+	break;
+    }
+}  // end transition
+
+//////////////////////
+void SdMMC::genMoore()
+{
+    switch(r_spi_fsm) {
+    case S_IDLE:
+	p_spi_miso = !p_spi_ss.read();
+        break;
+    case S_SEND_DATA:
+	p_spi_miso = (r_spi_shiftreg & 0x80) != 0;
+	break;
+    default:
+	p_spi_miso = !p_spi_ss.read();
+        break;
+    }
+} // end GenMoore()
+
+
+//////////////////////
+void SdMMC::handle_sdmmc_cmd(uint8_t cmd, uint32_t data)
+{
+	m_datalen_rcv = 0;
+	m_databuf[0] = 0x04; // illegal command
+	m_datalen_snd = 1;
+
+	if (m_sdstate == SD_IDLE)
+		m_databuf[0] |= 0x01; // idle
+
+	if ((cmd & 0x40) == 0) {
+		//illegal command
+		return;
+	}
+	cmd &= 0x3f;
+	if (m_acmd) {
+#ifdef SOCLIB_MODULE_DEBUG
+	std::cout << name() << " new acmd " << std::dec << (int)cmd << " args " << std::hex << data << " crc " << (int)r_cmdcrc << std::endl;
+#endif
+	    m_acmd = false;
+	    switch (cmd) {
+	    case 41:
+		m_databuf[0] = 0x0; // card ready
+		m_datalen_snd = 1;
+		m_sdstate = SD_READY;
+		break;
+	    case 51:
+		// send SCR
+		m_databuf[ 0] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
+		m_databuf[ 1] = 0xfe; // data token
+		m_databuf[ 2] = 0x00; // SCR_STRUCTURE / SD_SPEC
+		m_databuf[ 3] = 0x05; // DATA_STAT_AFTER_ERASE, SD_SECURITY, SD_BUS_WIDTHS
+		m_databuf[ 4] = 0;    // SD_SPEC3, EX_SECURITY, SD_SPEC4
+		m_databuf[ 5] = 0;    // CMD_SUPPORT
+		m_databuf[ 6] = 0;    // vendor specific
+		m_databuf[ 7] = 0;    // vendor specific
+		m_databuf[ 8] = 0;    // vendor specific
+		m_databuf[ 9] = 0;    // vendor specific
+		m_databuf[10] = 0x0;  // CRC16
+		m_databuf[11] = 0x0;  // CRC16
+		m_datalen_snd = 12;
+		break;
+	    default:
+		std::cout << name() << " unknown acmd " << std::dec
+		    << (int)cmd << std::endl;
+		break; // return illegal command
+	    }
+	} else {
+#ifdef SOCLIB_MODULE_DEBUG
+	std::cout << name() << " new cmd " << std::dec << (int)cmd << " args " << std::hex << data << " crc " << (int)r_cmdcrc << std::endl;
+#endif
+	    switch (cmd) {
+	    case 0:
+		m_databuf[0] = 0x1;
+		m_datalen_snd = 1;
+		m_sdstate = SD_IDLE;
+		break;
+	    case 8:
+		// reply with illegal command for now
+		break;
+	    case 9:
+	      {
+		// send CSD
+		// we use a block len of 1024
+		uint32_t csize = ((m_device_size + (512 * 1024) - 1) / (512 * 1024)) - 1;
+		m_databuf[ 0]  = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
+		m_databuf[ 1]  = 0xfe; // data token
+		m_databuf[ 2]  = 0x00; // CSD_STRUCTURE
+		m_databuf[ 3]  = 0xe;  // TAAC
+		m_databuf[ 4]  = 0;    // NSAC
+		m_databuf[ 5]  = 0x32; // TRAN_SPEED
+		m_databuf[ 6]  = 0x5b; // CCC_H
+		m_databuf[ 7]  = 0x5a; // CCC_L + READ_BL_LEN
+		m_databuf[ 8]  = 0x80; // READ_BL_PARTIAL, R/W_BLK_MISALIGN, DSR_IMP
+		m_databuf[ 8] |= (csize >> 10) & 0x03; // CSIZE[12-11]
+		m_databuf[ 9]  = (csize >>  2) & 0xff; // CSIZE[10-2]
+		m_databuf[10]  = (csize <<  6) & 0xc0; // CSIZE[1-0]
+		m_databuf[10] |= 0;    // R_CURR_MIN, R_CURR_MAX
+		m_databuf[11]  = 0x3;  // W_CURR_MIN, W_CURR_MAX, CSIZE_MULT[2-1];
+		m_databuf[12]  = 0xff; // CSIZE_MULT[1], ERASE_BLK_EN, ERASE_SECTOR_SIZE[6-1]
+		m_databuf[13]  = 0x80; // ERASE_SECTOR_SIZE[0]. WP_GRP_SIZE
+		m_databuf[14]  = 0x0a; // WP_GRP_ENABLE, R2W_FACTOR, WRITE_BL_LEN[2-3]
+		m_databuf[15]  = 0x40; // WRITE_BL_LEN[0-1], WR_BL_PARTIAL
+		m_databuf[16]  = 0;    // FILE_FORMAT
+		m_databuf[17]  = 0x1;  // CRC7
+		m_databuf[18]  = 0x0;  // CRC16
+		m_databuf[19]  = 0x0;  // CRC16
+		m_datalen_snd  = 20;
+		break;
+	      }
+	    case 10:
+		// send CID
+		m_databuf[ 0] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
+		m_databuf[ 1] = 0xfe; // data token
+		m_databuf[ 2] = 0xda; // MID
+		m_databuf[ 3] = 'P';  // OID
+		m_databuf[ 4] = '6';  // OID
+		m_databuf[ 5] = 's';  // PNM
+		m_databuf[ 6] = 'o';  // PNM
+		m_databuf[ 7] = 'c';  // PNM
+		m_databuf[ 8] = 's';  // PNM
+		m_databuf[ 9] = 'd';  // PNM
+		m_databuf[10] = 0x01; // PRV
+		m_databuf[11] = 0xde; // PSN
+		m_databuf[12] = 0xad; // PSN
+		m_databuf[13] = 0xbe; // PSN
+		m_databuf[14] = 0xef; // PSN
+		m_databuf[15] = 10;   // MDT
+		m_databuf[16] = 13;   // MDT
+		m_databuf[17] = 0x1;  // CRC7
+		m_databuf[18] = 0x0;  // CRC16
+		m_databuf[19] = 0x0;  // CRC16
+		m_datalen_snd = 20;
+		break;
+	    case 16:
+		// set block size
+		if (m_sdstate != SD_IDLE && data == 512) {
+			m_databuf[0] = 0x00;
+			m_datalen_snd = 1;
+		} // else illegal command
+		break;
+	    case 17:
+	      {
+		int ret;
+		// read data block
+		if (m_sdstate == SD_IDLE) {
+			// return illegal command
+			return;
+		}
+		if (data >= m_device_size) {
+			std::cerr << name() << " read: request " << data
+			    << " past end of file " << m_device_size << std::endl;
+			m_databuf[0] = 0x00; // R1 OK
+			m_databuf[1] = 0x08; // error tocken "out of range"
+			m_datalen_snd = 2;
+			return;
+		}
+		do {
+			if (lseek(m_fd, data, SEEK_SET) < 0) {
+				std::cerr << name() << " lseek: " <<
+				  strerror(errno) << std::endl;
+				m_databuf[0] = 0x00; // R1 OK
+				m_databuf[1] = 0x02; // error tocken "CC err"
+				m_datalen_snd = 2;
+				return;
+			}
+			ret = read(m_fd, &m_databuf[2], 512);
+		} while (ret < 0 && errno == EINTR);
+		if (ret < 0) {
+			std::cerr << name() << " read: " <<
+			  strerror(errno) << std::endl;
+			m_databuf[0] = 0x00; // R1 OK
+			m_databuf[1] = 0x04; // error tocken "card ECC failed"
+			m_datalen_snd = 2;
+			return;
+		}
+		m_databuf[514] = m_databuf[515] = 0; // XXX CRC
+		m_databuf[0] = 0x0; // R1
+		m_databuf[1] = 0xfe; // start block tocken
+		m_datalen_snd = 516;
+		break;
+	      }
+	    case 55:
+		// app-specific command follow
+		m_acmd = true;
+		m_databuf[0] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0;
+		m_datalen_snd = 1;
+		break;
+	    case 58:
+		// send OCR
+		m_databuf[4] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
+		m_databuf[3] = 0x80; // power up complete, SDSC
+		m_databuf[2] = 0xff; // all voltages supported
+		m_databuf[1] = 0x00; 
+		m_databuf[0] = 0x00; 
+		m_datalen_snd = 5;
+		break;
+	    default:
+		std::cout << name() << " unknown cmd " << std::dec
+		    << (int)cmd << std::endl;
+		break; // return illegal command
+	    }
+	}
+}
+
+void SdMMC::handle_sdmmc_write()
+{
+	return;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+SdMMC::SdMMC( sc_core::sc_module_name              name, 
+                                const std::string                    &filename,
+                                const uint32_t                       latency)
+
+: caba::BaseModule(name),
+	m_latency(latency),
+	p_clk("p_clk"),
+	p_resetn("p_resetn"),
+	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 SdMMC " << name << std::endl;
+
+	SC_METHOD(transition);
+    dont_initialize();
+    sensitive << p_clk.pos();
+
+	SC_METHOD(genMoore);
+    dont_initialize();
+    sensitive << p_clk.neg();
+
+    m_fd = ::open(filename.c_str(), O_RDWR);
+    if ( m_fd < 0 ) 
+    {
+	    std::cout << "Error in component SdMMC : " << name 
+	              << " Unable to open file " << filename << std::endl;
+	    exit(1);
+    }
+    m_device_size = lseek(m_fd, 0, SEEK_END);
+
+} // end constructor
+
+SdMMC::~SdMMC()
+{
+}
+
+
+//////////////////////////
+void SdMMC::print_trace()
+{
+	const char* spi_str[] = 
+    {
+		"S_IDLE",
+                "S_RECEIVE_CMD",
+                "S_RECEIVE_ARGS_START",
+                "S_RECEIVE_ARGS",
+                "S_RECEIVE_CRC",
+                "S_RECEIVE_DATA",
+                "S_RECEIVE_DATA_END",
+                "S_SEND_DATA",
+                "S_NOP",
+	};
+	if (r_spi_clk != p_spi_clk) {
+	std::cout << name() << " SPI_FSM : " << spi_str[r_spi_fsm] 
+	    << std::dec
+	    << " clk " << r_spi_clk << "->" << p_spi_clk << " ss " << p_spi_ss
+	    << " mosi " << p_spi_mosi << " miso " << p_spi_miso
+	    << std::endl;
+	std::cout << "         r_spi_shiftreg: " << std::hex << (int)r_spi_shiftreg
+	    << " r_spi_bitcount: " << (int)r_spi_bitcount
+	    << 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
+
