Working CPP way of writing data
This commit is contained in:
@@ -21,7 +21,7 @@ device = xc6slx9
|
|||||||
package = tqg144
|
package = tqg144
|
||||||
speedgrade = -2
|
speedgrade = -2
|
||||||
toplevel = top_generic
|
toplevel = top_generic
|
||||||
xst_opts = -vlgincdir rtl/util
|
xst_opts = -vlgincdir rtl/util -keep_hierarchy yes
|
||||||
files_verilog = rtl/util/conv.vh
|
files_verilog = rtl/util/conv.vh
|
||||||
rtl/toplevel/top_generic.v
|
rtl/toplevel/top_generic.v
|
||||||
rtl/core/nco_q15.v
|
rtl/core/nco_q15.v
|
||||||
@@ -59,7 +59,8 @@ files_verilog = rtl/util/conv.vh
|
|||||||
rtl/serv/serving.v
|
rtl/serv/serving.v
|
||||||
rtl/wb/wb_gpio.v
|
rtl/wb/wb_gpio.v
|
||||||
rtl/wb/wb_gpio_banks.v
|
rtl/wb/wb_gpio_banks.v
|
||||||
rtl/core/soclet.v
|
rtl/arch/spartan-6/jtag_if.v
|
||||||
|
rtl/core/mcu.v
|
||||||
files_con = boards/mimas_v1/constraints.ucf
|
files_con = boards/mimas_v1/constraints.ucf
|
||||||
files_other = rtl/util/rc_alpha_q15.vh
|
files_other = rtl/util/rc_alpha_q15.vh
|
||||||
rtl/util/clog2.vh
|
rtl/util/clog2.vh
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ module jtag_if #(
|
|||||||
.SHIFT(o_shift),
|
.SHIFT(o_shift),
|
||||||
.TCK(o_tck),
|
.TCK(o_tck),
|
||||||
.TDI(o_tdi),
|
.TDI(o_tdi),
|
||||||
|
.TDO(i_tdo),
|
||||||
.UPDATE(o_update)
|
.UPDATE(o_update)
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
414
rtl/core/mcu.v
Normal file
414
rtl/core/mcu.v
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
`timescale 1ns/1ps
|
||||||
|
`include "../util/clog2.vh"
|
||||||
|
|
||||||
|
module mcu #(
|
||||||
|
parameter memfile = "",
|
||||||
|
parameter memsize = 8192,
|
||||||
|
parameter sim = 1'b0
|
||||||
|
)(
|
||||||
|
input wire i_clk,
|
||||||
|
input wire i_rst,
|
||||||
|
|
||||||
|
input wire [31:0] i_GPI_A,
|
||||||
|
input wire [31:0] i_GPI_B,
|
||||||
|
input wire [31:0] i_GPI_C,
|
||||||
|
input wire [31:0] i_GPI_D,
|
||||||
|
output wire [31:0] o_GPO_A,
|
||||||
|
output wire [31:0] o_GPO_B,
|
||||||
|
output wire [31:0] o_GPO_C,
|
||||||
|
output wire [31:0] o_GPO_D
|
||||||
|
);
|
||||||
|
localparam WITH_CSR = 1;
|
||||||
|
localparam regs = 32+WITH_CSR*4;
|
||||||
|
localparam rf_width = 8;
|
||||||
|
|
||||||
|
wire rst;
|
||||||
|
wire rst_mem_reason;
|
||||||
|
wire timer_irq;
|
||||||
|
assign rst = i_rst | rst_mem_reason;
|
||||||
|
assign timer_irq = 1'b0;
|
||||||
|
|
||||||
|
// Busses
|
||||||
|
// CPU->memory
|
||||||
|
wire [31:0] wb_mem_adr;
|
||||||
|
wire [31:0] wb_mem_dat;
|
||||||
|
wire [3:0] wb_mem_sel;
|
||||||
|
wire wb_mem_we;
|
||||||
|
wire wb_mem_stb;
|
||||||
|
wire [31:0] wb_mem_rdt;
|
||||||
|
wire wb_mem_ack;
|
||||||
|
// CPU->peripherals
|
||||||
|
wire [31:0] wb_ext_adr;
|
||||||
|
wire [31:0] wb_ext_dat;
|
||||||
|
wire [3:0] wb_ext_sel;
|
||||||
|
wire wb_ext_we;
|
||||||
|
wire wb_ext_stb;
|
||||||
|
wire [31:0] wb_ext_rdt;
|
||||||
|
wire wb_ext_ack;
|
||||||
|
// CPU->RF
|
||||||
|
wire [6+WITH_CSR:0] rf_waddr;
|
||||||
|
wire [rf_width-1:0] rf_wdata;
|
||||||
|
wire rf_wen;
|
||||||
|
wire [6+WITH_CSR:0] rf_raddr;
|
||||||
|
wire [rf_width-1:0] rf_rdata;
|
||||||
|
wire rf_ren;
|
||||||
|
// combined RF and mem bus to actual RAM
|
||||||
|
wire [`CLOG2(memsize)-1:0] sram_waddr;
|
||||||
|
wire [rf_width-1:0] sram_wdata;
|
||||||
|
wire sram_wen;
|
||||||
|
wire [`CLOG2(memsize)-1:0] sram_raddr;
|
||||||
|
wire [rf_width-1:0] sram_rdata;
|
||||||
|
wire sram_ren;
|
||||||
|
|
||||||
|
// GPIO
|
||||||
|
wire [4*32-1:0] GPO;
|
||||||
|
wire [4*32-1:0] GPI;
|
||||||
|
assign o_GPO_A = GPO[32*1-1:32*0];
|
||||||
|
assign o_GPO_B = GPO[32*2-1:32*1];
|
||||||
|
assign o_GPO_C = GPO[32*3-1:32*2];
|
||||||
|
assign o_GPO_D = GPO[32*4-1:32*3];
|
||||||
|
assign GPI[32*1-1:32*0] = i_GPI_A;
|
||||||
|
assign GPI[32*2-1:32*1] = i_GPI_B;
|
||||||
|
assign GPI[32*3-1:32*2] = i_GPI_C;
|
||||||
|
assign GPI[32*4-1:32*3] = i_GPI_D;
|
||||||
|
|
||||||
|
// SERV core with mux splitting dbus into mem and ext and
|
||||||
|
// arbiter combining mem and ibus
|
||||||
|
// separate rst line to let other hardware keep core under reset
|
||||||
|
servile #(
|
||||||
|
.reset_pc(32'h0000_0000),
|
||||||
|
.reset_strategy("MINI"),
|
||||||
|
.rf_width(rf_width),
|
||||||
|
.sim(sim),
|
||||||
|
.with_csr(WITH_CSR),
|
||||||
|
.with_c(0),
|
||||||
|
.with_mdu(0)
|
||||||
|
) servile (
|
||||||
|
.i_clk(i_clk),
|
||||||
|
.i_rst(rst),
|
||||||
|
.i_timer_irq(timer_irq),
|
||||||
|
|
||||||
|
//Memory interface
|
||||||
|
.o_wb_mem_adr(wb_mem_adr),
|
||||||
|
.o_wb_mem_dat(wb_mem_dat),
|
||||||
|
.o_wb_mem_sel(wb_mem_sel),
|
||||||
|
.o_wb_mem_we(wb_mem_we),
|
||||||
|
.o_wb_mem_stb(wb_mem_stb),
|
||||||
|
.i_wb_mem_rdt(wb_mem_rdt),
|
||||||
|
.i_wb_mem_ack(wb_mem_ack),
|
||||||
|
|
||||||
|
//Extension interface
|
||||||
|
.o_wb_ext_adr(wb_ext_adr),
|
||||||
|
.o_wb_ext_dat(wb_ext_dat),
|
||||||
|
.o_wb_ext_sel(wb_ext_sel),
|
||||||
|
.o_wb_ext_we(wb_ext_we),
|
||||||
|
.o_wb_ext_stb(wb_ext_stb),
|
||||||
|
.i_wb_ext_rdt(wb_ext_rdt),
|
||||||
|
.i_wb_ext_ack(wb_ext_ack),
|
||||||
|
|
||||||
|
//RF IF
|
||||||
|
.o_rf_waddr(rf_waddr),
|
||||||
|
.o_rf_wdata(rf_wdata),
|
||||||
|
.o_rf_wen(rf_wen),
|
||||||
|
.o_rf_raddr(rf_raddr),
|
||||||
|
.o_rf_ren(rf_ren),
|
||||||
|
.i_rf_rdata(rf_rdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
// WB arbiter combining RF and mem interfaces into 1
|
||||||
|
// Last 128 bytes are used for registers
|
||||||
|
servile_rf_mem_if #(
|
||||||
|
.depth(memsize),
|
||||||
|
.rf_regs(regs)
|
||||||
|
) rf_mem_if (
|
||||||
|
.i_clk (i_clk),
|
||||||
|
.i_rst (i_rst),
|
||||||
|
|
||||||
|
.i_waddr(rf_waddr),
|
||||||
|
.i_wdata(rf_wdata),
|
||||||
|
.i_wen(rf_wen),
|
||||||
|
.i_raddr(rf_raddr),
|
||||||
|
.o_rdata(rf_rdata),
|
||||||
|
.i_ren(rf_ren),
|
||||||
|
|
||||||
|
.o_sram_waddr(sram_waddr),
|
||||||
|
.o_sram_wdata(sram_wdata),
|
||||||
|
.o_sram_wen(sram_wen),
|
||||||
|
.o_sram_raddr(sram_raddr),
|
||||||
|
.i_sram_rdata(sram_rdata),
|
||||||
|
// .o_sram_ren(sram_ren),
|
||||||
|
|
||||||
|
.i_wb_adr(wb_mem_adr[`CLOG2(memsize)-1:2]),
|
||||||
|
.i_wb_stb(wb_mem_stb),
|
||||||
|
.i_wb_we(wb_mem_we) ,
|
||||||
|
.i_wb_sel(wb_mem_sel),
|
||||||
|
.i_wb_dat(wb_mem_dat),
|
||||||
|
.o_wb_rdt(wb_mem_rdt),
|
||||||
|
.o_wb_ack(wb_mem_ack)
|
||||||
|
);
|
||||||
|
|
||||||
|
memory #(
|
||||||
|
.memfile(memfile),
|
||||||
|
.depth(memsize),
|
||||||
|
.sim(sim)
|
||||||
|
) mem (
|
||||||
|
.i_clk(i_clk),
|
||||||
|
.i_waddr(sram_waddr),
|
||||||
|
.i_wdata(sram_wdata),
|
||||||
|
.i_wen(sram_wen),
|
||||||
|
.i_raddr(sram_raddr),
|
||||||
|
.o_rdata(sram_rdata),
|
||||||
|
.o_core_reset(rst_mem_reason)
|
||||||
|
);
|
||||||
|
|
||||||
|
wb_gpio_banks #(
|
||||||
|
.BASE_ADDR(32'h40000000),
|
||||||
|
.NUM_BANKS(4)
|
||||||
|
) gpio (
|
||||||
|
.i_wb_clk(i_clk),
|
||||||
|
.i_wb_rst(rst),
|
||||||
|
.i_wb_dat(wb_ext_dat),
|
||||||
|
.i_wb_adr(wb_ext_adr),
|
||||||
|
.i_wb_we(wb_ext_we),
|
||||||
|
.i_wb_stb(wb_ext_stb),
|
||||||
|
.i_wb_sel(wb_ext_sel),
|
||||||
|
.o_wb_rdt(wb_ext_rdt),
|
||||||
|
.o_wb_ack(wb_ext_ack),
|
||||||
|
.i_gpio(GPI),
|
||||||
|
.o_gpio(GPO)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module jtag_mem_protocol #(
|
||||||
|
parameter aw = 8,
|
||||||
|
parameter chain = 1
|
||||||
|
)(
|
||||||
|
input wire i_clk,
|
||||||
|
input wire i_rst,
|
||||||
|
input wire [7:0] i_mem_rdata,
|
||||||
|
output reg o_mem_wen,
|
||||||
|
output reg [7:0] o_mem_wdata,
|
||||||
|
output reg [aw-1:0] o_mem_waddr,
|
||||||
|
output reg [aw-1:0] o_mem_raddr,
|
||||||
|
output reg o_core_reset
|
||||||
|
);
|
||||||
|
localparam FRAME_BITS = 42;
|
||||||
|
|
||||||
|
// Frame format (LSB-first on JTAG shift stream):
|
||||||
|
// [0] : core reset
|
||||||
|
// [1] : write (1=write, 0=read)
|
||||||
|
// [33:2] : address
|
||||||
|
// [41:34] : data
|
||||||
|
wire [31:0] cmd_addr_full;
|
||||||
|
wire cmd_reset;
|
||||||
|
wire cmd_write;
|
||||||
|
wire [7:0] cmd_data;
|
||||||
|
|
||||||
|
// JTAG interface wires
|
||||||
|
wire jtag_tck;
|
||||||
|
wire jtag_tdi;
|
||||||
|
wire jtag_drck;
|
||||||
|
wire jtag_capture;
|
||||||
|
wire jtag_shift;
|
||||||
|
wire jtag_update;
|
||||||
|
wire jtag_runtest;
|
||||||
|
wire jtag_reset;
|
||||||
|
wire jtag_sel;
|
||||||
|
|
||||||
|
// JTAG clock-domain regs
|
||||||
|
reg [FRAME_BITS-1:0] shift_q;
|
||||||
|
reg [FRAME_BITS-1:0] cmd_jtag_q;
|
||||||
|
reg update_toggle_jtag_q;
|
||||||
|
reg [FRAME_BITS-1:0] resp_meta_q;
|
||||||
|
reg [FRAME_BITS-1:0] resp_sync_q;
|
||||||
|
|
||||||
|
// Core clock-domain CDC regs
|
||||||
|
reg update_toggle_meta_q;
|
||||||
|
reg update_toggle_sync_q;
|
||||||
|
reg update_toggle_sync_d_q;
|
||||||
|
reg [FRAME_BITS-1:0] cmd_meta_q;
|
||||||
|
reg [FRAME_BITS-1:0] cmd_sync_q;
|
||||||
|
|
||||||
|
// Core clock-domain protocol state
|
||||||
|
reg [FRAME_BITS-1:0] resp_core_q;
|
||||||
|
reg read_pending_q;
|
||||||
|
reg [31:0] read_addr_full_q;
|
||||||
|
|
||||||
|
assign cmd_reset = cmd_sync_q[0];
|
||||||
|
assign cmd_write = cmd_sync_q[1];
|
||||||
|
assign cmd_addr_full = cmd_sync_q[33:2];
|
||||||
|
assign cmd_data = cmd_sync_q[41:34];
|
||||||
|
|
||||||
|
jtag_if #(
|
||||||
|
.chain(chain)
|
||||||
|
) jtag (
|
||||||
|
.i_tdo(shift_q[0]),
|
||||||
|
.o_tck(jtag_tck),
|
||||||
|
.o_tdi(jtag_tdi),
|
||||||
|
.o_drck(jtag_drck),
|
||||||
|
.o_capture(jtag_capture),
|
||||||
|
.o_shift(jtag_shift),
|
||||||
|
.o_update(jtag_update),
|
||||||
|
.o_runtest(jtag_runtest),
|
||||||
|
.o_reset(jtag_reset),
|
||||||
|
.o_sel(jtag_sel)
|
||||||
|
);
|
||||||
|
|
||||||
|
// JTAG domain: shift register and update event capture.
|
||||||
|
always @(posedge jtag_drck or posedge jtag_reset or posedge i_rst) begin
|
||||||
|
if (jtag_reset || i_rst) begin
|
||||||
|
shift_q <= {FRAME_BITS{1'b0}};
|
||||||
|
resp_meta_q <= {FRAME_BITS{1'b0}};
|
||||||
|
resp_sync_q <= {FRAME_BITS{1'b0}};
|
||||||
|
end else begin
|
||||||
|
resp_meta_q <= resp_core_q;
|
||||||
|
resp_sync_q <= resp_meta_q;
|
||||||
|
|
||||||
|
if (jtag_sel && jtag_capture) begin
|
||||||
|
shift_q <= resp_sync_q;
|
||||||
|
end else if (jtag_sel && jtag_shift) begin
|
||||||
|
shift_q <= {jtag_tdi, shift_q[FRAME_BITS-1:1]};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge jtag_update or posedge jtag_reset or posedge i_rst) begin
|
||||||
|
if (jtag_reset || i_rst) begin
|
||||||
|
cmd_jtag_q <= {FRAME_BITS{1'b0}};
|
||||||
|
update_toggle_jtag_q <= 1'b0;
|
||||||
|
end else if (jtag_sel) begin
|
||||||
|
cmd_jtag_q <= shift_q;
|
||||||
|
update_toggle_jtag_q <= ~update_toggle_jtag_q;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Core domain: receive command and execute against RAM port-B.
|
||||||
|
always @(posedge i_clk or posedge i_rst) begin
|
||||||
|
if (i_rst) begin
|
||||||
|
update_toggle_meta_q <= 1'b0;
|
||||||
|
update_toggle_sync_q <= 1'b0;
|
||||||
|
update_toggle_sync_d_q <= 1'b0;
|
||||||
|
cmd_meta_q <= {FRAME_BITS{1'b0}};
|
||||||
|
cmd_sync_q <= {FRAME_BITS{1'b0}};
|
||||||
|
o_mem_wen <= 1'b0;
|
||||||
|
o_mem_wdata <= 8'h00;
|
||||||
|
o_mem_waddr <= {aw{1'b0}};
|
||||||
|
o_mem_raddr <= {aw{1'b0}};
|
||||||
|
o_core_reset <= 1'b0;
|
||||||
|
resp_core_q <= {FRAME_BITS{1'b0}};
|
||||||
|
read_pending_q <= 1'b0;
|
||||||
|
read_addr_full_q <= 32'h0000_0000;
|
||||||
|
end else begin
|
||||||
|
// Defaults are one-cycle strobes for write/reset.
|
||||||
|
o_mem_wen <= 1'b0;
|
||||||
|
o_core_reset <= 1'b0;
|
||||||
|
|
||||||
|
update_toggle_meta_q <= update_toggle_jtag_q;
|
||||||
|
update_toggle_sync_q <= update_toggle_meta_q;
|
||||||
|
update_toggle_sync_d_q <= update_toggle_sync_q;
|
||||||
|
cmd_meta_q <= cmd_jtag_q;
|
||||||
|
cmd_sync_q <= cmd_meta_q;
|
||||||
|
|
||||||
|
// Complete pending read (port-B read is synchronous).
|
||||||
|
if (read_pending_q) begin
|
||||||
|
read_pending_q <= 1'b0;
|
||||||
|
resp_core_q[0] <= 1'b0;
|
||||||
|
resp_core_q[1] <= 1'b0;
|
||||||
|
resp_core_q[33:2] <= read_addr_full_q;
|
||||||
|
resp_core_q[41:34] <= i_mem_rdata;
|
||||||
|
end
|
||||||
|
|
||||||
|
// New JTAG command arrived.
|
||||||
|
if (update_toggle_sync_q ^ update_toggle_sync_d_q) begin
|
||||||
|
if (cmd_reset) begin
|
||||||
|
o_core_reset <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (cmd_write) begin
|
||||||
|
o_mem_waddr <= cmd_addr_full[aw-1:0];
|
||||||
|
o_mem_wdata <= cmd_data;
|
||||||
|
o_mem_wen <= 1'b1;
|
||||||
|
resp_core_q[0] <= cmd_reset;
|
||||||
|
resp_core_q[1] <= 1'b1;
|
||||||
|
resp_core_q[33:2] <= cmd_addr_full;
|
||||||
|
resp_core_q[41:34] <= cmd_data;
|
||||||
|
end else begin
|
||||||
|
o_mem_raddr <= cmd_addr_full[aw-1:0];
|
||||||
|
read_pending_q <= 1'b1;
|
||||||
|
read_addr_full_q <= cmd_addr_full;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Keep lint quiet for currently-unused JTAG outputs.
|
||||||
|
wire _unused_tck;
|
||||||
|
wire _unused_runtest;
|
||||||
|
assign _unused_tck = jtag_tck;
|
||||||
|
assign _unused_runtest = jtag_runtest;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module memory #(
|
||||||
|
parameter memfile = "",
|
||||||
|
parameter depth = 256,
|
||||||
|
parameter sim = 1'b0,
|
||||||
|
localparam aw = `CLOG2(depth)
|
||||||
|
)(
|
||||||
|
input wire i_clk,
|
||||||
|
input wire [aw-1:0] i_waddr,
|
||||||
|
input wire [7:0] i_wdata,
|
||||||
|
input wire i_wen,
|
||||||
|
input wire [aw-1:0] i_raddr,
|
||||||
|
output reg [7:0] o_rdata,
|
||||||
|
output wire o_core_reset
|
||||||
|
);
|
||||||
|
// The actual memory
|
||||||
|
reg [7:0]mem [0:depth-1];
|
||||||
|
|
||||||
|
// Second interface
|
||||||
|
wire wen_b;
|
||||||
|
wire [7:0] wdata_b;
|
||||||
|
wire [aw-1:0] waddr_b;
|
||||||
|
reg [7:0] rdata_b;
|
||||||
|
wire [aw-1:0] raddr_b;
|
||||||
|
jtag_mem_protocol #(
|
||||||
|
.aw(aw),
|
||||||
|
.chain(1)
|
||||||
|
) jtag_mem (
|
||||||
|
.i_clk(i_clk),
|
||||||
|
.i_rst(1'b0),
|
||||||
|
.i_mem_rdata(rdata_b),
|
||||||
|
.o_mem_wen(wen_b),
|
||||||
|
.o_mem_wdata(wdata_b),
|
||||||
|
.o_mem_waddr(waddr_b),
|
||||||
|
.o_mem_raddr(raddr_b),
|
||||||
|
.o_core_reset(o_core_reset)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Read/Write
|
||||||
|
always @(posedge i_clk) begin
|
||||||
|
// main interface
|
||||||
|
if (i_wen)
|
||||||
|
mem[i_waddr] <= i_wdata;
|
||||||
|
o_rdata <= mem[i_raddr];
|
||||||
|
// second interface
|
||||||
|
if (wen_b)
|
||||||
|
mem[waddr_b] <= wdata_b;
|
||||||
|
rdata_b <= mem[raddr_b];
|
||||||
|
end
|
||||||
|
|
||||||
|
// Preload memory
|
||||||
|
integer i;
|
||||||
|
initial begin
|
||||||
|
if(sim==1'b1) begin
|
||||||
|
for (i = 0; i < depth; i = i + 1)
|
||||||
|
mem[i] = 8'h00;
|
||||||
|
end
|
||||||
|
if(|memfile) begin
|
||||||
|
$display("Preloading %m from %s", memfile);
|
||||||
|
$readmemh(memfile, mem);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -7,11 +7,13 @@ module top_generic(
|
|||||||
output wire led_green,
|
output wire led_green,
|
||||||
output wire led_red,
|
output wire led_red,
|
||||||
|
|
||||||
output wire[5:0] r2r
|
output wire[5:0] r2r,
|
||||||
|
output wire[7:0] LED
|
||||||
);
|
);
|
||||||
`include "conv.vh"
|
`include "conv.vh"
|
||||||
assign led_green = 1'b0;
|
assign led_green = 1'b0;
|
||||||
assign led_red = 1'b0;
|
assign led_red = 1'b0;
|
||||||
|
assign LED = 8'h00;
|
||||||
|
|
||||||
// Clocking
|
// Clocking
|
||||||
wire clk_100;
|
wire clk_100;
|
||||||
@@ -27,7 +29,7 @@ module top_generic(
|
|||||||
wire [31:0] GPIO_C;
|
wire [31:0] GPIO_C;
|
||||||
wire [31:0] GPIO_D;
|
wire [31:0] GPIO_D;
|
||||||
|
|
||||||
soclet #(
|
mcu #(
|
||||||
.memfile("../sw/sweep/sweep.hex")
|
.memfile("../sw/sweep/sweep.hex")
|
||||||
) mcu (
|
) mcu (
|
||||||
.i_clk(clk_15),
|
.i_clk(clk_15),
|
||||||
|
|||||||
@@ -1,167 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Write USER JTAG data via iMPACT using SVF + play flow."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_IMPACT = "/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/impact"
|
|
||||||
DEFAULT_SETTINGS = "/opt/Xilinx/14.7/ISE_DS/settings64.sh"
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_int(value: str) -> int:
|
|
||||||
return int(value, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def _resolve_impact(binary: str | None) -> str | None:
|
|
||||||
if binary:
|
|
||||||
return binary if os.path.isfile(binary) else shutil.which(binary)
|
|
||||||
if os.path.isfile(DEFAULT_IMPACT):
|
|
||||||
return DEFAULT_IMPACT
|
|
||||||
return shutil.which("impact")
|
|
||||||
|
|
||||||
|
|
||||||
def _fmt_hex_for_bits(value: int, bits: int) -> str:
|
|
||||||
masked = value & ((1 << bits) - 1)
|
|
||||||
nibbles = (bits + 3) // 4
|
|
||||||
return f"{masked:0{nibbles}X}"
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Write USER JTAG data to Spartan-6 via iMPACT play (SVF)."
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--input",
|
|
||||||
required=True,
|
|
||||||
help="Input file to stream over USER JTAG (written byte-by-byte).",
|
|
||||||
)
|
|
||||||
parser.add_argument("--output", type=str, default=None)
|
|
||||||
parser.add_argument("--dr-bits", type=int, default=8, help="DR width in bits (default: 8).")
|
|
||||||
parser.add_argument("--ir-value", type=_parse_int, default=0x02, help="IR opcode (default USER1: 0x02).")
|
|
||||||
parser.add_argument("--ir-bits", type=int, default=6, help="IR width in bits (default: 6).")
|
|
||||||
parser.add_argument("--serial", default=None, help="Cable ESN/serial (example: D306180FABCD).")
|
|
||||||
parser.add_argument("--impact", default=None, help=f"Path/name of impact binary (default: {DEFAULT_IMPACT}).")
|
|
||||||
parser.add_argument(
|
|
||||||
"--settings",
|
|
||||||
default=DEFAULT_SETTINGS,
|
|
||||||
help=f"Xilinx settings script sourced for this run only (default: {DEFAULT_SETTINGS}).",
|
|
||||||
)
|
|
||||||
parser.add_argument("--dry-run", action="store_true", help="Print generated SVF/CMD and exit.")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.dr_bits <= 0 or args.ir_bits <= 0:
|
|
||||||
print("error: --dr-bits and --ir-bits must be > 0", file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
if args.dr_bits != 8:
|
|
||||||
print("error: this file-stream mode currently supports only --dr-bits 8", file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
impact = _resolve_impact(args.impact)
|
|
||||||
if impact is None:
|
|
||||||
print("error: impact binary not found", file=sys.stderr)
|
|
||||||
return 127
|
|
||||||
if not os.path.isfile(args.input):
|
|
||||||
print(f'error: input file not found: "{args.input}"', file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
ir_hex = _fmt_hex_for_bits(args.ir_value, args.ir_bits)
|
|
||||||
with open(args.input, "rb") as f:
|
|
||||||
payload = f.read()
|
|
||||||
if len(payload) == 0:
|
|
||||||
print("error: input file is empty", file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
svf_lines = [
|
|
||||||
"! Auto-generated by jtag_write_user_impact.py",
|
|
||||||
f"! Source file: {args.input} ({len(payload)} bytes)",
|
|
||||||
"TRST ABSENT;",
|
|
||||||
"ENDIR IDLE;",
|
|
||||||
"ENDDR IDLE;",
|
|
||||||
"STATE RESET;",
|
|
||||||
"STATE IDLE;",
|
|
||||||
f"SIR {args.ir_bits} TDI ({ir_hex});",
|
|
||||||
]
|
|
||||||
for byte in payload:
|
|
||||||
svf_lines.append(f"SDR 8 TDI ({byte:02X});")
|
|
||||||
svf_lines += [
|
|
||||||
"RUNTEST 16 TCK;",
|
|
||||||
"STATE IDLE;",
|
|
||||||
"",
|
|
||||||
]
|
|
||||||
svf_text = "\n".join(svf_lines)
|
|
||||||
|
|
||||||
cable_cmd = "setCable -port auto"
|
|
||||||
if args.serial:
|
|
||||||
cable_cmd += f" -esn {args.serial}"
|
|
||||||
|
|
||||||
if args.dry_run:
|
|
||||||
print("### SVF ###")
|
|
||||||
preview_limit = 64
|
|
||||||
if len(payload) <= preview_limit:
|
|
||||||
print(svf_text, end="")
|
|
||||||
else:
|
|
||||||
preview = "\n".join(svf_lines[:8 + preview_limit])
|
|
||||||
print(preview)
|
|
||||||
print(f"... ({len(payload) - preview_limit} more SDR lines omitted)")
|
|
||||||
print("### iMPACT CMD ###")
|
|
||||||
print("setMode -bs")
|
|
||||||
print(cable_cmd)
|
|
||||||
print("addDevice -p 1 -file <generated.svf>")
|
|
||||||
print("play")
|
|
||||||
print("quit")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
svf_path = None
|
|
||||||
cmd_path = None
|
|
||||||
try:
|
|
||||||
with tempfile.NamedTemporaryFile("w", suffix=".svf", delete=False) as sf:
|
|
||||||
sf.write(svf_text)
|
|
||||||
svf_path = sf.name
|
|
||||||
if args.output is not None:
|
|
||||||
with open(args.output, "w") as sf:
|
|
||||||
sf.write(svf_text)
|
|
||||||
|
|
||||||
cmd_text = "\n".join(
|
|
||||||
[
|
|
||||||
"setMode -bs",
|
|
||||||
cable_cmd,
|
|
||||||
f'addDevice -p 1 -file "{svf_path}"',
|
|
||||||
"play",
|
|
||||||
"quit",
|
|
||||||
"",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
with tempfile.NamedTemporaryFile("w", suffix=".cmd", delete=False) as cf:
|
|
||||||
cf.write(cmd_text)
|
|
||||||
cmd_path = cf.name
|
|
||||||
|
|
||||||
shell_cmd = (
|
|
||||||
f'source "{args.settings}" >/dev/null 2>&1 && '
|
|
||||||
f'"{impact}" -batch "{cmd_path}"'
|
|
||||||
)
|
|
||||||
proc = subprocess.run(["bash", "-lc", shell_cmd], text=True, capture_output=True)
|
|
||||||
output = (proc.stdout or "") + (proc.stderr or "")
|
|
||||||
print(output, end="")
|
|
||||||
return proc.returncode
|
|
||||||
finally:
|
|
||||||
if cmd_path is not None:
|
|
||||||
try:
|
|
||||||
os.unlink(cmd_path)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
if svf_path is not None:
|
|
||||||
try:
|
|
||||||
os.unlink(svf_path)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
raise SystemExit(main())
|
|
||||||
2
tools/.gitignore
vendored
Normal file
2
tools/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
test
|
||||||
32
tools/Makefile
Normal file
32
tools/Makefile
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
TOOLCHAIN_PREFIX ?=
|
||||||
|
|
||||||
|
CC := $(TOOLCHAIN_PREFIX)g++
|
||||||
|
|
||||||
|
TARGET := test
|
||||||
|
SRCS_C :=
|
||||||
|
SRCS_CPP:= test.cpp digilent_jtag.cpp
|
||||||
|
OBJS := $(SRCS_C:.c=.o) $(SRCS_CPP:.cpp=.o)
|
||||||
|
|
||||||
|
ADEPT_LIBDIR := /opt/packages/digilent.adept.runtime_2.27.9-x86_64/lib64
|
||||||
|
|
||||||
|
CFLAGS :=
|
||||||
|
ASFLAGS :=
|
||||||
|
LDFLAGS := -L$(ADEPT_LIBDIR) -Wl,--disable-new-dtags -Wl,-rpath,$(ADEPT_LIBDIR)
|
||||||
|
LIBS := -ldjtg -ldmgr -ldpcomm -ldabs -ldftd2xx
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: all clean size
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET) $(OBJS)
|
||||||
276
tools/digilent_jtag.cpp
Normal file
276
tools/digilent_jtag.cpp
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
#include "digilent_jtag.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <digilent/adept/dmgr.h>
|
||||||
|
#include <digilent/adept/djtg.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr int kDefaultIrBits = 6;
|
||||||
|
|
||||||
|
std::string ercToString(ERC erc) {
|
||||||
|
char code[cchErcMax] = {0};
|
||||||
|
char msg[cchErcMsgMax] = {0};
|
||||||
|
if (DmgrSzFromErc(erc, code, msg)) {
|
||||||
|
return std::string(code) + ": " + msg;
|
||||||
|
}
|
||||||
|
return "ERC=" + std::to_string(erc);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t getBit(const uint8_t* packed_bits, int bit_idx) {
|
||||||
|
return static_cast<uint8_t>((packed_bits[bit_idx / 8] >> (bit_idx % 8)) & 0x1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setBit(uint8_t* packed_bits, int bit_idx, uint8_t bit) {
|
||||||
|
const uint8_t mask = static_cast<uint8_t>(1u << (bit_idx % 8));
|
||||||
|
if (bit & 0x1u) {
|
||||||
|
packed_bits[bit_idx / 8] |= mask;
|
||||||
|
} else {
|
||||||
|
packed_bits[bit_idx / 8] &= static_cast<uint8_t>(~mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
DigilentJtag::DigilentJtag() : hif_(hifInvalid), enabled_port_(-1), last_error_() {}
|
||||||
|
|
||||||
|
DigilentJtag::~DigilentJtag() { close(); }
|
||||||
|
|
||||||
|
bool DigilentJtag::open(int port) {
|
||||||
|
close();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
if (!DmgrEnumDevices(&count)) {
|
||||||
|
return setErrorFromDmgr("DmgrEnumDevices");
|
||||||
|
}
|
||||||
|
if (count <= 0) {
|
||||||
|
return setError("open: no Digilent devices found");
|
||||||
|
}
|
||||||
|
|
||||||
|
DVC dvc{};
|
||||||
|
if (!DmgrGetDvc(0, &dvc)) {
|
||||||
|
return setErrorFromDmgr("DmgrGetDvc");
|
||||||
|
}
|
||||||
|
|
||||||
|
return open(std::string(dvc.szConn), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::open(const std::string& selector, int port) {
|
||||||
|
close();
|
||||||
|
|
||||||
|
if (selector.empty()) {
|
||||||
|
return setError("open: selector is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> sel(selector.begin(), selector.end());
|
||||||
|
sel.push_back('\0');
|
||||||
|
|
||||||
|
if (!DmgrOpen(&hif_, sel.data())) {
|
||||||
|
hif_ = hifInvalid;
|
||||||
|
return setErrorFromDmgr("DmgrOpen");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DjtgEnableEx(hif_, static_cast<INT32>(port))) {
|
||||||
|
if (!DjtgEnable(hif_)) {
|
||||||
|
DmgrClose(hif_);
|
||||||
|
hif_ = hifInvalid;
|
||||||
|
return setErrorFromDmgr("DjtgEnableEx/DjtgEnable");
|
||||||
|
}
|
||||||
|
enabled_port_ = 0;
|
||||||
|
} else {
|
||||||
|
enabled_port_ = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_error_.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigilentJtag::close() {
|
||||||
|
if (hif_ != hifInvalid) {
|
||||||
|
(void)DjtgDisable(hif_);
|
||||||
|
(void)DmgrClose(hif_);
|
||||||
|
}
|
||||||
|
hif_ = hifInvalid;
|
||||||
|
enabled_port_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::isOpen() const { return hif_ != hifInvalid; }
|
||||||
|
|
||||||
|
HIF DigilentJtag::handle() const { return hif_; }
|
||||||
|
|
||||||
|
bool DigilentJtag::setSpeed(uint32_t requested_hz, uint32_t* actual_hz) {
|
||||||
|
if (!isOpen()) {
|
||||||
|
return setError("setSpeed: device not open");
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD actual = 0;
|
||||||
|
if (!DjtgSetSpeed(hif_, static_cast<DWORD>(requested_hz), &actual)) {
|
||||||
|
return setErrorFromDmgr("DjtgSetSpeed");
|
||||||
|
}
|
||||||
|
if (actual_hz) {
|
||||||
|
*actual_hz = static_cast<uint32_t>(actual);
|
||||||
|
}
|
||||||
|
last_error_.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::setChain(int chain, int ir_bits) {
|
||||||
|
uint32_t opcode = 0;
|
||||||
|
if (chain == 1) {
|
||||||
|
opcode = 0x02; // USER1 on Spartan-6
|
||||||
|
} else if (chain == 2) {
|
||||||
|
opcode = 0x03; // USER2 on Spartan-6
|
||||||
|
} else {
|
||||||
|
return setError("setChain: unsupported chain index (expected 1 or 2)");
|
||||||
|
}
|
||||||
|
return setInstruction(opcode, ir_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::setInstruction(uint32_t instruction, int ir_bits) {
|
||||||
|
if (!isOpen()) {
|
||||||
|
return setError("setInstruction: device not open");
|
||||||
|
}
|
||||||
|
if (ir_bits <= 0 || ir_bits > 64) {
|
||||||
|
return setError("setInstruction: ir_bits out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force Test-Logic-Reset, then RTI.
|
||||||
|
uint8_t tlr = 0x3f; // 6 ones
|
||||||
|
if (!putTmsBits(&tlr, 6)) return false;
|
||||||
|
uint8_t rti = 0x00; // one zero
|
||||||
|
if (!putTmsBits(&rti, 1)) return false;
|
||||||
|
|
||||||
|
// RTI -> Shift-IR : 1,1,0,0 (LSB-first 0b0011)
|
||||||
|
uint8_t to_shift_ir = 0x03;
|
||||||
|
if (!putTmsBits(&to_shift_ir, 4)) return false;
|
||||||
|
|
||||||
|
std::vector<uint8_t> tx(static_cast<size_t>((ir_bits + 7) / 8), 0);
|
||||||
|
for (int i = 0; i < ir_bits && i < 64; ++i) {
|
||||||
|
if ((instruction >> i) & 0x1u) {
|
||||||
|
tx[static_cast<size_t>(i / 8)] |= static_cast<uint8_t>(1u << (i % 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> rx(tx.size(), 0);
|
||||||
|
|
||||||
|
if (ir_bits > 1) {
|
||||||
|
if (!putTdiBits(false, tx.data(), rx.data(), ir_bits - 1)) return false;
|
||||||
|
}
|
||||||
|
const uint8_t last_tx = getBit(tx.data(), ir_bits - 1);
|
||||||
|
uint8_t last_rx = 0;
|
||||||
|
if (!putTdiBits(true, &last_tx, &last_rx, 1)) return false;
|
||||||
|
|
||||||
|
// Exit1-IR -> Update-IR -> Idle: 1,0
|
||||||
|
uint8_t to_idle = 0x01;
|
||||||
|
if (!putTmsBits(&to_idle, 2)) return false;
|
||||||
|
|
||||||
|
last_error_.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::shiftData(const uint8_t* tx_bits, uint8_t* rx_bits, int bit_count) {
|
||||||
|
if (!isOpen()) {
|
||||||
|
return setError("shiftData: device not open");
|
||||||
|
}
|
||||||
|
if (bit_count <= 0) {
|
||||||
|
return setError("shiftData: bit_count must be > 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t nbytes = static_cast<size_t>((bit_count + 7) / 8);
|
||||||
|
std::vector<uint8_t> tx_zeros;
|
||||||
|
if (!tx_bits) {
|
||||||
|
tx_zeros.assign(nbytes, 0);
|
||||||
|
tx_bits = tx_zeros.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> rx_tmp;
|
||||||
|
if (!rx_bits) {
|
||||||
|
rx_tmp.assign(nbytes, 0);
|
||||||
|
rx_bits = rx_tmp.data();
|
||||||
|
} else {
|
||||||
|
std::memset(rx_bits, 0, nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enterShiftDR()) return false;
|
||||||
|
|
||||||
|
if (bit_count > 1) {
|
||||||
|
if (!putTdiBits(false, tx_bits, rx_bits, bit_count - 1)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t tx_last = getBit(tx_bits, bit_count - 1);
|
||||||
|
uint8_t rx_last = 0;
|
||||||
|
if (!putTdiBits(true, &tx_last, &rx_last, 1)) return false;
|
||||||
|
setBit(rx_bits, bit_count - 1, rx_last & 0x1u);
|
||||||
|
|
||||||
|
if (!leaveShiftToIdle()) return false;
|
||||||
|
|
||||||
|
last_error_.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::shiftData(const std::vector<uint8_t>& tx_bits, std::vector<uint8_t>* rx_bits, int bit_count) {
|
||||||
|
if (bit_count <= 0) {
|
||||||
|
return setError("shiftData(vector): bit_count must be > 0");
|
||||||
|
}
|
||||||
|
const size_t nbytes = static_cast<size_t>((bit_count + 7) / 8);
|
||||||
|
if (tx_bits.size() < nbytes) {
|
||||||
|
return setError("shiftData(vector): tx_bits is smaller than required bit_count");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> local_rx;
|
||||||
|
local_rx.assign(nbytes, 0);
|
||||||
|
|
||||||
|
if (!shiftData(tx_bits.data(), local_rx.data(), bit_count)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_bits) {
|
||||||
|
*rx_bits = std::move(local_rx);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& DigilentJtag::lastError() const { return last_error_; }
|
||||||
|
|
||||||
|
bool DigilentJtag::enterShiftDR() {
|
||||||
|
// Idle -> Select-DR -> Capture-DR -> Shift-DR : 1,0,0
|
||||||
|
uint8_t to_shift_dr = 0x01;
|
||||||
|
return putTmsBits(&to_shift_dr, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::leaveShiftToIdle() {
|
||||||
|
// Exit1-DR -> Update-DR -> Idle : 1,0
|
||||||
|
uint8_t to_idle = 0x01;
|
||||||
|
return putTmsBits(&to_idle, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::putTmsBits(const uint8_t* tms_bits, int bit_count) {
|
||||||
|
if (!DjtgPutTmsBits(hif_, fFalse, const_cast<uint8_t*>(tms_bits), nullptr, static_cast<DWORD>(bit_count), fFalse)) {
|
||||||
|
return setErrorFromDmgr("DjtgPutTmsBits");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::putTdiBits(bool tms, const uint8_t* tx_bits, uint8_t* rx_bits, int bit_count) {
|
||||||
|
if (!DjtgPutTdiBits(
|
||||||
|
hif_,
|
||||||
|
tms ? fTrue : fFalse,
|
||||||
|
const_cast<uint8_t*>(tx_bits),
|
||||||
|
rx_bits,
|
||||||
|
static_cast<DWORD>(bit_count),
|
||||||
|
fFalse)) {
|
||||||
|
return setErrorFromDmgr("DjtgPutTdiBits");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::setError(const std::string& msg) {
|
||||||
|
last_error_ = msg;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigilentJtag::setErrorFromDmgr(const std::string& where) {
|
||||||
|
last_error_ = where + " failed: " + ercToString(DmgrGetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
52
tools/digilent_jtag.hpp
Normal file
52
tools/digilent_jtag.hpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <digilent/adept/dpcdecl.h>
|
||||||
|
|
||||||
|
class DigilentJtag {
|
||||||
|
public:
|
||||||
|
DigilentJtag();
|
||||||
|
~DigilentJtag();
|
||||||
|
|
||||||
|
DigilentJtag(const DigilentJtag&) = delete;
|
||||||
|
DigilentJtag& operator=(const DigilentJtag&) = delete;
|
||||||
|
|
||||||
|
bool open(int port = 0);
|
||||||
|
bool open(const std::string& selector, int port = 0);
|
||||||
|
void close();
|
||||||
|
|
||||||
|
bool isOpen() const;
|
||||||
|
HIF handle() const;
|
||||||
|
|
||||||
|
bool setSpeed(uint32_t requested_hz, uint32_t* actual_hz = nullptr);
|
||||||
|
|
||||||
|
// For Spartan-6 style USER chains:
|
||||||
|
// chain=1 -> USER1 opcode 0x02, chain=2 -> USER2 opcode 0x03
|
||||||
|
bool setChain(int chain, int ir_bits = 6);
|
||||||
|
|
||||||
|
bool setInstruction(uint32_t instruction, int ir_bits);
|
||||||
|
|
||||||
|
// Shifts one DR transaction from Idle -> ShiftDR -> UpdateDR -> Idle.
|
||||||
|
// tx_bits is LSB-first in packed byte form.
|
||||||
|
// rx_bits, when non-null, receives captured TDO bits in the same packing.
|
||||||
|
bool shiftData(const uint8_t* tx_bits, uint8_t* rx_bits, int bit_count);
|
||||||
|
|
||||||
|
bool shiftData(const std::vector<uint8_t>& tx_bits, std::vector<uint8_t>* rx_bits, int bit_count);
|
||||||
|
|
||||||
|
const std::string& lastError() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool enterShiftDR();
|
||||||
|
bool leaveShiftToIdle();
|
||||||
|
bool putTmsBits(const uint8_t* tms_bits, int bit_count);
|
||||||
|
bool putTdiBits(bool tms, const uint8_t* tx_bits, uint8_t* rx_bits, int bit_count);
|
||||||
|
bool setError(const std::string& msg);
|
||||||
|
bool setErrorFromDmgr(const std::string& where);
|
||||||
|
|
||||||
|
HIF hif_;
|
||||||
|
int enabled_port_;
|
||||||
|
std::string last_error_;
|
||||||
|
};
|
||||||
19
tools/test.cpp
Normal file
19
tools/test.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "digilent_jtag.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char** argv){
|
||||||
|
|
||||||
|
DigilentJtag jtag;
|
||||||
|
if(!jtag.open()){
|
||||||
|
printf("Could not open programmer\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag.setChain(1);
|
||||||
|
|
||||||
|
uint8_t data_out = 0xAB;
|
||||||
|
uint8_t data_in;
|
||||||
|
jtag.shiftData(&data_out, &data_in, 8);
|
||||||
|
|
||||||
|
jtag.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user