Skip to content

Commit 0db0f87

Browse files
committed
initial implemementation
1 parent 4ad6368 commit 0db0f87

19 files changed

Lines changed: 2374 additions & 81 deletions

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,12 @@ set(STA_SOURCE
218218
spice/WriteSpice.cc
219219
spice/Xyce.cc
220220

221+
stadb/AnnoDb.cc
222+
stadb/NetDbReader.cc
223+
stadb/NetDbWriter.cc
224+
stadb/ParaDb.cc
225+
stadb/StaDb.cc
226+
221227
tcl/TclTypeHelpers.cc
222228

223229
util/Debug.cc
@@ -275,6 +281,7 @@ set(STA_TCL_FILES
275281
sdf/Sdf.tcl
276282
search/Search.tcl
277283
spice/WriteSpice.tcl
284+
stadb/StaDb.tcl
278285
verilog/Verilog.tcl
279286
)
280287

@@ -494,6 +501,7 @@ set(SWIG_FILES
494501
${STA_HOME}/search/Property.i
495502
${STA_HOME}/search/Search.i
496503
${STA_HOME}/spice/WriteSpice.i
504+
${STA_HOME}/stadb/StaDb.i
497505
${STA_HOME}/tcl/Exception.i
498506
${STA_HOME}/tcl/Collections.i
499507
${STA_HOME}/tcl/StaTclTypes.i

app/StaApp.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
%include "sdf/Sdf.i"
3838
%include "search/Search.i"
3939
%include "search/Property.i"
40+
%include "stadb/StaDb.i"
4041
%include "util/Util.i"
4142
%include "spice/WriteSpice.i"
4243
%include "verilog/Verilog.i"

include/sta/Sta.hh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,13 @@ public:
152152
Scene *scene,
153153
const MinMaxAll *min_max,
154154
bool infer_latches);
155-
// Compiled NLDM-only form of readLiberty
155+
// Compiled NLDM-only form of readLiberty (also used inside .stadb).
156156
virtual LibertyLibrary *readLibDb(std::string_view filename);
157157
void writeLibDb(LibertyLibrary *library,
158158
std::string_view filename);
159+
// Serialize / restore a full session (liberty, netlist, sdc, delays).
160+
void writeStaDb(std::string_view filename);
161+
void readStaDb(std::string_view filename);
159162
// tmp public
160163
void readLibertyAfter(LibertyLibrary *liberty,
161164
Scene *scene,

include/sta/StaDb.hh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// OpenSTA, Static Timing Analyzer
2+
// Copyright (c) 2026, Parallax Software, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
//
17+
// The origin of this software must not be misrepresented; you must not
18+
// claim that you wrote the original software.
19+
//
20+
// Altered source versions must be plainly marked as such, and must not be
21+
// misrepresented as being the original software.
22+
//
23+
// This notice may not be removed or altered from any source distribution.
24+
25+
#pragma once
26+
27+
#include <cstdint>
28+
#include <string>
29+
#include <string_view>
30+
31+
namespace sta {
32+
33+
class Sta;
34+
35+
// Serialized STA session database (.stadb).
36+
//
37+
// One file holds a snapshot of the loaded session, each part written as
38+
// objects and values rather than as the text it was originally read from:
39+
// liberty - NLDM libraries, LibDb encoding
40+
// network - the linked netlist: cells, instances, nets, pins, NetDb encoding
41+
// sdc - constraints
42+
// anno - every delay and slew in the timing graph, AnnoDb encoding
43+
//
44+
// writeStaDb serializes the live Sta state into that file.
45+
// readStaDb deserializes it back into a session that is ready to report on:
46+
// the network comes back linked and the delays come back annotated, so no
47+
// link_design, delay calculation or parasitics are needed to repeat a report.
48+
49+
constexpr uint32_t sta_db_version = 1;
50+
51+
void writeStaDb(Sta *sta,
52+
std::string_view filename);
53+
void readStaDb(Sta *sta,
54+
std::string_view filename);
55+
56+
} // namespace sta

liberty/LibDb.hh

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,11 @@ constexpr uint32_t lib_db_id_null = 0xFFFFFFFFu;
4747
enum class LibDbModelKind : uint8_t { none = 0, gate = 1, check = 2 };
4848
enum class LibDbPortKind : uint8_t { scalar = 0, bus = 1, bundle = 2 };
4949

50-
// Header for the libdb file.
50+
// Header for the libdb file. The rest of the file is one db block.
5151
struct LibDbHeader
5252
{
53-
uint32_t version; // version of the libdb format
54-
uint64_t string_bytes; // bytes of serialized strings
55-
uint64_t body_bytes; // bytes of serialized body
53+
uint32_t version; // version of the libdb format
54+
uint64_t block_bytes; // bytes of the packed string table + body
5655
};
5756

5857
// Builds the file body as a growing byte list. Also keeps a list of unique
@@ -195,6 +194,68 @@ private:
195194
bool failed_{false}; // true if we read past the end or bad string id
196195
};
197196

197+
////////////////////////////////////////////////////////////////
198+
// A "db block" is one self contained chunk of bytes:
199+
//
200+
// [u32 string_count][(u32 length, characters)*][body bytes]
201+
//
202+
// The string table comes first so the reader can rebuild it before walking the
203+
// body, which only holds indexes into it. Liberty, netlist and annotations all
204+
// use this shape, so a .stadb file can hold each of them as an opaque byte
205+
// range and hand it back unchanged at load time.
206+
207+
// Glue a writer's string list in front of its body.
208+
inline std::vector<uint8_t>
209+
dbPack(const DbWriter &writer)
210+
{
211+
DbWriter block;
212+
block.u32(static_cast<uint32_t>(writer.strings().size()));
213+
for (const std::string &s : writer.strings()) {
214+
block.u32(static_cast<uint32_t>(s.size()));
215+
for (char c : s)
216+
block.u8(static_cast<uint8_t>(c));
217+
}
218+
std::vector<uint8_t> bytes = block.bytes();
219+
bytes.insert(bytes.end(), writer.bytes().begin(), writer.bytes().end());
220+
return bytes;
221+
}
222+
223+
// Split a block back into its string list and body.
224+
// False means the block is truncated or the string table is corrupt.
225+
inline bool
226+
dbUnpack(const uint8_t *data,
227+
size_t size,
228+
// Return values.
229+
std::vector<std::string> &strings,
230+
std::vector<uint8_t> &body)
231+
{
232+
size_t pos = 0;
233+
auto next_u32 = [&](uint32_t &v) {
234+
if (pos + sizeof v > size)
235+
return false;
236+
std::memcpy(&v, data + pos, sizeof v);
237+
pos += sizeof v;
238+
return true;
239+
};
240+
241+
uint32_t count = 0;
242+
if (!next_u32(count))
243+
return false;
244+
strings.clear();
245+
strings.reserve(count);
246+
for (uint32_t i = 0; i < count; i++) {
247+
uint32_t length = 0;
248+
if (!next_u32(length) || pos + length > size)
249+
return false;
250+
strings.emplace_back(reinterpret_cast<const char *>(data + pos), length);
251+
pos += length;
252+
}
253+
body.assign(data + pos, data + size);
254+
return true;
255+
}
256+
257+
////////////////////////////////////////////////////////////////
258+
198259
// Compile an already loaded liberty library to filename.
199260
void writeLibDbFile(LibertyLibrary *library,
200261
std::string_view filename,
@@ -204,4 +265,12 @@ void writeLibDbFile(LibertyLibrary *library,
204265
LibertyLibrary *readLibDbFile(std::string_view filename,
205266
Network *network);
206267

268+
// Same encoding without the file wrapper, for .stadb liberty sections.
269+
std::vector<uint8_t> writeLibDbBytes(LibertyLibrary *library,
270+
Report *report);
271+
LibertyLibrary *readLibDbBytes(const uint8_t *data,
272+
size_t size,
273+
std::string_view label,
274+
Network *network);
275+
207276
} // namespace sta

liberty/LibDbReader.cc

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
// read_lib_db: rebuild one NLDM LibertyLibrary from a .libdb cache.
2626
//
27-
// File layout: [header][string_count][string table][body]
27+
// File layout: [header][db block: string table then body]
2828
// Body field order must match LibWriter in LibDbWriter.cc.
2929
// Shared axes/tables/attrs: first use reads id + full data; later uses reuse by id.
3030
// Strings: body stores an index; the string table holds the text once.
@@ -749,11 +749,29 @@ LibLoader::read()
749749
return lib_;
750750
}
751751

752+
LibertyLibrary *
753+
readLibDbBytes(const uint8_t *data,
754+
size_t size,
755+
std::string_view label,
756+
Network *network)
757+
{
758+
// Split the block into the string list and body, then rebuild the library.
759+
Report *report = network->report();
760+
std::vector<std::string> strings;
761+
std::vector<uint8_t> body;
762+
if (!dbUnpack(data, size, strings, body))
763+
report->error(1356, "{} has a corrupt string table.", label);
764+
765+
DbReader reader(body.data(), body.size(), &strings);
766+
LibLoader loader(reader, label, network);
767+
return loader.read();
768+
}
769+
752770
LibertyLibrary *
753771
readLibDbFile(std::string_view filename,
754772
Network *network)
755773
{
756-
// Validate .libdb + version, load string table, then LibLoader::read().
774+
// Validate .libdb + version, then hand the block to readLibDbBytes().
757775
Report *report = network->report();
758776
std::string path(filename);
759777

@@ -764,7 +782,7 @@ readLibDbFile(std::string_view filename,
764782
if (f == nullptr)
765783
report->error(1366, "cannot open {}.", path);
766784

767-
// File layout: [header][string_count][string bytes][body bytes]
785+
// File layout: [header][block]
768786
LibDbHeader hdr{};
769787
if (fread(&hdr, sizeof hdr, 1, f) != 1) {
770788
fclose(f);
@@ -776,39 +794,15 @@ readLibDbFile(std::string_view filename,
776794
path, hdr.version, lib_db_version);
777795
}
778796

779-
uint32_t string_count = 0;
780-
bool ok = fread(&string_count, sizeof string_count, 1, f) == 1;
781-
std::vector<uint8_t> string_bytes(hdr.string_bytes);
782-
if (ok && hdr.string_bytes)
783-
ok = fread(string_bytes.data(), hdr.string_bytes, 1, f) == 1;
784-
std::vector<uint8_t> body(hdr.body_bytes);
785-
if (ok && hdr.body_bytes)
786-
ok = fread(body.data(), hdr.body_bytes, 1, f) == 1;
797+
std::vector<uint8_t> block(hdr.block_bytes);
798+
bool ok = true;
799+
if (hdr.block_bytes)
800+
ok = fread(block.data(), hdr.block_bytes, 1, f) == 1;
787801
fclose(f);
788802
if (!ok)
789803
report->error(1363, "{} is truncated.", path);
790804

791-
// Unpack (length, characters)* into the string list DbReader::str() uses.
792-
std::vector<std::string> strings;
793-
strings.reserve(string_count);
794-
size_t pos = 0;
795-
for (uint32_t i = 0; i < string_count; i++) {
796-
uint32_t len = 0;
797-
bool len_ok = pos + sizeof len <= string_bytes.size();
798-
if (len_ok) {
799-
std::memcpy(&len, string_bytes.data() + pos, sizeof len);
800-
pos += sizeof len;
801-
}
802-
if (!len_ok || pos + len > string_bytes.size())
803-
report->error(1356, "{} has a corrupt string table.", path);
804-
strings.emplace_back(reinterpret_cast<const char *>(string_bytes.data() + pos), len);
805-
pos += len;
806-
}
807-
808-
// Hand body + string list to the loader; it rebuilds the library object.
809-
DbReader reader(body.data(), body.size(), &strings);
810-
LibLoader loader(reader, filename, network);
811-
return loader.read();
805+
return readLibDbBytes(block.data(), block.size(), filename, network);
812806
}
813807

814808
} // namespace sta

0 commit comments

Comments
 (0)