1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2020 gatecat <gatecat@ds0.me>
*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "log.h"
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
bool Arch::nexus_logic_tile_valid(LogicTileStatus <s) const
{
for (int s = 0; s < 4; s++) {
if (lts.slices[s].dirty) {
lts.slices[s].valid = false;
lts.slices[s].dirty = false;
CellInfo *lut0 = lts.cells[(s << 3) | BEL_LUT0];
CellInfo *lut1 = lts.cells[(s << 3) | BEL_LUT1];
CellInfo *ff0 = lts.cells[(s << 3) | BEL_FF0];
CellInfo *ff1 = lts.cells[(s << 3) | BEL_FF1];
if (s == 2) {
CellInfo *ramw = lts.cells[(s << 3) | BEL_RAMW];
// Nothing else in SLICEC can be used if the RAMW is used
if (ramw != nullptr) {
if (lut0 != nullptr || lut1 != nullptr || ff0 != nullptr || ff1 != nullptr)
return false;
}
}
if (lut0 != nullptr) {
// Check for overuse of M signal
if (lut0->lutInfo.mux2_used && ff0 != nullptr && ff0->ffInfo.m != nullptr)
return false;
}
// Check for correct use of FF0 DI
if (ff0 != nullptr && ff0->ffInfo.di != nullptr &&
(lut0 == nullptr || (ff0->ffInfo.di != lut0->lutInfo.f && ff0->ffInfo.di != lut0->lutInfo.ofx)))
return false;
if (lut1 != nullptr) {
// LUT1 cannot contain a MUX2
if (lut1->lutInfo.mux2_used)
return false;
// If LUT1 is carry then LUT0 must be carry too
if (lut1->lutInfo.is_carry && (lut0 == nullptr || !lut0->lutInfo.is_carry))
return false;
if (!lut1->lutInfo.is_carry && lut0 != nullptr && lut0->lutInfo.is_carry)
return false;
}
// Check for correct use of FF1 DI
if (ff1 != nullptr && ff1->ffInfo.di != nullptr && (lut1 == nullptr || ff1->ffInfo.di != lut1->lutInfo.f))
return false;
lts.slices[s].valid = true;
} else if (!lts.slices[s].valid) {
return false;
}
}
for (int h = 0; h < 2; h++) {
if (lts.halfs[h].dirty) {
bool found_ff = false;
FFControlSet ctrlset;
for (int i = 0; i < 2; i++) {
for (auto bel : {BEL_FF0, BEL_FF1, BEL_RAMW}) {
if (bel == BEL_RAMW && (h != 1 || i != 0))
continue;
CellInfo *ci = lts.cells[(h * 2 + i) << 3 | bel];
if (ci == nullptr)
continue;
if (!found_ff) {
ctrlset = ci->ffInfo.ctrlset;
found_ff = true;
} else if (ci->ffInfo.ctrlset != ctrlset) {
return false;
}
}
}
} else if (!lts.halfs[h].valid) {
return false;
}
}
return true;
}
bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const
{
if (bel_tile_is(bel, LOC_LOGIC)) {
LogicTileStatus *lts = tileStatus[bel.tile].lts;
if (lts == nullptr)
return true;
else
return nexus_logic_tile_valid(*lts);
} else {
return true;
}
}
NEXTPNR_NAMESPACE_END
|