{"id":555,"date":"2026-06-26T20:44:56","date_gmt":"2026-06-26T20:44:56","guid":{"rendered":"https:\/\/www.r3tr0.net\/?p=555"},"modified":"2026-06-26T20:44:56","modified_gmt":"2026-06-26T20:44:56","slug":"dma-single-player-always-wins","status":"publish","type":"post","link":"https:\/\/www.r3tr0.net\/index.php\/2026\/06\/26\/dma-single-player-always-wins\/","title":{"rendered":"DMA \/ Single player always wins\u2026"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">A bet you can&#8217;t lose \u2014 and somehow did<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Micro Channel arbitration is a tournament. Any device that wants the bus \u2014 a DMA controller, a bus-master card, the refresh logic \u2014 drops its 4\u2011bit&nbsp;<em>arbitration level<\/em>&nbsp;onto the shared&nbsp;<code class=\"\" data-line=\"\">ARB[3:0]<\/code>&nbsp;lines during the arbitration window, and the&nbsp;<strong>lowest level wins<\/strong>. The lines are open\u2011collector and active\u2011low: you pull down the bits that are&nbsp;<code class=\"\" data-line=\"\">0<\/code>&nbsp;in your level, you release the bits that are&nbsp;<code class=\"\" data-line=\"\">1<\/code>, and the wired\u2011AND of everyone&#8217;s drive settles to the winner. Lose a bit to someone with higher priority, and you drop out of all the lower bits too.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the thing about a tournament with one entrant:&nbsp;<strong>the single player always wins.<\/strong>&nbsp;When WonderMCA is the only card asking for the bus, its arbitration is a formality \u2014 present level&nbsp;<code class=\"\" data-line=\"\">0001<\/code>&nbsp;(DMA channel 1), nobody contests it, the planar grants it the bus, and the CDMA pushes a byte into our test port. That&#8217;s the whole game.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you remember the previous episode, Sound Blaster emulation was working , unstable, but working on Model 50Z and model 70. As part of my larger validation, I tested the WonderMCA on the Model 57 &amp; 56 SLC2 and it was a complete disaster, Model 56 &amp; 57 have something in common, the chassis has zero tolerance.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Prince of Persia was rebooting as soon as Digital Audio was starting&#8230;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So when I armed SBDIAG, expecting the Sound Blaster &#8220;TADA&#8221; to loop forever off chassis DMA, and instead got&nbsp;<strong>one<\/strong>&nbsp;TADA and then a&nbsp;<strong>frozen POST<\/strong>, I had a card that was losing a tournament it was the only player in. That should be impossible. It took most of a day, three independent bugs, and a trip through the chip&#8217;s own silicon manual to understand&nbsp;<em>how<\/em>&nbsp;you lose a race you can&#8217;t lose.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Layer 0: the firmware that quietly killed Core 1<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before the arbitration even mattered, the first symptom was blunter:&nbsp;<strong>CHRDY never released, and the bus hung.<\/strong>&nbsp;The MCA bus master asserts a cycle, our CPLD stretches it with CHRDY (a wait\u2011state), and the RP2350 firmware is supposed to pulse&nbsp;<code class=\"\" data-line=\"\">RP_REL<\/code>&nbsp;to tear the latch down. CHRDY staying asserted means&nbsp;<em>nobody is pulsing RP_REL<\/em>&nbsp;\u2014 i.e. Core 1, which runs the whole bus handler, is dead.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The give\u2011away was a regression I&#8217;d caused that morning. I&#8217;d &#8220;optimised&#8221;&nbsp;<code class=\"\" data-line=\"\">main_core1()<\/code>&nbsp;by splitting its one\u2011time init out into a separate&nbsp;<code class=\"\" data-line=\"\">__not_in_flash_func(core1_init)<\/code>&nbsp;to reclaim ~700 bytes of the 4 KB SCRATCH_X budget. Clean idea, green build, scratch_x shrank 2024 \u2192 1312 bytes. And it bricked Core 1: the GPIO coprocessor (CP0) enable, and the fragile single\u2011translation\u2011unit assumptions of that hand\u2011tuned loop, do not survive being chopped into two functions across two memory regions. Pull the card, POST completes; card in, frozen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Lesson, logged:<\/strong>&nbsp;keep&nbsp;<code class=\"\" data-line=\"\">main_core1<\/code>&nbsp;a single&nbsp;<code class=\"\" data-line=\"\">__scratch_x<\/code>&nbsp;function. I reverted the split. You don&#8217;t refactor the load\u2011bearing wall to save a picture frame&#8217;s worth of bytes. CHRDY released again, and the&nbsp;<em>real<\/em>&nbsp;DMA debugging could start.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Layer 1: a clock that &#8220;needs patching&#8221;<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With the bus alive, the DMA still didn&#8217;t arbitrate. Time for the CPLD. WonderMCA&#8217;s arbitration is an ATF1508 design that mirrors a known\u2011good Verilog reference (<code class=\"\" data-line=\"\">mcsb.v<\/code>). I opened the fitter report \u2014 and the fitter was&nbsp;<em>telling me it was unhappy<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">## Warning : Placement fail        (fitter pass 1)\n## Warning : Placement fail        (fitter pass 2)\nRP_DMA_GRANT.C equation needs patching.\nMCA_PREEMPT.OE equation needs patching.\n3 control equations need patching\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code class=\"\" data-line=\"\">RP_DMA_GRANT.C<\/code>&nbsp;is the&nbsp;<strong>clock<\/strong>&nbsp;of the grant flip\u2011flop \u2014 the FF the firmware reads to know it&#8217;s been granted the bus. A&nbsp;<em>clock<\/em>&nbsp;getting &#8220;patched&#8221; onto a feedback node instead of a clean global\u2011clock net is exactly the kind of fragile that makes a grant latch unreliable. The source said&nbsp;<code class=\"\" data-line=\"\">RP_DMA_GRANT.CK = valid_io;<\/code>&nbsp;\u2014 a combinational product term, not a clock pin. The design comment even confessed it:&nbsp;<em>&#8220;Easy revert: change CK back to plain ADL.&#8221;<\/em>&nbsp;So I did \u2014&nbsp;<code class=\"\" data-line=\"\">RP_DMA_GRANT.CK = ADL<\/code>, which sits on GCLK2 (PIN 2). The patch on the grant clock vanished. 3 \u2192 1.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One down. But the boot still froze, and now I could see why on the logic analyzer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Layer 2: ARB0 held low, forever<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The LA told a strange story. With DMA channel&nbsp;<strong>1<\/strong>&nbsp;selected, the card should present&nbsp;<code class=\"\" data-line=\"\">0001<\/code>: drive ARB3\/2\/1 low,&nbsp;<strong>release ARB0<\/strong>. Instead:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>ARB1 = 1<\/strong>\u00a0(not driven \u2014 it should be 0 for DMA1), and<\/li>\n\n\n\n<li><strong>ARB0 = 0<\/strong>,\u00a0<em>all the time<\/em>\u00a0\u2014 even at idle, even with nothing arbitrating.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"622\" src=\"https:\/\/www.r3tr0.net\/wp-content\/uploads\/2026\/06\/Screen-Shot-2026-06-26-at-22.43.03-1024x622.png\" alt=\"\" class=\"wp-image-556\" style=\"width:600px\" srcset=\"https:\/\/www.r3tr0.net\/wp-content\/uploads\/2026\/06\/Screen-Shot-2026-06-26-at-22.43.03-1024x622.png 1024w, https:\/\/www.r3tr0.net\/wp-content\/uploads\/2026\/06\/Screen-Shot-2026-06-26-at-22.43.03-300x182.png 300w, https:\/\/www.r3tr0.net\/wp-content\/uploads\/2026\/06\/Screen-Shot-2026-06-26-at-22.43.03-768x466.png 768w, https:\/\/www.r3tr0.net\/wp-content\/uploads\/2026\/06\/Screen-Shot-2026-06-26-at-22.43.03-1536x933.png 1536w, https:\/\/www.r3tr0.net\/wp-content\/uploads\/2026\/06\/Screen-Shot-2026-06-26-at-22.43.03-600x364.png 600w, https:\/\/www.r3tr0.net\/wp-content\/uploads\/2026\/06\/Screen-Shot-2026-06-26-at-22.43.03.png 1792w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">ARB0 stuck low is catastrophic, and the arbitration math says exactly why. For DMA1 the card&#8217;s win condition reduces to a single term:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">drop_cum = !MCA_ARB_0          \/* card_arb0 = 1, no higher-bit dropout *\/\narb_won  = !drop_cum &amp; DMA_SESSION = MCA_ARB_0 &amp; DMA_SESSION\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The card can only win if ARB0 reads HIGH.<\/strong>&nbsp;It releases ARB0 and trusts the bus terminator to pull it up; a level\u20110 contender pulling it low is the&nbsp;<em>only<\/em>&nbsp;legitimate reason to lose there. With ARB0 nailed low by something,&nbsp;<code class=\"\" data-line=\"\">arb_won<\/code>&nbsp;is&nbsp;<code class=\"\" data-line=\"\">0<\/code>&nbsp;on every cycle. The single player loses every hand because the table is rigged.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So who&#8217;s rigging it? The CPLD declares&nbsp;<code class=\"\" data-line=\"\">MCA_ARB_0<\/code>&nbsp;as a pure&nbsp;<strong>input<\/strong>&nbsp;\u2014 it shouldn&#8217;t be driving anything. The card\u2011out test settled it instantly:&nbsp;<strong>pull WonderMCA, POST completes.<\/strong>&nbsp;It was us. Our own CPLD was holding ARB0 low and freezing the whole planar&#8217;s arbitration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The cross-check: what the reference actually does<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before &#8220;fixing&#8221; anything I read the Verilog reference in detail, because the LA and the source disagreed about whether ARB0 should ever be driven.&nbsp;<code class=\"\" data-line=\"\">mcsb.v<\/code>&nbsp;is unambiguous:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">inout  &#091;3:0] arb;                                   &lt;em&gt;\/\/ bidirectional, all 4&lt;\/em&gt;\nassign arb&#091;i] = (~arb_en | arb_out&#091;i]) ? 1&#039;bZ : 1&#039;b0;   &lt;em&gt;\/\/ open-drain&lt;\/em&gt;\nassign arb_out&#091;0] = card_arb&#091;0] | ~arb_match&#091;1] | ~arb_match&#091;2] | ~arb_match&#091;3];\ncard_arb (DMA1) = 0001;                             &lt;em&gt;\/\/ card_arb&#091;0] = 1&lt;\/em&gt;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For DMA1,&nbsp;<code class=\"\" data-line=\"\">card_arb[0]=1<\/code>&nbsp;\u2192&nbsp;<code class=\"\" data-line=\"\">arb_out[0]=1<\/code>&nbsp;\u2192&nbsp;<code class=\"\" data-line=\"\">arb[0]<\/code>&nbsp;is&nbsp;<strong>always released (Hi\u2011Z)<\/strong>. The reference never drives ARB0 on our channels. It&nbsp;<em>also<\/em>&nbsp;declares the line&nbsp;<code class=\"\" data-line=\"\">inout<\/code>&nbsp;\u2014 a real bidirectional open\u2011drain pin. The&nbsp;<code class=\"\" data-line=\"\">.pld<\/code>&nbsp;matched the&nbsp;<em>logic<\/em>&nbsp;(ARB0 released) but had quietly made the pin&nbsp;<strong>input\u2011only<\/strong>&nbsp;to dodge a WinCUPL quirk. That mismatch was the thread to pull.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Layer 3: the trap \u2014 when &#8220;off&#8221; means &#8220;always on&#8221;<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the part that cost the most hours. On this ATF1508 \/ WinCUPL flow, the open\u2011drain&nbsp;<em>emulation<\/em>&nbsp;everyone uses \u2014<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">MCA_ARB_0     = &#039;b&#039;0;\nMCA_ARB_0.OE  = participate &amp; !card_arb0 &amp; !drop_1;   \/* the OE controls drive *\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u2014&nbsp;<strong>traps when the OE folds to a compile\u2011time constant 0.<\/strong>&nbsp;Because&nbsp;<code class=\"\" data-line=\"\">card_arb0 = 1<\/code>,&nbsp;<code class=\"\" data-line=\"\">!card_arb0 = 0<\/code>, the whole OE simplifies to&nbsp;<code class=\"\" data-line=\"\">0<\/code>, and the fitter then &#8220;optimises&#8221;&nbsp;<em>&#8220;output\u2011enable always 0&#8221;<\/em>&nbsp;into&nbsp;<em>&#8220;no OE term, output always on&#8221;<\/em>&nbsp;\u2014 and drives the pin to its value,&nbsp;<code class=\"\" data-line=\"\">0<\/code>,&nbsp;<strong>low, forever.<\/strong>&nbsp;The cure the design had reached for \u2014 removing the equation entirely so the pin is input\u2011only \u2014&nbsp;<em>looked<\/em>&nbsp;right in the fitter report (<code class=\"\" data-line=\"\">MC88 57 -- MCA_ARB_0 INPUT<\/code>) but a stale JED on the part still carried the old driving build, and even&nbsp;<code class=\"\" data-line=\"\">MCA_CD_DS16.OE = &#039;b&#039;0<\/code>&nbsp;(my attempt to &#8220;disable&#8221; DS16) hit the same trap: the fit showed that macrocell&nbsp;<strong>on<\/strong>, driving&nbsp;<code class=\"\" data-line=\"\">\/CD-DS16<\/code>&nbsp;low = 16\u2011bit forced&nbsp;<em>on<\/em>. Three different ways to say &#8220;don&#8217;t drive this pin,&#8221; three ways the fitter said &#8220;fine, I&#8217;ll drive it low.&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is the moment the whole bug clicked:&nbsp;<strong>you cannot disable an ATF1508 output by giving it a constant\u20110 enable.<\/strong>&nbsp;The OE trick is a footgun the fitter loads for you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The fix: use the silicon&#8217;s real open-collector mode<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The ATF150x macrocells have a&nbsp;<em>hardware<\/em>&nbsp;open\u2011collector output \u2014 drive low or release, in the buffer itself, no OE product term to collapse. It&#8217;s not in the WinCUPL&nbsp;<em>language<\/em>&nbsp;manual (that only documents&nbsp;<code class=\"\" data-line=\"\">.OE<\/code>); it lives in the&nbsp;<strong>ATF15xx Device Fitter User&#8217;s Guide<\/strong>, as a fitter strategy you select from CUPL source:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">PROPERTY ATMEL { open_collector = MCA_ARB_0, MCA_ARB_1, MCA_ARB_2, MCA_ARB_3, MCA_PREEMPT };\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With the pin in real OC mode you stop emulating and just write the&nbsp;<strong>bus value<\/strong>&nbsp;\u2014&nbsp;<code class=\"\" data-line=\"\">0<\/code>&nbsp;drives low,&nbsp;<code class=\"\" data-line=\"\">1<\/code>&nbsp;releases \u2014 which is&nbsp;<em>exactly<\/em>&nbsp;the Verilog:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">MCA_ARB_0   = !participate # card_arb0 # drop_1;   \/* folds to 1 -&gt; always released, no jam *\/\nMCA_ARB_1   = !participate # card_arb1 # drop_2;\nMCA_ARB_2   = !participate # card_arb2 # drop_3;\nMCA_ARB_3   = !participate # card_arb3;\nMCA_PREEMPT = !preempt_drive;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No&nbsp;<code class=\"\" data-line=\"\">.OE<\/code>&nbsp;anywhere on these pins, so there is&nbsp;<strong>no constant\u20110 OE for the fitter to invert into a permanent low<\/strong>. ARB0&#8217;s equation folds to&nbsp;<code class=\"\" data-line=\"\">1<\/code>&nbsp;\u2014 and in OC mode&nbsp;<code class=\"\" data-line=\"\">1<\/code>&nbsp;means&nbsp;<em>release<\/em>, not&nbsp;<em>drive high<\/em>&nbsp;\u2014 so it sits Hi\u2011Z, exactly as the single\u2011player tournament requires.&nbsp;<code class=\"\" data-line=\"\">\/CD-DS16<\/code>, by contrast, is genuinely a&nbsp;<strong>totem\u2011pole<\/strong>&nbsp;output (it must actively drive both 8\u2011 and 16\u2011bit states for a fast early sample), so it stays push\u2011pull and&nbsp;<em>out<\/em>&nbsp;of the open\u2011collector list:&nbsp;<code class=\"\" data-line=\"\">MCA_CD_DS16 = !ds16_drive;<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The one caveat I left in the source in bold:&nbsp;<strong>verify the&nbsp;<code class=\"\" data-line=\"\">.fit<\/code>&nbsp;echoes&nbsp;<code class=\"\" data-line=\"\">Open_collector = MCA_ARB_0, \u2026<\/code>.<\/strong>&nbsp;If WinCUPL silently ignores the directive, those value\u2011equations become&nbsp;<em>push\u2011pull<\/em>&nbsp;outputs driving the open\u2011drain bus high \u2014 bus contention, worse than the bug. The fitter&#8217;s own echo is the ground truth.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The single player wins again<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Rev 72 burned to the CPLD. ARB0 released to the terminator&#8217;s HIGH, the card presented&nbsp;<code class=\"\" data-line=\"\">0001<\/code>, the planar granted it the bus, the CDMA streamed bytes into the SB port \u2014 and the TADA&nbsp;<strong>looped<\/strong>, continuously, the way a 22 kHz auto\u2011init DMA transfer is supposed to. The tournament has one entrant again, and the one entrant wins.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What this one taught me<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>A tool&#8217;s optimiser is part of your circuit.<\/strong>\u00a0The bug wasn&#8217;t in my logic \u2014\u00a0<code class=\"\" data-line=\"\">drop_cum<\/code>,\u00a0<code class=\"\" data-line=\"\">arb_out<\/code>, the levels all matched the reference. It was WinCUPL turning &#8220;never drive&#8221; into &#8220;always drive low.&#8221; Read the fitter report like it&#8217;s a teammate; it was warning me in plain English for hours.<\/li>\n\n\n\n<li><strong>Use the device&#8217;s real feature, not an emulation of it.<\/strong>\u00a0Hardware open\u2011collector existed the whole time. The\u00a0<code class=\"\" data-line=\"\">=&#039;b&#039;0; .OE=cond<\/code>\u00a0pattern is a decades\u2011old habit that happens to detonate on this part when the condition is constant.<\/li>\n\n\n\n<li><strong>The manual you grabbed might be the wrong manual.<\/strong>\u00a0The open\u2011collector syntax wasn&#8217;t in the WinCUPL\u00a0<em>language<\/em>\u00a0reference at all \u2014 it was a\u00a0<em>fitter<\/em>\u00a0strategy in a separate Microchip guide. An afternoon of &#8220;it&#8217;s not documented&#8221; was really &#8220;it&#8217;s documented elsewhere.&#8221;<\/li>\n\n\n\n<li><strong>Bisect across layers, not just lines.<\/strong>\u00a0Three unrelated bugs stacked \u2014 a firmware regression, a clock placement, and the OE trap \u2014 each masking the next. Card\u2011out tests, the fitter echo, and the LA each isolated one layer. Guessing would never have peeled them apart.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Different MCA chassis, different fitter quirks, the same lesson WonderMCA keeps teaching: the bus is honest, the silicon is honest, the tools have opinions \u2014 and you don&#8217;t really understand a system until you understand how it can lose a game it can&#8217;t lose.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A bet you can&#8217;t lose \u2014 and somehow did Micro Channel arbitration is a tournament. Any device that wants the bus \u2014 a DMA controller, a bus-master card, the refresh logic \u2014 drops its 4\u2011bit&nbsp;arbitration level&nbsp;onto the shared&nbsp;ARB[3:0]&nbsp;lines during the arbitration window, and the&nbsp;lowest level wins. The lines are open\u2011collector and active\u2011low: you pull down [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-555","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/posts\/555","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/comments?post=555"}],"version-history":[{"count":1,"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/posts\/555\/revisions"}],"predecessor-version":[{"id":557,"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/posts\/555\/revisions\/557"}],"wp:attachment":[{"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/media?parent=555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/categories?post=555"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.r3tr0.net\/index.php\/wp-json\/wp\/v2\/tags?post=555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}