2 * Inter-Thread Communication Unit emulation.
4 * Copyright (c) 2016 Imagination Technologies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qemu/units.h"
23 #include "qemu/module.h"
24 #include "qapi/error.h"
25 #include "hw/core/cpu.h"
26 #include "hw/misc/mips_itu.h"
27 #include "hw/qdev-properties.h"
28 #include "target/mips/cpu.h"
30 #define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8)
31 /* Initialize as 4kB area to fit all 32 cells with default 128B grain.
32 Storage may be resized by the software. */
33 #define ITC_STORAGE_ADDRSPACE_SZ 0x1000
35 #define ITC_FIFO_NUM_MAX 16
36 #define ITC_SEMAPH_NUM_MAX 16
37 #define ITC_AM1_NUMENTRIES_OFS 20
39 #define ITC_CELL_PV_MAX_VAL 0xFFFF
41 #define ITC_CELL_TAG_FIFO_DEPTH 28
42 #define ITC_CELL_TAG_FIFO_PTR 18
43 #define ITC_CELL_TAG_FIFO 17
44 #define ITC_CELL_TAG_T 16
45 #define ITC_CELL_TAG_F 1
46 #define ITC_CELL_TAG_E 0
48 #define ITC_AM0_BASE_ADDRESS_MASK 0xFFFFFC00ULL
49 #define ITC_AM0_EN_MASK 0x1
51 #define ITC_AM1_ADDR_MASK_MASK 0x1FC00
52 #define ITC_AM1_ENTRY_GRAIN_MASK 0x7
54 typedef enum ITCView
{
64 #define ITC_ICR0_CELL_NUM 16
65 #define ITC_ICR0_BLK_GRAIN 8
66 #define ITC_ICR0_BLK_GRAIN_MASK 0x7
67 #define ITC_ICR0_ERR_AXI 2
68 #define ITC_ICR0_ERR_PARITY 1
69 #define ITC_ICR0_ERR_EXEC 0
71 MemoryRegion
*mips_itu_get_tag_region(MIPSITUState
*itu
)
76 static uint64_t itc_tag_read(void *opaque
, hwaddr addr
, unsigned size
)
78 MIPSITUState
*tag
= (MIPSITUState
*)opaque
;
79 uint64_t index
= addr
>> 3;
81 if (index
>= ITC_ADDRESSMAP_NUM
) {
82 qemu_log_mask(LOG_GUEST_ERROR
, "Read 0x%" PRIx64
"\n", addr
);
86 return tag
->ITCAddressMap
[index
];
89 void itc_reconfigure(MIPSITUState
*tag
)
91 uint64_t *am
= &tag
->ITCAddressMap
[0];
92 MemoryRegion
*mr
= &tag
->storage_io
;
93 hwaddr address
= am
[0] & ITC_AM0_BASE_ADDRESS_MASK
;
94 uint64_t size
= (1 * KiB
) + (am
[1] & ITC_AM1_ADDR_MASK_MASK
);
95 bool is_enabled
= (am
[0] & ITC_AM0_EN_MASK
) != 0;
98 address
= (tag
->saar
[0] & 0xFFFFFFFFE000ULL
) << 4;
99 size
= 1ULL << ((tag
->saar
[0] >> 1) & 0x1f);
100 is_enabled
= tag
->saar
[0] & 1;
103 memory_region_transaction_begin();
104 if (!(size
& (size
- 1))) {
105 memory_region_set_size(mr
, size
);
107 memory_region_set_address(mr
, address
);
108 memory_region_set_enabled(mr
, is_enabled
);
109 memory_region_transaction_commit();
112 static void itc_tag_write(void *opaque
, hwaddr addr
,
113 uint64_t data
, unsigned size
)
115 MIPSITUState
*tag
= (MIPSITUState
*)opaque
;
116 uint64_t *am
= &tag
->ITCAddressMap
[0];
117 uint64_t am_old
, mask
;
118 uint64_t index
= addr
>> 3;
122 mask
= ITC_AM0_BASE_ADDRESS_MASK
| ITC_AM0_EN_MASK
;
125 mask
= ITC_AM1_ADDR_MASK_MASK
| ITC_AM1_ENTRY_GRAIN_MASK
;
128 qemu_log_mask(LOG_GUEST_ERROR
, "Bad write 0x%" PRIx64
"\n", addr
);
133 am
[index
] = (data
& mask
) | (am_old
& ~mask
);
134 if (am_old
!= am
[index
]) {
135 itc_reconfigure(tag
);
139 static const MemoryRegionOps itc_tag_ops
= {
140 .read
= itc_tag_read
,
141 .write
= itc_tag_write
,
143 .max_access_size
= 8,
145 .endianness
= DEVICE_NATIVE_ENDIAN
,
148 static inline uint32_t get_num_cells(MIPSITUState
*s
)
150 return s
->num_fifo
+ s
->num_semaphores
;
153 static inline ITCView
get_itc_view(hwaddr addr
)
155 return (addr
>> 3) & 0xf;
158 static inline int get_cell_stride_shift(const MIPSITUState
*s
)
160 /* Minimum interval (for EntryGain = 0) is 128 B */
162 return 7 + ((s
->icr0
>> ITC_ICR0_BLK_GRAIN
) &
163 ITC_ICR0_BLK_GRAIN_MASK
);
165 return 7 + (s
->ITCAddressMap
[1] & ITC_AM1_ENTRY_GRAIN_MASK
);
169 static inline ITCStorageCell
*get_cell(MIPSITUState
*s
,
172 uint32_t cell_idx
= addr
>> get_cell_stride_shift(s
);
173 uint32_t num_cells
= get_num_cells(s
);
175 if (cell_idx
>= num_cells
) {
176 cell_idx
= num_cells
- 1;
179 return &s
->cell
[cell_idx
];
182 static void wake_blocked_threads(ITCStorageCell
*c
)
186 if (cs
->halted
&& (c
->blocked_threads
& (1ULL << cs
->cpu_index
))) {
187 cpu_interrupt(cs
, CPU_INTERRUPT_WAKE
);
190 c
->blocked_threads
= 0;
194 void block_thread_and_exit(ITCStorageCell
*c
)
196 c
->blocked_threads
|= 1ULL << current_cpu
->cpu_index
;
197 current_cpu
->halted
= 1;
198 current_cpu
->exception_index
= EXCP_HLT
;
199 cpu_loop_exit_restore(current_cpu
, current_cpu
->mem_io_pc
);
202 /* ITC Bypass View */
204 static inline uint64_t view_bypass_read(ITCStorageCell
*c
)
207 return c
->data
[c
->fifo_out
];
213 static inline void view_bypass_write(ITCStorageCell
*c
, uint64_t val
)
215 if (c
->tag
.FIFO
&& (c
->tag
.FIFOPtr
> 0)) {
216 int idx
= (c
->fifo_out
+ c
->tag
.FIFOPtr
- 1) % ITC_CELL_DEPTH
;
220 /* ignore a write to the semaphore cell */
223 /* ITC Control View */
225 static inline uint64_t view_control_read(ITCStorageCell
*c
)
227 return ((uint64_t)c
->tag
.FIFODepth
<< ITC_CELL_TAG_FIFO_DEPTH
) |
228 (c
->tag
.FIFOPtr
<< ITC_CELL_TAG_FIFO_PTR
) |
229 (c
->tag
.FIFO
<< ITC_CELL_TAG_FIFO
) |
230 (c
->tag
.T
<< ITC_CELL_TAG_T
) |
231 (c
->tag
.E
<< ITC_CELL_TAG_E
) |
232 (c
->tag
.F
<< ITC_CELL_TAG_F
);
235 static inline void view_control_write(ITCStorageCell
*c
, uint64_t val
)
237 c
->tag
.T
= (val
>> ITC_CELL_TAG_T
) & 1;
238 c
->tag
.E
= (val
>> ITC_CELL_TAG_E
) & 1;
239 c
->tag
.F
= (val
>> ITC_CELL_TAG_F
) & 1;
246 /* ITC Empty/Full View */
248 static uint64_t view_ef_common_read(ITCStorageCell
*c
, bool blocking
)
258 if (blocking
&& c
->tag
.E
) {
259 block_thread_and_exit(c
);
262 if (c
->blocked_threads
) {
263 wake_blocked_threads(c
);
266 if (c
->tag
.FIFOPtr
> 0) {
267 ret
= c
->data
[c
->fifo_out
];
268 c
->fifo_out
= (c
->fifo_out
+ 1) % ITC_CELL_DEPTH
;
272 if (c
->tag
.FIFOPtr
== 0) {
279 static uint64_t view_ef_sync_read(ITCStorageCell
*c
)
281 return view_ef_common_read(c
, true);
284 static uint64_t view_ef_try_read(ITCStorageCell
*c
)
286 return view_ef_common_read(c
, false);
289 static inline void view_ef_common_write(ITCStorageCell
*c
, uint64_t val
,
298 if (blocking
&& c
->tag
.F
) {
299 block_thread_and_exit(c
);
302 if (c
->blocked_threads
) {
303 wake_blocked_threads(c
);
306 if (c
->tag
.FIFOPtr
< ITC_CELL_DEPTH
) {
307 int idx
= (c
->fifo_out
+ c
->tag
.FIFOPtr
) % ITC_CELL_DEPTH
;
312 if (c
->tag
.FIFOPtr
== ITC_CELL_DEPTH
) {
317 static void view_ef_sync_write(ITCStorageCell
*c
, uint64_t val
)
319 view_ef_common_write(c
, val
, true);
322 static void view_ef_try_write(ITCStorageCell
*c
, uint64_t val
)
324 view_ef_common_write(c
, val
, false);
329 static uint64_t view_pv_common_read(ITCStorageCell
*c
, bool blocking
)
331 uint64_t ret
= c
->data
[0];
337 if (c
->data
[0] > 0) {
339 } else if (blocking
) {
340 block_thread_and_exit(c
);
346 static uint64_t view_pv_sync_read(ITCStorageCell
*c
)
348 return view_pv_common_read(c
, true);
351 static uint64_t view_pv_try_read(ITCStorageCell
*c
)
353 return view_pv_common_read(c
, false);
356 static inline void view_pv_common_write(ITCStorageCell
*c
)
362 if (c
->data
[0] < ITC_CELL_PV_MAX_VAL
) {
366 if (c
->blocked_threads
) {
367 wake_blocked_threads(c
);
371 static void view_pv_sync_write(ITCStorageCell
*c
)
373 view_pv_common_write(c
);
376 static void view_pv_try_write(ITCStorageCell
*c
)
378 view_pv_common_write(c
);
381 static void raise_exception(int excp
)
383 current_cpu
->exception_index
= excp
;
384 cpu_loop_exit(current_cpu
);
387 static uint64_t itc_storage_read(void *opaque
, hwaddr addr
, unsigned size
)
389 MIPSITUState
*s
= (MIPSITUState
*)opaque
;
390 ITCStorageCell
*cell
= get_cell(s
, addr
);
391 ITCView view
= get_itc_view(addr
);
397 s
->icr0
|= 1 << ITC_ICR0_ERR_AXI
;
398 raise_exception(EXCP_DBE
);
404 ret
= view_bypass_read(cell
);
406 case ITCVIEW_CONTROL
:
407 ret
= view_control_read(cell
);
409 case ITCVIEW_EF_SYNC
:
410 ret
= view_ef_sync_read(cell
);
413 ret
= view_ef_try_read(cell
);
415 case ITCVIEW_PV_SYNC
:
416 ret
= view_pv_sync_read(cell
);
419 ret
= view_pv_try_read(cell
);
421 case ITCVIEW_PV_ICR0
:
425 qemu_log_mask(LOG_GUEST_ERROR
,
426 "itc_storage_read: Bad ITC View %d\n", (int)view
);
433 static void itc_storage_write(void *opaque
, hwaddr addr
, uint64_t data
,
436 MIPSITUState
*s
= (MIPSITUState
*)opaque
;
437 ITCStorageCell
*cell
= get_cell(s
, addr
);
438 ITCView view
= get_itc_view(addr
);
443 s
->icr0
|= 1 << ITC_ICR0_ERR_AXI
;
444 raise_exception(EXCP_DBE
);
450 view_bypass_write(cell
, data
);
452 case ITCVIEW_CONTROL
:
453 view_control_write(cell
, data
);
455 case ITCVIEW_EF_SYNC
:
456 view_ef_sync_write(cell
, data
);
459 view_ef_try_write(cell
, data
);
461 case ITCVIEW_PV_SYNC
:
462 view_pv_sync_write(cell
);
465 view_pv_try_write(cell
);
467 case ITCVIEW_PV_ICR0
:
469 /* clear ERROR bits */
470 s
->icr0
&= ~(data
& 0x7);
474 s
->icr0
|= data
& 0x700;
477 qemu_log_mask(LOG_GUEST_ERROR
,
478 "itc_storage_write: Bad ITC View %d\n", (int)view
);
484 static const MemoryRegionOps itc_storage_ops
= {
485 .read
= itc_storage_read
,
486 .write
= itc_storage_write
,
487 .endianness
= DEVICE_NATIVE_ENDIAN
,
490 static void itc_reset_cells(MIPSITUState
*s
)
494 memset(s
->cell
, 0, get_num_cells(s
) * sizeof(s
->cell
[0]));
496 for (i
= 0; i
< s
->num_fifo
; i
++) {
497 s
->cell
[i
].tag
.E
= 1;
498 s
->cell
[i
].tag
.FIFO
= 1;
499 s
->cell
[i
].tag
.FIFODepth
= ITC_CELL_DEPTH_SHIFT
;
503 static void mips_itu_init(Object
*obj
)
505 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
506 MIPSITUState
*s
= MIPS_ITU(obj
);
508 memory_region_init_io(&s
->storage_io
, OBJECT(s
), &itc_storage_ops
, s
,
509 "mips-itc-storage", ITC_STORAGE_ADDRSPACE_SZ
);
510 sysbus_init_mmio(sbd
, &s
->storage_io
);
512 memory_region_init_io(&s
->tag_io
, OBJECT(s
), &itc_tag_ops
, s
,
513 "mips-itc-tag", ITC_TAG_ADDRSPACE_SZ
);
516 static void mips_itu_realize(DeviceState
*dev
, Error
**errp
)
518 MIPSITUState
*s
= MIPS_ITU(dev
);
521 if (s
->num_fifo
> ITC_FIFO_NUM_MAX
) {
522 error_setg(errp
, "Exceed maximum number of FIFO cells: %d",
526 if (s
->num_semaphores
> ITC_SEMAPH_NUM_MAX
) {
527 error_setg(errp
, "Exceed maximum number of Semaphore cells: %d",
532 error_setg(errp
, "Missing 'cpu[0]' property");
536 env
= &MIPS_CPU(s
->cpu0
)->env
;
538 s
->saar
= env
->CP0_SAAR
;
541 s
->cell
= g_new(ITCStorageCell
, get_num_cells(s
));
544 static void mips_itu_reset(DeviceState
*dev
)
546 MIPSITUState
*s
= MIPS_ITU(dev
);
549 s
->saar
[0] = 0x11 << 1;
550 s
->icr0
= get_num_cells(s
) << ITC_ICR0_CELL_NUM
;
552 s
->ITCAddressMap
[0] = 0;
553 s
->ITCAddressMap
[1] =
554 ((ITC_STORAGE_ADDRSPACE_SZ
- 1) & ITC_AM1_ADDR_MASK_MASK
) |
555 (get_num_cells(s
) << ITC_AM1_NUMENTRIES_OFS
);
562 static Property mips_itu_properties
[] = {
563 DEFINE_PROP_UINT32("num-fifo", MIPSITUState
, num_fifo
,
565 DEFINE_PROP_UINT32("num-semaphores", MIPSITUState
, num_semaphores
,
567 DEFINE_PROP_LINK("cpu[0]", MIPSITUState
, cpu0
, TYPE_MIPS_CPU
, ArchCPU
*),
568 DEFINE_PROP_END_OF_LIST(),
571 static void mips_itu_class_init(ObjectClass
*klass
, void *data
)
573 DeviceClass
*dc
= DEVICE_CLASS(klass
);
575 device_class_set_props(dc
, mips_itu_properties
);
576 dc
->realize
= mips_itu_realize
;
577 dc
->reset
= mips_itu_reset
;
580 static const TypeInfo mips_itu_info
= {
581 .name
= TYPE_MIPS_ITU
,
582 .parent
= TYPE_SYS_BUS_DEVICE
,
583 .instance_size
= sizeof(MIPSITUState
),
584 .instance_init
= mips_itu_init
,
585 .class_init
= mips_itu_class_init
,
588 static void mips_itu_register_types(void)
590 type_register_static(&mips_itu_info
);
593 type_init(mips_itu_register_types
)