[1054] | 1 | /* -*- c++ -*- |
---|
| 2 | * |
---|
| 3 | * SOCLIB_LGPL_HEADER_BEGIN |
---|
| 4 | * |
---|
| 5 | * This file is part of SoCLib, GNU LGPLv2.1. |
---|
| 6 | * |
---|
| 7 | * SoCLib is free software; you can redistribute it and/or modify it |
---|
| 8 | * under the terms of the GNU Lesser General Public License as published |
---|
| 9 | * by the Free Software Foundation; version 2.1 of the License. |
---|
| 10 | * |
---|
| 11 | * SoCLib is distributed in the hope that it will be useful, but |
---|
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
| 14 | * Lesser General Public License for more details. |
---|
| 15 | * |
---|
| 16 | * You should have received a copy of the GNU Lesser General Public |
---|
| 17 | * License along with SoCLib; if not, write to the Free Software |
---|
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
---|
| 19 | * 02110-1301 USA |
---|
| 20 | * |
---|
| 21 | * SOCLIB_LGPL_HEADER_END |
---|
| 22 | * |
---|
| 23 | * Copyright (c) UPMC, Lip6, Asim |
---|
| 24 | * Nicolas Pouillon <nipo@ssji.net>, 2007 |
---|
| 25 | * |
---|
| 26 | * Maintainers: alain |
---|
| 27 | */ |
---|
| 28 | |
---|
| 29 | #include "../include/vci_tty_tsar.h" |
---|
| 30 | #include "tty.h" |
---|
| 31 | |
---|
| 32 | #include <stdarg.h> |
---|
| 33 | |
---|
| 34 | namespace soclib { |
---|
| 35 | namespace caba { |
---|
| 36 | |
---|
| 37 | #define tmpl(t) template<typename vci_param> t VciTtyTsar<vci_param> |
---|
| 38 | |
---|
| 39 | //////////////////////// |
---|
| 40 | tmpl(void)::transition() |
---|
| 41 | { |
---|
| 42 | if (!p_resetn) |
---|
| 43 | { |
---|
| 44 | r_fsm_state = IDLE; |
---|
| 45 | for( size_t channel = 0 ; channel < m_term.size() ; channel++ ) |
---|
| 46 | { |
---|
| 47 | r_rx_irq_enable[channel] = 0; |
---|
| 48 | r_tx_irq_enable[channel] = 0; |
---|
| 49 | } |
---|
| 50 | return; |
---|
| 51 | } |
---|
| 52 | |
---|
| 53 | switch ( r_fsm_state.read() ) |
---|
| 54 | { |
---|
| 55 | ////////// |
---|
| 56 | case IDLE: // waiting a VCI command |
---|
| 57 | { |
---|
| 58 | if ( not p_vci.cmdval.read() ) break; |
---|
| 59 | |
---|
| 60 | vci_addr_t address = p_vci.address.read(); |
---|
| 61 | size_t cell = (size_t)((address & 0xFFF)>>2); |
---|
| 62 | size_t reg = cell % TTY_SPAN; |
---|
| 63 | size_t channel = cell / TTY_SPAN; |
---|
| 64 | bool seg_error = true; |
---|
| 65 | |
---|
| 66 | r_srcid = p_vci.srcid.read(); |
---|
| 67 | r_trdid = p_vci.trdid.read(); |
---|
| 68 | r_pktid = p_vci.pktid.read(); |
---|
| 69 | |
---|
| 70 | std::list<soclib::common::Segment>::iterator seg; |
---|
| 71 | for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) |
---|
| 72 | { |
---|
| 73 | if ( seg->contains( address ) and p_vci.eop.read() ) |
---|
| 74 | { |
---|
| 75 | seg_error = false; |
---|
| 76 | break; |
---|
| 77 | } |
---|
| 78 | } |
---|
| 79 | |
---|
| 80 | ///////////////////////////////////////////////////////// |
---|
| 81 | if ( not seg_error and // write char |
---|
| 82 | (p_vci.cmd.read() == vci_param::CMD_WRITE) and |
---|
| 83 | (reg == TTY_WRITE ) and |
---|
| 84 | channel < m_term.size() ) |
---|
| 85 | { |
---|
| 86 | // suppose an infinite write buffer (never full) |
---|
| 87 | m_term[channel]->putc( p_vci.wdata.read() ); |
---|
| 88 | |
---|
| 89 | r_fsm_state = RSP_WRITE; |
---|
| 90 | } |
---|
| 91 | ///////////////////////////////////////////////////////// |
---|
| 92 | else if ( not seg_error and // read char |
---|
| 93 | (p_vci.cmd.read() == vci_param::CMD_READ) and |
---|
| 94 | (reg == TTY_READ) and |
---|
| 95 | channel < m_term.size() ) |
---|
| 96 | { |
---|
| 97 | vci_data_t byte = m_term[channel]->getc(); |
---|
| 98 | |
---|
| 99 | // skip CR code |
---|
| 100 | if ( byte == 0x0d ) r_rdata = m_term[channel]->getc(); |
---|
| 101 | else r_rdata = byte; |
---|
| 102 | |
---|
| 103 | r_fsm_state = RSP_READ; |
---|
| 104 | } |
---|
| 105 | ///////////////////////////////////////////////////////// |
---|
| 106 | else if ( not seg_error and // read status |
---|
| 107 | (p_vci.cmd.read() == vci_param::CMD_READ) and |
---|
| 108 | (reg == TTY_STATUS) and |
---|
| 109 | channel < m_term.size() ) |
---|
| 110 | { |
---|
| 111 | // read buffer can be empty => bit 0 can be 0 or 1 |
---|
| 112 | // write buffer is never full => bit 1 is always 0 |
---|
| 113 | |
---|
| 114 | r_rdata = m_term[channel]->hasData(); |
---|
| 115 | r_fsm_state = RSP_READ; |
---|
| 116 | } |
---|
| 117 | ///////////////////////////////////////////////////////// |
---|
| 118 | else if ( not seg_error and // set / reset rx_irq |
---|
| 119 | (p_vci.cmd.read() == vci_param::CMD_WRITE) and |
---|
| 120 | (reg == TTY_RX_IRQ_ENABLE) and |
---|
| 121 | channel < m_term.size() ) |
---|
| 122 | { |
---|
| 123 | r_rx_irq_enable[channel] = p_vci.wdata.read(); |
---|
| 124 | r_fsm_state = RSP_WRITE; |
---|
| 125 | } |
---|
| 126 | ///////////////////////////////////////////////////////// |
---|
| 127 | else if ( not seg_error and // set / reset tx_irq |
---|
| 128 | (p_vci.cmd.read() == vci_param::CMD_WRITE) and |
---|
| 129 | (reg == TTY_TX_IRQ_ENABLE) and |
---|
| 130 | channel < m_term.size() ) |
---|
| 131 | { |
---|
| 132 | r_tx_irq_enable[channel] = p_vci.wdata.read(); |
---|
| 133 | r_fsm_state = RSP_WRITE; |
---|
| 134 | } |
---|
| 135 | ///////////////////////////////////////////////////////// |
---|
| 136 | else if ( p_vci.eop.read() ) |
---|
| 137 | { |
---|
| 138 | r_fsm_state = RSP_ERROR; |
---|
| 139 | } |
---|
| 140 | break; |
---|
| 141 | } |
---|
| 142 | /////////////// |
---|
| 143 | case RSP_ERROR: // return an error response |
---|
| 144 | case RSP_READ: // return a valid read response |
---|
| 145 | case RSP_WRITE: // return a valid write response |
---|
| 146 | { |
---|
| 147 | if ( p_vci.rspack.read() ) r_fsm_state = IDLE; |
---|
| 148 | break; |
---|
| 149 | } |
---|
| 150 | } // end switch r_fsm_state |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | ////////////////////// |
---|
| 154 | tmpl(void)::genMoore() |
---|
| 155 | { |
---|
| 156 | if ( r_fsm_state.read() == IDLE ) |
---|
| 157 | { |
---|
| 158 | p_vci.cmdack = true; |
---|
| 159 | p_vci.rspval = false; |
---|
| 160 | p_vci.rdata = 0; |
---|
| 161 | p_vci.rsrcid = 0; |
---|
| 162 | p_vci.rtrdid = 0; |
---|
| 163 | p_vci.rpktid = 0; |
---|
| 164 | p_vci.rerror = vci_param::ERR_NORMAL; |
---|
| 165 | p_vci.reop = true; |
---|
| 166 | } |
---|
| 167 | else if ( r_fsm_state.read() == RSP_WRITE ) |
---|
| 168 | { |
---|
| 169 | p_vci.cmdack = false; |
---|
| 170 | p_vci.rspval = true; |
---|
| 171 | p_vci.rdata = 0; |
---|
| 172 | p_vci.rsrcid = r_srcid.read(); |
---|
| 173 | p_vci.rtrdid = r_trdid.read(); |
---|
| 174 | p_vci.rpktid = r_pktid.read(); |
---|
| 175 | p_vci.rerror = vci_param::ERR_NORMAL; |
---|
| 176 | p_vci.reop = true; |
---|
| 177 | } |
---|
| 178 | else if ( r_fsm_state.read() == RSP_READ ) |
---|
| 179 | { |
---|
| 180 | p_vci.cmdack = false; |
---|
| 181 | p_vci.rspval = true; |
---|
| 182 | p_vci.rdata = r_rdata.read(); |
---|
| 183 | p_vci.rsrcid = r_srcid.read(); |
---|
| 184 | p_vci.rtrdid = r_trdid.read(); |
---|
| 185 | p_vci.rpktid = r_pktid.read(); |
---|
| 186 | p_vci.rerror = vci_param::ERR_NORMAL; |
---|
| 187 | p_vci.reop = true; |
---|
| 188 | } |
---|
| 189 | else if ( r_fsm_state.read() == RSP_ERROR ) |
---|
| 190 | { |
---|
| 191 | p_vci.cmdack = false; |
---|
| 192 | p_vci.rspval = true; |
---|
| 193 | p_vci.rdata = 0; |
---|
| 194 | p_vci.rsrcid = r_srcid.read(); |
---|
| 195 | p_vci.rtrdid = r_trdid.read(); |
---|
| 196 | p_vci.rpktid = r_pktid.read(); |
---|
| 197 | p_vci.rerror = vci_param::ERR_GENERAL_DATA_ERROR; |
---|
| 198 | p_vci.reop = true; |
---|
| 199 | } |
---|
| 200 | |
---|
| 201 | for ( size_t channel = 0; channel < m_term.size(); channel++ ) |
---|
| 202 | { |
---|
| 203 | // activate RX_IRQ if RX buffer not empty and RX_IRQ enable |
---|
| 204 | p_irq_rx[channel] = (bool)m_term[channel]->hasData() && |
---|
| 205 | r_rx_irq_enable[channel].read(); |
---|
| 206 | |
---|
| 207 | // activate TX_IRQ if TX_IRQ enable ( TX buffer is never full ) |
---|
| 208 | p_irq_tx[channel] = r_tx_irq_enable[channel].read(); |
---|
| 209 | } |
---|
| 210 | } |
---|
| 211 | |
---|
| 212 | /////////////////////////////////////////////////////// |
---|
| 213 | tmpl(void)::init(const std::vector<std::string> &names) |
---|
| 214 | { |
---|
| 215 | size_t channel = 0; |
---|
| 216 | |
---|
| 217 | for ( std::vector<std::string>::const_iterator i = names.begin(); |
---|
| 218 | i != names.end(); |
---|
| 219 | ++i ) |
---|
| 220 | { |
---|
| 221 | assert( (channel < 32) and "VCI_TTY_TSAR ERROR : no more than 32 channels"); |
---|
| 222 | m_term.push_back(soclib::common::allocateTty(*i)); |
---|
| 223 | channel++; |
---|
| 224 | } |
---|
| 225 | |
---|
| 226 | p_irq_rx = new sc_out<bool>[m_term.size()]; |
---|
| 227 | p_irq_tx = new sc_out<bool>[m_term.size()]; |
---|
| 228 | |
---|
| 229 | SC_METHOD(transition); |
---|
| 230 | dont_initialize(); |
---|
| 231 | sensitive << p_clk.pos(); |
---|
| 232 | |
---|
| 233 | SC_METHOD(genMoore); |
---|
| 234 | dont_initialize(); |
---|
| 235 | sensitive << p_clk.neg(); |
---|
| 236 | } |
---|
| 237 | |
---|
| 238 | ///////////////////////////////////////////////// |
---|
| 239 | tmpl(/**/)::VciTtyTsar( sc_module_name name, |
---|
| 240 | const IntTab &index, |
---|
| 241 | const MappingTable &mt, |
---|
| 242 | const char *first_name, ...) |
---|
| 243 | : soclib::caba::BaseModule(name), |
---|
| 244 | p_clk("clk"), |
---|
| 245 | p_resetn("resetn"), |
---|
| 246 | p_vci("vci"), |
---|
| 247 | m_seglist(mt.getSegmentList(index)) |
---|
| 248 | { |
---|
| 249 | std::cout << " - Building VciTtyTsar " << name << std::endl; |
---|
| 250 | |
---|
| 251 | std::list<soclib::common::Segment>::iterator seg; |
---|
| 252 | for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) |
---|
| 253 | { |
---|
| 254 | std::cout << " => segment " << seg->name() |
---|
| 255 | << " / base = " << std::hex << seg->baseAddress() |
---|
| 256 | << " / size = " << seg->size() << std::endl; |
---|
| 257 | } |
---|
| 258 | |
---|
| 259 | va_list va_tty; |
---|
| 260 | |
---|
| 261 | va_start (va_tty, first_name); |
---|
| 262 | std::vector<std::string> args; |
---|
| 263 | const char *cur_tty = first_name; |
---|
| 264 | while (cur_tty) |
---|
| 265 | { |
---|
| 266 | args.push_back(cur_tty); |
---|
| 267 | |
---|
| 268 | cur_tty = va_arg( va_tty, char * ); |
---|
| 269 | } |
---|
| 270 | va_end( va_tty ); |
---|
| 271 | |
---|
| 272 | init(args); |
---|
| 273 | } |
---|
| 274 | |
---|
| 275 | ///////////////////////////////////////////////////////////// |
---|
| 276 | tmpl(/**/)::VciTtyTsar( sc_module_name name, |
---|
| 277 | const IntTab &index, |
---|
| 278 | const MappingTable &mt, |
---|
| 279 | const std::vector<std::string> &names ) |
---|
| 280 | : soclib::caba::BaseModule(name), |
---|
| 281 | p_clk("clk"), |
---|
| 282 | p_resetn("resetn"), |
---|
| 283 | p_vci("vci"), |
---|
| 284 | m_seglist(mt.getSegmentList(index)) |
---|
| 285 | { |
---|
| 286 | std::cout << " - Building VciMultiTTy " << name << std::endl; |
---|
| 287 | |
---|
| 288 | std::list<soclib::common::Segment>::iterator seg; |
---|
| 289 | for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) |
---|
| 290 | { |
---|
| 291 | std::cout << " => segment " << seg->name() |
---|
| 292 | << " / base = " << std::hex << seg->baseAddress() |
---|
| 293 | << " / size = " << seg->size() << std::endl; |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | init(names); |
---|
| 297 | } |
---|
| 298 | |
---|
| 299 | ///////////////////////// |
---|
| 300 | tmpl(/**/)::~VciTtyTsar() |
---|
| 301 | { |
---|
| 302 | for (unsigned int i=0; i<m_term.size(); i++ ) |
---|
| 303 | delete m_term[i]; |
---|
| 304 | |
---|
| 305 | delete[] p_irq_rx; |
---|
| 306 | delete[] p_irq_tx; |
---|
| 307 | } |
---|
| 308 | |
---|
| 309 | ///////////////////////////////////////// |
---|
| 310 | tmpl(void)::print_trace( size_t channel ) |
---|
| 311 | { |
---|
| 312 | const char* state_str[] = { "IDLE", |
---|
| 313 | "RSP_WRITE", |
---|
| 314 | "RSP_READ", |
---|
| 315 | "RSP_ERROR", }; |
---|
| 316 | |
---|
| 317 | std::cout << "MULTI_TTY " << name() |
---|
| 318 | << " : fsm = " << state_str[r_fsm_state.read()] << std::dec |
---|
| 319 | << " / RX_IRQ[" << channel << "] = " << r_rx_irq_enable[channel].read() |
---|
| 320 | << " / TX_IRQ[" << channel << "] = " << r_tx_irq_enable[channel].read() |
---|
| 321 | << std::endl; |
---|
| 322 | } |
---|
| 323 | |
---|
| 324 | }} |
---|
| 325 | |
---|
| 326 | // Local Variables: |
---|
| 327 | // tab-width: 4 |
---|
| 328 | // c-basic-offset: 4 |
---|
| 329 | // c-file-offsets:((innamespace . 0)(inline-open . 0)) |
---|
| 330 | // indent-tabs-mode: nil |
---|
| 331 | // End: |
---|
| 332 | |
---|
| 333 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 |
---|
| 334 | |
---|