open-standards/wai/wai-quantum-landscape-fpga/rtl/landscape_port.v
Transaction Science c1137390e2 wai-quantum-landscape-fpga: named for what it is, with its README, provenance, workflow and first measurements
The crate is wai-quantum-landscape-fpga, beside the fabric's simulated FPGA member, which has its own
workflow. The README gives the board and part as data, what the design does and refuses, what it
takes to build, the build and load steps, the checks and the power protocol. No bitstream is
distributed: the vendor tool's licence limits a bitstream holding its components to that vendor's
devices, which Apache-2.0 does not carry, so the README gives the build and the sha256 of the
bitstream measured.

measurements/2026-11-05 holds the first version's raw power logs and the predictions committed
before them, unchanged. The workflow runs the unit tests and every check against the model of the
logic on each change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-06 03:05:19 -05:00

67 lines
2.6 KiB
Verilog

// SPDX-License-Identifier: Apache-2.0
// The job port: register reads and writes carried over the PS's EMIO GPIO lines.
//
// Why not AXI. A PS load or store to an AXI address whose PL slave is gone never completes, and it
// takes the whole board with it until someone power-cycles it. This board is shared and remote, and
// another session's reload can replace the design between two accesses. An EMIO line is a PS
// register: with the design gone a read returns junk, the ID check fails, and the job gets an
// error. The cost is speed: about 1.6 us a register access, measured.
//
// The PS offers 95 EMIO lines (banks 3, 4 and 31 bits of 5):
// emio_o[31:0] wdata (bank 3) emio_i[63:32] rdata (bank 4)
// emio_o[79:64] addr (bank 5, 15:0) emio_o[80] req (toggle) emio_o[81] we
// emio_i[82] ack (toggle) emio_i[83] busy emio_i[84] done
// busy and done are wired straight through, so polling for the end of a job takes no transaction.
//
// Handshake: the host writes wdata, then addr/we/req in one register write. The req edge crosses a
// two-flop synchroniser, so by the time it is seen addr, we and wdata have long been stable; they are
// latched then, and ack toggles once the access is done.
`timescale 1ns/1ps
`default_nettype none
module landscape_port (
input wire clk,
input wire [94:0] emio_o,
output wire [94:0] emio_i
);
(* ASYNC_REG = "TRUE" *) reg req_s1 = 1'b0, req_s2 = 1'b0;
reg req_d = 1'b0;
reg [6:0] por = 7'd0; // the PS's lines may hold anything when we are configured
wire por_done = por[6];
always @(posedge clk) begin
req_s1 <= emio_o[80];
req_s2 <= req_s1;
req_d <= req_s2;
if (!por_done) por <= por + 7'd1;
end
reg stb = 1'b0, we = 1'b0, ack = 1'b0;
reg [15:0] addr = 16'd0;
reg [31:0] wdata = 32'd0;
reg [3:0] wait_cnt = 4'd0;
wire [31:0] rdata;
wire busy, done;
always @(posedge clk) begin
stb <= 1'b0;
if (por_done && (req_s2 ^ req_d)) begin
addr <= emio_o[79:64];
we <= emio_o[81];
wdata <= emio_o[31:0];
stb <= 1'b1;
wait_cnt <= 4'd4;
end else if (wait_cnt != 4'd0) begin
wait_cnt <= wait_cnt - 4'd1;
if (wait_cnt == 4'd1) ack <= ~ack;
end
end
landscape_core core (
.clk(clk), .reg_stb(stb), .reg_we(we), .reg_addr(addr), .reg_wdata(wdata),
.reg_rdata(rdata), .busy_o(busy), .done_o(done)
);
assign emio_i = {10'd0, done, busy, ack, 18'd0, rdata, 32'd0};
endmodule
`default_nettype wire