/* -*- 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 * Nicolas Pouillon , 2007 * * Maintainers: alain */ #include "../include/vci_tty_tsar.h" #include "tty.h" #include namespace soclib { namespace caba { #define tmpl(t) template t VciTtyTsar //////////////////////// tmpl(void)::transition() { if (!p_resetn) { r_fsm_state = IDLE; for( size_t channel = 0 ; channel < m_term.size() ; channel++ ) { r_rx_irq_enable[channel] = 0; r_tx_irq_enable[channel] = 0; } return; } switch ( r_fsm_state.read() ) { ////////// case IDLE: // waiting a VCI command { if ( not p_vci.cmdval.read() ) break; vci_addr_t address = p_vci.address.read(); size_t cell = (size_t)((address & 0xFFF)>>2); size_t reg = cell % TTY_SPAN; size_t channel = cell / TTY_SPAN; bool seg_error = true; r_srcid = p_vci.srcid.read(); r_trdid = p_vci.trdid.read(); r_pktid = p_vci.pktid.read(); std::list::iterator seg; for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) { if ( seg->contains( address ) and p_vci.eop.read() ) { seg_error = false; break; } } ///////////////////////////////////////////////////////// if ( not seg_error and // write char (p_vci.cmd.read() == vci_param::CMD_WRITE) and (reg == TTY_WRITE ) and channel < m_term.size() ) { // suppose an infinite write buffer (never full) m_term[channel]->putc( p_vci.wdata.read() ); r_fsm_state = RSP_WRITE; } ///////////////////////////////////////////////////////// else if ( not seg_error and // read char (p_vci.cmd.read() == vci_param::CMD_READ) and (reg == TTY_READ) and channel < m_term.size() ) { vci_data_t byte = m_term[channel]->getc(); // skip CR code if ( byte == 0x0d ) r_rdata = m_term[channel]->getc(); else r_rdata = byte; r_fsm_state = RSP_READ; } ///////////////////////////////////////////////////////// else if ( not seg_error and // read status (p_vci.cmd.read() == vci_param::CMD_READ) and (reg == TTY_STATUS) and channel < m_term.size() ) { // read buffer can be empty => bit 0 can be 0 or 1 // write buffer is never full => bit 1 is always 0 r_rdata = m_term[channel]->hasData(); r_fsm_state = RSP_READ; } ///////////////////////////////////////////////////////// else if ( not seg_error and // set / reset rx_irq (p_vci.cmd.read() == vci_param::CMD_WRITE) and (reg == TTY_RX_IRQ_ENABLE) and channel < m_term.size() ) { r_rx_irq_enable[channel] = p_vci.wdata.read(); r_fsm_state = RSP_WRITE; } ///////////////////////////////////////////////////////// else if ( not seg_error and // set / reset tx_irq (p_vci.cmd.read() == vci_param::CMD_WRITE) and (reg == TTY_TX_IRQ_ENABLE) and channel < m_term.size() ) { r_tx_irq_enable[channel] = p_vci.wdata.read(); r_fsm_state = RSP_WRITE; } ///////////////////////////////////////////////////////// else if ( p_vci.eop.read() ) { r_fsm_state = RSP_ERROR; } break; } /////////////// case RSP_ERROR: // return an error response case RSP_READ: // return a valid read response case RSP_WRITE: // return a valid write response { if ( p_vci.rspack.read() ) r_fsm_state = IDLE; break; } } // end switch r_fsm_state } ////////////////////// tmpl(void)::genMoore() { if ( r_fsm_state.read() == IDLE ) { p_vci.cmdack = true; p_vci.rspval = false; p_vci.rdata = 0; p_vci.rsrcid = 0; p_vci.rtrdid = 0; p_vci.rpktid = 0; p_vci.rerror = vci_param::ERR_NORMAL; p_vci.reop = true; } else if ( r_fsm_state.read() == RSP_WRITE ) { p_vci.cmdack = false; p_vci.rspval = true; p_vci.rdata = 0; p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_NORMAL; p_vci.reop = true; } else if ( r_fsm_state.read() == RSP_READ ) { p_vci.cmdack = false; p_vci.rspval = true; p_vci.rdata = r_rdata.read(); p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_NORMAL; p_vci.reop = true; } else if ( r_fsm_state.read() == RSP_ERROR ) { p_vci.cmdack = false; p_vci.rspval = true; p_vci.rdata = 0; p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_GENERAL_DATA_ERROR; p_vci.reop = true; } for ( size_t channel = 0; channel < m_term.size(); channel++ ) { // activate RX_IRQ if RX buffer not empty and RX_IRQ enable p_irq_rx[channel] = (bool)m_term[channel]->hasData() && r_rx_irq_enable[channel].read(); // activate TX_IRQ if TX_IRQ enable ( TX buffer is never full ) p_irq_tx[channel] = r_tx_irq_enable[channel].read(); } } /////////////////////////////////////////////////////// tmpl(void)::init(const std::vector &names) { size_t channel = 0; for ( std::vector::const_iterator i = names.begin(); i != names.end(); ++i ) { assert( (channel < 32) and "VCI_TTY_TSAR ERROR : no more than 32 channels"); m_term.push_back(soclib::common::allocateTty(*i)); channel++; } p_irq_rx = new sc_out[m_term.size()]; p_irq_tx = new sc_out[m_term.size()]; SC_METHOD(transition); dont_initialize(); sensitive << p_clk.pos(); SC_METHOD(genMoore); dont_initialize(); sensitive << p_clk.neg(); } ///////////////////////////////////////////////// tmpl(/**/)::VciTtyTsar( sc_module_name name, const IntTab &index, const MappingTable &mt, const char *first_name, ...) : soclib::caba::BaseModule(name), p_clk("clk"), p_resetn("resetn"), p_vci("vci"), m_seglist(mt.getSegmentList(index)) { std::cout << " - Building VciTtyTsar " << name << std::endl; std::list::iterator seg; for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) { std::cout << " => segment " << seg->name() << " / base = " << std::hex << seg->baseAddress() << " / size = " << seg->size() << std::endl; } va_list va_tty; va_start (va_tty, first_name); std::vector args; const char *cur_tty = first_name; while (cur_tty) { args.push_back(cur_tty); cur_tty = va_arg( va_tty, char * ); } va_end( va_tty ); init(args); } ///////////////////////////////////////////////////////////// tmpl(/**/)::VciTtyTsar( sc_module_name name, const IntTab &index, const MappingTable &mt, const std::vector &names ) : soclib::caba::BaseModule(name), p_clk("clk"), p_resetn("resetn"), p_vci("vci"), m_seglist(mt.getSegmentList(index)) { std::cout << " - Building VciMultiTTy " << name << std::endl; std::list::iterator seg; for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) { std::cout << " => segment " << seg->name() << " / base = " << std::hex << seg->baseAddress() << " / size = " << seg->size() << std::endl; } init(names); } ///////////////////////// tmpl(/**/)::~VciTtyTsar() { for (unsigned int i=0; i