Building a RISC-V system-on-chip with a hardware speech engine on a small FPGA board, using an AI agent and Lattice Prompt 1.1
This project turns a Lattice MachXO4 Development Board into a small talking machine. You type a sentence into a serial terminal, and the board speaks it through a speaker. It reports back over the UART, blinks its LEDs, shows the last character on the 7-segment display, and plays a short melody every ten minutes.
The design was not drawn by hand in the usual way. It was built by an AI agent (Claude Code), driven by a written prompt and a series of short follow-up instructions. Lattice Prompt 1.1 connects the agent to Lattice Propel and Lattice Radiant. The agent configured the IP, wrote the firmware and the Verilog, ran the builds, checked the timing, and programmed the board. An engineer reviewed and approved each step.
This article explains the tools, the board, the idea, the final architecture.LLM Prompt used see attachment !
Lattice Prompt 1.1 is a tool layer that lets an AI coding agent work directly with the Lattice FPGA toolchain. It connects to the agent through the Model Context Protocol (MCP), so the agent calls defined tool functions instead of guessing command lines.
In this project the agent used it for:
IP catalog and configuration: looking up IP versions and parameters (RISC-V SM core, system memory, UART, GPIO, AHB-Lite and APB interconnect, PLL) and configuring them in a Propel session.
Propel SoC generation: building the SoC from a script, adding a custom APB peripheral, assigning addresses and generating the design and the system environment files.
Firmware flow: compiling the C firmware for the RISC-V core, converting it into a memory image, and that image into the system memory. A built-in check confirms the firmware really ended up in the memory initialisation.
Radiant builds: synthesis, map, place and route, bitstream and JEDEC generation, run in the background.
Quality gates: timing validation in all corners, resource usage, constraint coverage and topology checks. A build only counts as done when these gates pass.
Programming: writing the JEDEC file into the on-chip flash over JTAG. A live run needs an explicit confirmation.
Design record: a running design plan (HTML) that keeps the decisions, deviations, open items and history.
The value is not only automation. The tool layer also guards against known traps. It warns when a firmware image did not reach the memory, refuses to call a build complete without a timing check, and keeps programming behind a confirmation step.
- The hardware: Lattice MachXO4 Development Board MAchXO4 eval board LFMXO4-110-EVN - link
Used in this project:
Audio: G12 drives a small speaker We use the STEMMA SPEAKER & AUDIO AMPLIFIER from Adafruit
The PWM carrier is 32 kHz, well above hearing, and the speaker and the amplifier filter it out.
- The idea: one prompt, one SoC, one voice The starting point was a written prompt that described the product, not the implementation:
- Receive ASCII text over the UART and speak it on a PWM pin.
- Answer with the status messages
TTS OK.,TTS EXEandTTS RDY. - Use the board LEDs and the 7-segment display for status.
- Keep the given pin assignment unchanged.
The project ran in two phases:
*1.*The speech engine. A compact text-to-speech engine was developed and tuned by ear on the board. It has a tiny custom processor (TTSCPU) for the letter-to-sound rules and the prosody, and a formant synthesizer in hardware.
*2.*The SoC. The prompt asked for a system built with Lattice Propel around a soft RISC-V processor. The agent first tried a RISC-V MC with a separate hardware multiplier. After review the final architecture became:
A RISC-V SM core running C firmware from 16 KB of on-chip memory.The speech engine packaged as a memory-mapped APB peripheral: a custom Propel IP with its own driver (tts.h / tts.c).
Talking to the board
Plain text is spoken. A few characters control the timing, and tones can be mixed in:
Firmware flow (RISC-V): the firmware starts up and sends TTS OK., then speaks a boot phrase. After that, each character received on the UART is passed to the TTS block. When a line is complete, it sends TTS EXE, starts the speech, waits until it is done and sends TTS RDY. Button presses and the ten-minute jingle use the same driver calls. main() contains no direct register access.
Each release follows the same pipeline, and the agent runs all of it:
-
Change the source: firmware, RTL or the engine ROM.
-
Run the checks that fit the change:
- If the speech engine changed: instruction-level simulation, bit-exact against a Python reference model, and RTL simulation in Questa.
- If only the RISC-V firmware changed: no simulation, because the hardware is unchanged.
-
Compile the firmware, convert it to a memory image and load it into the Propel system memory. Confirm that the image is really in the generated RTL
-
Generate the SoC in Propel and run the Radiant build.
-
Pass the gates: timing in all corners, resources and constraint coverage.
-
Create a release folder with the bitstream, the JEDEC file, the programming chain file, a README with SHA256 hashes and a sources archive.
7.Update the HTML design record and the Word design report.
- Program the board, only after the engineer approves.
Final results (SM_v1.5): 0 failing timing endpoints.
- Fmax 27.0 MHz against a 24 MHz target.
- 2, 057 registers (20%),
- 6, 077 LUT4 (65%),
- 44 of 48 block RAMs (92%).
- The firmware uses 9.3 KB of the 16 KB memory.
Licensing: the first bitstream failed on an IP license check. The agent tracked down which core triggered it. Evaluation-bitstream mode turned out not to be available for this device, and the issue was fixed with a licens
Tool upgrade: the move to Propel and Radiant 2026.1.1 forced newer IP versions. The new RISC-V core enabled its JTAG debug port by default, and that port clashed with the board pin D10. Turning off debug fixed placement.
Programming from the command line: the first attempts drove every output pin low during programming, and all LEDs and segments lit up. The cause was a hand-written chain file that lacked the "I/O vector" setting, which keeps the pins tri-stated. Using the chain file saved by the Radiant Programmer GUI fixed it for good. The agent stored this as a permanent rule.
Engineering judgement still matters: the engineer steered the key choices. Examples are dropping the external multiplier, moving the speech engine into a dedicated APB peripheral, giving it a proper driver, and skipping full simulations for firmware-only changes.
Get a Lattice MachXO4 Development Board, Lattice Radiant and Propel 2026.1.1, and an AI coding agent with Lattice Prompt 1.1 connected.
- Write a prompt that describes what the board must do: the interfaces, the messages, the pins. Leave outhow .
- Let the agent propose an architecture, and challenge it. In this project the best design came from that discussion.
- Insist on gates: timing validation, a firmware-in-memory check, a release folder with hashes, and a confirmation before programming.
- Add features one small step at a time. Each step should be a short instruction and end in a numbered release
- Connect a speaker through a small transistor amplifier to the PWM pin, open a terminal at 19200 baud and type:
Lattice? Mag X-O for is running!
Tools: Lattice Propel 2026.1.1, Lattice Radiant 2026.1.1 (LSE), Questa 2026.1.1, Lattice Prompt 1.1, Claude Code. Device: MachXO4 LFMXO4-110HC-6BBG484C.
[Read more](<javascript:void(0)>)