ext: Fix undefined-behavior bug in bitshift
[gem5.git] / ext / nomali / lib / jobcontrol.cc
1 /*
2 * Copyright (c) 2014-2015 ARM Limited
3 * All rights reserved
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Authors: Andreas Sandberg
18 */
19
20 #include "jobcontrol.hh"
21
22 #include "gpu.hh"
23 #include "regutils.hh"
24
25 namespace NoMali {
26
27 JobControl::JobControl(GPU &_gpu)
28 : GPUBlockInt(_gpu,
29 RegAddr(JOB_IRQ_RAWSTAT),
30 RegAddr(JOB_IRQ_CLEAR),
31 RegAddr(JOB_IRQ_MASK),
32 RegAddr(JOB_IRQ_STATUS))
33 {
34 slots.reserve(16);
35 for (int i = 0; i < 16; ++i)
36 slots.emplace_back(_gpu, *this, i);
37
38 }
39
40 JobControl::~JobControl()
41 {
42 }
43
44 void
45 JobControl::reset()
46 {
47 GPUBlockInt::reset();
48
49 for (auto &js : slots)
50 js.reset();
51 }
52
53 uint32_t
54 JobControl::readReg(RegAddr addr)
55 {
56 if (addr >= RegAddr(JOB_SLOT0)) {
57 return slots[getJobSlotNo(addr)].readReg(getJobSlotAddr(addr));
58 } else {
59 return GPUBlockInt::readReg(addr);
60 }
61 }
62
63 void
64 JobControl::writeReg(RegAddr addr, uint32_t value)
65 {
66 switch(addr.value) {
67 case JOB_IRQ_CLEAR:
68 // Update JS state for all jobs that were affected by the IRQ
69 // clear
70 updateJsState((value & 0xFFFF) | ((value & 0xFFFF0000) >> 16));
71
72 // FALLTHROUGH - IRQ handling in base class
73 case JOB_IRQ_RAWSTAT:
74 case JOB_IRQ_MASK:
75 case JOB_IRQ_STATUS:
76 GPUBlockInt::writeReg(addr, value);
77 break;
78
79 default:
80 if (addr >= RegAddr(JOB_SLOT0))
81 slots[getJobSlotNo(addr)].writeReg(getJobSlotAddr(addr), value);
82 break;
83 }
84 }
85
86 uint32_t
87 JobControl::readRegRaw(RegAddr addr)
88 {
89 if (addr >= RegAddr(JOB_SLOT0)) {
90 return slots[getJobSlotNo(addr)].readRegRaw(getJobSlotAddr(addr));
91 } else {
92 return GPUBlockInt::readRegRaw(addr);
93 }
94 }
95
96
97 void
98 JobControl::writeRegRaw(RegAddr addr, uint32_t value)
99 {
100 if (addr >= RegAddr(JOB_SLOT0)) {
101 slots[getJobSlotNo(addr)].writeRegRaw(getJobSlotAddr(addr), value);
102 } else {
103 GPUBlockInt::writeRegRaw(addr, value);
104 }
105 }
106
107 void
108 JobControl::jobDone(uint8_t slot)
109 {
110 assert(slot <= 15);
111 raiseInterrupt(1 << slot);
112 }
113
114 void
115 JobControl::jobFailed(uint8_t slot)
116 {
117 assert(slot <= 15);
118 raiseInterrupt(0x10000 << slot);
119 }
120
121 void
122 JobControl::updateJsState(uint16_t jobs)
123 {
124 // The JS_STATE register contains two bits per job slot; one bit
125 // representing an active job and one bit representing the queued
126 // job. We need to mask out bits of the jobs affected by this update.
127 const uint32_t job_mask(jobs | (jobs << 16));
128 uint16_t js_state(regs[RegAddr(JOB_IRQ_JS_STATE)] & ~job_mask);
129
130 // Find if there is an active or active next job for all jobs in
131 // the job mask.
132 for (int i = 0; i < 16; ++i) {
133 const JobSlot &slot(slots[i]);
134 if (jobs & (1 << i)) {
135 js_state |= slot.active() ? (1 << i) : 0 |
136 slot.activeNext() ? (0x10000 << i) : 0;
137 }
138 }
139 regs[RegAddr(JOB_IRQ_JS_STATE)] = js_state;
140 }
141
142 void
143 JobControl::onInterrupt(int set)
144 {
145 gpu.intJob(set);
146 }
147
148 }