Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: SS_AsiSpace.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | ||
22 | #include "SS_AsiSpace.h" | |
23 | #include "SS_Strand.h" | |
24 | #include "SS_AsiCtrReg.h" | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <new> | |
28 | ||
29 | SS_AsiSpace::SS_AsiSpace()/*{{{*/ | |
30 | : | |
31 | mask(~SS_Vaddr(0)), | |
32 | fail(0,mask,0,0,no_rd,no_wr,no_rd,no_wr), | |
33 | table(0), | |
34 | table_copy(false), | |
35 | block(0), | |
36 | free_range_index(ALLOC), | |
37 | alloc(0), | |
38 | size(0), | |
39 | asi(0) | |
40 | {} | |
41 | /*}}}*/ | |
42 | SS_AsiSpace::~SS_AsiSpace()/*{{{*/ | |
43 | { | |
44 | if (table) free(table); | |
45 | while (block) | |
46 | { | |
47 | Block* p = block; | |
48 | block = p->next; | |
49 | delete p; | |
50 | } | |
51 | } | |
52 | /*}}}*/ | |
53 | SS_AsiSpace::Error SS_AsiSpace::no_rd( SS_Node*, void*, SS_Strand*, SS_Vaddr, uint64_t* )/*{{{*/ | |
54 | { | |
55 | return SS_AsiSpace::NO_READ; | |
56 | } | |
57 | /*}}}*/ | |
58 | SS_AsiSpace::Error SS_AsiSpace::no_wr( SS_Node*, void*, SS_Strand*, SS_Vaddr, uint64_t )/*{{{*/ | |
59 | { | |
60 | return SS_AsiSpace::NO_WRITE; | |
61 | } | |
62 | /*}}}*/ | |
63 | SS_AsiSpace::Error SS_AsiSpace::ld64( SS_Strand* s, SS_Vaddr addr, uint64_t* data )/*{{{*/ | |
64 | { | |
65 | addr &= mask; | |
66 | Range* r = find(addr); | |
67 | return (r->ld)(r->obj,r->reg,s,addr,data); | |
68 | } | |
69 | /*}}}*/ | |
70 | SS_AsiSpace::Error SS_AsiSpace::st64( SS_Strand* s, SS_Vaddr addr, uint64_t data )/*{{{*/ | |
71 | { | |
72 | addr &= mask; | |
73 | Range* r = find(addr); | |
74 | return (r->st)(r->obj,r->reg,s,addr,data); | |
75 | } | |
76 | /*}}}*/ | |
77 | SS_AsiSpace::Error SS_AsiSpace::rd64( SS_Strand* s, SS_Vaddr addr, uint64_t* data )/*{{{*/ | |
78 | { | |
79 | addr &= mask; | |
80 | Range* r = find(addr); | |
81 | return (r->rd)(r->obj,r->reg,s,addr,data); | |
82 | } | |
83 | /*}}}*/ | |
84 | SS_AsiSpace::Error SS_AsiSpace::wr64( SS_Strand* s, SS_Vaddr addr, uint64_t data )/*{{{*/ | |
85 | { | |
86 | addr &= mask; | |
87 | Range* r = find(addr); | |
88 | return (r->wr)(r->obj,r->reg,s,addr,data); | |
89 | } | |
90 | /*}}}*/ | |
91 | void SS_AsiSpace::merge( SS_AsiSpace& asi_space )/*{{{*/ | |
92 | { | |
93 | if (asi_space.size) | |
94 | { | |
95 | // If there is ranges defined in this space then we need to | |
96 | // do some merging. If this is the first merge then we assume | |
97 | // that the ranges associated with this ASI are defined at one | |
98 | // level (SS_Node) only. If so then we can do a cheap copy. | |
99 | // Else we need to do a quick copy and poper insert the rest | |
100 | ||
101 | mask &= asi_space.mask; | |
102 | ||
103 | if (size == 0) // do cheap copy first | |
104 | { | |
105 | alloc = asi_space.alloc; | |
106 | size = asi_space.size; | |
107 | table = asi_space.table; | |
108 | table_copy = true; | |
109 | } | |
110 | else | |
111 | { | |
112 | if (table_copy) // real copy first, then insert proper | |
113 | { | |
114 | Range** old_table = table; | |
115 | table = (Range**)malloc(sizeof(Range*) * alloc); | |
116 | for (uint_t i=0; i < size; i++) | |
117 | table[i] = old_table[i]; | |
118 | table_copy = false; | |
119 | } | |
120 | for (uint_t i=0; i < asi_space.size; i++) | |
121 | add(asi_space.table[i]); | |
122 | } | |
123 | } | |
124 | } | |
125 | /*}}}*/ | |
126 | void SS_AsiSpace::add( SS_Vaddr va, SS_Node* obj, SS_AsiCtrReg& reg )/*{{{*/ | |
127 | { | |
128 | add(va,va,obj,®,SS_AsiCtrReg::ld64,SS_AsiCtrReg::st64,SS_AsiCtrReg::rd64,SS_AsiCtrReg::wr64); | |
129 | } | |
130 | /*}}}*/ | |
131 | void SS_AsiSpace::add( SS_Vaddr va, SS_Node* obj, SS_SharedAsiCtrReg& reg )/*{{{*/ | |
132 | { | |
133 | add(va,va,obj,®,SS_SharedAsiCtrReg::ld64,SS_SharedAsiCtrReg::st64, | |
134 | SS_SharedAsiCtrReg::rd64,SS_SharedAsiCtrReg::wr64); | |
135 | } | |
136 | /*}}}*/ | |
137 | void SS_AsiSpace::add( SS_Vaddr va, SS_Node* obj, void* reg, Read ld, Write st, Read rd, Write wr )/*{{{*/ | |
138 | { | |
139 | add(va,va,obj,reg,ld,st,rd,wr); | |
140 | } | |
141 | /*}}}*/ | |
142 | void SS_AsiSpace::add( SS_Vaddr lo, SS_Vaddr hi, SS_Node* obj, void* reg, Read ld, Write st, Read rd, Write wr )/*{{{*/ | |
143 | { | |
144 | if (ld == 0) ld = no_rd; | |
145 | if (st == 0) st = no_wr; | |
146 | if (rd == 0) rd = no_rd; | |
147 | if (wr == 0) wr = no_wr; | |
148 | ||
149 | if (size == alloc) | |
150 | { | |
151 | alloc += ALLOC; | |
152 | table = (Range**)realloc(table,sizeof(Range*) * alloc); | |
153 | } | |
154 | ||
155 | if (free_range_index == ALLOC) | |
156 | { | |
157 | // Allocate a new block of Range object. Avoid the C++ constructor | |
158 | // call as each range will be initialised below anyways. | |
159 | ||
160 | free_range_index = 0; | |
161 | Block* new_block = (Block*)malloc(sizeof(Block)); | |
162 | new_block->next = block; | |
163 | block = new_block; | |
164 | } | |
165 | ||
166 | Range* new_range = &block->page[free_range_index++]; | |
167 | new(new_range) Range(lo,hi,obj,reg,ld,st,rd,wr); | |
168 | ||
169 | add(new_range); | |
170 | } | |
171 | /*}}}*/ | |
172 | void SS_AsiSpace::add( Range* new_range )/*{{{*/ | |
173 | { | |
174 | if (size == alloc) | |
175 | { | |
176 | alloc += ALLOC; | |
177 | table = (Range**)realloc(table,sizeof(Range*) * alloc); | |
178 | } | |
179 | ||
180 | SS_Vaddr hi = new_range->hi; | |
181 | SS_Vaddr lo = new_range->lo; | |
182 | ||
183 | // Check if we can just append the new range first. | |
184 | // This will save a lot of time binary searching and | |
185 | // moving part of the table around. | |
186 | ||
187 | if ((size == 0) || (table[size - 1]->hi < new_range->lo)) | |
188 | { | |
189 | table[size] = new_range; | |
190 | } | |
191 | else | |
192 | { | |
193 | uint_t l = 0; | |
194 | uint_t h = size; | |
195 | uint_t m = size >> 1; | |
196 | Range* r = table[m]; | |
197 | ||
198 | while (l != m) | |
199 | { | |
200 | ((hi < r->lo) ? h : l) = m; | |
201 | m = l + ((h - l) >> 1); | |
202 | r = table[m]; | |
203 | } | |
204 | if (hi < r->lo) | |
205 | { | |
206 | for (uint_t i=size; i > m; i--) | |
207 | table[i] = table[i-1]; | |
208 | table[m] = new_range; | |
209 | } | |
210 | else if (r->hi < lo) | |
211 | { | |
212 | for (uint_t i=size; i > (m + 1); i--) | |
213 | table[i] = table[i-1]; | |
214 | table[m+1] = new_range; | |
215 | } | |
216 | else | |
217 | { | |
218 | fprintf(stderr,"SS_AsiSpace: asi 0x%x add with lo=0x%llx and hi=0x%llx overlaps with lo=0x%llx and hi=0x%llx\n",asi(),lo,hi,r->lo,r->hi); | |
219 | exit(-1); | |
220 | } | |
221 | } | |
222 | ||
223 | ++size; | |
224 | } | |
225 | /*}}}*/ |