source: trunk/modules/vci_block_device_tsar/caba/source/src/vci_block_device_tsar.cpp @ 2

Last change on this file since 2 was 2, checked in by nipo, 14 years ago

Import TSAR modules in TSAR's own svn

  • Property svn:eol-style set to native
  • Property svn:keywords set to "Author Date Id Rev URL Revision"
  • Property svn:mime-type set to text/plain
File size: 10.1 KB
Line 
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 *         Eric Guthmuller  <eric.guthmuller@polytechnique.edu>, 2009
26 */
27
28#include <stdint.h>
29#include <iostream>
30#include "register.h"
31#include "../include/vci_block_device_tsar.h"
32#include <fcntl.h>
33#include "block_device_tsar.h"
34
35namespace soclib { namespace caba {
36
37#ifdef SOCLIB_MODULE_DEBUG
38    namespace {
39        const char* SoclibBlockDeviceRegisters_str[] = {
40            "BLOCK_DEVICE_BUFFER",
41            "BLOCK_DEVICE_LBA",
42            "BLOCK_DEVICE_COUNT",
43            "BLOCK_DEVICE_OP",
44            "BLOCK_DEVICE_STATUS",
45            "BLOCK_DEVICE_IRQ_ENABLE",
46            "BLOCK_DEVICE_SIZE",
47            "BLOCK_DEVICE_BLOCK_SIZE"
48        };
49        const char* SoclibBlockDeviceOp_str[] = {
50            "BLOCK_DEVICE_NOOP",
51            "BLOCK_DEVICE_READ",
52            "BLOCK_DEVICE_WRITE",
53        };
54        const char* SoclibBlockDeviceStatus_str[] = {
55            "BLOCK_DEVICE_IDLE",
56            "BLOCK_DEVICE_BUSY",
57            "BLOCK_DEVICE_READ_SUCCESS",
58            "BLOCK_DEVICE_WRITE_SUCCESS",
59            "BLOCK_DEVICE_READ_ERROR",
60            "BLOCK_DEVICE_WRITE_ERROR",
61            "BLOCK_DEVICE_ERROR",
62        };
63    }
64#endif
65
66#define tmpl(t) template<typename vci_param> t VciBlockDeviceTsar<vci_param>
67
68tmpl(void)::ended(int status)
69{
70#ifdef SOCLIB_MODULE_DEBUG
71    std::cout
72        << name()
73        << " finished current operation ("
74        << SoclibBlockDeviceOp_str[m_current_op]
75        << ") with the status "
76        << SoclibBlockDeviceStatus_str[status]
77        << std::endl;
78#endif
79
80        if ( m_irq_enabled )
81                r_irq = true;
82        m_current_op = m_op = BLOCK_DEVICE_NOOP;
83    m_status = status;
84}
85
86tmpl(bool)::on_write(int seg, typename vci_param::addr_t addr, typename vci_param::data_t data, int be)
87{
88    int cell = (int)addr / vci_param::B;
89
90#ifdef SOCLIB_MODULE_DEBUG
91    std::cout
92        << name()
93        << " write config register "
94        << SoclibBlockDeviceRegisters_str[cell]
95        << " with data 0x"
96        << std::hex << data.read()
97        << std::endl;
98#endif
99
100        switch ((enum SoclibBlockDeviceRegisters)cell) {
101    case BLOCK_DEVICE_BUFFER:
102                m_buffer = data;
103                return true;
104    case BLOCK_DEVICE_COUNT:
105        m_count = data;
106        return true;
107    case BLOCK_DEVICE_LBA:
108                m_lba = data;
109                return true;
110    case BLOCK_DEVICE_OP:
111        if ( m_status == BLOCK_DEVICE_BUSY ) {
112            std::cerr << name() << " warning: receiving a new command while busy, ignored" << std::endl;
113        } else {
114            m_op = data;
115        }
116                return true;
117    case BLOCK_DEVICE_IRQ_ENABLE:
118                m_irq_enabled = data;
119                return true;
120    default:
121        return false;
122        }
123}
124
125tmpl(bool)::on_read(int seg, typename vci_param::addr_t addr, typename vci_param::data_t &data)
126{
127    int cell = (int)addr / vci_param::B;
128
129#ifdef SOCLIB_MODULE_DEBUG
130    std::cout
131        << name()
132        << " read config register "
133        << SoclibBlockDeviceRegisters_str[cell]
134        << std::endl;
135#endif
136
137        switch ((enum SoclibBlockDeviceRegisters)cell) {
138    case BLOCK_DEVICE_SIZE:
139        data = (typename vci_param::fast_data_t)m_device_size;
140        return true;
141    case BLOCK_DEVICE_BLOCK_SIZE:
142        data = m_block_size;
143        return true;
144    case BLOCK_DEVICE_STATUS:
145        data = m_status;
146        if (m_status != BLOCK_DEVICE_BUSY) {
147            m_status = BLOCK_DEVICE_IDLE;
148            r_irq = false;
149        }
150        return true;
151    default:
152        return false;
153        }
154}
155
156tmpl(void)::read_done( req_t *req )
157{
158    if ( ! req->failed() && m_chunck_offset < m_transfer_size ) {
159#ifdef SOCLIB_MODULE_DEBUG
160    std::cout
161        << name()
162        << " completed transferring a chunck. Do now the next one..."
163        << std::endl;
164#endif
165        next_req();
166        return;
167    }
168
169        ended( req->failed() ? BLOCK_DEVICE_READ_ERROR : BLOCK_DEVICE_READ_SUCCESS );
170    delete m_data;
171        delete req;
172}
173
174tmpl(void)::write_finish( req_t *req )
175{
176    if ( ! req->failed() && m_chunck_offset < m_transfer_size ) {
177#ifdef SOCLIB_MODULE_DEBUG
178    std::cout
179        << name()
180        << " completed transferring a chunck. Do now the next one..."
181        << std::endl;
182#endif
183        next_req();
184        return;
185    }
186
187        ended(
188        ( ! req->failed() && ::write( m_fd, (char *)m_data, m_transfer_size ) > 0 )
189        ? BLOCK_DEVICE_WRITE_SUCCESS : BLOCK_DEVICE_WRITE_ERROR );
190    delete m_data;
191        delete req;
192}
193
194tmpl(void)::next_req()
195{
196    switch (m_current_op) {
197    case BLOCK_DEVICE_READ:
198    {
199        m_transfer_size = m_count * m_block_size;
200        if ( m_chunck_offset == 0 ) {
201            if ( m_lba + m_count > m_device_size ) {
202                std::cerr << name() << " warning: trying to read beyond end of device" << std::endl;
203                ended(BLOCK_DEVICE_READ_ERROR);
204                break;
205            }
206            m_data = new uint8_t[m_transfer_size];
207            lseek(m_fd, m_lba*m_block_size, SEEK_SET);
208            int retval = ::read(m_fd, m_data, m_transfer_size);
209            if ( retval < 0 ) {
210                ended(BLOCK_DEVICE_READ_ERROR);
211                break;
212            }
213        }
214        size_t chunck_size = m_transfer_size-m_chunck_offset;
215        if( m_chunck_offset == 0 )
216            chunck_size = ((m_buffer & ~(m_burst_size-1)) + m_burst_size) - m_buffer;
217        if ( chunck_size > m_burst_size )
218            chunck_size = m_burst_size;
219        VciInitSimpleWriteReq<vci_param> *req =
220            new VciInitSimpleWriteReq<vci_param>(
221                m_buffer+m_chunck_offset, m_data+m_chunck_offset, chunck_size );
222        m_chunck_offset += chunck_size;
223        req->setDone( this, ON_T(read_done) );
224        m_vci_init_fsm.doReq( req );
225                m_status = BLOCK_DEVICE_BUSY;
226        break;
227    }
228    case BLOCK_DEVICE_WRITE:
229    {
230        m_transfer_size = m_count * m_block_size;
231        if ( m_chunck_offset == 0 ) {
232            if ( m_lba + m_count > m_device_size ) {
233                std::cerr << name() << " warning: trying to write beyond end of device" << std::endl;
234                ended(BLOCK_DEVICE_WRITE_ERROR);
235                break;
236            }
237            m_data = new uint8_t[m_transfer_size];
238            lseek(m_fd, m_lba*m_block_size, SEEK_SET);
239        }
240        size_t chunck_size = m_transfer_size-m_chunck_offset;
241        if ( (( m_buffer + m_chunck_offset ) & ( m_burst_size-1 )) )
242            chunck_size = 4;
243        if ( chunck_size < m_burst_size )
244            chunck_size = 4;
245        if ( chunck_size > m_burst_size )
246            chunck_size = m_burst_size;
247        VciInitSimpleReadReq<vci_param> *req =
248            new VciInitSimpleReadReq<vci_param>(
249                m_data+m_chunck_offset, m_buffer+m_chunck_offset, chunck_size );
250        m_chunck_offset += chunck_size;
251        req->setDone( this, ON_T(write_finish) );
252        m_vci_init_fsm.doReq( req );
253                m_status = BLOCK_DEVICE_BUSY;
254        break;
255    }
256    default:
257        ended(BLOCK_DEVICE_ERROR);
258        break;
259    }
260}
261
262tmpl(void)::transition()
263{
264        if (!p_resetn) {
265                m_vci_target_fsm.reset();
266                m_vci_init_fsm.reset();
267                r_irq = false;
268                m_irq_enabled = false;
269                m_status = BLOCK_DEVICE_IDLE;
270                return;
271        }
272
273        if ( m_current_op == BLOCK_DEVICE_NOOP &&
274                 m_op != BLOCK_DEVICE_NOOP ) {
275#ifdef SOCLIB_MODULE_DEBUG
276    std::cout
277        << name()
278        << " launch an operation "
279        << SoclibBlockDeviceOp_str[m_op]
280        << std::endl;
281#endif
282                m_current_op = m_op;
283        m_op = BLOCK_DEVICE_NOOP;
284        m_chunck_offset = 0;
285        next_req();
286        }
287
288        m_vci_target_fsm.transition();
289        m_vci_init_fsm.transition();
290}
291
292tmpl(void)::genMoore()
293{
294        m_vci_target_fsm.genMoore();
295        m_vci_init_fsm.genMoore();
296
297        p_irq = r_irq && m_irq_enabled;
298}
299
300tmpl(/**/)::VciBlockDeviceTsar(
301    sc_module_name name,
302    const MappingTable &mt,
303    const IntTab &srcid,
304    const IntTab &tgtid,
305    const std::string &filename,
306    const uint32_t block_size,
307    const uint32_t burst_size)
308        : caba::BaseModule(name),
309          m_vci_target_fsm(p_vci_target, mt.getSegmentList(tgtid)),
310          m_vci_init_fsm(p_vci_initiator, mt.indexForId(srcid)),
311      m_block_size(block_size),
312      m_burst_size(burst_size),
313      p_clk("clk"),
314      p_resetn("resetn"),
315      p_vci_target("vci_target"),
316      p_vci_initiator("vci_initiator"),
317      p_irq("irq")
318{
319        m_vci_target_fsm.on_read_write(on_read, on_write);
320
321    m_fd = ::open(filename.c_str(), O_RDWR);
322    if ( m_fd < 0 ) {
323        throw soclib::exception::RunTimeError(
324            std::string("Unable to open file ")+filename);
325    }
326    m_device_size = lseek(m_fd, 0, SEEK_END) / m_block_size;
327    if ( m_device_size > ((uint64_t)1<<(vci_param::B*8)) ) {
328        std::cerr
329            << "Warning: block device " << filename
330            << " has more blocks than addressable with "
331            << (8*vci_param::B) << "." << std::endl;
332        m_device_size = ((uint64_t)1<<(vci_param::B*8));
333    }
334#ifdef SOCLIB_MODULE_DEBUG
335    std::cout
336        << name
337        << " = Opened "
338        << filename
339        << " which has "
340        << m_device_size
341        << " blocks of "
342        << m_block_size
343        << " bytes"
344        << std::endl;
345#endif
346
347        SC_METHOD(transition);
348        dont_initialize();
349        sensitive << p_clk.pos();
350
351        SC_METHOD(genMoore);
352        dont_initialize();
353        sensitive << p_clk.neg();
354}
355
356}}
357
358// Local Variables:
359// tab-width: 4
360// c-basic-offset: 4
361// c-file-offsets:((innamespace . 0)(inline-open . 0))
362// indent-tabs-mode: nil
363// End:
364
365// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
366
Note: See TracBrowser for help on using the repository browser.