STEP: 1574 / Date: 2026-08-30 / Test: 69/69 PASS / Type: STEP 1570 spec を 実 artifact 生成器に格上げ (Verilog + .cst + testbench skeleton)
❶ ConnectorSpec → Verilog + Gowin .cst + testbench の 三点セット skeleton emitter。 STEP 1570 で定義した spec 5 軸 (lines / encoding / clock / power / physical) + 5 layer roles (receiver / decoder / oscillator / arbiter / output) を Verilog port list + 層別 sub-module stub に mapping。
❷ Deterministic — 同じ (spec, board profile) は 常に 同じ text を返す (diff 可能、 CI 化 前提)。 Tang Nano 9K の 27 MHz clk を default 想定、 board profile で pin 番号を substitute。
❸ Skeleton であって完成品ではない — 各 layer に TODO marker + synthesizable pass-through default で「そのまま合成通る空箱」。 実 protocol (JJY pulse 幅解析 / Manchester transition 検出) は 生成器が意図的に refuse、 手書き or Phase C spike で埋める。
STEP 1570 = 「入力条件を定式化する枠」、 本 STEP 1574 = 「入力から生成物を吐く一段目」。 生成物は skeleton だが、 これで「schema 保持者」 から 「生成器の入口」に一歩進む。
import {
RADIO_CLOCK_SPEC,
generateArtifacts,
type BoardProfile,
} from 'src/fpga/connector-generator';
const board: BoardProfile = {
name: 'tang-nano-9k',
ioType: 'LVCMOS33',
clkFrequencyMHz: 27,
pinAssignments: { clk: '52', rst_n: '4', rx_line_0: '25', output_pulse: '10' },
};
const bundle = generateArtifacts(RADIO_CLOCK_SPEC, board);
// bundle.verilog — top module + 5 layer stubs
// bundle.cst — .cst with real pins where mapped, __PIN_TBD__ elsewhere
// bundle.testbench — smoke testbench (clk + rst + minimal stimulus)
// bundle.files — { 'connector_radio_clock_jjy.v': ..., '...cst': ..., '..._tb.v': ... }
// bundle.generatorNotes — honest scope notes (4 lines)
| Role | Ports 追加 | 備考 |
|---|---|---|
| (常時) | clk, rst_n | 27 MHz + active-low reset |
receiver (single N 本) | rx_line_0..rx_line_{N-1} | lines.count に応じて 1..4 本 |
receiver (differential-pair M pair) | rx_diff_p_0..M-1, rx_diff_n_0..M-1 | LVDS-like 想定 |
decoder | frame_valid, parity_ok, decoded_frame[63:0] | frame 幅 64 bit fixed (v0.1) |
arbiter | sync_locked, using_local_only | 受信成功 / 自走 fallback |
output | output_pulse | 1 line pulse driver |
connector_radio_clock_jjy.v)// ═══════════════════════════════════════════════════════════════
// connector_radio_clock_jjy.v — auto-generated skeleton (STEP 1574 HDL generator)
// Spec: 電波時計型 (JJY pulse-width, self+sync) (id=radio-clock-jjy)
// Roles: receiver, decoder, oscillator, arbiter, output
// Encoding=pulse-width / Clock=self-plus-sync / Power=none
// ───────────────────────────────────────────────────────────────
// This is a STRUCTURAL SKELETON, not a complete implementation.
// Every layer sub-module contains a TODO marker; the defaults are
// synthesizable pass-throughs so the top compiles as-is.
// Actual protocol logic must be filled in by hand or Phase C spike.
// ═══════════════════════════════════════════════════════════════
`timescale 1ns / 1ps
module connector_radio_clock_jjy (
input wire clk,
input wire rst_n,
input wire rx_line_0,
output wire frame_valid,
output wire parity_ok,
output wire [63:0] decoded_frame,
output wire sync_locked,
output wire using_local_only,
output wire output_pulse
);
// ── receiver layer ─────────────────────────────────────────────
// TODO(receiver): implement physical signal capture per spec.encoding=pulse-width.
// For pulse-width (JJY): sample the receive line at >=10x symbol rate, output width in ticks.
// This stub wires raw_bit to a default source for downstream wiring only.
wire raw_bit;
wire raw_valid;
assign raw_bit = rx_line_0;
assign raw_valid = 1'b1;
// ── decoder layer ──────────────────────────────────────────────
// TODO(decoder): implement pulse-width → frame parser.
// Frame: 60 秒 (1 bit/sec × 60)、 minute marker で 同期
// Sync marker: true
// Parity: even
// This stub emits zero frame + parity_ok=1 as pass-through default.
reg [63:0] decoded_frame_r = 64'h0;
reg frame_valid_r = 1'b0;
reg parity_ok_r = 1'b1;
assign decoded_frame = decoded_frame_r;
assign frame_valid = frame_valid_r;
assign parity_ok = parity_ok_r;
// ── oscillator layer ───────────────────────────────────────────
// TODO(oscillator): implement NCO / prescaler for self-running clock.
// Clock domains declared: 2
// For 27 MHz → 1 Hz on Tang Nano 9K: divide by 27_000_000 or use NCO.
// This stub uses a simple counter to produce local_tick at ~1 Hz assuming 27 MHz clk.
reg [24:0] local_counter = 25'd0;
reg local_tick = 1'b0;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
local_counter <= 25'd0;
local_tick <= 1'b0;
end else if (local_counter == 25'd27_000_000 - 1) begin
local_counter <= 25'd0;
local_tick <= ~local_tick;
end else begin
local_counter <= local_counter + 25'd1;
end
end
// ── arbiter layer ──────────────────────────────────────────────
// TODO(arbiter): implement "load from decoder if frame_valid & parity_ok, else
// continue on oscillator". Timeout: fall back to local after N missed frames.
// Clock strategy: self-plus-sync
// This stub asserts sync_locked=parity_ok when a frame arrives; using_local_only
// is the complement — real design should latch these across seconds.
assign sync_locked = frame_valid & parity_ok;
assign using_local_only = ~sync_locked;
// ── output layer ───────────────────────────────────────────────
// TODO(output): implement downstream driver. For step-motor: 1 pulse per second.
// This stub drives output_pulse from local_tick as a placeholder.
assign output_pulse = local_tick;
endmodule
connector_radio_clock_jjy.cst) — Tang Nano 9K profile// ═══════════════════════════════════════════════════════════════ // Gowin .cst pin constraint skeleton (STEP 1574 HDL generator) // Spec: 電波時計型 (JJY pulse-width, self+sync) (id=radio-clock-jjy) // Board profile: tang-nano-9k // Default IO_TYPE: LVCMOS33 // Assumed clk: 27 MHz (create_clock -period 37.037 ns) // ─────────────────────────────────────────────────────────────── // PLACEHOLDERS (__PIN_TBD__) MUST be replaced with real pin numbers // from the target board pinout before synthesis. Using wrong pins // can drive contention on physical nets. // ═══════════════════════════════════════════════════════════════ IO_LOC "clk" 52; IO_PORT "clk" IO_TYPE=LVCMOS33; IO_LOC "rst_n" 4; IO_PORT "rst_n" IO_TYPE=LVCMOS33; IO_LOC "rx_line_0" 25; IO_PORT "rx_line_0" IO_TYPE=LVCMOS33; IO_LOC "frame_valid" __PIN_TBD__; IO_PORT "frame_valid" IO_TYPE=LVCMOS33; IO_LOC "parity_ok" __PIN_TBD__; IO_PORT "parity_ok" IO_TYPE=LVCMOS33; IO_LOC "decoded_frame" __PIN_TBD__; IO_PORT "decoded_frame" IO_TYPE=LVCMOS33; IO_LOC "sync_locked" __PIN_TBD__; IO_PORT "sync_locked" IO_TYPE=LVCMOS33; IO_LOC "using_local_only" __PIN_TBD__; IO_PORT "using_local_only" IO_TYPE=LVCMOS33; IO_LOC "output_pulse" 10; IO_PORT "output_pulse" IO_TYPE=LVCMOS33;
connector_radio_clock_jjy_tb.v)// ═══════════════════════════════════════════════════════════════
// connector_radio_clock_jjy_tb.v — auto-generated testbench skeleton (STEP 1574)
// ───────────────────────────────────────────────────────────────
// Verifies: clock generation, reset propagation, module instantiation.
// Does NOT verify protocol correctness — that is Phase C spike work.
// ═══════════════════════════════════════════════════════════════
`timescale 1ns / 1ps
module connector_radio_clock_jjy_tb;
reg clk = 1'b0;
reg rst_n = 1'b0;
reg rx_line_0 = 1'b0;
wire frame_valid;
wire parity_ok;
wire [63:0] decoded_frame;
wire sync_locked;
wire using_local_only;
wire output_pulse;
// Clock: 27 MHz, period 37.037 ns
always #(18.519) clk = ~clk;
// DUT instantiation
connector_radio_clock_jjy dut (
.clk(clk), .rst_n(rst_n),
.rx_line_0(rx_line_0),
.frame_valid(frame_valid), .parity_ok(parity_ok), .decoded_frame(decoded_frame),
.sync_locked(sync_locked), .using_local_only(using_local_only),
.output_pulse(output_pulse)
);
initial begin
// Reset pulse (10 clock cycles low)
#(370.370) rst_n = 1'b1;
// Drive rx_line_0 with a placeholder pulse pattern (0 → 1 → 0)
#(3703.704) rx_line_0 = 1'b1;
#(3703.704) rx_line_0 = 1'b0;
// Run for a short simulated time then finish
#(37037.037) $finish;
end
initial begin
$dumpfile("connector_radio_clock_jjy_tb.vcd");
$dumpvars(0, connector_radio_clock_jjy_tb);
end
endmodule
__PIN_TBD__ は 該 board の pin 番号に置き換え必須。 wrong pin は physical net contention (物理的短絡) を起こす risk あり — 合成前に pin 表を突合せよ。connector_generate_hdl)src/fpga/connector-generator/generator/verilog.tssrc/fpga/connector-generator/generator/cst.tssrc/fpga/connector-generator/generator/testbench.tssrc/fpga/connector-generator/generator/index.ts (generateArtifacts())test/step1574-hardware-connector-hdl-gen-test.ts (69/69 PASS)scripts/generate-step1574-samples.ts (site page 生成再現用)