2 * Register Definition API
4 * Copyright (c) 2016 Xilinx Inc.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "qemu/osdep.h"
19 #include "hw/register.h"
23 static inline void register_write_val(RegisterInfo *reg, uint64_t val)
27 switch (reg->data_size) {
29 *(uint8_t *)reg->data = val;
32 *(uint16_t *)reg->data = val;
35 *(uint32_t *)reg->data = val;
38 *(uint64_t *)reg->data = val;
41 g_assert_not_reached();
45 static inline uint64_t register_read_val(RegisterInfo *reg)
47 switch (reg->data_size) {
49 return *(uint8_t *)reg->data;
51 return *(uint16_t *)reg->data;
53 return *(uint32_t *)reg->data;
55 return *(uint64_t *)reg->data;
57 g_assert_not_reached();
59 return 0; /* unreachable */
62 void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
63 const char *prefix, bool debug)
65 uint64_t old_val, new_val, test, no_w_mask;
66 const RegisterAccessInfo *ac;
72 if (!ac || !ac->name) {
73 qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state "
74 "(written value: %#" PRIx64 ")\n", prefix, val);
78 old_val = reg->data ? register_read_val(reg) : ac->reset;
80 test = (old_val ^ val) & ac->rsvd;
82 qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit"
83 "fields: %#" PRIx64 ")\n", prefix, test);
86 test = val & ac->unimp;
88 qemu_log_mask(LOG_UNIMP,
89 "%s:%s writing %#" PRIx64 " to unimplemented bits:" \
91 prefix, reg->access->name, val, ac->unimp);
94 /* Create the no write mask based on the read only, write to clear and
97 no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we;
98 new_val = (val & ~no_w_mask) | (old_val & no_w_mask);
99 new_val &= ~(val & ac->w1c);
102 new_val = ac->pre_write(reg, new_val);
106 qemu_log("%s:%s: write of value %#" PRIx64 "\n", prefix, ac->name,
110 register_write_val(reg, new_val);
112 if (ac->post_write) {
113 ac->post_write(reg, new_val);
117 uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
121 const RegisterAccessInfo *ac;
126 if (!ac || !ac->name) {
127 qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n",
132 ret = reg->data ? register_read_val(reg) : ac->reset;
134 register_write_val(reg, ret & ~(ac->cor & re));
136 /* Mask based on the read enable size */
140 ret = ac->post_read(reg, ret);
144 qemu_log("%s:%s: read of value %#" PRIx64 "\n", prefix,
151 void register_reset(RegisterInfo *reg)
155 if (!reg->data || !reg->access) {
159 register_write_val(reg, reg->access->reset);
162 void register_write_memory(void *opaque, hwaddr addr,
163 uint64_t value, unsigned size)
165 RegisterInfoArray *reg_array = opaque;
166 RegisterInfo *reg = NULL;
170 for (i = 0; i < reg_array->num_elements; i++) {
171 if (reg_array->r[i]->access->addr == addr) {
172 reg = reg_array->r[i];
178 qemu_log_mask(LOG_GUEST_ERROR, "Write to unimplemented register at " \
179 "address: %#" PRIx64 "\n", addr);
183 /* Generate appropriate write enable mask */
184 if (reg->data_size < size) {
185 we = MAKE_64BIT_MASK(0, reg->data_size * 8);
187 we = MAKE_64BIT_MASK(0, size * 8);
190 register_write(reg, value, we, reg_array->prefix,
194 uint64_t register_read_memory(void *opaque, hwaddr addr,
197 RegisterInfoArray *reg_array = opaque;
198 RegisterInfo *reg = NULL;
202 for (i = 0; i < reg_array->num_elements; i++) {
203 if (reg_array->r[i]->access->addr == addr) {
204 reg = reg_array->r[i];
210 qemu_log_mask(LOG_GUEST_ERROR, "Read to unimplemented register at " \
211 "address: %#" PRIx64 "\n", addr);
215 read_val = register_read(reg, size * 8, reg_array->prefix,
218 return extract64(read_val, 0, size * 8);