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]>
67 lines
2.6 KiB
Verilog
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
|