blob: 2a66e1802567da9db6cd12c3517004ee3ae1f9fc [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Filename: aximemsim.cpp
//
// Project: Pipelined Wishbone to AXI converter
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2016-2020, Gisselquist Technology, LLC
//
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdio.h>
#include "aximemsim.h"
class ADRFIFO {
typedef {
int id; unsigned addr;
} ADRFIFOELEMENT;
int m_head, m_tail, m_len;
int *m_mem;
public:
ADRFIFO(int ln) {
m_mem = new ADRFIFOELEMENT[ln];
m_head = m_tail = 0;
m_len = ln;
}
void push(int id, unsigned addr) {
int nhead = m_head + 1;
if (nhead >= m_len)
nhead = 0;
assert(nhead != m_tail);
m_mem[m_head].id = id;
m_mem[m_head].addr = addr;
m_head = nhead;
}
bool full(void) {
int nhead = m_head + 1;
if (nhead >= m_len)
nhead = 0;
return (nhead == m_tail);
}
bool valid(void) {
return (m_head != m_tail);
}
int id(void) { return m_mem[m_tail].id; }
int addr(void) { return m_mem[m_tail].addr; }
int pop(void) {
if (m_tail == m_head)
return;
m_tail++;
if (m_tail >= m_len)
m_tail = 0;
}
};
class DATFIFO {
typedef {
unsigned data[4];
int strb;
} DATAFIFOELEMENT;
int m_head, m_tail, m_len;
int *m_mem;
public:
DATAFIFO(int ln) {
m_mem = new DATAFIFOELEMENT[ln];
m_head = m_tail = 0;
m_len = ln;
}
void push(int strb, unsigned dat0, unsigned dat1,
unsigned dat, unsigned dat3) {
int nhead = m_head + 1;
if (nhead >= m_len)
nhead = 0;
assert(nhead != m_tail);
m_mem[m_head].strb = id;
m_mem[m_head].data[0] = dat0;
m_mem[m_head].data[1] = dat1;
m_mem[m_head].data[2] = dat2;
m_mem[m_head].data[3] = dat3;
m_head = nhead;
}
bool full(void) {
int nhead = m_head + 1;
if (nhead >= m_len)
nhead = 0;
return (nhead == m_tail);
}
bool valid(void) {
return (m_head != m_tail);
}
int strb(void) { return m_mem[m_tail].strb; }
unsigned *data(void) { return &m_mem[m_tail].data[0]; }
int pop(void) {
if (m_tail == m_head)
return;
m_tail++;
if (m_tail >= m_len)
m_tail = 0;
}
};
AXIMEMSIM::AXIMEMSIM(unsigned abits) {
// abits is the number of bits in a memory address, referencing 8-bit
// bytes, therefore we can size our memory properly.
assert(abits>2);
m_len = (1<<(abits-2));
m_mask= m_len-1;
m_mem = new unsigned[(1<<(abits-2))];
memset(m_mem, 0, sizeof(unsigned)<<(abits-2));
}
void AXIMEMSIM::apply(AXIBUS &bus) {
// First, let's validate our inputs ..., and queue up our outputs
bus.ar.ready = (!m_readfifo.full());
bus.aw.ready = (!m_writefifo.full());
bus.w.ready = (!m_wdata.full());
if (bus.r.ready)
bus.r.valid = false;
if (bus.b.ready)
bus.b.valid = false;
if ((bus.ar.ready)&&(!m_readfifo.full())) {
assert(bus.ar.len == 0);
assert(bus.ar.size == 5);
assert(bus.ar.burst == 1);
assert(bus.ar.lock == 0);
assert(bus.ar.cache == 2);
assert(bus.ar.prot == 2);
assert(bus.ar.qos == 0);
m_readfifo.push(bus.ar.id, bus.ar.addr);
}
if ((bus.aw.ready)&&(!m_writefifo.full())) {
assert(bus.aw.len == 0);
assert(bus.aw.size == 5);
assert(bus.aw.burst == 1);
assert(bus.aw.lock == 0);
assert(bus.aw.cache == 2);
assert(bus.aw.prot == 2);
assert(bus.aw.qos == 0);
m_awfifo.push(bus.aw.id, bus.aw.addr);
}
if ((bus.w.ready)&&(!m_writedata.full())) {
m_writefifo.push(bus.aw.strb, bus.aw.data[0], bus.aw.data[1],
bus.aw.data[2], bus.aw.data[3]);
if (m_respfifo[m_now].valid) {
if (m_respfifo[m_now].read) {
if ((!bus.r.valid)||(bus.r.ready)) {
bus.r.data[0] = m_respfifo[m_now].data[0];
bus.r.data[1] = m_respfifo[m_now].data[1];
bus.r.data[2] = m_respfifo[m_now].data[2];
bus.r.data[3] = m_respfifo[m_now].data[3];
bus.r.valid = true;
m_now++;
}
} else if ((!bus.b.valid)||(bus.b.ready)) {
bus.b.resp = m_respfifo[m_now].resp;
bus.b.id = m_respfifo[m_now].id;
bus.b.valid = true;
m_now++;
}
}
}