getreadystack commited on
Commit
a80fc32
·
verified ·
1 Parent(s): 4b09dff

Upload index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +217 -17
index.html CHANGED
@@ -1,19 +1,219 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>Vivado xsim Migration — check your vhdl for free</title>
7
+ <meta name="description" content="This free browser tool flags VHDL lines that Vivado xsim accepts but GHDL rejects or requires flags for.">
8
+ <style>
9
+ :root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
10
+ .wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
11
+ textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
12
+ .bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
13
+ input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
14
+ table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
15
+ .sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
16
+ .note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
17
+ </style>
18
+ <script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
19
+ <!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/ghdl-migration-check"><style data-yj-mfit="1">#out{max-width:100%}#out td,#out th{overflow-wrap:anywhere}#out pre,#out code{white-space:pre-wrap;overflow-wrap:anywhere}@media (max-width:640px){table{display:block;max-width:100%;overflow-x:auto}pre{max-width:100%;overflow-x:auto}code,a{overflow-wrap:anywhere}img,svg,video,canvas,iframe{max-width:100%}textarea,input,select{max-width:100%;box-sizing:border-box}.yj-lgbar{position:static!important;justify-content:flex-end;margin:0 0 10px}#out table:not(:has(tr>:nth-child(4))){display:table;table-layout:fixed;width:100%}#out table:has(tr>:nth-child(4)),#out table:has(tr>:nth-child(4)) tbody,#out table:has(tr>:nth-child(4)) tr,#out table:has(tr>:nth-child(4)) td{display:block;width:auto;overflow:visible}#out table:has(tr>:nth-child(4)) thead{display:none}#out table:has(tr>:nth-child(4)) tr{padding:10px 0;border-bottom:1px solid rgba(128,128,128,.28)}#out table:has(tr>:nth-child(4)) td{border:0;padding:1px 0}#out table:has(tr>:nth-child(4)) td:nth-child(-n+3){display:inline-block;margin-right:10px;font-size:12px;opacity:.78}}</style>
20
+ </head>
21
+ <body>
22
+ <div class="wrap">
23
+ <h1>Vivado xsim Migration — check your vhdl for free</h1>
24
+ <p class="lede">GHDL migration check: flags VHDL lines that Vivado xsim accepts but GHDL rejects or needs flags for — UNISIM, XPM, std_logic_unsigned, VHDL-2008 without --std=08, plain shared variables, encrypted IP. Runs entirely in your browser — nothing is uploaded.</p>
25
+ <textarea id="src" spellcheck="false">-- tb_uart_rx.vhd : testbench that ran in Vivado xsim
26
+ library ieee;
27
+ use ieee.std_logic_1164.all;
28
+ use ieee.std_logic_unsigned.all;
29
+ library unisim;
30
+ use unisim.vcomponents.all;
31
+ library xpm;
32
+ use xpm.vcomponents.all;
33
+
34
+ entity tb_uart_rx is
35
+ end entity;
36
+
37
+ architecture sim of tb_uart_rx is
38
+ signal clk : std_logic := '0';
39
+ signal rx : std_logic := '1';
40
+ signal count : std_logic_vector(7 downto 0) := (others =&gt; '0');
41
+ shared variable errors : integer := 0;
42
+ begin
43
+ clk &lt;= not clk after 5 ns;
44
+
45
+ counter : process(all)
46
+ begin
47
+ if rising_edge(clk) then
48
+ count &lt;= count + 1;
49
+ end if;
50
+ end process;
51
+
52
+ stim : process
53
+ begin
54
+ wait for 10 us;
55
+ assert errors = 0 report "RX errors seen" severity error;
56
+ std.env.stop;
57
+ end process;
58
+ end architecture;</textarea>
59
+ <div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
60
+ <div id="out" aria-live="polite"></div>
61
+ <div id="paid"><strong>Free here:</strong> Check the open .vhd testbench or source for Vivado-only lines, with the GHDL fix and flag on each line. <strong>In the editor:</strong> Scan every .vhd file in the workspace in one pass and export a Markdown GHDL migration report with the ghdl -a flag set per library — that part asks for a licence key.</div>
62
+ <p class="buy"><a href="https://getreadystack.com/api/buy/cl/polar_cl_xKrdYeTAeNRUpn4SK67wtaLXOUBVYfW8S0l0f1emErz" data-polar-checkout data-polar-checkout-theme="light">Get the full version — $29</a> · $29 once · one licence key per person or team seat. Mouser lists a Vivado ML Enterprise node-locked seat at $5,063.25; GHDL is free.</p>
63
+ <script defer data-auto-init src="https://cdn.jsdelivr.net/npm/@polar-sh/checkout@latest/dist/embed.global.js"></script>
64
+ <p class="note">Same engine as the VS Code extension, byte for byte.</p>
65
+ </div>
66
+ <script>var GH_RULES = [
67
+ {"id": "GH01", "check": "unisim-library", "sev": "error", "kind": "regex", "needs": "",
68
+ "re": "^\\s*library\\s+(?:\\w+\\s*,\\s*)*unisim\\b", "flags": "i",
69
+ "msg": "library unisim: Xilinx primitives ship with Vivado, not with GHDL. Compile them once with GHDL's vendor script compile-xilinx-vivado.sh (libraries/vendors) against your Vivado install and pass -P\u003cdir\u003e, or replace the primitive with generic RTL.",
70
+ "source": "https://ghdl.github.io/ghdl/getting/PrecompVendorPrimitives.html"},
71
+ {"id": "GH02", "check": "xpm-macro-library", "sev": "error", "kind": "regex", "needs": "",
72
+ "re": "^\\s*library\\s+(?:\\w+\\s*,\\s*)*xpm\\b", "flags": "i",
73
+ "msg": "library xpm: Xilinx Parameterized Macros are SystemVerilog source; the VHDL package only declares components. GHDL simulates VHDL only, so an XPM instance has no model. Replace it with an inferred VHDL FIFO/RAM or a behavioural model for simulation.",
74
+ "source": "https://docs.amd.com/r/en-US/ug953-vivado-7series-libraries/XPM_FIFO_ASYNC"},
75
+ {"id": "GH03", "check": "unimacro-library", "sev": "error", "kind": "regex", "needs": "",
76
+ "re": "^\\s*library\\s+(?:\\w+\\s*,\\s*)*unimacro\\b", "flags": "i",
77
+ "msg": "library unimacro: another Vivado-only library. Compile it with compile-xilinx-vivado.sh like UNISIM, or replace the macro with generic RTL.",
78
+ "source": "https://ghdl.github.io/ghdl/getting/PrecompVendorPrimitives.html"},
79
+ {"id": "GH04", "check": "secureip-library", "sev": "error", "kind": "regex", "needs": "",
80
+ "re": "^\\s*library\\s+(?:\\w+\\s*,\\s*)*secureip\\b", "flags": "i",
81
+ "msg": "library secureip: encrypted hard-IP models that only Vivado's simulator can decrypt. GHDL cannot load them; stub the block with a behavioural model in the testbench.",
82
+ "source": "https://ghdl.github.io/ghdl/getting/PrecompVendorPrimitives.html"},
83
+ {"id": "GH05", "check": "synopsys-packages", "sev": "warn", "kind": "regex", "needs": "synopsys",
84
+ "re": "^\\s*use\\s+ieee\\.std_logic_(?:arith|unsigned|signed)\\b", "flags": "i",
85
+ "msg": "std_logic_arith / std_logic_unsigned / std_logic_signed are Synopsys packages, not IEEE. GHDL analyses them only with -fsynopsys. Better fix: use ieee.numeric_std.all and unsigned()/signed() casts.",
86
+ "source": "https://ghdl.github.io/ghdl/using/InvokingGHDL.html"},
87
+ {"id": "GH06", "check": "vhdl2008-process-all", "sev": "warn", "kind": "regex", "needs": "std08",
88
+ "re": "\\bprocess\\s*\\(\\s*all\\s*\\)", "flags": "i",
89
+ "msg": "process(all) is VHDL-2008. GHDL's default standard is 93c, so analysis fails unless every ghdl -a / -e / -r call gets --std=08.",
90
+ "source": "https://ghdl.github.io/ghdl/using/InvokingGHDL.html"},
91
+ {"id": "GH07", "check": "vhdl2008-matching-op", "sev": "warn", "kind": "regex", "needs": "std08",
92
+ "re": "\\?(?:/=|\u003c=|\u003e=|=|\u003c|\u003e)", "flags": "",
93
+ "msg": "Matching operators (?=, ?/=, ?\u003c, ...) are VHDL-2008. Pass --std=08 to GHDL.",
94
+ "source": "https://ghdl.github.io/ghdl/using/InvokingGHDL.html"},
95
+ {"id": "GH08", "check": "vhdl2008-std-env", "sev": "warn", "kind": "regex", "needs": "std08",
96
+ "re": "\\bstd\\.env\\b", "flags": "i",
97
+ "msg": "std.env (stop/finish) is VHDL-2008. Pass --std=08 to GHDL, or end a VHDL-93 testbench with an assert ... severity failure.",
98
+ "source": "https://ghdl.github.io/ghdl/using/InvokingGHDL.html"},
99
+ {"id": "GH09", "check": "vhdl2008-context", "sev": "warn", "kind": "regex", "needs": "std08",
100
+ "re": "^\\s*context\\s+\\w+\\.\\w+\\s*;", "flags": "i",
101
+ "msg": "Context references are VHDL-2008. Pass --std=08 to GHDL (VUnit and OSVVM contexts need it too).",
102
+ "source": "https://ghdl.github.io/ghdl/using/InvokingGHDL.html"},
103
+ {"id": "GH10", "check": "vhdl2008-to-string", "sev": "warn", "kind": "regex", "needs": "std08",
104
+ "re": "\\bto_(?:h|o)?string\\s*\\(", "flags": "i",
105
+ "msg": "to_string / to_hstring / to_ostring are VHDL-2008 functions. Pass --std=08 to GHDL.",
106
+ "source": "https://ghdl.github.io/ghdl/using/InvokingGHDL.html"},
107
+ {"id": "GH11", "check": "shared-variable-not-protected", "sev": "error", "kind": "shared", "needs": "relaxed",
108
+ "re": "^\\s*shared\\s+variable\\s+\\w+(?:\\s*,\\s*\\w+)*\\s*:\\s*(?:integer|natural|positive|boolean|bit|bit_vector|std_logic|std_ulogic|std_logic_vector|std_ulogic_vector|unsigned|signed|real|time|string|line)\\b", "flags": "i",
109
+ "msg": "A shared variable of a plain type is legal in VHDL-93 only. This file needs --std=08, and there GHDL stops with an error: the type must be protected. Wrap it in a protected type, or pass -frelaxed to downgrade it to a warning.",
110
+ "source": "https://ghdl.github.io/ghdl/using/InvokingGHDL.html"},
111
+ {"id": "GH12", "check": "encrypted-ip-envelope", "sev": "error", "kind": "regex", "needs": "",
112
+ "re": "`protect\\s+begin_protected", "flags": "i",
113
+ "msg": "IEEE 1735 protected envelope: this block is encrypted for vendor simulators. GHDL cannot decrypt it; ask the IP vendor for a plain behavioural model or stub the block.",
114
+ "source": "https://ghdl.github.io/ghdl/getting/PrecompVendorPrimitives.html"}
115
+ ]
116
+ ;</script>
117
+ <script>// GHDL Migration Check engine: finds VHDL lines that Vivado xsim accepts but GHDL rejects or needs a flag for.
118
+ // Same file runs in Node (VS Code extension, verify) and in the browser (free web page).
119
+ (function (root) {
120
+ const RULES = (typeof module !== 'undefined') ? require('./rules.json') : root.GH_RULES;
121
+
122
+ // Flags already set for this file, read from comments such as "-- ghdl -a --std=08 -fsynopsys".
123
+ function flagsIn(lines) {
124
+ const c = lines.filter(l => /--/.test(l)).map(l => l.slice(l.indexOf('--'))).join(' ');
125
+ return {
126
+ std08: /--std=(?:08|2008)\b/i.test(c),
127
+ synopsys: /-fsynopsys\b|--ieee=synopsys\b/i.test(c),
128
+ relaxed: /-frelaxed\b/i.test(c)
129
+ };
130
+ }
131
+
132
+ function check(text, opts) {
133
+ const lines = String(text || '').split(/\r?\n/);
134
+ const flags = flagsIn(lines);
135
+ const compiled = RULES.map(r => Object.assign({ rx: new RegExp(r.re, r.flags || '') }, r));
136
+ const code = lines.map(l => { const k = l.indexOf('--'); return k >= 0 ? l.slice(0, k) : l; });
137
+ const raw = [];
138
+ code.forEach((line, i) => {
139
+ if (!line.trim()) return;
140
+ for (const r of compiled) {
141
+ if (r.needs && flags[r.needs]) continue;
142
+ if (r.rx.test(line)) raw.push({ r, line: i + 1, text: lines[i].trim() });
143
+ }
144
+ });
145
+ // A plain shared variable only breaks once the file needs --std=08.
146
+ const needs08 = flags.std08 || raw.some(h => h.r.needs === 'std08');
147
+ const findings = raw
148
+ .filter(h => h.r.kind !== 'shared' || needs08)
149
+ .map(h => ({ check: h.r.check, id: h.r.id, sev: h.r.sev, msg: h.r.msg, line: h.line, text: h.text }));
150
+ const ghdlFlags = [needs08 ? '--std=08' : '', findings.some(f => f.id === 'GH05') || flags.synopsys ? '-fsynopsys' : ''].filter(Boolean).join(' ');
151
+ return { findings, errors: findings.filter(f => f.sev === 'error').length, warnings: findings.filter(f => f.sev === 'warn').length,
152
+ ghdl_cmd: ('ghdl -a ' + ghdlFlags).trim(), as_of: (opts && opts.today) || '' };
153
+ }
154
+
155
+ const api = { engine: { check }, RULES, RULE_COUNT: RULES.length };
156
+ if (typeof module !== 'undefined') module.exports = api;
157
+ root.GHENGINE = api;
158
+ })(typeof window !== 'undefined' ? window : globalThis);
159
+ </script>
160
+ <script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
161
+ 'use strict';
162
+ function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
163
+ function summaryLine(res) {
164
+ const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
165
+ return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
166
+ }
167
+ function toText(res, label) {
168
+ const f = (res && res.findings) || [];
169
+ const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
170
+ f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
171
+ return lines.join('\n');
172
+ }
173
+ function toHtml(res) {
174
+ const f = (res && res.findings) || [];
175
+ if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
176
+ const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
177
+ return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
178
+ }
179
+ var GHREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
180
+ if (typeof module !== 'undefined' && module.exports) module.exports = GHREPORT;
181
+ else window.GHREPORT = GHREPORT;
182
+ </script>
183
+ <script>
184
+ (function(){
185
+ var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
186
+ today.value=new Date().toISOString().slice(0,10);
187
+ function run(){ try { var res=window.GHENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.GHREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
188
+ go.onclick=run; if (src.value.trim()) run();
189
+ })();
190
+ </script>
191
+
192
+
193
+ <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/ghdl-migration-check" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'ghdl-migration-check',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/team" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
194
+ <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind GHDL Migration Check — Vivado xsim to GHDL every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"ghdl-migration-check",lang:"en",source:"rule_alert"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);document.addEventListener("click",function(ev){var b=ev.target&&ev.target.closest?ev.target.closest("button,input[type=submit]"):null;if(b&&!b.closest("[data-yj],[data-yj-cta],[data-yj-install],[data-yj-alert],.yj-find,.yj-related,#yj-ask,.yjp"))mv(ev);},true);})();</script></section>
195
+
196
+ <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the full version <span class="yj-price">$29</span></h2><p class="yj-cta-paid" style="margin:.25rem 0 .6rem;color:#1f2a37">Scan every .vhd file in the workspace in one pass and export a Markdown GHDL migration report with the ghdl -a flag set per library</p><p class="yj-cta-pay" style="margin:.25rem 0 1rem;color:#5b6b7c;font-size:.94rem">One payment, one licence key for this tool. The key is shown right after payment.</p><p class="yj-cta-anchor" style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">Mouser lists a Vivado ML Enterprise node-locked seat (EF-VIVADO-ENTER-NL) at $5,063.25, checked 2026-09-29; GHDL itself is free under GPL-2.0.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_xKrdYeTAeNRUpn4SK67wtaLXOUBVYfW8S0l0f1emErz" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
197
+ <!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
198
+ <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
199
+
200
+ <script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-29">Updated 2026-09-29</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-29","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku410505_result_card.jpg" alt="GHDL Migration Check — Vivado xsim to GHDL" loading="lazy" style="max-width:100%;border-radius:6px"></p>
201
+ <p>Migrate from Vivado xsim to GHDL: six lines in a 34-line testbench stop the first ghdl -a run</p>
202
+ <p>FPGA verification engineers moving VHDL testbenches from AMD Vivado&#x27;s xsim to GHDL: one 34-line UART testbench that ran clean in xsim produced 6 findings in GHDL Migration Check — 3 errors and 3 warnings — before GHDL ever saw it.</p>
203
+ <h3>Why teams move the testbench, not the synthesis</h3>
204
+ <p>Vivado ML Standard and its simulator are free, but larger devices need Vivado ML Enterprise, and Mouser lists a node-locked Enterprise seat (EF-VIVADO-ENTER-NL) at $5,063.25 (checked 2026-09-29). GHDL is free under GPL-2.0 and installs in seconds on a CI runner. So a common split is one Vivado seat for synthesis and GHDL for every testbench run.</p>
205
+ <p>The catch: xsim and GHDL do not accept the same VHDL by default.</p>
206
+ <h3>The six lines</h3>
207
+ <p>The sample file is tb_uart_rx.vhd. Here is what the check reported, with the fix for each line:</p>
208
+ <table><thead><tr><th>Vivado xsim line</th><th>GHDL fix</th></tr></thead><tbody><tr><td>library unisim;</td><td>compile UNISIM with compile-xilinx-vivado.sh</td></tr><tr><td>library xpm;</td><td>inferred VHDL FIFO, no XPM</td></tr><tr><td>shared variable errors : integer</td><td>protected type, or -frelaxed</td></tr><tr><td>use ieee.std_logic_unsigned.all;</td><td>use ieee.numeric_std.all;</td></tr><tr><td>process(all)</td><td>ghdl -a --std=08</td></tr><tr><td>std.env.stop;</td><td>--std=08</td></tr></tbody></table>
209
+ <p>Three of them are errors, because a flag alone will not fix them:</p>
210
+ <ul><li><strong>library unisim</strong> — Xilinx primitives ship with Vivado. GHDL has a vendor script, compile-xilinx-vivado.sh, that compiles them from your Vivado install; after that you pass -P with the output directory.</li><li><strong>library xpm</strong> — XPM macros are SystemVerilog. The VHDL package only declares the components. GHDL simulates VHDL, so an XPM FIFO has no model; swap in an inferred FIFO or a behavioural model for simulation.</li><li><strong>shared variable errors : integer</strong> — legal in VHDL-93. But this file uses process(all) and std.env, so it needs --std=08, and under 2008 GHDL stops: a shared variable must be of a protected type. Wrap it, or pass -frelaxed to turn the error into a warning.</li></ul>
211
+ <p>The other three are warnings: they need a flag. GHDL&#x27;s default standard is 93c, so process(all) and std.env.stop fail until every ghdl -a, -e and -r call gets --std=08. std_logic_unsigned is a Synopsys package; GHDL takes it with -fsynopsys, and the cleaner fix is numeric_std.</p>
212
+ <h3>Why not just run GHDL</h3>
213
+ <p>GHDL stops at the first analysis error in a file. You fix library unisim, run again, meet process(all), run again, meet the shared variable. A chatbot will suggest flags from memory but cannot see your file. The check lists every line in one pass and prints the command the file needs — here ghdl -a --std=08 -fsynopsys.</p>
214
+ <h3>What it covers</h3>
215
+ <p>12 rules: UNISIM, UNIMACRO, SECUREIP and XPM libraries; Synopsys std_logic_arith, std_logic_unsigned and std_logic_signed; five VHDL-2008 features (process(all), matching operators such as ?=, std.env, context references, to_string and to_hstring); plain shared variables in files that need 2008; and IEEE 1735 protected envelopes that GHDL cannot decrypt.</p>
216
+ <p>If the file already records its flags in a comment, such as -- ghdl -a --std=08 -fsynopsys, the rules those flags cover stay quiet, so the list shrinks to what is really left.</p>
217
+ <h3>Try it on your file</h3>
218
+ <p>Open a .vhd file in VS Code and run GHDL Migration Check: Check this file, or paste it into the free web page. The file check is free and complete. A licence key adds a scan of every .vhd file in the workspace and a Markdown migration report per library.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku410505_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku410505_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does GHDL Migration Check do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads a VHDL testbench or source file and flags every line that Vivado xsim accepts but GHDL rejects or needs a flag for: UNISIM, UNIMACRO, SECUREIP and XPM libraries, Synopsys std_logic_unsigned, VHDL-2008 features without --std=08, plain shared variables and IEEE 1735 encrypted blocks. Each finding carries the GHDL fix and the ghdl -a flags the file needs.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is GHDL Migration Check for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">FPGA and ASIC verification engineers who wrote VHDL testbenches in AMD Vivado&#x27;s xsim simulator and now want them to run in GHDL, usually in a CI pipeline, a VUnit or cocotb flow, or on a laptop without a Vivado install. It also suits teams handing a Vivado project to a contractor who only has open-source tools.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just run GHDL and fix the errors?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">GHDL stops at the first analysis error in a file, so you learn about library unisim, then process(all), then the shared variable, one run at a time. A chatbot guesses flags from memory and cannot see your file. This check lists every Vivado-only line in one pass, with the flag or code change for each.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence key?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free, with no key: check the open .vhd file in VS Code or paste it into the web page, and get every finding with its GHDL fix and the ghdl -a command line. The $29 licence key adds a one-pass scan of every .vhd file in the workspace and a Markdown migration report with the flag set per library.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does staying on the Vivado route cost?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Vivado ML Standard and its xsim simulator are free, but larger devices need Vivado ML Enterprise; Mouser lists a node-locked Enterprise seat (EF-VIVADO-ENTER-NL) at $5,063.25, checked 2026-09-29. GHDL is free under GPL-2.0, so many teams keep one Vivado seat for synthesis and run testbenches in GHDL. This check costs $29 once.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does GHDL Migration Check do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads a VHDL testbench or source file and flags every line that Vivado xsim accepts but GHDL rejects or needs a flag for: UNISIM, UNIMACRO, SECUREIP and XPM libraries, Synopsys std_logic_unsigned, VHDL-2008 features without --std=08, plain shared variables and IEEE 1735 encrypted blocks. Each finding carries the GHDL fix and the ghdl -a flags the file needs."}}, {"@type": "Question", "name": "Who is GHDL Migration Check for?", "acceptedAnswer": {"@type": "Answer", "text": "FPGA and ASIC verification engineers who wrote VHDL testbenches in AMD Vivado's xsim simulator and now want them to run in GHDL, usually in a CI pipeline, a VUnit or cocotb flow, or on a laptop without a Vivado install. It also suits teams handing a Vivado project to a contractor who only has open-source tools."}}, {"@type": "Question", "name": "Why not just run GHDL and fix the errors?", "acceptedAnswer": {"@type": "Answer", "text": "GHDL stops at the first analysis error in a file, so you learn about library unisim, then process(all), then the shared variable, one run at a time. A chatbot guesses flags from memory and cannot see your file. This check lists every Vivado-only line in one pass, with the flag or code change for each."}}, {"@type": "Question", "name": "What is free and what needs a licence key?", "acceptedAnswer": {"@type": "Answer", "text": "Free, with no key: check the open .vhd file in VS Code or paste it into the web page, and get every finding with its GHDL fix and the ghdl -a command line. The $29 licence key adds a one-pass scan of every .vhd file in the workspace and a Markdown migration report with the flag set per library."}}, {"@type": "Question", "name": "What does staying on the Vivado route cost?", "acceptedAnswer": {"@type": "Answer", "text": "Vivado ML Standard and its xsim simulator are free, but larger devices need Vivado ML Enterprise; Mouser lists a node-locked Enterprise seat (EF-VIVADO-ENTER-NL) at $5,063.25, checked 2026-09-29. GHDL is free under GPL-2.0, so many teams keep one Vivado seat for synthesis and run testbenches in GHDL. This check costs $29 once."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:410505,slug:"ghdl-migration-check",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/robots-txt-ai-crawler-audit"><span class="yj-rel-t">AI Crawler Rules - robots.txt Audit for AI Search</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/age-gate-lint"><span class="yj-rel-t">Age Gate Lint — UK Online Safety Act</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/almalinux-migration-lint"><span class="yj-rel-t">AlmaLinux Migration Lint — CentOS 7/8</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/brave-search-api-migration-check"><span class="yj-rel-t">Brave Search API Migration Check — Google Custom Search &amp; Bing</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/bulk-sender-lint"><span class="yj-rel-t">Bulk Sender Lint - the Gmail, Yahoo and Outlook.com rules, checked in your mai</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cinc-migration-check"><span class="yj-rel-t">Cinc Migration Check: Chef Infra licence gate lint</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
219
  </html>