// 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