<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>retro-silicon</title><link>https://retro-silicon.particlesector.com/</link><description>Recent content on retro-silicon</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 27 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://retro-silicon.particlesector.com/index.xml" rel="self" type="application/rss+xml"/><item><title>A second FPGA family: the PYNQ-Z2</title><link>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-27-second-fpga-family/</link><pubDate>Tue, 27 Oct 2026 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-27-second-fpga-family/</guid><description>&lt;p&gt;The NES runs on an AMD Zynq-7020, on a TUL PYNQ-Z2, built entirely with the open-source openXC7 toolchain, and every test gives the Tang boards&amp;rsquo; CRCs: nestest, the save-state round trip, all 42 PPU test ROMs, and HDMI at 720p, checked by checksum and through the capture device. The parts it shares with the Tang boards now count as Portable: verified on two FPGA families.&lt;/p&gt;&#10;&lt;p&gt;Getting there turned up four limits of the toolchain, each worked around in the board&amp;rsquo;s own files or in a part that now avoids it on every board: clock settings with fractions came out wrong, the ninth bit of a 9-bit-wide block RAM was lost, deep memories built from cascaded block RAM couldn&amp;rsquo;t be placed, and the timing varied widely from one placement to the next.&lt;/p&gt;</description></item><item><title>The picture on HDMI</title><link>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-26-hdmi/</link><pubDate>Mon, 26 Oct 2026 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-26-hdmi/</guid><description>&lt;p&gt;The NES&amp;rsquo;s picture now goes out over HDMI at 720p: three times its size, centred, with the console kept in step with the display so each display frame shows one NES frame whole. On the Tang Nano 20K a checksum of every symbol sent to the display matches the simulation&amp;rsquo;s, a desk monitor shows the picture, and a USB capture device&amp;rsquo;s picture of each test&amp;rsquo;s frame matches the frame the console drew.&lt;/p&gt;</description></item><item><title>First frames: 42 PPU test ROMs match MesenCE</title><link>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-25-ppu-frames-match-mesen/</link><pubDate>Sun, 25 Oct 2026 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-25-ppu-frames-match-mesen/</guid><description>&lt;p&gt;The picture processor, &lt;code&gt;video/ppu-2c02&lt;/code&gt;, draws its first frames on the board, and they match the reference emulator exactly. Its timing follows MesenCE&amp;rsquo;s, so a frame from the core and a frame from MesenCE can be compared as raw palette values, CRC for CRC.&lt;/p&gt;&#10;&lt;p&gt;42 test ROMs pass that way, in the simulation and on the Tang Nano 20K: blargg&amp;rsquo;s VBL and NMI tests, PPU open bus and OAM reads, the sprite hit and overflow tests, VBL/NMI timing, palette RAM, nmi_sync and full_palette. A whole frame captured from the board line by line matches MesenCE&amp;rsquo;s pixel for pixel. Five bugs planted in the PPU on purpose were each caught by the ROMs.&lt;/p&gt;</description></item><item><title>Save states that move between boards</title><link>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-25-save-states-between-boards/</link><pubDate>Sun, 25 Oct 2026 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-25-save-states-between-boards/</guid><description>&lt;p&gt;The NES now runs on a second board, the Sipeed Tang Console 138K, with its memory in block RAM, and every test gives the same CRCs as on the Tang Nano 20K: nestest &lt;code&gt;0xebba51ce&lt;/code&gt;, and all 42 PPU test ROMs with MesenCE&amp;rsquo;s frames.&lt;/p&gt;&#10;&lt;p&gt;A save-state controller stops the system at a frame boundary and copies the CPU, the PPU and every RAM, 20,920 bytes, out through the test shell and back. Saved partway through a test, reset, restored and finished, a run ends with the same frame, line CRCs, bus trace and cycle count as an uninterrupted one. A state saved halfway on either board also finishes on the other with MesenCE&amp;rsquo;s frames, for nmi_sync, sprite_overflow-3 and ppu_vbl_nmi-10.&lt;/p&gt;</description></item><item><title>nestest on the board</title><link>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-24-nestest-on-the-board/</link><pubDate>Sat, 24 Oct 2026 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-24-nestest-on-the-board/</guid><description>&lt;p&gt;The CPU now runs on real hardware. On the Sipeed Tang Nano 20K, &lt;code&gt;systems/nes&lt;/code&gt; reads its program from the board&amp;rsquo;s SDRAM through the new &lt;code&gt;memory/sdram&lt;/code&gt; controller, and nestest&amp;rsquo;s run gives the bus-trace CRC &lt;code&gt;0xebba51ce&lt;/code&gt;: a checksum of every bus cycle, the same in the simulation, on the board, and from the CPU&amp;rsquo;s own test bench.&lt;/p&gt;&#10;&lt;p&gt;The SDRAM controller worked on the board the first time: 8 MB of random data written and read back with the simulation&amp;rsquo;s CRC. The simulation had caught two of its bugs first.&lt;/p&gt;</description></item><item><title>The 6502, cycle for cycle</title><link>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-24-the-6502/</link><pubDate>Sat, 24 Oct 2026 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/systems/nes/log/2026-10-24-the-6502/</guid><description>&lt;p&gt;The NES&amp;rsquo;s CPU core, &lt;code&gt;cpu/6502&lt;/code&gt;, matches the original chip on every bus access. In simulation it ran in lockstep with perfect6502, a transistor-level model of the real 6502, over two million cycles of random code with random interrupts, and on 1,500 decimal-mode cases. All 8,991 lines of nestest&amp;rsquo;s reference log match, cycle counts included, and blargg&amp;rsquo;s test of every official opcode passes.&lt;/p&gt;&#10;&lt;p&gt;The lockstep also turned up three things outside our own code: a memory bug in perfect6502&amp;rsquo;s newest version, an operation perfect6502 leaves out of three rarely used opcodes, and the exact half-cycle at which the chip samples its interrupt lines.&lt;/p&gt;</description></item><item><title>About</title><link>https://retro-silicon.particlesector.com/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/about/</guid><description>&lt;p&gt;retro-silicon is an open library of FPGA parts for rebuilding retro systems: CPUs, video and sound chips, memory controllers, and the systems built from them. The code is at &lt;a href="https://github.com/particlesector/retro-silicon"&gt;github.com/particlesector/retro-silicon&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h2 id="how-the-cores-are-verified"&gt;How the cores are verified&lt;/h2&gt;&#10;&lt;p&gt;A core is only as good as the evidence that it behaves like the original. Each part goes through the same steps.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Simulation first.&lt;/strong&gt; Every part has tests that run in &lt;a href="https://www.veripool.org/verilator/"&gt;Verilator&lt;/a&gt;, a simulator that turns the hardware description into a fast C++ model. Where there&amp;rsquo;s a software model to compare against, the tests use it: the 6502 CPU runs in lockstep with &lt;a href="https://github.com/mist64/perfect6502"&gt;perfect6502&lt;/a&gt;, a transistor-level simulation of the real chip, for millions of half-cycles.&lt;/p&gt;</description></item><item><title>common/cdc</title><link>https://retro-silicon.particlesector.com/components/common/cdc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/common/cdc/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/common/cdc/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;A flip-flop synchronizer: brings a signal from another clock domain into this one through &lt;code&gt;STAGES&lt;/code&gt; flip-flops, so a value that changes near the clock edge settles before anything uses it.&lt;/p&gt;&#10;&lt;p&gt;Module &lt;code&gt;cdc_sync&lt;/code&gt;. It&amp;rsquo;s safe only for signals whose bits can be taken in any mix of old and new without harm:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;a level;&lt;/li&gt;&#10;&lt;li&gt;a toggle, one bit that flips once per event;&lt;/li&gt;&#10;&lt;li&gt;a Gray-coded count, which changes one bit per step;&lt;/li&gt;&#10;&lt;li&gt;a value the sending side holds steady from before a toggle it sends until after the toggle is seen here.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ports"&gt;Ports&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Port&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Dir&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Width&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;clk&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;This domain&amp;rsquo;s clock&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;d&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;From the other domain&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;d&lt;/code&gt;, &lt;code&gt;STAGES&lt;/code&gt; clocks later&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="parameters"&gt;Parameters&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Parameter&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Bits&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;STAGES&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Flip-flops in the chain, 2 or more&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="status"&gt;Status&lt;/h2&gt;&#10;&lt;p&gt;Sim test: the output is the input &lt;code&gt;STAGES&lt;/code&gt; clocks later. In &lt;code&gt;video/line-scaler&lt;/code&gt; and &lt;code&gt;systems/nes&lt;/code&gt;, between the NES&amp;rsquo;s clock and the HDMI pixel clock, on a Tang Nano 20K.&lt;/p&gt;</description></item><item><title>common/clock-enable</title><link>https://retro-silicon.particlesector.com/components/common/clock-enable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/common/clock-enable/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/common/clock-enable/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;A clock enable at NUM/DEN of the clock rate, exact on average: a phase accumulator gains NUM each enabled clock and fires when it reaches DEN, so pulses come floor(DEN/NUM) or ceil(DEN/NUM) clocks apart and never drift. It&amp;rsquo;s how a system on one fast clock runs a chip at its original rate: the NES&amp;rsquo;s PPU dot rate, 236.25/44 MHz, is NUM = 35, DEN = 176 from 27 MHz.&lt;/p&gt;</description></item><item><title>common/crc32</title><link>https://retro-silicon.particlesector.com/components/common/crc32/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/common/crc32/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/common/crc32/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;CRC-32 as used by zlib, Ethernet and PNG (IEEE 802.3 polynomial, reflected, initial value and final XOR &lt;code&gt;0xFFFFFFFF&lt;/code&gt;), consuming &lt;code&gt;W&lt;/code&gt; bits per enabled clock, bit 0 first: by default one byte. The test shell uses it for frame, scanline and audio CRCs, and the harness&amp;rsquo;s software &lt;code&gt;rig::Crc32&lt;/code&gt; matches it.&lt;/p&gt;&#10;&lt;h2 id="ports"&gt;Ports&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Port&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Dir&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Width&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;clk&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Clock&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;rst&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Synchronous; restarts the CRC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;en&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Consume &lt;code&gt;data&lt;/code&gt; this cycle&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Next byte, or &lt;code&gt;W&lt;/code&gt; bits&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;crc&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;32&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CRC of every byte since reset, final XOR applied&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;st_we&lt;/code&gt;, &lt;code&gt;st_wdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1, 32&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Save state: set the CRC to &lt;code&gt;st_wdata&lt;/code&gt;, ahead of any byte that clock&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="parameters"&gt;Parameters&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Parameter&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Bits per enabled clock, 1 to 32&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="save-state"&gt;Save state&lt;/h2&gt;&#10;&lt;p&gt;One word, the CRC: &lt;code&gt;crc&lt;/code&gt; is its read side (it needs no address). Writing a saved CRC back makes the next bytes go on from it exactly as if the bytes before it had gone in. Tie &lt;code&gt;st_we&lt;/code&gt; low where nothing restores the CRC.&lt;/p&gt;</description></item><item><title>common/fifo</title><link>https://retro-silicon.particlesector.com/components/common/fifo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/common/fifo/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/common/fifo/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Synchronous first-in, first-out queue. The read port is registered, so synthesis maps the storage to block RAM: &lt;code&gt;rdata&lt;/code&gt; holds a byte the cycle after its read is accepted.&lt;/p&gt;&#10;&lt;h2 id="ports"&gt;Ports&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Port&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Dir&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Width&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;clk&lt;/code&gt;, &lt;code&gt;rst&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Clock; synchronous reset, which empties the FIFO&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;wdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;WIDTH&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entry to write&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;wen&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Write &lt;code&gt;wdata&lt;/code&gt;; ignored when full&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;full&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;No room for a write this cycle&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ren&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Read the oldest entry; ignored when empty&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;rdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;WIDTH&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The entry read on the previous cycle; held otherwise&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;empty&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Nothing to read this cycle&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="parameters"&gt;Parameters&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Parameter&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;WIDTH&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Bits per entry&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DEPTH_LOG2&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;11&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;log2 of the entry count; 2,048 × 8 bits is one 18 Kbit Gowin BSRAM&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="status"&gt;Status&lt;/h2&gt;&#10;&lt;p&gt;Sim tests at 16 and 2,048 entries: it fills to its depth, ignores a write when full and a read when empty, empties on reset, and matches a software queue over 100,000 cycles of random reads and writes. On a Tang Nano 20K, inside &lt;code&gt;systems/uart-echo&lt;/code&gt;, it carried 100 MB at 1.5 Mbaud with no errors.&lt;/p&gt;</description></item><item><title>common/por</title><link>https://retro-silicon.particlesector.com/components/common/por/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/common/por/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/common/por/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Power-on reset: holds &lt;code&gt;rst&lt;/code&gt; high for &lt;code&gt;CYCLES&lt;/code&gt; clocks after the FPGA is configured, then low for good. It&amp;rsquo;s the one block that relies on a register&amp;rsquo;s initial value, which FPGAs load at configuration; everything else resets from its &lt;code&gt;rst&lt;/code&gt;. It won&amp;rsquo;t work on an ASIC or an FPGA that ignores initial values; use a reset pin there instead.&lt;/p&gt;</description></item><item><title>common/save-state</title><link>https://retro-silicon.particlesector.com/components/common/save-state/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/common/save-state/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/common/save-state/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Saves a system&amp;rsquo;s whole state into a block-RAM buffer and loads it back, by walking a list of byte regions on the system&amp;rsquo;s own bus: the regions where the system maps its components&amp;rsquo; save-state ports (&lt;a href="https://github.com/particlesector/retro-silicon/blob/ac84cec/docs/conventions.md"&gt;docs/conventions.md&lt;/a&gt;) and its memories. A save taken on one board loads on any other board running the same system, at any clock.&lt;/p&gt;</description></item><item><title>common/uart</title><link>https://retro-silicon.particlesector.com/components/common/uart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/common/uart/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/common/uart/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;8N1 UART: a receiver (&lt;code&gt;uart_rx&lt;/code&gt;) and a transmitter (&lt;code&gt;uart_tx&lt;/code&gt;), each set to a rate by &lt;code&gt;CLKS_PER_BIT&lt;/code&gt; (clock frequency divided by baud rate).&lt;/p&gt;&#10;&lt;h2 id="uart_rx"&gt;uart_rx&lt;/h2&gt;&#10;&lt;p&gt;Synchronises &lt;code&gt;rx&lt;/code&gt; through three flops, samples each bit at its middle, and goes back to idle in the middle of the stop bit, so a sender running slightly fast never loses sync. A low pulse shorter than half a bit is ignored as a glitch.&lt;/p&gt;</description></item><item><title>cpu/6502</title><link>https://retro-silicon.particlesector.com/components/cpu/6502/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/cpu/6502/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/cpu/6502/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;An NMOS 6502 that is cycle-exact on the bus: one access per CPU cycle, including the original&amp;rsquo;s dummy reads and writes, so memory-mapped hardware sees what it would on the real chip. The NES&amp;rsquo;s 2A03 is this CPU with &lt;code&gt;DECIMAL = 0&lt;/code&gt;; the Atari 2600&amp;rsquo;s 6507 and the C64&amp;rsquo;s 6510 keep decimal mode.&lt;/p&gt;&#10;&lt;p&gt;Module &lt;code&gt;cpu_6502&lt;/code&gt; (the folder name can&amp;rsquo;t start a module name).&lt;/p&gt;</description></item><item><title>debug/test-shell</title><link>https://retro-silicon.particlesector.com/components/debug/test-shell/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/debug/test-shell/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/debug/test-shell/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;A UART command engine that gives a host framed, CRC-checked access to a core: it reads and writes the core&amp;rsquo;s bus, and reports a build ID so every result ties to the exact RTL that produced it. Later blocks (ROM loader, run control, video and audio CRCs, frame dump, trace buffer) are reached through the same commands and bus.&lt;/p&gt;</description></item><item><title>debug/video-probe</title><link>https://retro-silicon.particlesector.com/components/debug/video-probe/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/debug/video-probe/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/debug/video-probe/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Checks and captures a system&amp;rsquo;s video for the test shell: a CRC-32 of each frame and of each line, and a capture of one chosen line at a time that holds the system until the host has read it. Holding a system&amp;rsquo;s clock enables leaves its behaviour unchanged, so a frame dumped line by line is exactly the frame it would have shown, at the link&amp;rsquo;s speed rather than the video&amp;rsquo;s.&lt;/p&gt;</description></item><item><title>memory/arbiter</title><link>https://retro-silicon.particlesector.com/components/memory/arbiter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/memory/arbiter/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/memory/arbiter/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Shares one byte-port memory among N clients by fixed priority, client 0 first. A system takes its memory through this, so a board can put any memory behind the one port: &lt;code&gt;memory/sdram&lt;/code&gt; on the Tang Nano 20K, &lt;code&gt;memory/bram&lt;/code&gt; on the Tang Console 138K.&lt;/p&gt;&#10;&lt;p&gt;Module &lt;code&gt;mem_arbiter&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="timing"&gt;Timing&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Ports:&lt;/strong&gt; the clients&amp;rsquo; and the memory&amp;rsquo;s all work as &lt;code&gt;memory/sdram&lt;/code&gt;&amp;rsquo;s user port: hold &lt;code&gt;req&lt;/code&gt; (with &lt;code&gt;addr&lt;/code&gt;, &lt;code&gt;we&lt;/code&gt;, &lt;code&gt;wdata&lt;/code&gt;) until &lt;code&gt;ack&lt;/code&gt;, a one-clock pulse that also marks &lt;code&gt;rdata&lt;/code&gt; valid on a read. &lt;code&gt;req&lt;/code&gt; may still be high while &lt;code&gt;ack&lt;/code&gt; is.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Grant:&lt;/strong&gt; when the memory is free, the first requesting client is granted on the next clock, and its request goes straight to the memory until the memory acks. The ack goes to that client in the same clock.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Latency:&lt;/strong&gt; a client waits for the rest of any access already running, then for every client before it. Client 0 waits for at most one access, plus the grant clock and its own access; that bound is what lets a CPU fit its reads into a fixed cycle.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ports"&gt;Ports&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Port&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Dir&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Width&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;clk&lt;/code&gt;, &lt;code&gt;rst&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Clock; synchronous reset, which drops any grant&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;c_req&lt;/code&gt;, &lt;code&gt;c_we&lt;/code&gt;, &lt;code&gt;c_ack&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in, in, out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;N&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Per client&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;c_addr&lt;/code&gt;, &lt;code&gt;c_wdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;N×AW, N×8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Client i in bits &lt;code&gt;[i*AW +: AW]&lt;/code&gt; and &lt;code&gt;[i*8 +: 8]&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;c_rdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Read data, for the client being acked&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;m_req&lt;/code&gt;, &lt;code&gt;m_we&lt;/code&gt;, &lt;code&gt;m_addr&lt;/code&gt;, &lt;code&gt;m_wdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1, 1, AW, 8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;To the memory&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;m_ack&lt;/code&gt;, &lt;code&gt;m_rdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1, 8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;From the memory&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="parameters"&gt;Parameters&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Parameter&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Clients&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;AW&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;23&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Address bits&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="status"&gt;Status&lt;/h2&gt;&#10;&lt;p&gt;Sim test (N = 3) against a memory with a random latency of 1 to 7 clocks, with three clients each keeping requests going in its own part of the address space: 200,000 clocks in which every request is served exactly once, every read gives the byte last written, and client 0 never waits more than two accesses. In &lt;code&gt;systems/nes&lt;/code&gt; it serves the CPU&amp;rsquo;s PRG reads and the shell, on both boards.&lt;/p&gt;</description></item><item><title>memory/bram</title><link>https://retro-silicon.particlesector.com/components/memory/bram/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/memory/bram/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/memory/bram/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;2^AW bytes of block RAM behind &lt;code&gt;memory/sdram&lt;/code&gt;&amp;rsquo;s byte port, for a board whose own memory a system can&amp;rsquo;t use yet, such as the Tang Console 138K&amp;rsquo;s DDR3. Every access takes one clock. Addresses wrap at 2^AW, so a wider port mirrors it.&lt;/p&gt;&#10;&lt;p&gt;Module &lt;code&gt;bram_mem&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="ports"&gt;Ports&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Port&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Dir&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Width&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;clk&lt;/code&gt;, &lt;code&gt;rst&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Clock; synchronous reset (the contents stay)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;req&lt;/code&gt;, &lt;code&gt;we&lt;/code&gt;, &lt;code&gt;addr&lt;/code&gt;, &lt;code&gt;wdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1, 1, IW, 8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;An access, held until &lt;code&gt;ack&lt;/code&gt;; &lt;code&gt;req&lt;/code&gt; may still be high while &lt;code&gt;ack&lt;/code&gt; is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ack&lt;/code&gt;, &lt;code&gt;rdata&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1, 8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;One-clock pulse a clock after &lt;code&gt;req&lt;/code&gt;; read data with it&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ready&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;out&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Always high: block RAM needs no power-up sequence&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="parameters"&gt;Parameters&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Parameter&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;AW&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;18&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Bytes: 2^AW (256 KB)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;IW&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;23&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The port&amp;rsquo;s address width; bits above AW are ignored&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="status"&gt;Status&lt;/h2&gt;&#10;&lt;p&gt;Sim test (AW = 10, IW = 12): 40,000 random reads and writes, through the mirror, against a byte array, each acked in one clock, with &lt;code&gt;req&lt;/code&gt; left high during the ack. In &lt;code&gt;systems/nes&lt;/code&gt; (&lt;code&gt;nes_bram&lt;/code&gt;) it holds PRG ROM on the Tang Console 138K.&lt;/p&gt;</description></item><item><title>memory/sdram</title><link>https://retro-silicon.particlesector.com/components/memory/sdram/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/memory/sdram/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/memory/sdram/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Controller for a 2M × 32 SDR SDRAM (8 MB: 4 banks, 2048 rows, 256 columns), such as the 64 Mbit chip inside the Tang Nano 20K&amp;rsquo;s GW2AR-18. The user side is a byte port. Each access opens its row and closes it with auto-precharge, so every access takes the same number of clocks except when a refresh gets there first; that fixed bound is what lets a system fit an access into a CPU cycle.&lt;/p&gt;</description></item><item><title>video/hdmi</title><link>https://retro-silicon.particlesector.com/components/video/hdmi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/video/hdmi/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/video/hdmi/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Video timing and TMDS encoding for an HDMI output in DVI mode: picture and syncs, no data islands yet (audio and InfoFrames come with the APU). Every HDMI sink accepts DVI. Each pixel clock it gives the three 10-bit symbols to send; a board&amp;rsquo;s serializers send them at ten times the pixel rate, bit 0 first. The defaults are CEA-861&amp;rsquo;s 1280x720 at 60 Hz, a 74.25 MHz pixel clock.&lt;/p&gt;</description></item><item><title>video/line-scaler</title><link>https://retro-silicon.particlesector.com/components/video/line-scaler/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/video/line-scaler/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/video/line-scaler/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;Shows a source&amp;rsquo;s frames on a display that runs on another clock, scaled up by a whole number, through a ring of &lt;code&gt;2^LINES_LOG2&lt;/code&gt; source lines in block RAM instead of a frame buffer. It&amp;rsquo;s how the NES (256x240) reaches 720p: three times its size, 768x720, in the middle of the 1280-pixel line, with 32 lines of block RAM (four of the GW2AR-18&amp;rsquo;s) rather than a whole frame.&lt;/p&gt;</description></item><item><title>video/ppu-2c02</title><link>https://retro-silicon.particlesector.com/components/video/ppu-2c02/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://retro-silicon.particlesector.com/components/video/ppu-2c02/</guid><description>&lt;!-- Generated by tools/site/site.py from retro-silicon's components/video/ppu-2c02/README.md at ac84cec; edit that README, not this file. --&gt;&#10;&lt;p&gt;The NES&amp;rsquo;s 2C02 picture processing unit (NTSC), dot-exact: 341 dots by 262 lines, with background and sprite rendering, scrolling, the palette, VBL and NMI, sprite 0 hit, and sprite overflow with its hardware bug. Its timing follows the 2C02 as &lt;a href="https://github.com/nesdev-org/MesenCE"&gt;MesenCE&lt;/a&gt; models it, so its frames match MesenCE&amp;rsquo;s pixel for pixel; that is how it&amp;rsquo;s tested.&lt;/p&gt;</description></item></channel></rss>