
/* -*- 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, Asim
 *         alain.greiner@lip6.fr april 2011
 *
 * Maintainers: alain
 */

//////////////////////////////////////////////////////////////////////////////////////
// This component is a simplified disk controller with a VCI interface.
// 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, 
// as well as the block size (bytes), and the burst size (bytes). 
// This component has a DMA capability, and is both a target and an initiator.
// Both read and write transfers are supported. An IRQ is optionally
// asserted when the transfer is completed. 
//
// As a target this block device controler contains 8 memory mapped registers,
// taking 32 bytes in the address space.
// - BLOCK_DEVICE_BUFFER        0x00 (read/write)    Memory buffer base address.
// - BLOCK_DEVICE_COUNT         0x04 (read/write)    Number of blocks to be transfered.
// - BLOCK_DEVICE_LBA           0x08 (read/write)    Index of first block in the file.
// - BLOCK_DEVICE_OP            0x0C (write-only)    Writing here starts the operation.
// - BLOCK_DEVICE_STATUS        0x10 (read-only)     Block Device status.
// - BLOCK_DEVICE_IRQ_ENABLE    0x14 (read/write)    IRQ enabled if non zero.
// - BLOCK_DEVICE_SIZE          0x18 (read-only)     Number of addressable blocks.
// - BLOCK_DEVICE_BLOCK_SIZE    0x1C (read_only)     Block size in bytes.
//
// The following operations codes are supported: 
// - BLOCK_DEVICE_NOOP          No operation
// - BLOCK_DEVICE_READ          From block device to memory
// - BLOCK_DEVICE_WRITE         From memory to block device 
//
// The BLOCK_DEVICE_STATUS is actually defined by the initiator FSM state.
// The following values are defined for device status:
// -BLOCK_DEVICE_IDLE           0
// -BLOCK_DEVICE_BUSY           1
// -BLOCK_DEVICE_READ_SUCCESS   2
// -BLOCK_DEVICE_WRITE_SUCCESS  3
// -BLOCK_DEVICE_READ_ERROR     4
// -BLOCK_DEVICE_WRITE_ERROR    5
//
// In the 4 states READ_ERROR, READ_SUCCESS, WRITE_ERROR, WRITE_SUCCESS,
// the IRQ is asserted (if it is enabled).
// A read access to the BLOCK_DEVICE_STATUS in these 4 states reset 
// the initiator FSM state to IDLE, and acknowledge the IRQ.
// Any write access to registers BUFFER, COUNT, LBA, OP is ignored
// if the device is not IDLE.
///////////////////////////////////////////////////////////////////////////

#ifndef SOCLIB_VCI_BLOCK_DEVICE_TSAR_V4_H
#define SOCLIB_VCI_BLOCK_DEVICE_TSAR_V4_H

#include <stdint.h>
#include <systemc>
#include "caba_base_module.h"
#include "mapping_table.h"

namespace soclib {
namespace caba {

using namespace sc_core;

template<typename vci_param>
class VciBlockDeviceTsarV4
	: 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<bool>           		r_irq_enable;   	// default value is true
    sc_signal<uint32_t>       		r_nblocks;      	// number of blocks to be transfered
    sc_signal<uint32_t>       		r_buf_address;  	// memory buffer address
    sc_signal<uint32_t>       		r_lba;          	// first block index
    sc_signal<bool>           		r_read;         	// requested operation
    sc_signal<uint32_t>       		r_flit_count;   	// flit 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_latency_count;	// latency access (for each block)
    sc_signal<bool>           		r_go;           	// transmit command from T_FSM to M_FSM
    sc_signal<sc_uint<vci_param::S> >	r_srcid;		// save srcid
    sc_signal<sc_uint<vci_param::T> >	r_trdid;		// save trdid
    sc_signal<sc_uint<vci_param::P> >	r_pktid;		// save pktid

    uint32_t*   			m_local_buffer; 	// capacity is one block (block_size bytes)

    // structural parameters
    soclib::common::Segment     	m_segment;      	// segment associated to target
    uint32_t              		m_srcid;        	// initiator index
    int                         	m_fd;           	// File descriptor
    uint64_t                    	m_device_size;  	// Total number of blocks
    const uint32_t              	m_flits_per_block;	// number of flits in a block
    const uint32_t              	m_flits_per_burst;	// number of flits in a burst
    const uint32_t              	m_bursts_per_block;	// number of bursts in a block
    const uint32_t              	m_latency;      	// device latency

    // methods
    void transition();
    void genMoore();

    //  Master FSM states
    enum {
    M_IDLE              = 0,
    M_READ_BLOCK        = 1,
    M_READ_CMD          = 2,
    M_READ_RSP          = 3,
    M_READ_TEST         = 4,
    M_READ_SUCCESS      = 5,
    M_READ_ERROR        = 6,
    M_WRITE_BLOCK       = 7,
    M_WRITE_CMD         = 8,
    M_WRITE_RSP         = 9,
    M_WRITE_TEST        = 10,
    M_WRITE_SUCCESS     = 11,
    M_WRITE_ERROR       = 12,
    };

    // Target FSM states
    enum {
    T_IDLE              = 0,
    T_WRITE_BUFFER      = 1,
    T_READ_BUFFER       = 2,
    T_WRITE_COUNT       = 3,
    T_READ_COUNT        = 4,
    T_WRITE_LBA         = 5,
    T_READ_LBA          = 6,
    T_WRITE_OP          = 7,
    T_READ_STATUS       = 8,
    T_WRITE_IRQEN       = 9,
    T_READ_IRQEN        = 10,
    T_READ_SIZE         = 11,
    T_READ_BLOCK        = 12,
    T_READ_ERROR        = 13,
    T_WRITE_ERROR       = 14,
    };

    // Error codes values
    enum {
    VCI_READ_OK		= 0,
    VCI_READ_ERROR	= 1,
    VCI_WRITE_OK	= 2,
    VCI_WRITE_ERROR	= 3,
    };

protected:

    SC_HAS_PROCESS(VciBlockDeviceTsarV4);

public:

    // ports
    sc_in<bool> 					p_clk;
    sc_in<bool> 					p_resetn;
    soclib::caba::VciInitiator<vci_param> 		p_vci_initiator;
    soclib::caba::VciTarget<vci_param> 			p_vci_target;
    sc_out<bool> 					p_irq;

    void print_trace();

    // Constructor   
    VciBlockDeviceTsarV4(
		sc_module_name 				name,
		const soclib::common::MappingTable 	&mt,
		const soclib::common::IntTab 		&srcid,
		const soclib::common::IntTab 		&tgtid,
        	const std::string 			&filename,
        	const uint32_t 				block_size = 512,
        	const uint32_t 				burst_size = 64,
                const uint32_t				latency = 0);
};

}}

#endif /* SOCLIB_VCI_BLOCK_DEVICE_TSAR_V4_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

