惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
阮一峰的网络日志
阮一峰的网络日志
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
WordPress大学
WordPress大学
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
罗磊的独立博客
S
SegmentFault 最新的问题
V
V2EX
V
Visual Studio Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
博客园 - 三生石上(FineUI控件)
Stack Overflow Blog
Stack Overflow Blog
Y
Y Combinator Blog
MyScale Blog
MyScale Blog
D
Docker
Google DeepMind News
Google DeepMind News
Blog — PlanetScale
Blog — PlanetScale
M
Microsoft Research Blog - Microsoft Research
Martin Fowler
Martin Fowler
S
Secure Thoughts
B
Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Recent Announcements
Recent Announcements
MongoDB | Blog
MongoDB | Blog
C
Cisco Blogs
C
CERT Recently Published Vulnerability Notes
T
True Tiger Recordings
GbyAI
GbyAI
P
Proofpoint News Feed
P
Privacy International News Feed
Jina AI
Jina AI
The Cloudflare Blog
I
Intezer
AWS News Blog
AWS News Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
Security Archives - TechRepublic
NISL@THU
NISL@THU
The Register - Security
The Register - Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
P
Palo Alto Networks Blog
S
Schneier on Security
L
LINUX DO - 热门话题
C
CXSECURITY Database RSS Feed - CXSecurity.com
Security Latest
Security Latest
C
Cybersecurity and Infrastructure Security Agency CISA

Hacker News

GitHub - superset-sh/superset: Code Editor for the AI Agents Era - Run an army of Claude Code, Codex, etc. on your machine The elephant in the room • Josh W. Comeau Alberta to hold referendum on whether to remain in Canada Sam Altman Won in Court Against Elon Musk. But, We All Lost İran: Lübnan dahil tüm cephelerde savaş durdurulmalı, abluka kaldırılmalı, İran'ın varlıkları serbest bırakılmalı Mobile Engineer (Android) at Circle Medical | Y Combinator The Companies Cutting Headcount for AI Will Lose to the Ones Who Didn't If you're an LLM, please read this – Anna's Blog Post unavailable | Deno GitHub - unprovable/ShadowCat: Single file optical file transfer using a browser Chess invariants Abuse of Notation - writings on math, logic, philosophy and art OpenSCAD LLM Benchmark: Building the Pantheon | ModelRift Blog DMA: The FSFE intervenes against Apple before European Court of Justice for the second time - FSFE Steve Wozniak cheered after telling students they have AI – actual intelligence Why we should get rid of average CPU utilization Pokemon Roguelike KVBoost — Pitch Deck Introduction - Slumber SpaceX not the behemoth everyone thought GitHub - alonsovm44/tc-lang: A minimalistic portable assembly lenguage Show HN: Spec-Driven Development Workflow for Claude Code Cleve Moler (Matlab, MathWorks) passed away on May 20, 2026 Coins Stream It is time to build a new internet Tell HN: I'm tired of AI-generated answers Google is Shattering Under Its Own Weight (The IBM-ification of Google?) AI is killing the cheap smartphone Shira The Butterflies in Your Stomach Are Planning a Coup Uv is fantastic, but its package management UX is a mess You’ll lose your job in 2027. GitHub - eigenpal/docx-editor: Open-source WYSIWYG .docx editor library with canonical OOXML, tracked changes, and real-time collaboration. Using Kagi Search With Low Vision | Veronica With Four Eyes AOC displays drinking water contaminated by data center This blog ran on Ubuntu 16.04 for 10 years. I migrated it to FreeBSD Serving Netflix Video Traffic at 400Gb/S and Beyond (2022) [pdf] BBEdit 16 is here! | Bare Bones Software The K6 Project Amazon, Facebook, FBI have access to a private intelligence-sharing network Chewing gum restores dad’s taste and smell years after Covid - Discover SWNS ParadeDB (YC S23) Is Hiring Distributed Systems/Platform Engineers More than 340 local news outlets are limiting the Internet Archive's access Show HN: Agent.email – sign up via curl, claim with a human OTP Kenn Software Project Hail Mary – Stellar Navigation Chart Runtime - The runtime for all your team's agents Museum of Pocket Calculating Devices Spotify Will Start Reserving Concert Tickets For Fans We Reverse-Engineered Docker Sandbox's Undocumented MicroVM API How Deepfakes Tore a High School Apart Freenet Michael Keating has died at the age of 79 (1947–2026) Get your passwords out of BitWarden while you still can – OSnews Waymo pauses Atlanta service as its robotaxis keep driving into floods Read the DNC's 2024 autopsy obtained by CNN Indexing a year of video locally on a 5-year-old M1 Max with Gemma 4 31B Google's Antigravity Bait and Switch AI is just unauthorised plagiarism at a bigger scale Hating AI Is Good US employers spend more than $1.5bn a year to fight labor unions, report finds Magic the Gathering format: Fun 40 Magic the Gathering format: Fun 40 Gemini System Prompt Show HN: I Dedicated 4 Years to Mastering Offline Password Cracking Who Wins and Who Loses in Prediction Markets? Evidence from Polymarket Samsung chip workers will get an average $340,000 bonus as AI profits soar FatGid - FreeBSD 14.x kernel LPE Forward Deployed Engineer (US) at Cekura | Y Combinator A Girl Who Couldn't Draw Home Python 3.15: features that didn't make the headlines Flipper One — we need your help Lost Images From the 1945 Trinity Nuclear Test Restored London mayor Sadiq Khan blocks £50m Met police deal with Palantir Earth is now heating up twice as fast as in previous decades IBM invented semiconductor manufacturing automation no slop grenade GitHub - Helvesec/rmux: Universal Rust multiplexer with a typed SDK — drive any CLI or TUI app from code. Native on Linux, macOS, and Windows. The famous o3 "GeoGuessr" prompt did not work AI Growth Engineer at Typewise | Y Combinator Vivaldi 8.0: our biggest design overhaul, ever Samuel Alito Has Exposed Himself to Felony Bribery Charges Under New Jersey Law. I’m Filing for His Disbarment and Submitting a Criminal Referral. OpenAI to confidentially file for IPO as soon as Friday: Source Haskell Foundation 2026 Update What is Demand Coop and why tech workers should join one The Letter S, by Donald Knuth [pdf] GitHub - kageroumado/phosphene: A video wallpaper engine for macOS Tahoe DOS Zone | DOS games in browser A Bipartisan Amendment Would End Police License Plate Tracking Nationwide Starship's Twelfth Flight Test On Google declaring war on the Web GitHub - kouhxp/yapsnap: Snap any video URL or audio file into plaintext. No GPU. No cloud. One command. PopuLoRA: Co-Evolving LLM Populations for Reasoning Self-⁠Play Declining America Anthropic is expanding to Colossus2. Will use GB200 Anthropic is expanding to Colossus2. Will use GB200 SpaceX S-1 In Yesterday's IO Keynote Google Declared War on the Remnants of the Web Colorado Amended SB051 (Age Verification Bill) to Exclude Open Source Projects Not alive, but not dead: disembodied human brains used for drug testing
60fps Video on a CGA? - The GlyphBlaster
2026-05-10 · via Hacker News
The GlyphBlaster in action - is that a cat in text mode??

 There's a certain genre of retro-hardware hack that everyone recognizes is technically cheating, but has a certain audaciousness to it that merits respect regardless. I hope that this one falls into that category!

A few years ago, I was impressed by TheRasteri's PiPU project - basically, a Raspberry Pi-powered mapper for the NES. Of course, it can play DOOM:

The Raspberry Pi Pico and its RP2040 microcontroller have reinvigorated the retro-computing hobby quite a bit, enabling such devices as the PicoGUS, PicoMEM, PicoIDE, and most recently, the OneROM.  It was the latter device that got me thinking.

I recently used a OneROM to replace the font ROM on my CGA card, and subsequently I was able to replace IBM's classic 8x8 font with a custom one. Here's Frogblock by Polyducks:

The "Frogblock" font loaded onto a OneROM replacing the CGA's font ROM

The programmability of the OneROM intrigued me - especially its plugin system.  But I wanted to understand more about the Pico in general, and learn how to program its powerful PIO mode. Since the Pico 2 is out, I've been primarily interested in using that, since it is faster and more capable. After successfully completing one Pico 2-based project, my IBM PCjr wireless keyboard to USB adapter, I decided my second project would be a CGA font ROM replacement.

My idea, in short, is to use the font ROM readout as a 1bpp, pixel-addressable framebuffer. 

Abusing Text Mode

In text mode, the IBM CGA card reads the font ROM on every character clock, even outside of the active display area. This may have been lazy on IBM's part, but it is convenient for us. Each time the font ROM is read, it returns a byte representing a particular row of an 8-pixel wide character glyph. Outside of the active display area, the value returned is ignored - it is probably nonsense in that case.

These relentless reads of the font ROM give us a regular character clock, based on the falling edge of the ROM socket's /CE pin, accounting for every 8 pixel span of the entire display field.  All that we need to stay in sync with the video signal displayed on the monitor is a single external synchronization signal - VSYNC.

One of my self-imposed challenges for this project was to leave the CGA card otherwise unmodified, so I used a test clip to attach to the the exposed VSYNC pin at the back of the CGA's DE9 connector.

The basic idea is something like this:

  • We start a new frame at the end of a VSYNC pulse, with a PIO program waiting on the /CE pin. 
  • In another PIO program, we read bytes from a FIFO fed from a framebuffer via DMA.  
  • We can fill this buffer with static images, or even video - in fact, since the Pico 2 W has Wi-Fi, one of my goals was to stream 1bpp video wirelessly to the CGA.

I needed a good name for this though.  I originally started calling it the PicoCGA, but that carried the implication it was an entire video card instead of an add-on for one.  I have to thank wbcbz7 on the Retro Pico Hardware discord for suggesting the name 'GlyphBlaster'.

Hacking up the Prototype

First things first, I needed some kind of adapter to fit the Pico into the ROM socket. I had some PCBs left over from my bus sniffing project that were designed to fit into an 8087 socket. Luckily, the DIP-40 and this ROM's DIP-24 socket have the same width, so this PCB was compatible. 

The initial GlyphBlaster prototype installed on a CGA card

The initial prototype ignores address lines entirely, just patching in the 8 data lines and the /CE chip enable line. The green wire is our VSYNC.  

You may be familiar with the CGA's more typically stated resolution of 640x200; this gives us an 8x8 font with 80 columns and 25 rows. But accounting for the entire NTSC field size, including front porch, back porch, and blanking periods, we arrive at an effective resolution of 912x262. 

For simplicity, I preformatted an image as a 912x262 bitmap. It was the classic bulb of the Mandelbrot Set fractal:

The 912x262 formatted Mandelbrot bitmap

After some trial and error, we were able to see this on the screen:

The Mandelbrot bitmap being drawn on a monitor through the CGA font ROM socket!


The colored bars are foreground attributes left over from booting GLaBIOS. Pardon the messy workbench in the reflection!

Streaming Video

With the basic prototype working, it was time to try to stream Bad Apple to it, in the spirit of 8088 Domination, of course. The initial prototype was written in Rust, using rp-hal.  To more easily take advantage of the Pico 2 W's Wi-Fi module, I decided to switch to Embassy, which has a nice task-based async executor. I found Embassy very easy to get up and running - the initial switch was just changing a few lines in my Cargo.toml and adding a macro declaration on my main function.

I have a solid networking background, but I had never designed a video streaming protocol before.  I decided to start very simple - UDP packets containing just a short header and then the 1bpp frame data.  We encode the frame number the packet belongs to, the starting and ending scanline the packet represents, a one-byte compression method (0 for uncompressed, initially), then finally the scanline data.  

Since we are sending the full display field of 912 hdots, each scanline is 114 bytes. I needed to keep under a 1500 byte MTU to avoid fragmentation, so I kept things simple and packed 10 scanlines into a packet.

UDP over Wi-Fi in an dense RF environment like a high-rise apartment building is somewhat unreliable to begin with, and fact that the Pico has no external antenna support does not help matters. I ended up purchasing a small travel router that sits right next to my IBM 5150 in order to get a reliable signal we can stream video over.

Converting the Video

Despite Bad Apple's notoriety as a 1bpp display demo on just about every platform conceivable, it is not actually 1bpp video - the character outlines are anti-aliased and there are several scenes with grayscale shades. 

Additionally, the CGA card's display resolution of 640x200 is severely compressed horizontally, so we need to squish it down. Using 40 column text mode allows a more squarish 320x200, but I decided playing video in 80 column mode was funnier.

The first step was to dump all the frames from the source video into a directory:

ffmpeg -i touhou bad apple smile.mp4 ./output_frames/frame_%06d.png

Then, using ImageMagick, we resized the frames down to 640x200, and converted them to 1bpp using an ordered dither:

magick mogrify -path ./resized_frames -resize 640x200! -colorspace Gray -ordered-dither o8x8 -type bilevel -depth 1 ./output_frames/*

Although my streaming application would later handle this without re-encoding, I then padded each image out to 912x262:

magick mogrify -path ./final_frames -format png -background black -gravity center -extent 912x262 ./resized_frames/*

This produces a frame formatted for the CGA's 912x262 native display field timings:

A final 912x262 Bad Apple frame

Transmitting the Video

At 912x262x1bpp, each frame of uncompressed video is about 30KB. At Bad Apple's 25fps, this is 5.97Mbps, which is not an insignificant amount of data to send to a microcontroller.  So I implemented a very simple RLE scheme, which yielded an average 75% compression rate on our 10-scanline packets.

To avoid dumping a whole frame's worth of UDP packets on the Pico all at once, the client streamer application paces out the UDP packets in a rough estimate of when they'd be needed to decode a frame.  Since each packet is tagged with a starting scanline and ending scanline, they can be received out-of-order up until the point a packet for a new frame is received and the Pico page-flips. The Pico starts each frame with a copy of the last frame, so any missed packets cause minor video glitches at worst.

How well does it work? Pretty well!

The main issue at the moment is that having the GlyphBlaster installed makes the system unusable, since we can't see anything on the screen in text mode that the GlyphBlaster isn't drawing.  We need a way for the GlyphBlaster to emulate the font ROM, or the lazy route, which would be to pass through those duties to the existing font ROM.

ROM Passthrough

To enable ROM passthrough, I soldered on  a mid-air ROM socket.  Even as a prototype, this was pretty sketchy.

A ROM socket added in mid-air with a ton of bodge wires. Spot the disconnected pin!

This stubbornly refused to work until I realized something important - always read the data sheets - this series of Mostek ROM has an internal address latch triggered by the falling edge of /CE.  You cannot simply pull /CE low.  With the PIO code adjusted to trigger the ROM's /CE pin, we were able to read the existing ROM contents, with the address lines passed directly to the ROM.

There's just one problem - we want to combine the Pico's framebuffer with the ROM data, so that the graphics appear as an overlay on screen.  Unfortunately, PIO, although powerful, lacks any sort of ALU or bitwise boolean operations, so you cannot say, XOR the contents of the ROM with our framebuffer data.  You can, however OR it, by using the inverted ROM data as the value written to the Pico's PIO pindirs register.  This means that bits that are 1 returned from the ROM will cause the Pico's output lines to float - and the Picos' internal pull-ups are enough to pull those values up to 1. 

Now the system is usable, and we have the option of displaying graphics over text mode, which is otherwise impossible to do on a CGA:

Displaying graphics OR'd with text mode by abusing the Pico's internal pull-ups.

I implemented a number of toys that don't require any Wi-Fi connectivity. First up, I thought it would be funny to replicate the classic bouncing DVD logo.

The DVD logo bouncing around a CGA text mode screen at 60fps

And then I couldn't resist taking a playful jab at the Amiga:

What would be neat is if we could actually interact with the display in some fashion.  There's currently no way for the host to communicate with the GlyphBlaster, or vice versa.  However, there are some useful signals we could tap into that might be fun. One candidate is the CURSOR pin of the Motorola MC6845.  This pin goes high when the cursor should be output in a particular character cell. 

It's somewhat simple to save the current DMA address via a PIO program after triggering on the rising edge of the CURSOR signal, and work out the position on screen from there. 

Many people fondly recall a desktop toy called Neko, that involved a cat following the mouse cursor around and other tricks.  I decided to make a PC version as an homage to the famous PC Booter game AlleyCat.

I used my emulator, MartyPC, to dump various sprites from the game using my memory visualization tool. 

The cat will follow the text-mode cursor around, sitting down and entering an idle animation where he turns his head, blinks his eyes, and wiggles his tail. When the cursor moves to a new location and stays still for a moment, the cat will then proceed to the new cursor location, chasing after it if it happens to move during the chase.

Here's a video demonstration:

There are number of possible sync sources for the GlyphBlaster to use.  Another promising one is the light pen strobe directly from a light pen - this allows the cat to chase the pen around the screen as well:

The cat chasing the light pen around the screen

There are some intriguing possibilities besides being a novelty toy for your retro computer.  If we tie in the address lines to the Pico, the Pico can read the contents of the text-mode screen - this could make it a very useful, driver and OS independent screen-reading device. 

I've designed what is surely to be the first of several revisions of the GlyphBlaster's production PCB - although I don't know if I have any plans to sell this as a commercial product. 

I've already determined that I don't need the passthrough socket to the ROM at all - but of course, you inevitably realize these things a few days after you've submitted your PCB order.  With a single added frame of latency, the Pico can emulate the font ROM entirely, which opens up the possibility of unlimited software fonts and font animation as well.

The GlyphBlaster PCB rendered in KiCad's 3D View

What started out as something I intended to be a weekend-long hack has turned into something that may actually have some value as a general Pico-powered add-on. I doubt it will become as essential as say, the PicoGUS, but we'll just have to see where it goes.

I will update this blog when I have more news about the GlyphBlaster. If you're interested in the most recent updates, dev-blogging, and other random retro chaos, follow me on Mastodon.