/docs
-/tests/nomali_test0
-/tests/nomali_test_ints
+/tests/nomali_test*
+!/tests/nomali_test*.*
*~
*.o
*.d
"lib/mali_midgard.cc",
"lib/mali_t6xx.cc",
"lib/mali_t7xx.cc",
+ "lib/addrspace.cc",
"lib/mmu.cc",
"lib/nomali_api.cc",
]
/*
- * Copyright (c) 2014-2015 ARM Limited
+ * Copyright (c) 2014-2016 ARM Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
NOMALI_CALLBACK_MEMREAD,
/** Model write physical memory callback */
NOMALI_CALLBACK_MEMWRITE,
+ /** Model reset callback */
+ NOMALI_CALLBACK_RESET,
/** Number of defined callbacks */
NOMALI_CALLBACK_NUM_CALLBACKS
nomali_addr_t addr, uint32_t value);
uint32_t (*memread)(nomali_handle_t h, void *usr,
nomali_addr_t addr);
+ void (*reset)(nomali_handle_t h, void *usr);
} func;
} nomali_callback_t;
gpucontrol.o \
jobcontrol.o \
jobslot.o \
+ addrspace.o \
mmu.o \
\
mali_midgard.o \
--- /dev/null
+/*
+ * Copyright (c) 2016 ARM Limited
+ * All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include "jobslot.hh"
+
+#include <cassert>
+#include <cstdlib>
+
+#include "addrspace.hh"
+#include "gpu.hh"
+#include "regutils.hh"
+
+namespace NoMali {
+
+const std::vector<AddrSpace::cmd_t> AddrSpace::cmds {
+ &AddrSpace::cmdNop, // ASn_COMMAND_NOP
+ &AddrSpace::cmdUpdate, // ASn_COMMAND_UPDATE
+ &AddrSpace::cmdLock, // ASn_COMMAND_LOCK
+ &AddrSpace::cmdUnlock, // ASn_COMMAND_UNLOCK
+ &AddrSpace::cmdFlushPT, // ASn_COMMAND_FLUSH_PT
+ &AddrSpace::cmdFlushMem, // ASn_COMMAND_FLUSH_MEM
+};
+
+AddrSpace::AddrSpace(GPU &_gpu, MMU &_mmu, uint8_t _id)
+ : GPUBlock(_gpu, ASn_NO_REGS),
+ id(_id),
+ mmu(_mmu)
+{
+}
+
+AddrSpace::AddrSpace(AddrSpace &&rhs)
+ : GPUBlock(std::move(rhs)),
+ id(std::move(rhs.id)),
+ mmu(rhs.mmu)
+{
+}
+
+AddrSpace::~AddrSpace()
+{
+}
+
+void
+AddrSpace::writeReg(RegAddr addr, uint32_t value)
+{
+ switch (addr.value) {
+ case ASn_COMMAND:
+ asCommand(value);
+ break;
+
+ case ASn_TRANSTAB_LO:
+ case ASn_TRANSTAB_HI:
+ case ASn_MEMATTR_LO:
+ case ASn_MEMATTR_HI:
+ case ASn_LOCKADDR_LO:
+ case ASn_LOCKADDR_HI:
+ GPUBlock::writeReg(addr, value);
+ break;
+
+ default:
+ // Ignore writes by default
+ break;
+ };
+}
+
+void
+AddrSpace::asCommand(uint32_t cmd)
+{
+ if (cmd < cmds.size())
+ (this->*cmds[cmd])(cmd);
+}
+
+void
+AddrSpace::cmdNop(uint32_t cmd)
+{
+ assert(cmd == ASn_COMMAND_NOP);
+}
+
+
+void
+AddrSpace::cmdUpdate(uint32_t cmd)
+{
+ assert(cmd == ASn_COMMAND_UPDATE);
+}
+
+void
+AddrSpace::cmdLock(uint32_t cmd)
+{
+ assert(cmd == ASn_COMMAND_LOCK);
+}
+
+void
+AddrSpace::cmdUnlock(uint32_t cmd)
+{
+ assert(cmd == ASn_COMMAND_UNLOCK);
+}
+
+void
+AddrSpace::cmdFlushPT(uint32_t cmd)
+{
+ assert(cmd == ASn_COMMAND_FLUSH_PT);
+}
+
+void
+AddrSpace::cmdFlushMem(uint32_t cmd)
+{
+ assert(cmd == ASn_COMMAND_FLUSH_MEM);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 ARM Limited
+ * All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#ifndef _LIBNOMALIMODEL_ADDRSPACE_HH
+#define _LIBNOMALIMODEL_ADDRSPACE_HH
+
+#include <vector>
+
+#include "gpublock.hh"
+#include "types.hh"
+
+namespace NoMali {
+
+class GPU;
+
+class MMU;
+
+/**
+ * Midgard job slot implementation.
+ *
+ * A job slot is a part of a JobControl block that controls the state
+ * of one out of 16 active jobs. Each slot can contain one running job
+ * and a pending job.
+ */
+class AddrSpace
+ : public GPUBlock
+{
+ public:
+ AddrSpace(GPU &_gpu, MMU &_mmu, uint8_t slot_id);
+ AddrSpace(AddrSpace &&rhs);
+ virtual ~AddrSpace();
+
+ void writeReg(RegAddr idx, uint32_t value) override;
+
+ protected:
+ /**
+ * @{
+ * @name Address Space Control
+ */
+
+
+ /** @} */
+
+ /**
+ * @{
+ * @name Job slot commands
+ */
+
+ /**
+ * Address space command dispatcher.
+ *
+ * This method is called whenever there is a write to the
+ * ASn_COMMAND register. The method uses a lookup table to call
+ * the right command handling method.
+ *
+ * @param cmd Command number (see the Midgard architecture
+ * specification)
+ */
+ void asCommand(uint32_t cmd);
+
+ /**
+ * Command handler for No-ops.
+ *
+ * @param cmd Command number (see the Midgard architecture
+ * specification)
+ */
+ void cmdNop(uint32_t cmd);
+
+ void cmdUpdate(uint32_t cmd);
+ void cmdLock(uint32_t cmd);
+ void cmdUnlock(uint32_t cmd);
+ void cmdFlushPT(uint32_t cmd);
+ void cmdFlushMem(uint32_t cmd);
+
+ /** @} */
+
+ /** Address space ID */
+ const uint8_t id;
+
+ /** Parent MMU block */
+ MMU &mmu;
+
+ private:
+ typedef void (AddrSpace::*cmd_t)(uint32_t);
+
+ /**
+ * Mapping between command IDs and command handling methods.
+ *
+ * @note The order of this vector <i>MUST</i> correspond to the
+ * address space command IDs in the Midgard architecture
+ * specification.
+ */
+ static const std::vector<cmd_t> cmds;
+};
+
+}
+
+#endif // _LIBNOMALIMODEL_ADDRSPACE_HH
{
}
+void
+JobControl::reset()
+{
+ GPUBlockInt::reset();
+
+ for (auto &js : slots)
+ js.reset();
+}
+
uint32_t
JobControl::readReg(RegAddr addr)
{
JobControl(GPU &_gpu);
virtual ~JobControl();
+ void reset() override;
+
uint32_t readReg(RegAddr idx) override;
void writeReg(RegAddr idx, uint32_t value) override;
/*
- * Copyright (c) 2014-2015 ARM Limited
+ * Copyright (c) 2014-2016 ARM Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
namespace NoMali {
+static const Status STATUS_IDLE(Status::CLASS_NOFAULT, 0, 0);
+static const Status STATUS_DONE(Status::CLASS_NOFAULT, 0, 1);
+static const Status STATUS_ACTIVE(Status::CLASS_NOFAULT, 1, 0);
+
const std::vector<JobSlot::cmd_t> JobSlot::cmds {
&JobSlot::cmdNop, // JSn_COMMAND_NOP
&JobSlot::cmdStart, // JSn_COMMAND_START
return;
// Reset the status register
- regs[RegAddr(JSn_STATUS)] = 0;
+ regs[RegAddr(JSn_STATUS)] = STATUS_ACTIVE.value;
// Transfer the next job configuration to the active job
// configuration
regs.set64(RegAddr(JSn_AFFINITY_LO),
regs.get64(RegAddr(JSn_AFFINITY_NEXT_LO)));
regs[RegAddr(JSn_CONFIG)] = regs[RegAddr(JSn_CONFIG_NEXT)];
- regs[RegAddr(JSn_COMMAND)] = regs[RegAddr(JSn_COMMAND_NEXT)];
// Reset the next job configuration
regs.set64(RegAddr(JSn_HEAD_NEXT_LO), 0);
- regs.set64(RegAddr(JSn_AFFINITY_NEXT_LO), 0);
- regs[RegAddr(JSn_CONFIG_NEXT)] = 0;
regs[RegAddr(JSn_COMMAND_NEXT)] = 0;
runJob();
void
JobSlot::runJob()
{
- exitJob(Status(Status::CLASS_NOFAULT, 0, 1), // JSn_STATUS_DONE
+ exitJob(STATUS_DONE,
0); // Time stamp counter value
}
/*
- * Copyright (c) 2014-2015 ARM Limited
+ * Copyright (c) 2014-2016 ARM Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
RegAddr(MMU_IRQ_RAWSTAT),
RegAddr(MMU_IRQ_CLEAR),
RegAddr(MMU_IRQ_MASK),
- RegAddr(MMU_IRQ_STATUS)),
- regs(BLOCK_NUM_REGS)
+ RegAddr(MMU_IRQ_STATUS))
{
+ spaces.reserve(16);
+ for (int i = 0; i < 16; ++i)
+ spaces.emplace_back(_gpu, *this, i);
}
MMU::~MMU()
{
}
+void
+MMU::reset()
+{
+ GPUBlockInt::reset();
+
+ for (auto &as : spaces)
+ as.reset();
+}
+
+uint32_t
+MMU::readReg(RegAddr addr)
+{
+ if (isAddrSpaceReg(addr)) {
+ return spaces[getAddrSpaceNo(addr)].readReg(getAddrSpaceAddr(addr));
+ } else {
+ return GPUBlockInt::readReg(addr);
+ }
+}
+
void
MMU::writeReg(RegAddr addr, uint32_t value)
{
break;
default:
- // Ignore writes by default
+ if (isAddrSpaceReg(addr)) {
+ AddrSpace &as(spaces[getAddrSpaceNo(addr)]);
+ as.writeReg(getAddrSpaceAddr(addr), value);
+ }
break;
};
}
+uint32_t
+MMU::readRegRaw(RegAddr addr)
+{
+ if (isAddrSpaceReg(addr)) {
+ return spaces[getAddrSpaceNo(addr)].readRegRaw(getAddrSpaceAddr(addr));
+ } else {
+ return GPUBlockInt::readRegRaw(addr);
+ }
+}
+
+void
+MMU::writeRegRaw(RegAddr addr, uint32_t value)
+{
+ if (isAddrSpaceReg(addr)) {
+ spaces[getAddrSpaceNo(addr)].writeRegRaw(getAddrSpaceAddr(addr), value);
+ } else {
+ GPUBlockInt::writeRegRaw(addr, value);
+ }
+}
+
void
MMU::onInterrupt(int set)
{
/*
- * Copyright (c) 2014-2015 ARM Limited
+ * Copyright (c) 2014-2016 ARM Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
#include <vector>
#include "gpublock.hh"
+#include "addrspace.hh"
#include "types.hh"
namespace NoMali {
MMU(GPU &_gpu);
virtual ~MMU();
+ void reset() override;
+
+ uint32_t readReg(RegAddr idx) override;
void writeReg(RegAddr idx, uint32_t value) override;
+ uint32_t readRegRaw(RegAddr idx) override;
+ void writeRegRaw(RegAddr idx, uint32_t value) override;
+
protected:
void onInterrupt(int set) override;
- RegVector regs;
+ /** Address spaces belonging to this MMU block */
+ std::vector<AddrSpace> spaces;
};
}
/*
- * Copyright (c) 2014-2015 ARM Limited
+ * Copyright (c) 2014-2016 ARM Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
public:
void callbackInt(nomali_int_t intno, int set);
+ void callbackReset();
private:
nomali_callback_t callbacks[NOMALI_CALLBACK_NUM_CALLBACKS];
: BaseGpu(std::forward<Args>(args)...),
api(_api)
{
+ reset();
+ }
+
+ void reset() override {
BaseGpu::reset();
+ api.callbackReset();
}
public:
c.func.interrupt(static_cast<nomali_handle_t>(this), c.usr, intno, set);
}
+void
+NoMaliApi::callbackReset()
+{
+ const nomali_callback_t &c(callbacks[NOMALI_CALLBACK_RESET]);
+
+ if (c.func.reset)
+ c.func.reset(static_cast<nomali_handle_t>(this), c.usr);
+}
+
static NoMaliApi *
/*
- * Copyright (c) 2014-2015 ARM Limited
+ * Copyright (c) 2014-2016 ARM Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
return addr - slot_base;
}
+
/** Number of registers per job slot */
static const unsigned JSn_NO_REGS = 0x20;
+/**
+ * Does this MMU register belong to an address space block?
+ *
+ * @return 1 if the address maps to a valid address space block, 0
+ * otherwise.
+ */
+static inline bool
+isAddrSpaceReg(const RegAddr &addr)
+{
+ return addr.value >= MMU_AS0 && addr.value <= 0x7FF;
+}
+
+/**
+ * Get the address space number owning an address within the MMU
+ * block.
+ *
+ * @param addr Address relative to the JobControl block.
+ */
+static inline unsigned
+getAddrSpaceNo(const RegAddr &addr)
+{
+ assert(isAddrSpaceReg(addr));
+ return (addr.value - MMU_AS0) >> 6;
+}
+
+/**
+ * Get a AS-relative address from a MMU-relative
+ * address.
+ *
+ * @param addr Address relative to the MMU block.
+ * @return Address relative the start of the address space block.
+ */
+static inline RegAddr
+getAddrSpaceAddr(const RegAddr &addr)
+{
+ const unsigned as_no(getAddrSpaceNo(addr));
+ const RegAddr as_base(RegAddr(MMU_AS0 + as_no * 0x40));
+ return addr - as_base;
+}
+
+/** Number of registers per address space */
+static const unsigned ASn_NO_REGS = 0x10;
+
}
#endif //_LIBNOMALIMODEL_REGUTILS_HH
TESTS := $(addprefix $(d)/nomali_, \
test0 \
test_ints \
+ test_reset \
+ test_mmu \
)
OBJS := $(HELPER_OBJS) $(addsuffix .o, $(TESTS))
/*
- * Copyright (c) 2014-2015 ARM Limited
+ * Copyright (c) 2014-2016 ARM Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
#define E_NOMALI_BAIL(c) \
do { \
+ nomali_error_t error; \
if ((error = (c)) != NOMALI_E_OK) { \
test_bail(# c " failed: %s (%i)", \
nomali_errstr(error), error); \
} \
} while (0)
+#define NOMALI_TEST_REG(t, handle, reg, test) \
+ do { \
+ uint32_t value; \
+ E_NOMALI_BAIL( \
+ nomali_reg_read(handle, &value, (reg))); \
+ if (!(test)) { \
+ test_fail(t); \
+ } else { \
+ test_ok(t); \
+ } \
+ } while (0)
+
+
#endif /* _TESTS_NOMALI_TEST_HELPERS_H */
static void
test_gpu_int(nomali_handle_t h)
{
- nomali_error_t error = NOMALI_E_OK;
int int_triggered = 0;
nomali_callback_t int_callback = {
.type = NOMALI_CALLBACK_INT,
};
nomali_handle_t h;
- nomali_error_t error = NOMALI_E_OK;
E_NOMALI_BAIL(nomali_create(&h, &cfg));
--- /dev/null
+/*
+ * Copyright (c) 2016 ARM Limited
+ * All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include <libnomali/nomali.h>
+#include <inttypes.h>
+
+#include "nomali_test_helpers.h"
+#include "../lib/mali_midg_regmap.h"
+
+#define TEST_ASn_STATUS(n) \
+ NOMALI_TEST_REG("AS" # n "_STATUS", h, MMU_AS_REG(n, ASn_STATUS), \
+ value == 0)
+
+int
+main(int argc, char **argv)
+{
+ const nomali_config_t cfg = {
+ .type = NOMALI_GPU_T60X,
+ .ver_maj = 0,
+ .ver_min = 1,
+ .ver_status = 0,
+ };
+ nomali_handle_t h;
+ uint32_t value;
+
+ E_NOMALI_BAIL(nomali_create(&h, &cfg));
+
+ TEST_ASn_STATUS(0);
+ TEST_ASn_STATUS(1);
+ TEST_ASn_STATUS(2);
+ TEST_ASn_STATUS(3);
+ TEST_ASn_STATUS(4);
+ TEST_ASn_STATUS(5);
+ TEST_ASn_STATUS(6);
+ TEST_ASn_STATUS(7);
+ TEST_ASn_STATUS(8);
+ TEST_ASn_STATUS(9);
+ TEST_ASn_STATUS(10);
+ TEST_ASn_STATUS(11);
+ TEST_ASn_STATUS(12);
+ TEST_ASn_STATUS(13);
+ TEST_ASn_STATUS(14);
+ TEST_ASn_STATUS(15);
+
+ E_NOMALI_BAIL(nomali_destroy(h));
+
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 ARM Limited
+ * All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include <libnomali/nomali.h>
+#include <inttypes.h>
+
+#include "nomali_test_helpers.h"
+#include "../lib/mali_midg_regmap.h"
+
+#define TEST_ASn_STATUS(n) \
+ E_NOMALI_TEST_REG("AS" # n "_STATUS", h, MMU_AS_REG(n, ASn_STATUS), \
+ value == 0)
+
+static void
+on_reset(nomali_handle_t h, void *usr)
+{
+ E_NOMALI_BAIL(nomali_reg_write_raw(h, 0x0000, 0xC0FFEE));
+}
+
+int
+main(int argc, char **argv)
+{
+ const nomali_config_t cfg = {
+ .type = NOMALI_GPU_T60X,
+ .ver_maj = 0,
+ .ver_min = 1,
+ .ver_status = 0,
+ };
+
+ nomali_callback_t reset_callback = {
+ .type = NOMALI_CALLBACK_RESET,
+ .usr = NULL,
+ .func.reset = &on_reset,
+ };
+
+ nomali_handle_t h;
+ nomali_error_t error;
+
+ E_NOMALI_BAIL(nomali_create(&h, &cfg));
+
+ NOMALI_TEST_REG("gpu_id", h, 0x0000, value == 0x69560010);
+
+ E_NOMALI_TEST("reg_callback", nomali_set_callback(h, &reset_callback));
+ E_NOMALI_BAIL(nomali_reset(h));
+
+ NOMALI_TEST_REG("custom_gpu_id", h, 0x0000, value == 0xC0FFEE);
+
+ E_NOMALI_BAIL(nomali_destroy(h));
+
+
+ return 0;
+}
#include <stdio.h>
#ifdef __cplusplus
-#extern "C" {
+extern "C" {
#endif
extern unsigned test_current;