12SN/A/*
213483Srekai.gonzalezalberquilla@arm.com * Copyright (c) 2015,2017-2018 ARM Limited
311008Sandreas.sandberg@arm.com * All rights reserved
411008Sandreas.sandberg@arm.com *
511008Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall
611008Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual
711008Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating
811008Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software
911008Sandreas.sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
1011008Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated
1111008Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
1211008Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form.
132SN/A *
142SN/A * Redistribution and use in source and binary forms, with or without
152SN/A * modification, are permitted provided that the following conditions are
162SN/A * met: redistributions of source code must retain the above copyright
172SN/A * notice, this list of conditions and the following disclaimer;
182SN/A * redistributions in binary form must reproduce the above copyright
192SN/A * notice, this list of conditions and the following disclaimer in the
202SN/A * documentation and/or other materials provided with the distribution;
212SN/A * neither the name of the copyright holders nor the names of its
222SN/A * contributors may be used to endorse or promote products derived from
232SN/A * this software without specific prior written permission.
242SN/A *
252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362665Ssaidi@eecs.umich.edu *
3711008Sandreas.sandberg@arm.com * Authors: Andreas Sandberg
382SN/A */
392SN/A
4011008Sandreas.sandberg@arm.com#ifndef __BASE_CIRCLEBUF_HH__
4111008Sandreas.sandberg@arm.com#define __BASE_CIRCLEBUF_HH__
422SN/A
4311008Sandreas.sandberg@arm.com#include <algorithm>
4411008Sandreas.sandberg@arm.com#include <cassert>
4511008Sandreas.sandberg@arm.com#include <vector>
462SN/A
4713483Srekai.gonzalezalberquilla@arm.com#include "base/circular_queue.hh"
4812334Sgabeblack@google.com#include "base/logging.hh"
4911008Sandreas.sandberg@arm.com#include "sim/serialize.hh"
5011008Sandreas.sandberg@arm.com
5111008Sandreas.sandberg@arm.com/**
5213483Srekai.gonzalezalberquilla@arm.com * Circular buffer backed by a vector though a CircularQueue.
5311008Sandreas.sandberg@arm.com *
5411008Sandreas.sandberg@arm.com * The data in the cricular buffer is stored in a standard
5513483Srekai.gonzalezalberquilla@arm.com * vector.
5611008Sandreas.sandberg@arm.com *
5711008Sandreas.sandberg@arm.com */
5811008Sandreas.sandberg@arm.comtemplate<typename T>
5913483Srekai.gonzalezalberquilla@arm.comclass CircleBuf : public CircularQueue<T>
602SN/A{
6111008Sandreas.sandberg@arm.com  public:
6211008Sandreas.sandberg@arm.com    explicit CircleBuf(size_t size)
6313483Srekai.gonzalezalberquilla@arm.com        : CircularQueue<T>(size) {}
6413483Srekai.gonzalezalberquilla@arm.com    using CircularQueue<T>::empty;
6513483Srekai.gonzalezalberquilla@arm.com    using CircularQueue<T>::size;
6613483Srekai.gonzalezalberquilla@arm.com    using CircularQueue<T>::capacity;
6713483Srekai.gonzalezalberquilla@arm.com    using CircularQueue<T>::begin;
6813483Srekai.gonzalezalberquilla@arm.com    using CircularQueue<T>::end;
6913483Srekai.gonzalezalberquilla@arm.com    using CircularQueue<T>::pop_front;
7013483Srekai.gonzalezalberquilla@arm.com    using CircularQueue<T>::advance_tail;
7111008Sandreas.sandberg@arm.com
7211008Sandreas.sandberg@arm.com    /**
7311008Sandreas.sandberg@arm.com     * Copy buffer contents without advancing the read pointer
7411008Sandreas.sandberg@arm.com     *
7511008Sandreas.sandberg@arm.com     * @param out Output iterator/pointer
7611008Sandreas.sandberg@arm.com     * @param len Number of elements to copy
7711008Sandreas.sandberg@arm.com     */
7811008Sandreas.sandberg@arm.com    template <class OutputIterator>
7911008Sandreas.sandberg@arm.com    void peek(OutputIterator out, size_t len) const {
8011460Sandreas.sandberg@arm.com        peek(out, 0, len);
8111460Sandreas.sandberg@arm.com    }
8211460Sandreas.sandberg@arm.com
8311460Sandreas.sandberg@arm.com    /**
8411460Sandreas.sandberg@arm.com     * Copy buffer contents without advancing the read pointer
8511460Sandreas.sandberg@arm.com     *
8611460Sandreas.sandberg@arm.com     * @param out Output iterator/pointer
8711460Sandreas.sandberg@arm.com     * @param offset Offset into the ring buffer
8811460Sandreas.sandberg@arm.com     * @param len Number of elements to copy
8911460Sandreas.sandberg@arm.com     */
9011460Sandreas.sandberg@arm.com    template <class OutputIterator>
9111460Sandreas.sandberg@arm.com    void peek(OutputIterator out, off_t offset, size_t len) const {
9211460Sandreas.sandberg@arm.com        panic_if(offset + len > size(),
9311008Sandreas.sandberg@arm.com                 "Trying to read past end of circular buffer.\n");
9411008Sandreas.sandberg@arm.com
9513483Srekai.gonzalezalberquilla@arm.com        std::copy(begin() + offset, begin() + offset + len, out);
9611008Sandreas.sandberg@arm.com    }
9711008Sandreas.sandberg@arm.com
9811008Sandreas.sandberg@arm.com    /**
9911008Sandreas.sandberg@arm.com     * Copy buffer contents and advance the read pointer
10011008Sandreas.sandberg@arm.com     *
10111008Sandreas.sandberg@arm.com     * @param out Output iterator/pointer
10211008Sandreas.sandberg@arm.com     * @param len Number of elements to read
10311008Sandreas.sandberg@arm.com     */
10411008Sandreas.sandberg@arm.com    template <class OutputIterator>
10511008Sandreas.sandberg@arm.com    void read(OutputIterator out, size_t len) {
10611008Sandreas.sandberg@arm.com        peek(out, len);
10713483Srekai.gonzalezalberquilla@arm.com        pop_front(len);
10811008Sandreas.sandberg@arm.com    }
10911008Sandreas.sandberg@arm.com
11011008Sandreas.sandberg@arm.com    /**
11111008Sandreas.sandberg@arm.com     * Add elements to the end of the ring buffers and advance.
11211008Sandreas.sandberg@arm.com     *
11311008Sandreas.sandberg@arm.com     * @param in Input iterator/pointer
11411008Sandreas.sandberg@arm.com     * @param len Number of elements to read
11511008Sandreas.sandberg@arm.com     */
11611008Sandreas.sandberg@arm.com    template <class InputIterator>
11711008Sandreas.sandberg@arm.com    void write(InputIterator in, size_t len) {
11811008Sandreas.sandberg@arm.com        // Writes that are larger than the backing store are allowed,
11911008Sandreas.sandberg@arm.com        // but only the last part of the buffer will be written.
12013483Srekai.gonzalezalberquilla@arm.com        if (len > capacity()) {
12113483Srekai.gonzalezalberquilla@arm.com            in += len - capacity();
12213483Srekai.gonzalezalberquilla@arm.com            len = capacity();
12311008Sandreas.sandberg@arm.com        }
12411008Sandreas.sandberg@arm.com
12513483Srekai.gonzalezalberquilla@arm.com        std::copy(in, in + len, end());
12613483Srekai.gonzalezalberquilla@arm.com        advance_tail(len);
12711008Sandreas.sandberg@arm.com    }
1282SN/A};
1292SN/A
13011008Sandreas.sandberg@arm.com/**
13111008Sandreas.sandberg@arm.com * Simple FIFO implementation backed by a circular buffer.
13211008Sandreas.sandberg@arm.com *
13311008Sandreas.sandberg@arm.com * This class provides the same basic functionallity as the circular
13411008Sandreas.sandberg@arm.com * buffer with the folling differences:
13511008Sandreas.sandberg@arm.com * <ul>
13611008Sandreas.sandberg@arm.com *    <li>Writes are checked to ensure that overflows can't happen.
13711008Sandreas.sandberg@arm.com *    <li>Unserialization ensures that the data in the checkpoint fits
13811008Sandreas.sandberg@arm.com *        in the buffer.
13911008Sandreas.sandberg@arm.com * </ul>
14011008Sandreas.sandberg@arm.com */
14111008Sandreas.sandberg@arm.comtemplate<typename T>
14211008Sandreas.sandberg@arm.comclass Fifo
14311008Sandreas.sandberg@arm.com{
14411008Sandreas.sandberg@arm.com  public:
14511008Sandreas.sandberg@arm.com    typedef T value_type;
14611008Sandreas.sandberg@arm.com
14711008Sandreas.sandberg@arm.com  public:
14811008Sandreas.sandberg@arm.com    Fifo(size_t size)
14911008Sandreas.sandberg@arm.com        : buf(size) {}
15011008Sandreas.sandberg@arm.com
15111008Sandreas.sandberg@arm.com    bool empty() const { return buf.empty(); }
15211008Sandreas.sandberg@arm.com    size_t size() const { return buf.size(); }
15311008Sandreas.sandberg@arm.com    size_t capacity() const { return buf.capacity(); }
15411008Sandreas.sandberg@arm.com
15511008Sandreas.sandberg@arm.com    void flush() { buf.flush(); }
15611008Sandreas.sandberg@arm.com
15711008Sandreas.sandberg@arm.com    template <class OutputIterator>
15811008Sandreas.sandberg@arm.com    void peek(OutputIterator out, size_t len) const { buf.peek(out, len); }
15911008Sandreas.sandberg@arm.com    template <class OutputIterator>
16011008Sandreas.sandberg@arm.com    void read(OutputIterator out, size_t len) { buf.read(out, len); }
16111008Sandreas.sandberg@arm.com
16211008Sandreas.sandberg@arm.com    template <class InputIterator>
16311008Sandreas.sandberg@arm.com    void write(InputIterator in, size_t len) {
16411008Sandreas.sandberg@arm.com        panic_if(size() + len > capacity(),
16511008Sandreas.sandberg@arm.com                 "Trying to overfill FIFO buffer.\n");
16611008Sandreas.sandberg@arm.com        buf.write(in, len);
16711008Sandreas.sandberg@arm.com    }
16811008Sandreas.sandberg@arm.com
16911008Sandreas.sandberg@arm.com  private:
17011008Sandreas.sandberg@arm.com    CircleBuf<value_type> buf;
17111008Sandreas.sandberg@arm.com};
17211008Sandreas.sandberg@arm.com
17311008Sandreas.sandberg@arm.com
17411008Sandreas.sandberg@arm.comtemplate <typename T>
17512032Sandreas.sandberg@arm.comvoid
17611008Sandreas.sandberg@arm.comarrayParamOut(CheckpointOut &cp, const std::string &name,
17711008Sandreas.sandberg@arm.com              const CircleBuf<T> &param)
17811008Sandreas.sandberg@arm.com{
17911008Sandreas.sandberg@arm.com    std::vector<T> temp(param.size());
18011008Sandreas.sandberg@arm.com    param.peek(temp.begin(), temp.size());
18111008Sandreas.sandberg@arm.com    arrayParamOut(cp, name, temp);
18211008Sandreas.sandberg@arm.com}
18311008Sandreas.sandberg@arm.com
18411008Sandreas.sandberg@arm.comtemplate <typename T>
18512032Sandreas.sandberg@arm.comvoid
18611008Sandreas.sandberg@arm.comarrayParamIn(CheckpointIn &cp, const std::string &name,
18711008Sandreas.sandberg@arm.com             CircleBuf<T> &param)
18811008Sandreas.sandberg@arm.com{
18911008Sandreas.sandberg@arm.com    std::vector<T> temp;
19011008Sandreas.sandberg@arm.com    arrayParamIn(cp, name, temp);
19111008Sandreas.sandberg@arm.com
19211008Sandreas.sandberg@arm.com    param.flush();
19311008Sandreas.sandberg@arm.com    param.write(temp.cbegin(), temp.size());
19411008Sandreas.sandberg@arm.com}
19511008Sandreas.sandberg@arm.com
19611008Sandreas.sandberg@arm.comtemplate <typename T>
19712032Sandreas.sandberg@arm.comvoid
19811008Sandreas.sandberg@arm.comarrayParamOut(CheckpointOut &cp, const std::string &name,
19911008Sandreas.sandberg@arm.com              const Fifo<T> &param)
20011008Sandreas.sandberg@arm.com{
20111008Sandreas.sandberg@arm.com    std::vector<T> temp(param.size());
20211008Sandreas.sandberg@arm.com    param.peek(temp.begin(), temp.size());
20311008Sandreas.sandberg@arm.com    arrayParamOut(cp, name, temp);
20411008Sandreas.sandberg@arm.com}
20511008Sandreas.sandberg@arm.com
20611008Sandreas.sandberg@arm.comtemplate <typename T>
20712032Sandreas.sandberg@arm.comvoid
20811008Sandreas.sandberg@arm.comarrayParamIn(CheckpointIn &cp, const std::string &name,
20911008Sandreas.sandberg@arm.com             Fifo<T> &param)
21011008Sandreas.sandberg@arm.com{
21111008Sandreas.sandberg@arm.com    std::vector<T> temp;
21211008Sandreas.sandberg@arm.com    arrayParamIn(cp, name, temp);
21311008Sandreas.sandberg@arm.com
21411008Sandreas.sandberg@arm.com    fatal_if(param.capacity() < temp.size(),
21511008Sandreas.sandberg@arm.com             "Trying to unserialize data into too small FIFO\n");
21611008Sandreas.sandberg@arm.com
21711008Sandreas.sandberg@arm.com    param.flush();
21811008Sandreas.sandberg@arm.com    param.write(temp.cbegin(), temp.size());
21911008Sandreas.sandberg@arm.com}
22011008Sandreas.sandberg@arm.com
22111008Sandreas.sandberg@arm.com#endif // __BASE_CIRCLEBUF_HH__
222