source: trunk/modules/vci_block_device_tsar_v2/caba/source/src/vci_block_device_tsar_v2.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_v2.h"
32#include <fcntl.h>
33#include "block_device_tsar_v2.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 VciBlockDeviceTsarV2<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 = m_burst_size - (( m_buffer + m_chunck_offset ) & ( m_burst_size-1 ));
243        if ( chunck_size > m_burst_size )
244            chunck_size = m_burst_size;
245        VciInitSimpleReadReq<vci_param> *req =
246            new VciInitSimpleReadReq<vci_param>(
247                m_data+m_chunck_offset, m_buffer+m_chunck_offset, chunck_size );
248        m_chunck_offset += chunck_size;
249        req->setDone( this, ON_T(write_finish) );
250        m_vci_init_fsm.doReq( req );
251                m_status = BLOCK_DEVICE_BUSY;
252        break;
253    }
254    default:
255        ended(BLOCK_DEVICE_ERROR);
256        break;
257    }
258}
259
260tmpl(void)::transition()
261{
262        if (!p_resetn) {
263                m_vci_target_fsm.reset();
264                m_vci_init_fsm.reset();
265                r_irq = false;
266                m_irq_enabled = false;
267                m_status = BLOCK_DEVICE_IDLE;
268                return;
269        }
270
271        if ( m_current_op == BLOCK_DEVICE_NOOP &&
272                 m_op != BLOCK_DEVICE_NOOP ) {
273#ifdef SOCLIB_MODULE_DEBUG
274    std::cout
275        << name()
276        << " launch an operation "
277        << SoclibBlockDeviceOp_str[m_op]
278        << std::endl;
279#endif
280                m_current_op = m_op;
281        m_op = BLOCK_DEVICE_NOOP;
282        m_chunck_offset = 0;
283        next_req();
284        }
285
286        m_vci_target_fsm.transition();
287        m_vci_init_fsm.transition();
288}
289
290tmpl(void)::genMoore()
291{
292        m_vci_target_fsm.genMoore();
293        m_vci_init_fsm.genMoore();
294
295        p_irq = r_irq && m_irq_enabled;
296}
297
298tmpl(/**/)::VciBlockDeviceTsarV2(
299    sc_module_name name,
300    const MappingTable &mt,
301    const IntTab &srcid,
302    const IntTab &tgtid,
303    const std::string &filename,
304    const uint32_t block_size,
305    const uint32_t burst_size)
306        : caba::BaseModule(name),
307          m_vci_target_fsm(p_vci_target, mt.getSegmentList(tgtid)),
308          m_vci_init_fsm(p_vci_initiator, mt.indexForId(srcid)),
309      m_block_size(block_size),
310      m_burst_size(burst_size),
311      p_clk("clk"),
312      p_resetn("resetn"),
313      p_vci_target("vci_target"),
314      p_vci_initiator("vci_initiator"),
315      p_irq("irq")
316{
317        m_vci_target_fsm.on_read_write(on_read, on_write);
318
319    m_fd = ::open(filename.c_str(), O_RDWR);
320    if ( m_fd < 0 ) {
321        throw soclib::exception::RunTimeError(
322            std::string("Unable to open file ")+filename);
323    }
324    m_device_size = lseek(m_fd, 0, SEEK_END) / m_block_size;
325    if ( m_device_size > ((uint64_t)1<<(vci_param::B*8)) ) {
326        std::cerr
327            << "Warning: block device " << filename
328            << " has more blocks than addressable with "
329            << (8*vci_param::B) << "." << std::endl;
330        m_device_size = ((uint64_t)1<<(vci_param::B*8));
331    }
332#ifdef SOCLIB_MODULE_DEBUG
333    std::cout
334        << name
335        << " = Opened "
336        << filename
337        << " which has "
338        << m_device_size
339        << " blocks of "
340        << m_block_size
341        << " bytes"
342        << std::endl;
343#endif
344
345        SC_METHOD(transition);
346        dont_initialize();
347        sensitive << p_clk.pos();
348
349        SC_METHOD(genMoore);
350        dont_initialize();
351        sensitive << p_clk.neg();
352}
353
354}}
355
356// Local Variables:
357// tab-width: 4
358// c-basic-offset: 4
359// c-file-offsets:((innamespace . 0)(inline-open . 0))
360// indent-tabs-mode: nil
361// End:
362
363// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
364
Note: See TracBrowser for help on using the repository browser.