*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/log.h"
#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
#include "hw/misc/mips_itu.h"
#define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8)
#define ITC_SEMAPH_NUM_MAX 16
#define ITC_AM1_NUMENTRIES_OFS 20
+#define ITC_CELL_PV_MAX_VAL 0xFFFF
+
#define ITC_CELL_TAG_FIFO_DEPTH 28
#define ITC_CELL_TAG_FIFO_PTR 18
#define ITC_CELL_TAG_FIFO 17
{
MIPSITUState *tag = (MIPSITUState *)opaque;
uint64_t index = addr >> 3;
- uint64_t ret = 0;
- switch (index) {
- case 0 ... ITC_ADDRESSMAP_NUM:
- ret = tag->ITCAddressMap[index];
- break;
- default:
+ if (index >= ITC_ADDRESSMAP_NUM) {
qemu_log_mask(LOG_GUEST_ERROR, "Read 0x%" PRIx64 "\n", addr);
- break;
+ return 0;
}
- return ret;
+ return tag->ITCAddressMap[index];
}
static void itc_reconfigure(MIPSITUState *tag)
uint64_t *am = &tag->ITCAddressMap[0];
MemoryRegion *mr = &tag->storage_io;
hwaddr address = am[0] & ITC_AM0_BASE_ADDRESS_MASK;
- uint64_t size = (1 << 10) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
+ uint64_t size = (1 * KiB) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
bool is_enabled = (am[0] & ITC_AM0_EN_MASK) != 0;
memory_region_transaction_begin();
static void QEMU_NORETURN block_thread_and_exit(ITCStorageCell *c)
{
c->blocked_threads |= 1ULL << current_cpu->cpu_index;
- cpu_restore_state(current_cpu, current_cpu->mem_io_pc);
current_cpu->halted = 1;
current_cpu->exception_index = EXCP_HLT;
- cpu_loop_exit(current_cpu);
+ cpu_loop_exit_restore(current_cpu, current_cpu->mem_io_pc);
+}
+
+/* ITC Bypass View */
+
+static inline uint64_t view_bypass_read(ITCStorageCell *c)
+{
+ if (c->tag.FIFO) {
+ return c->data[c->fifo_out];
+ } else {
+ return c->data[0];
+ }
+}
+
+static inline void view_bypass_write(ITCStorageCell *c, uint64_t val)
+{
+ if (c->tag.FIFO && (c->tag.FIFOPtr > 0)) {
+ int idx = (c->fifo_out + c->tag.FIFOPtr - 1) % ITC_CELL_DEPTH;
+ c->data[idx] = val;
+ }
+
+ /* ignore a write to the semaphore cell */
}
/* ITC Control View */
view_ef_common_write(c, val, false);
}
+/* ITC P/V View */
+
+static uint64_t view_pv_common_read(ITCStorageCell *c, bool blocking)
+{
+ uint64_t ret = c->data[0];
+
+ if (c->tag.FIFO) {
+ return 0;
+ }
+
+ if (c->data[0] > 0) {
+ c->data[0]--;
+ } else if (blocking) {
+ block_thread_and_exit(c);
+ }
+
+ return ret;
+}
+
+static uint64_t view_pv_sync_read(ITCStorageCell *c)
+{
+ return view_pv_common_read(c, true);
+}
+
+static uint64_t view_pv_try_read(ITCStorageCell *c)
+{
+ return view_pv_common_read(c, false);
+}
+
+static inline void view_pv_common_write(ITCStorageCell *c)
+{
+ if (c->tag.FIFO) {
+ return;
+ }
+
+ if (c->data[0] < ITC_CELL_PV_MAX_VAL) {
+ c->data[0]++;
+ }
+
+ if (c->blocked_threads) {
+ wake_blocked_threads(c);
+ }
+}
+
+static void view_pv_sync_write(ITCStorageCell *c)
+{
+ view_pv_common_write(c);
+}
+
+static void view_pv_try_write(ITCStorageCell *c)
+{
+ view_pv_common_write(c);
+}
+
static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
{
MIPSITUState *s = (MIPSITUState *)opaque;
uint64_t ret = -1;
switch (view) {
+ case ITCVIEW_BYPASS:
+ ret = view_bypass_read(cell);
+ break;
case ITCVIEW_CONTROL:
ret = view_control_read(cell);
break;
case ITCVIEW_EF_TRY:
ret = view_ef_try_read(cell);
break;
+ case ITCVIEW_PV_SYNC:
+ ret = view_pv_sync_read(cell);
+ break;
+ case ITCVIEW_PV_TRY:
+ ret = view_pv_try_read(cell);
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"itc_storage_read: Bad ITC View %d\n", (int)view);
ITCView view = get_itc_view(addr);
switch (view) {
+ case ITCVIEW_BYPASS:
+ view_bypass_write(cell, data);
+ break;
case ITCVIEW_CONTROL:
view_control_write(cell, data);
break;
case ITCVIEW_EF_TRY:
view_ef_try_write(cell, data);
break;
+ case ITCVIEW_PV_SYNC:
+ view_pv_sync_write(cell);
+ break;
+ case ITCVIEW_PV_TRY:
+ view_pv_try_write(cell);
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"itc_storage_write: Bad ITC View %d\n", (int)view);