| 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 | |
|---|