URL
https://opencores.org/ocsvn/ftdi_wb_bridge/ftdi_wb_bridge/trunk
Subversion Repositories ftdi_wb_bridge
Compare Revisions
- This comparison shows the changes necessary to convert path
/ftdi_wb_bridge/trunk
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/testbench/simulation.svh
0,0 → 1,57
`timescale 1ns/1ps |
|
//----------------------------------------------------------------- |
// assert_task |
//----------------------------------------------------------------- |
task automatic assert_task(input v, string file, int line, input string s); |
begin |
if (!v) |
begin |
$display("ASSERT: %s:%0d - %s", file, line, s); |
$finish(1); |
end |
end |
endtask |
|
//----------------------------------------------------------------- |
// ASSERT |
//----------------------------------------------------------------- |
`define ASSERT(v) assert_task(v, `__FILE__, `__LINE__, `"v`") |
|
//----------------------------------------------------------------- |
// CLOCK_GEN |
//----------------------------------------------------------------- |
`define CLOCK_GEN(NAME, CYCLE) \ |
reg ``NAME; \ |
initial \ |
begin \ |
``NAME <= 0; \ |
forever # (``CYCLE / 2) ``NAME = ~``NAME; \ |
end |
|
//----------------------------------------------------------------- |
// RESET_GEN |
//----------------------------------------------------------------- |
`define RESET_GEN(NAME, DELAY) \ |
reg ``NAME; \ |
initial \ |
begin \ |
``NAME <= 1; \ |
# ``DELAY \ |
``NAME <= 0; \ |
end |
|
//----------------------------------------------------------------- |
// TB_VCD |
//----------------------------------------------------------------- |
`define TB_VCD(TOP, NAME) \ |
initial \ |
begin \ |
$dumpfile(``NAME); \ |
$dumpvars(0,``TOP); \ |
end |
|
//----------------------------------------------------------------- |
// TB_RUN_FOR |
//----------------------------------------------------------------- |
`define TB_RUN_FOR(TIME) initial #``TIME $finish; |
/testbench/wb_slave.sv
0,0 → 1,231
//----------------------------------------------------------------- |
// Module |
//----------------------------------------------------------------- |
module wb_slave |
( |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
|
// Wishbone I/F |
input [31:0] addr_i /*verilator public*/, |
input [31:0] data_i /*verilator public*/, |
output reg [31:0] data_o /*verilator public*/, |
input [3:0] sel_i /*verilator public*/, |
input cyc_i /*verilator public*/, |
input stb_i /*verilator public*/, |
input [2:0] cti_i /*verilator public*/, |
input we_i /*verilator public*/, |
output reg ack_o /*verilator public*/, |
output reg stall_o /*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
parameter MAX_RESP_RATE = 0; |
parameter RESP_DELAY_RATE = 3; |
|
parameter RANDOM_STALLS = 1; |
parameter STALL_RATE = 3; |
|
`include "simulation.svh" |
|
//----------------------------------------------------------------- |
// Request Queue |
//----------------------------------------------------------------- |
typedef struct |
{ |
reg [31:0] address; |
reg [31:0] data; |
reg [3:0] sel; |
reg we; |
} request_t; |
|
request_t requests[$]; |
|
//----------------------------------------------------------------- |
// Memory |
//----------------------------------------------------------------- |
reg [31:0] mem[*]; |
|
//----------------------------------------------------------------- |
// write |
//----------------------------------------------------------------- |
task automatic write(input [31:0] addr, input [31:0] data); |
begin |
mem[addr[31:2]] = data; |
end |
endtask |
|
//----------------------------------------------------------------- |
// read |
//----------------------------------------------------------------- |
task automatic read(input [31:0] addr, output [31:0] data); |
begin |
if (mem.exists(addr[31:2])) |
data = mem[addr[31:2]]; |
else |
data = 32'bx; |
end |
endtask |
//----------------------------------------------------------------- |
// read8 |
//----------------------------------------------------------------- |
task automatic read8(input [31:0] addr, output [7:0] data); |
begin |
if (mem.exists(addr[31:2])) |
begin |
reg [31:0] tmp_data; |
tmp_data = mem[addr[31:2]]; |
|
case (addr[1:0]) |
0: data = tmp_data[7:0]; |
1: data = tmp_data[15:8]; |
2: data = tmp_data[23:16]; |
3: data = tmp_data[31:24]; |
endcase |
end |
else |
data = 8'bx; |
end |
endtask |
//----------------------------------------------------------------- |
// write_bytes |
//----------------------------------------------------------------- |
task automatic write_bytes(input [31:0] addr, input [31:0] data, input [31:0] sel); |
begin |
reg [31:0] new_data; |
|
read(addr, new_data); |
|
if (sel[3]) |
new_data[31:24] = data[31:24]; |
if (sel[2]) |
new_data[23:16] = data[23:16]; |
if (sel[1]) |
new_data[15:8] = data[15:8]; |
if (sel[0]) |
new_data[7:0] = data[7:0]; |
|
write(addr, new_data); |
end |
endtask |
|
//----------------------------------------------------------------- |
// response |
//----------------------------------------------------------------- |
initial |
begin |
request_t req; |
|
ack_o = 1'b0; |
data_o = 32'bz; |
|
forever |
begin |
@(posedge clk_i); |
|
ack_o = 1'b0; |
data_o = 32'bz; |
|
if (!MAX_RESP_RATE) |
begin |
repeat ($urandom_range(RESP_DELAY_RATE,0)) @(posedge clk_i); |
end |
|
if (requests.size() > 0) |
begin |
req = requests.pop_front(); |
|
// Write |
if (req.we) |
begin |
ack_o = 1'b1; |
data_o = 32'bz; |
|
write_bytes(req.address, req.data, req.sel); |
end |
// Read |
else |
begin |
ack_o = 1'b1; |
read(req.address, data_o); |
end |
end |
end |
end |
|
//----------------------------------------------------------------- |
// request |
//----------------------------------------------------------------- |
always @(posedge clk_i) |
begin |
// Request presented and accepted |
if (stb_i && cyc_i && !stall_o) |
begin |
request_t req; |
|
req.address = addr_i; |
req.data = data_i; |
req.sel = sel_i; |
req.we = we_i; |
|
requests.push_back(req); |
end |
end |
|
always @(posedge rst_i or posedge clk_i) |
if (rst_i) |
stall_o <= 1'b0; |
else |
begin |
if (RANDOM_STALLS) |
stall_o <= ($urandom_range(STALL_RATE,0) == 0); |
end |
|
//----------------------------------------------------------------- |
// CTI |
//----------------------------------------------------------------- |
initial |
begin |
reg burst; |
reg [2:0] burst_cnt; |
|
burst = 1'b0; |
burst_cnt = 0; |
|
forever |
begin |
@(posedge clk_i); |
|
// Start of burst |
if (stb_i && cyc_i && !stall_o && cti_i == 3'b010) |
begin |
burst_cnt = 7; |
burst = 1; |
|
while (burst_cnt != 0) |
begin |
@(posedge clk_i); |
|
if (stb_i && cyc_i && !stall_o) |
begin |
if (burst_cnt == 1) |
begin |
`ASSERT(cti_i == 3'b111); |
end |
|
burst_cnt = burst_cnt - 1; |
end |
end |
|
burst = 0; |
end |
else if (stb_i && cyc_i && !stall_o) |
begin |
`ASSERT(cti_i == 3'b111); |
end |
end |
end |
|
endmodule |
/testbench/makefile
0,0 → 1,29
TRACE ?= 1 |
|
all: compile run view |
|
# Testbench |
SRC+= ./top_tb.sv wb_slave.sv |
|
SRC+= ../rtl/ftdi_if.v ../rtl/ftdi_sync.v |
|
ifeq ($(TRACE),1) |
SRC_FLAGS += +define+TRACE=$(TRACE) |
endif |
|
INC_DIRS = -I. |
|
compile : |
vlib work |
vlog $(SRC) $(SRC_FLAGS) |
|
run : compile |
vsim -c -do "run -all" top_tb |
|
view : compile |
ifeq ($(TRACE),1) |
gtkwave waveform.vcd gtksettings.sav |
endif |
|
clean : |
-rm -rf work waveform.vcd transcript |
/testbench/gtksettings.sav
0,0 → 1,32
@28 |
top_tb.clk |
top_tb.rst |
@200 |
- |
-WB |
@22 |
#{top_tb.u_dut.mem_addr_o[31:0]} top_tb.u_dut.mem_addr_o[31] top_tb.u_dut.mem_addr_o[30] top_tb.u_dut.mem_addr_o[29] top_tb.u_dut.mem_addr_o[28] top_tb.u_dut.mem_addr_o[27] top_tb.u_dut.mem_addr_o[26] top_tb.u_dut.mem_addr_o[25] top_tb.u_dut.mem_addr_o[24] top_tb.u_dut.mem_addr_o[23] top_tb.u_dut.mem_addr_o[22] top_tb.u_dut.mem_addr_o[21] top_tb.u_dut.mem_addr_o[20] top_tb.u_dut.mem_addr_o[19] top_tb.u_dut.mem_addr_o[18] top_tb.u_dut.mem_addr_o[17] top_tb.u_dut.mem_addr_o[16] top_tb.u_dut.mem_addr_o[15] top_tb.u_dut.mem_addr_o[14] top_tb.u_dut.mem_addr_o[13] top_tb.u_dut.mem_addr_o[12] top_tb.u_dut.mem_addr_o[11] top_tb.u_dut.mem_addr_o[10] top_tb.u_dut.mem_addr_o[9] top_tb.u_dut.mem_addr_o[8] top_tb.u_dut.mem_addr_o[7] top_tb.u_dut.mem_addr_o[6] top_tb.u_dut.mem_addr_o[5] top_tb.u_dut.mem_addr_o[4] top_tb.u_dut.mem_addr_o[3] top_tb.u_dut.mem_addr_o[2] top_tb.u_dut.mem_addr_o[1] top_tb.u_dut.mem_addr_o[0] |
#{top_tb.u_dut.mem_data_o[31:0]} top_tb.u_dut.mem_data_o[31] top_tb.u_dut.mem_data_o[30] top_tb.u_dut.mem_data_o[29] top_tb.u_dut.mem_data_o[28] top_tb.u_dut.mem_data_o[27] top_tb.u_dut.mem_data_o[26] top_tb.u_dut.mem_data_o[25] top_tb.u_dut.mem_data_o[24] top_tb.u_dut.mem_data_o[23] top_tb.u_dut.mem_data_o[22] top_tb.u_dut.mem_data_o[21] top_tb.u_dut.mem_data_o[20] top_tb.u_dut.mem_data_o[19] top_tb.u_dut.mem_data_o[18] top_tb.u_dut.mem_data_o[17] top_tb.u_dut.mem_data_o[16] top_tb.u_dut.mem_data_o[15] top_tb.u_dut.mem_data_o[14] top_tb.u_dut.mem_data_o[13] top_tb.u_dut.mem_data_o[12] top_tb.u_dut.mem_data_o[11] top_tb.u_dut.mem_data_o[10] top_tb.u_dut.mem_data_o[9] top_tb.u_dut.mem_data_o[8] top_tb.u_dut.mem_data_o[7] top_tb.u_dut.mem_data_o[6] top_tb.u_dut.mem_data_o[5] top_tb.u_dut.mem_data_o[4] top_tb.u_dut.mem_data_o[3] top_tb.u_dut.mem_data_o[2] top_tb.u_dut.mem_data_o[1] top_tb.u_dut.mem_data_o[0] |
#{top_tb.u_dut.mem_data_i[31:0]} top_tb.u_dut.mem_data_i[31] top_tb.u_dut.mem_data_i[30] top_tb.u_dut.mem_data_i[29] top_tb.u_dut.mem_data_i[28] top_tb.u_dut.mem_data_i[27] top_tb.u_dut.mem_data_i[26] top_tb.u_dut.mem_data_i[25] top_tb.u_dut.mem_data_i[24] top_tb.u_dut.mem_data_i[23] top_tb.u_dut.mem_data_i[22] top_tb.u_dut.mem_data_i[21] top_tb.u_dut.mem_data_i[20] top_tb.u_dut.mem_data_i[19] top_tb.u_dut.mem_data_i[18] top_tb.u_dut.mem_data_i[17] top_tb.u_dut.mem_data_i[16] top_tb.u_dut.mem_data_i[15] top_tb.u_dut.mem_data_i[14] top_tb.u_dut.mem_data_i[13] top_tb.u_dut.mem_data_i[12] top_tb.u_dut.mem_data_i[11] top_tb.u_dut.mem_data_i[10] top_tb.u_dut.mem_data_i[9] top_tb.u_dut.mem_data_i[8] top_tb.u_dut.mem_data_i[7] top_tb.u_dut.mem_data_i[6] top_tb.u_dut.mem_data_i[5] top_tb.u_dut.mem_data_i[4] top_tb.u_dut.mem_data_i[3] top_tb.u_dut.mem_data_i[2] top_tb.u_dut.mem_data_i[1] top_tb.u_dut.mem_data_i[0] |
#{top_tb.u_dut.mem_sel_o[3:0]} top_tb.u_dut.mem_sel_o[3] top_tb.u_dut.mem_sel_o[2] top_tb.u_dut.mem_sel_o[1] top_tb.u_dut.mem_sel_o[0] |
@28 |
top_tb.u_dut.mem_we_o |
top_tb.u_dut.mem_cyc_o |
top_tb.u_dut.mem_stb_o |
top_tb.u_dut.mem_stall_i |
top_tb.u_dut.mem_ack_i |
@200 |
- |
-FTDI |
@28 |
top_tb.u_dut.ftdi_rxf_i |
@22 |
#{top_tb.u_dut.ftdi_d_io[7:0]} top_tb.u_dut.ftdi_d_io[7] top_tb.u_dut.ftdi_d_io[6] top_tb.u_dut.ftdi_d_io[5] top_tb.u_dut.ftdi_d_io[4] top_tb.u_dut.ftdi_d_io[3] top_tb.u_dut.ftdi_d_io[2] top_tb.u_dut.ftdi_d_io[1] top_tb.u_dut.ftdi_d_io[0] |
@28 |
top_tb.u_dut.ftdi_rd_o |
top_tb.u_dut.u_sync.ftdi_txe_i |
top_tb.u_dut.u_sync.ftdi_wr_o |
@200 |
- |
[pattern_trace] 1 |
[pattern_trace] 0 |
/testbench/top_tb.sv
0,0 → 1,405
`timescale 100ps/100ps |
|
//----------------------------------------------------------------- |
// Module |
//----------------------------------------------------------------- |
module top_tb ; |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
parameter MAX_DELAY = 0; |
|
//----------------------------------------------------------------- |
// Simulation |
//----------------------------------------------------------------- |
`include "simulation.svh" |
|
`CLOCK_GEN(clk, 100) |
`RESET_GEN(rst, 100) |
|
`ifdef TRACE |
`TB_VCD(top_tb, "waveform.vcd") |
`endif |
|
`TB_RUN_FOR(10ms) |
|
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
wire [31:0] mem_addr; |
wire [31:0] mem_data_w; |
wire [31:0] mem_data_r; |
wire [3:0] mem_sel; |
wire mem_stb; |
wire mem_cyc; |
wire mem_we; |
wire mem_stall; |
wire mem_ack; |
|
reg ftdi_rxf; |
reg ftdi_txe; |
wire ftdi_rd; |
wire ftdi_wr; |
reg [7:0] ftdi_data; |
|
wire [7:0] ftdi_data_io_w; |
|
reg [7:0] mem[*]; |
|
reg [7:0] gpio_in; |
wire [7:0] gpio_out; |
|
//----------------------------------------------------------------- |
// mem_write |
//----------------------------------------------------------------- |
task automatic mem_write(input [31:0] addr, input [7:0] data); |
begin |
mem[addr] = data; |
end |
endtask |
|
//----------------------------------------------------------------- |
// mem_read |
//----------------------------------------------------------------- |
task automatic mem_read(input [31:0] addr, output [7:0] data); |
begin |
if (mem.exists(addr)) |
data = mem[addr]; |
else |
data = 8'bx; |
end |
endtask |
//----------------------------------------------------------------- |
// write_to_ftdi |
//----------------------------------------------------------------- |
task automatic write_to_ftdi(input [31:0] addr, input [11:0] len); |
begin |
integer i; |
reg [7:0] data; |
reg [31:0] addr_tmp; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_rxf <= 1'b0; |
ftdi_data <= {len[11:8], 4'h1}; // WRITE |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_rxf <= 1'b0; |
ftdi_data <= len[7:0]; // LEN |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
// ADDR |
addr_tmp = addr; |
for (i=0;i<4;i=i+1) |
begin |
ftdi_rxf <= 1'b0; |
|
data = addr_tmp[31:24]; |
addr_tmp = {addr_tmp[23:0], 8'b0}; |
|
$display("ADDR%d: %x", i, data); |
ftdi_data <= data; // DATA |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
end |
|
// DATA |
addr_tmp = addr; |
for (i=0;i<len;i=i+1) |
begin |
ftdi_rxf <= 1'b0; |
|
data = $urandom; |
|
$display("BYTE%d: %x", i, data); |
ftdi_data <= data; // DATA |
|
mem_write(addr_tmp, data); |
addr_tmp += 1; |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
end |
end |
endtask |
//----------------------------------------------------------------- |
// write_gp |
//----------------------------------------------------------------- |
task automatic write_gp(input [7:0] gp); |
begin |
integer i; |
reg [7:0] data; |
reg [31:0] addr_tmp; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_rxf <= 1'b0; |
ftdi_data <= {4'b0, 4'h3}; // GP_WR |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_rxf <= 1'b0; |
|
data = $urandom; |
|
ftdi_data <= data; // DATA |
|
mem_write(addr_tmp, data); |
addr_tmp += 1; |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
repeat (2) @(posedge clk); |
`ASSERT(gpio_out == data); |
end |
endtask |
//----------------------------------------------------------------- |
// read_gp |
//----------------------------------------------------------------- |
task automatic read_gp(output [7:0] gp); |
begin |
integer i; |
reg [7:0] data; |
reg [31:0] addr_tmp; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_rxf <= 1'b0; |
ftdi_data <= {4'b0, 4'h4}; // GP_RD |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_txe <= 1'b0; |
|
@(posedge ftdi_wr); |
|
$display("GPIO_IN: %x", u_dut.u_sync.tx_data_q); |
|
ftdi_txe <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
end |
endtask |
//----------------------------------------------------------------- |
// check_mem |
//----------------------------------------------------------------- |
task automatic check_mem(input [31:0] addr, input [31:0] len); |
begin |
integer i; |
reg [7:0] data; |
reg [7:0] actual_data; |
|
// Compare |
for (i=0;i<len;i=i+1) |
begin |
|
mem_read(addr, data); |
u_wbs.read8(addr, actual_data); |
|
if (data !== actual_data) |
begin |
$display("Error @ %x: %x != %x", addr, data, actual_data); |
$finish; |
end |
|
addr += 1; |
|
end |
end |
endtask |
//----------------------------------------------------------------- |
// read_from_ftdi |
//----------------------------------------------------------------- |
task automatic read_from_ftdi(input [31:0] addr, input [11:0] len); |
begin |
integer i; |
reg [7:0] data; |
reg [31:0] addr_tmp; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_rxf <= 1'b0; |
ftdi_data <= {len[11:8], 4'h2}; // READ |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
ftdi_rxf <= 1'b0; |
ftdi_data <= len[7:0]; // LEN |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
|
// ADDR |
addr_tmp = addr; |
for (i=0;i<4;i=i+1) |
begin |
ftdi_rxf <= 1'b0; |
|
data = addr_tmp[31:24]; |
addr_tmp = {addr_tmp[23:0], 8'b0}; |
|
$display("ADDR%d: %x", i, data); |
ftdi_data <= data; // DATA |
|
@(posedge ftdi_rd); |
ftdi_rxf <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
end |
|
// DATA |
addr_tmp = addr; |
for (i=0;i<len;i=i+1) |
begin |
ftdi_txe <= 1'b0; |
|
@(posedge ftdi_wr); |
|
data = $urandom; |
|
$display("READ%d: %x", i, u_dut.u_sync.tx_data_q); |
// TODO: COMP |
mem_write(addr_tmp, u_dut.u_sync.tx_data_q); |
addr_tmp += 1; |
|
ftdi_txe <= 1'b1; |
|
repeat ($urandom_range(MAX_DELAY,0)) @(posedge clk); |
end |
end |
endtask |
|
//----------------------------------------------------------------- |
// Testbench |
//----------------------------------------------------------------- |
initial |
begin |
reg [7:0] tmp; |
|
ftdi_rxf = 1'b1; |
ftdi_data = 8'bz; |
ftdi_txe = 1'b1; |
|
gpio_in = 8'h55; |
|
forever |
begin |
repeat (10) @(posedge clk); |
|
write_to_ftdi(32'h00000000, 16); |
write_gp(4'ha); |
write_to_ftdi(32'h00000010, 16); |
|
read_gp(tmp); |
`ASSERT(tmp == 8'h55); |
|
repeat (100) @(posedge clk); |
check_mem(32'h00000000, 32); |
|
read_from_ftdi(32'h00000000, 16); |
|
repeat (100) @(posedge clk); |
check_mem(32'h00000000, 16); |
|
write_to_ftdi(32'h00000100, 15); |
repeat (100) @(posedge clk); |
check_mem(32'h00000100, 15); |
|
write_to_ftdi(32'h00000201, 14); |
repeat (100) @(posedge clk); |
check_mem(32'h00000201, 14); |
|
write_to_ftdi(32'h00000001, 1); |
repeat (100) @(posedge clk); |
check_mem(32'h00000001, 1); |
|
$finish; |
end |
end |
|
//----------------------------------------------------------------- |
// Instantiation |
//----------------------------------------------------------------- |
assign ftdi_data_io_w = !ftdi_rd ? ftdi_data : 8'bz; |
|
ftdi_if |
u_dut |
( |
.clk_i(clk), |
.rst_i(rst), |
|
// FTDI (async FIFO interface) |
.ftdi_rxf_i(ftdi_rxf), |
.ftdi_txe_i(ftdi_txe), |
.ftdi_siwua_o(), |
.ftdi_wr_o(ftdi_wr), |
.ftdi_rd_o(ftdi_rd), |
.ftdi_d_io(ftdi_data_io_w), |
|
// General Purpose |
.gp_o(gpio_out), |
.gp_i(gpio_in), |
|
// Wishbone Interface |
.mem_addr_o(mem_addr), |
.mem_data_o(mem_data_w), |
.mem_data_i(mem_data_r), |
.mem_sel_o(mem_sel), |
.mem_we_o(mem_we), |
.mem_cyc_o(mem_cyc), |
.mem_stb_o(mem_stb), |
.mem_stall_i(mem_stall), |
.mem_ack_i(mem_ack) |
); |
|
wb_slave |
#( |
.RANDOM_STALLS(1), |
.MAX_RESP_RATE(0) |
) |
u_wbs |
( |
.clk_i(clk), |
.rst_i(rst), |
|
.addr_i(mem_addr), |
.data_i(mem_data_w), |
.data_o(mem_data_r), |
.sel_i(mem_sel), |
.cyc_i(mem_cyc), |
.stb_i(mem_stb), |
.cti_i(3'b111), |
.we_i(mem_we), |
.stall_o(mem_stall), |
.ack_o(mem_ack) |
); |
|
endmodule |
/rtl/ftdi_sync.v
0,0 → 1,277
//----------------------------------------------------------------- |
// FTDI Asynchronous FIFO Interface |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2015 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for |
// use in closed source commercial applications please contact me |
// for details. |
//----------------------------------------------------------------- |
// |
// This file is open source HDL; you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as |
// published by the Free Software Foundation; either version 2 of |
// the License, or (at your option) any later version. |
// |
// This file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public |
// License along with this file; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
// USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: ftdi_sync - Async FT245 FIFO interface |
//----------------------------------------------------------------- |
module ftdi_sync |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
#( |
parameter CLK_DIV = 0 // 0 - X |
) |
|
//----------------------------------------------------------------- |
// Ports |
//----------------------------------------------------------------- |
( |
input clk_i, |
input rst_i, |
|
// FTDI (async FIFO interface) |
input ftdi_rxf_i, |
input ftdi_txe_i, |
output ftdi_siwua_o, |
output reg ftdi_wr_o, |
output reg ftdi_rd_o, |
inout [7:0] ftdi_d_io, |
|
// Synchronous Interface |
output [7:0] data_o, |
input [7:0] data_i, |
input wr_i, |
input rd_i, |
output wr_accept_o, |
output reg rd_ready_o |
); |
|
//----------------------------------------------------------------- |
// Defines / Local params |
//----------------------------------------------------------------- |
localparam STATE_W = 2; |
localparam STATE_IDLE = 2'd0; |
localparam STATE_TX_SETUP = 2'd1; |
localparam STATE_TX = 2'd2; |
localparam STATE_RX = 2'd3; |
|
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
|
// Xilinx placement pragmas: |
//synthesis attribute IOB of tx_data_q is "TRUE" |
//synthesis attribute IOB of ftdi_rd_o is "TRUE" |
//synthesis attribute IOB of ftdi_wr_o is "TRUE" |
|
// Current state |
reg [STATE_W-1:0] state_q; |
|
reg tx_ready_q; |
|
reg ftdi_rxf_ms_q; |
reg ftdi_txe_ms_q; |
reg ftdi_rxf_q; |
reg ftdi_txe_q; |
|
reg [7:0] rx_data_q; |
reg [7:0] tx_data_q; |
|
//----------------------------------------------------------------- |
// Resample async signals |
//----------------------------------------------------------------- |
always @ (posedge clk_i or posedge rst_i) |
if (rst_i) |
begin |
ftdi_rxf_ms_q <= 1'b1; |
ftdi_txe_ms_q <= 1'b1; |
ftdi_rxf_q <= 1'b1; |
ftdi_txe_q <= 1'b1; |
end |
else |
begin |
ftdi_rxf_q <= ftdi_rxf_ms_q; |
ftdi_rxf_ms_q <= ftdi_rxf_i; |
|
ftdi_txe_q <= ftdi_txe_ms_q; |
ftdi_txe_ms_q <= ftdi_txe_i; |
end |
|
//----------------------------------------------------------------- |
// Clock divider |
//----------------------------------------------------------------- |
reg [CLK_DIV:0] clk_div_q; |
|
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
clk_div_q <= {1'b1, {(CLK_DIV){1'b0}}}; |
else if (CLK_DIV > 0) |
clk_div_q <= {clk_div_q[0], clk_div_q[CLK_DIV:1]}; |
else |
clk_div_q <= ~clk_div_q; |
|
wire clk_en_w = clk_div_q[0]; |
|
//----------------------------------------------------------------- |
// Sample flag |
//----------------------------------------------------------------- |
// Sample read data when both RD# and RXF# are low |
wire rx_sample_w = (state_q == STATE_RX) & clk_en_w; |
|
// Target accepts data when WR# and TXE# are low |
wire tx_sent_w = (state_q == STATE_TX) & clk_en_w; |
|
wire rx_ready_w = ~ftdi_rxf_q & clk_en_w; |
wire tx_space_w = ~ftdi_txe_q & clk_en_w; |
|
wire rx_start_w = (state_q == STATE_IDLE) & rx_ready_w & !rd_ready_o; |
wire tx_start_w = (state_q == STATE_IDLE) & tx_space_w & tx_ready_q; |
|
//----------------------------------------------------------------- |
// Next State Logic |
//----------------------------------------------------------------- |
reg [STATE_W-1:0] next_state_r; |
always @ * |
begin |
next_state_r = state_q; |
|
case (state_q) |
//----------------------------------------- |
// STATE_IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
if (rx_start_w) |
next_state_r = STATE_RX; |
else if (tx_start_w) |
next_state_r = STATE_TX_SETUP; |
end |
//----------------------------------------- |
// STATE_RX |
//----------------------------------------- |
STATE_RX : |
begin |
if (clk_en_w) |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// STATE_TX_SETUP |
//----------------------------------------- |
STATE_TX_SETUP : |
begin |
if (clk_en_w) |
next_state_r = STATE_TX; |
end |
//----------------------------------------- |
// STATE_TX |
//----------------------------------------- |
STATE_TX : |
begin |
if (clk_en_w) |
next_state_r = STATE_IDLE; |
end |
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
state_q <= STATE_IDLE; |
else |
state_q <= next_state_r; |
|
//----------------------------------------------------------------- |
// rd_ready_o |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
rd_ready_o <= 1'b0; |
else if (rx_sample_w) |
rd_ready_o <= 1'b1; |
else if (rd_i) |
rd_ready_o <= 1'b0; |
|
//----------------------------------------------------------------- |
// tx_ready_q |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
tx_ready_q <= 1'b0; |
else if (tx_sent_w) |
tx_ready_q <= 1'b0; |
else if (wr_i) |
tx_ready_q <= 1'b1; |
|
assign wr_accept_o = !tx_ready_q; |
|
//----------------------------------------------------------------- |
// RD# |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
ftdi_rd_o <= 1'b1; |
else if (rx_start_w) |
ftdi_rd_o <= 1'b0; |
else if (rx_sample_w) |
ftdi_rd_o <= 1'b1; |
|
//----------------------------------------------------------------- |
// WR# |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
ftdi_wr_o <= 1'b1; |
else if ((state_q == STATE_TX_SETUP) && clk_en_w) |
ftdi_wr_o <= 1'b0; |
else if (tx_sent_w) |
ftdi_wr_o <= 1'b1; |
|
//----------------------------------------------------------------- |
// Rx Data |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
rx_data_q <= 8'b0; |
else if (rx_sample_w) |
rx_data_q <= ftdi_d_io; |
|
//----------------------------------------------------------------- |
// Tx Data |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
tx_data_q <= 8'b0; |
else if (wr_i && wr_accept_o) |
tx_data_q <= data_i; |
|
//----------------------------------------------------------------- |
// Outputs |
//----------------------------------------------------------------- |
|
// Tristate output |
assign ftdi_d_io = (state_q == STATE_TX_SETUP || state_q == STATE_TX) ? tx_data_q : 8'hzz; |
assign ftdi_siwua_o = 1'b1; |
|
assign data_o = rx_data_q; |
|
endmodule |
/rtl/ftdi_if.v
0,0 → 1,529
//----------------------------------------------------------------- |
// FTDI Asynchronous FIFO Interface |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2015 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for |
// use in closed source commercial applications please contact me |
// for details. |
//----------------------------------------------------------------- |
// |
// This file is open source HDL; you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as |
// published by the Free Software Foundation; either version 2 of |
// the License, or (at your option) any later version. |
// |
// This file is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public |
// License along with this file; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
// USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: ftdi_if - Async FT245 FIFO interface |
//----------------------------------------------------------------- |
module ftdi_if |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
#( |
parameter CLK_DIV = 2, // 2 - X |
parameter LITTLE_ENDIAN = 1, // 0 or 1 |
parameter ADDR_W = 32, |
parameter GP_OUTPUTS = 8, // 1 - 8 |
parameter GP_INPUTS = 8, // 1 - 8 |
parameter GP_IN_EVENT_MASK = 8'h00 |
) |
|
//----------------------------------------------------------------- |
// Ports |
//----------------------------------------------------------------- |
( |
input clk_i, |
input rst_i, |
|
// FTDI (async FIFO interface) |
input ftdi_rxf_i, |
input ftdi_txe_i, |
output ftdi_siwua_o, |
output ftdi_wr_o, |
output ftdi_rd_o, |
inout [7:0] ftdi_d_io, |
|
// General Purpose IO |
output [GP_OUTPUTS-1:0] gp_o, |
input [GP_INPUTS-1:0] gp_i, |
|
// Wishbone Interface (Master) |
output [ADDR_W-1:0] mem_addr_o, |
output [31:0] mem_data_o, |
input [31:0] mem_data_i, |
output [3:0] mem_sel_o, |
output reg mem_we_o, |
output reg mem_stb_o, |
output mem_cyc_o, |
input mem_ack_i, |
input mem_stall_i |
); |
|
//----------------------------------------------------------------- |
// Defines / Local params |
//----------------------------------------------------------------- |
localparam CMD_NOP = 4'd0; |
localparam CMD_WR = 4'd1; |
localparam CMD_RD = 4'd2; |
localparam CMD_GP_WR = 4'd3; |
localparam CMD_GP_RD = 4'd4; |
localparam CMD_GP_RD_CLR = 4'd5; |
|
`define CMD_R 3:0 |
`define LEN_UPPER_R 7:4 |
`define LEN_LOWER_R 7:0 |
|
localparam LEN_W = 12; |
|
localparam DATA_W = 8; |
|
localparam STATE_W = 4; |
localparam STATE_IDLE = 4'd0; |
localparam STATE_CMD = 4'd1; |
localparam STATE_LEN = 4'd2; |
localparam STATE_ADDR0 = 4'd3; |
localparam STATE_ADDR1 = 4'd4; |
localparam STATE_ADDR2 = 4'd5; |
localparam STATE_ADDR3 = 4'd6; |
localparam STATE_WRITE = 4'd7; |
localparam STATE_READ = 4'd8; |
localparam STATE_DATA0 = 4'd9; |
localparam STATE_DATA1 = 4'd10; |
localparam STATE_DATA2 = 4'd11; |
localparam STATE_DATA3 = 4'd12; |
localparam STATE_GP_WR = 4'd13; |
localparam STATE_GP_RD = 4'd14; |
|
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
|
// Async I/F <-> sync I/F |
wire [DATA_W-1:0] data_tx_w; |
wire [DATA_W-1:0] data_rx_w; |
wire wr_w; |
wire rd_w; |
wire wr_accept_w; |
wire rx_ready_w; |
|
// Current state |
reg [STATE_W-1:0] state_q; |
|
// Transfer length (for WB read / writes) |
reg [LEN_W-1:0] len_q; |
|
// Mem address (some bits might be unused if ADDR_W < 32) |
reg [31:0] mem_addr_q; |
reg mem_cyc_q; |
|
// Byte Index |
reg [1:0] data_idx_q; |
|
// Word storage |
reg [31:0] data_q; |
|
// GPIO Output Flops |
reg [GP_OUTPUTS-1:0] gp_out_q; |
|
// GPIO Input Flops |
reg [GP_INPUTS-1:0] gp_in_q; |
|
//----------------------------------------------------------------- |
// Next State Logic |
//----------------------------------------------------------------- |
reg [STATE_W-1:0] next_state_r; |
always @ * |
begin |
next_state_r = state_q; |
|
case (state_q) |
//----------------------------------------- |
// STATE_IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
if (rx_ready_w) |
next_state_r = STATE_CMD; |
end |
//----------------------------------------- |
// STATE_CMD |
//----------------------------------------- |
STATE_CMD : |
begin |
if (data_rx_w[`CMD_R] == CMD_NOP) |
next_state_r = STATE_IDLE; |
else if (data_rx_w[`CMD_R] == CMD_WR || data_rx_w[`CMD_R] == CMD_RD) |
next_state_r = STATE_LEN; |
else if (data_rx_w[`CMD_R] == CMD_GP_WR) |
next_state_r = STATE_GP_WR; |
else if (data_rx_w[`CMD_R] == CMD_GP_RD) |
next_state_r = STATE_GP_RD; |
else |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// STATE_LEN |
//----------------------------------------- |
STATE_LEN : |
begin |
if (rx_ready_w) |
next_state_r = STATE_ADDR0; |
end |
//----------------------------------------- |
// STATE_ADDR |
//----------------------------------------- |
STATE_ADDR0 : if (rx_ready_w) next_state_r = STATE_ADDR1; |
STATE_ADDR1 : if (rx_ready_w) next_state_r = STATE_ADDR2; |
STATE_ADDR2 : if (rx_ready_w) next_state_r = STATE_ADDR3; |
STATE_ADDR3 : |
begin |
if (rx_ready_w && mem_we_o) |
next_state_r = STATE_WRITE; |
else if (rx_ready_w) |
next_state_r = STATE_READ; |
end |
//----------------------------------------- |
// STATE_WRITE |
//----------------------------------------- |
STATE_WRITE : |
begin |
if (len_q == {LEN_W{1'b0}} && mem_ack_i) |
next_state_r = STATE_IDLE; |
else |
next_state_r = STATE_WRITE; |
end |
//----------------------------------------- |
// STATE_READ |
//----------------------------------------- |
STATE_READ : |
begin |
// Data ready |
if (mem_ack_i) |
next_state_r = STATE_DATA0; |
end |
//----------------------------------------- |
// STATE_DATA |
//----------------------------------------- |
STATE_DATA0 : |
begin |
if (wr_accept_w) |
next_state_r = STATE_DATA1; |
end |
STATE_DATA1 : |
begin |
if (wr_accept_w) |
next_state_r = STATE_DATA2; |
end |
STATE_DATA2 : |
begin |
if (wr_accept_w) |
next_state_r = STATE_DATA3; |
end |
STATE_DATA3 : |
begin |
if (wr_accept_w && (len_q != {LEN_W{1'b0}})) |
next_state_r = STATE_READ; |
else if (wr_accept_w) |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// STATE_GP_WR |
//----------------------------------------- |
STATE_GP_WR : |
begin |
if (rx_ready_w) |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// STATE_GP_RD |
//----------------------------------------- |
STATE_GP_RD : |
begin |
if (wr_accept_w) |
next_state_r = STATE_IDLE; |
end |
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
state_q <= STATE_IDLE; |
else |
state_q <= next_state_r; |
|
//----------------------------------------------------------------- |
// Async -> Sync I/O |
//----------------------------------------------------------------- |
ftdi_sync |
#( .CLK_DIV(CLK_DIV) ) |
u_sync |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
// FTDI (async FIFO interface) |
.ftdi_rxf_i(ftdi_rxf_i), |
.ftdi_txe_i(ftdi_txe_i), |
.ftdi_siwua_o(ftdi_siwua_o), |
.ftdi_wr_o(ftdi_wr_o), |
.ftdi_rd_o(ftdi_rd_o), |
.ftdi_d_io(ftdi_d_io), |
|
// Synchronous Interface |
.data_o(data_rx_w), |
.data_i(data_tx_w), |
.wr_i(wr_w), |
.rd_i(rd_w), |
.wr_accept_o(wr_accept_w), |
.rd_ready_o(rx_ready_w) |
); |
|
//----------------------------------------------------------------- |
// RD/WR to and from async FTDI I/F |
//----------------------------------------------------------------- |
|
// Write to FTDI interface in the following states |
assign wr_w = (state_q == STATE_DATA0) | |
(state_q == STATE_DATA1) | |
(state_q == STATE_DATA2) | |
(state_q == STATE_DATA3) | |
(state_q == STATE_GP_RD); |
|
// Accept data in the following states |
assign rd_w = (state_q == STATE_CMD) | |
(state_q == STATE_LEN) | |
(state_q == STATE_ADDR0) | |
(state_q == STATE_ADDR1) | |
(state_q == STATE_ADDR2) | |
(state_q == STATE_ADDR3) | |
(state_q == STATE_WRITE && !mem_cyc_o) | |
(state_q == STATE_GP_WR); |
|
//----------------------------------------------------------------- |
// Capture length |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
len_q <= {LEN_W{1'b0}}; |
else if (state_q == STATE_CMD && rx_ready_w) |
len_q[11:8] <= data_rx_w[`LEN_UPPER_R]; |
else if (state_q == STATE_LEN && rx_ready_w) |
len_q[7:0] <= data_rx_w[`LEN_LOWER_R]; |
else if (state_q == STATE_WRITE && rx_ready_w && !mem_cyc_o) |
len_q <= len_q - {{(LEN_W-1){1'b0}}, 1'b1}; |
else if (state_q == STATE_READ && (mem_cyc_o && mem_ack_i)) |
len_q <= len_q - {{(LEN_W-1){1'b0}}, 1'b1}; |
else if (((state_q == STATE_DATA0) || (state_q == STATE_DATA1) || (state_q == STATE_DATA2)) && wr_accept_w) |
len_q <= len_q - {{(LEN_W-1){1'b0}}, 1'b1}; |
|
//----------------------------------------------------------------- |
// Capture addr |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
mem_addr_q <= 'd0; |
else if (state_q == STATE_ADDR0 && rx_ready_w) |
mem_addr_q[31:24] <= data_rx_w; |
else if (state_q == STATE_ADDR1 && rx_ready_w) |
mem_addr_q[23:16] <= data_rx_w; |
else if (state_q == STATE_ADDR2 && rx_ready_w) |
mem_addr_q[15:8] <= data_rx_w; |
else if (state_q == STATE_ADDR3 && rx_ready_w) |
mem_addr_q[7:0] <= data_rx_w; |
// Address increment on every access issued |
else if (state_q == STATE_WRITE && (mem_cyc_o && mem_ack_i)) |
mem_addr_q <= {mem_addr_q[31:2], 2'b0} + 'd4; |
else if (state_q == STATE_READ && (mem_cyc_o && mem_ack_i)) |
mem_addr_q <= {mem_addr_q[31:2], 2'b0} + 'd4; |
|
assign mem_addr_o = {mem_addr_q[ADDR_W-1:2], 2'b0}; |
|
//----------------------------------------------------------------- |
// Data Index |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
data_idx_q <= 2'b0; |
else if (state_q == STATE_ADDR3) |
data_idx_q <= data_rx_w[1:0]; |
else if (state_q == STATE_WRITE && rx_ready_w && !mem_cyc_o) |
data_idx_q <= data_idx_q + 2'd1; |
|
//----------------------------------------------------------------- |
// Data Sample |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
data_q <= 32'b0; |
// In idle state, just sample GPIO inputs flops in-case of reads |
else if (state_q == STATE_IDLE) |
data_q <= {{(32-GP_INPUTS){1'b0}}, gp_in_q}; |
// Write to memory |
else if (state_q == STATE_WRITE && rx_ready_w && !mem_cyc_o) |
begin |
if (LITTLE_ENDIAN) |
begin |
case (data_idx_q) |
2'd0: data_q[7:0] <= data_rx_w; |
2'd1: data_q[15:8] <= data_rx_w; |
2'd2: data_q[23:16] <= data_rx_w; |
2'd3: data_q[31:24] <= data_rx_w; |
endcase |
end |
else |
begin |
case (data_idx_q) |
2'd3: data_q[7:0] <= data_rx_w; |
2'd2: data_q[15:8] <= data_rx_w; |
2'd1: data_q[23:16] <= data_rx_w; |
2'd0: data_q[31:24] <= data_rx_w; |
endcase |
end |
end |
// Read from memory |
else if (state_q == STATE_READ && mem_ack_i) |
begin |
if (LITTLE_ENDIAN) |
data_q <= mem_data_i; |
else |
data_q <= {mem_data_i[7:0], mem_data_i[15:8], mem_data_i[23:16], mem_data_i[31:24]}; |
end |
// Shift data out (read response -> FTDI) |
else if (((state_q == STATE_DATA0) || (state_q == STATE_DATA1) || (state_q == STATE_DATA2)) && wr_accept_w) |
begin |
data_q <= {8'b0, data_q[31:8]}; |
end |
|
assign data_tx_w = data_q[7:0]; |
|
assign mem_data_o = data_q; |
|
//----------------------------------------------------------------- |
// Wishbone: STB |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
mem_stb_o <= 1'b0; |
else if (mem_stb_o) |
begin |
if (!mem_stall_i) |
mem_stb_o <= 1'b0; |
end |
// Every 4th byte, issue bus access |
else if (state_q == STATE_WRITE && rx_ready_w && (data_idx_q == 2'd3 || len_q == 1)) |
mem_stb_o <= 1'b1; |
// Read request |
else if (state_q == STATE_READ && !mem_cyc_o) |
mem_stb_o <= 1'b1; |
|
//----------------------------------------------------------------- |
// Wishbone: SEL |
//----------------------------------------------------------------- |
reg [3:0] mem_sel_q; |
reg [3:0] mem_sel_r; |
|
always @ * |
begin |
mem_sel_r = 4'b1111; |
|
case (data_idx_q) |
2'd0: mem_sel_r = 4'b0001; |
2'd1: mem_sel_r = 4'b0011; |
2'd2: mem_sel_r = 4'b0111; |
2'd3: mem_sel_r = 4'b1111; |
endcase |
|
case (mem_addr_q[1:0]) |
2'd0: mem_sel_r = mem_sel_r & 4'b1111; |
2'd1: mem_sel_r = mem_sel_r & 4'b1110; |
2'd2: mem_sel_r = mem_sel_r & 4'b1100; |
2'd3: mem_sel_r = mem_sel_r & 4'b1000; |
endcase |
end |
|
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
mem_sel_q <= 4'b0; |
// Idle - reset for read requests |
else if (state_q == STATE_IDLE) |
mem_sel_q <= 4'b1111; |
// Every 4th byte, issue bus access |
else if (state_q == STATE_WRITE && rx_ready_w && (data_idx_q == 2'd3 || len_q == 1)) |
mem_sel_q <= mem_sel_r; |
|
assign mem_sel_o = LITTLE_ENDIAN ? mem_sel_q : {mem_sel_q[0], mem_sel_q[1], mem_sel_q[2], mem_sel_q[3]}; |
|
//----------------------------------------------------------------- |
// Wishbone: WE |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
mem_we_o <= 1'b0; |
else if (state_q == STATE_CMD && rx_ready_w) |
mem_we_o <= (data_rx_w[`CMD_R] == CMD_WR); |
|
//----------------------------------------------------------------- |
// Wishbone: CYC |
//----------------------------------------------------------------- |
always @ (posedge clk_i or posedge rst_i) |
if (rst_i == 1'b1) |
mem_cyc_q <= 1'b0; |
else if (mem_stb_o) |
mem_cyc_q <= 1'b1; |
else if (mem_ack_i) |
mem_cyc_q <= 1'b0; |
|
assign mem_cyc_o = mem_stb_o | mem_cyc_q; |
|
//----------------------------------------------------------------- |
// General Purpose Outputs |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
gp_out_q <= {(GP_OUTPUTS){1'b0}}; |
else if (state_q == STATE_GP_WR && rx_ready_w) |
gp_out_q <= data_rx_w[GP_OUTPUTS-1:0]; |
|
assign gp_o = gp_out_q; |
|
//----------------------------------------------------------------- |
// General Purpose Inputs |
//----------------------------------------------------------------- |
reg [GP_INPUTS-1:0] gp_in_r; |
always @ * |
begin |
// GPIO inputs can be normal or pulse capture with clear on read. |
// GP_IN_EVENT_MASK indicates which are 'pulse capture' ones. |
if ((state_q == STATE_GP_RD) && wr_accept_w) |
gp_in_r = gp_i; |
else |
gp_in_r = (gp_in_q & GP_IN_EVENT_MASK) | gp_i; |
end |
|
always @ (posedge rst_i or posedge clk_i) |
if (rst_i) |
gp_in_q <= {(GP_INPUTS){1'b0}}; |
else |
gp_in_q <= gp_in_r; |
|
endmodule |
/sw/poke.c
0,0 → 1,77
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define DEFAULT_FTDI_IFACE 1 |
|
//----------------------------------------------------------------- |
// main: |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int err = 0; |
int c; |
int help = 0; |
int ftdi_iface = DEFAULT_FTDI_IFACE; |
uint32_t addr = 0xFFFFFFFF; |
uint32_t value = 0; |
int quiet = 0; |
|
while ((c = getopt (argc, argv, "a:v:i:q")) != -1) |
{ |
switch(c) |
{ |
case 'a': |
addr = (uint32_t)strtoul(optarg, NULL, 0); |
break; |
case 'v': |
value = (uint32_t)strtoul(optarg, NULL, 0); |
break; |
case 'i': |
ftdi_iface = (int)strtol(optarg, NULL, 0); |
break; |
case 'q': |
quiet = 1; |
break; |
default: |
help = 1; |
break; |
} |
} |
|
if (help || addr == 0xFFFFFFFF) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-a 0xNNNNNNNN = Address to write\n"); |
fprintf (stderr,"-v 0xNNNNNNNN = Data to write\n"); |
fprintf (stderr,"-i id = FTDI interface ID (0 = A, 1 = B)\n"); |
fprintf (stderr,"-q = Quiet mode\n"); |
|
exit(-1); |
} |
|
// Try and communicate with FTDI interface |
if (ftdi_hw_init(ftdi_iface) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing / check connection\n"); |
exit(-2); |
} |
|
if (!quiet) |
printf("Write 0x%x to 0x%x\n", value, addr); |
|
if (ftdi_hw_mem_write_word(addr, value) != sizeof(value)) |
{ |
fprintf(stderr, "ERROR: Could not write to device\n"); |
err = 1; |
} |
|
ftdi_hw_close(); |
|
return err; |
} |
/sw/load.c
0,0 → 1,170
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define CHUNK_SIZE 256 |
#define DEFAULT_FTDI_IFACE 1 |
|
//----------------------------------------------------------------- |
// load_file_to_mem |
//----------------------------------------------------------------- |
static uint8_t* load_file_to_mem(const char *filename, long size_override, int *pSize) |
{ |
uint8_t *buf = NULL; |
FILE *f = fopen(filename, "rb"); |
|
*pSize = 0; |
|
if (f) |
{ |
long size; |
|
// Get size of file |
fseek(f, 0, SEEK_END); |
size = ftell(f); |
rewind(f); |
|
// User overriden file size |
if (size_override >= 0) |
{ |
if (size > size_override) |
size = size_override; |
} |
|
buf = (uint8_t*)malloc(size); |
if (buf) |
{ |
// Read file data into allocated memory |
int len = fread(buf, 1, size, f); |
if (len != size) |
{ |
free(buf); |
buf = NULL; |
} |
else |
*pSize = size; |
} |
fclose(f); |
} |
|
return buf; |
} |
//----------------------------------------------------------------- |
// upload |
//----------------------------------------------------------------- |
static int upload(uint32_t addr, uint8_t *buf, int length) |
{ |
int err = 0; |
int i; |
int size; |
|
for (i=0;i<length;i+=CHUNK_SIZE) |
{ |
size = (length - i); |
if (size > CHUNK_SIZE) |
size = CHUNK_SIZE; |
|
if (ftdi_hw_mem_write(addr, buf, size) != size) |
{ |
fprintf(stderr, "Upload: Error uploading file\n"); |
err = 1; |
break; |
} |
|
addr += CHUNK_SIZE; |
buf += CHUNK_SIZE; |
|
printf("\r%d%%", (i * 100) / length); |
fflush(stdout); |
} |
|
return err; |
} |
//----------------------------------------------------------------- |
// main |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int c; |
long size_override = -1; |
char *filename = NULL; |
int help = 0; |
int err = 1; |
int size; |
uint32_t address = 0x0; |
uint8_t *buf; |
int ftdi_iface = DEFAULT_FTDI_IFACE; |
|
while ((c = getopt (argc, argv, "f:s:a:i:")) != -1) |
{ |
switch(c) |
{ |
case 'f': |
filename = optarg; |
break; |
case 's': |
size_override = strtol(optarg, NULL, 0); |
break; |
case 'a': |
address = strtoul(optarg, NULL, 0); |
break; |
case 'i': |
ftdi_iface = (int)strtol(optarg, NULL, 0); |
break; |
default: |
help = 1; |
break; |
} |
} |
|
if (help || filename == NULL) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-f filename.bin = Executable to load (binary)\n"); |
fprintf (stderr,"-a 0xnnnn = Address to load to (default to 0x0)\n"); |
fprintf (stderr,"-i id = FTDI interface ID (0 = A, 1 = B)\n"); |
fprintf (stderr,"-s 0xnnnn = Size override\n"); |
|
exit(-1); |
} |
|
// Try and communicate with FTDI interface |
if (ftdi_hw_init(ftdi_iface) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing / check connection\n"); |
exit(-2); |
} |
|
// Read file into memory |
buf = load_file_to_mem(filename, size_override, &size); |
if (buf) |
{ |
printf("Loading %s (%dKB) to 0x%x:\n", filename, (size + 1023) / 1024, address); |
|
// Upload file to target |
err = upload(address, buf, size); |
|
// Free file memory |
free(buf); |
buf = NULL; |
|
if (!err) |
printf("\rDone!\n"); |
else |
printf("\rFailed!\n"); |
} |
else |
{ |
fprintf (stderr,"Error: Could not open image\n"); |
err = 1; |
} |
|
ftdi_hw_close(); |
|
return err; |
} |
/sw/makefile.mk
0,0 → 1,31
############################################################################### |
## Makefile |
############################################################################### |
|
# Target |
TARGET ?= test |
|
# Options |
CFLAGS = -g |
LDFLAGS = |
LIBS = -lftdi |
|
# Source Files |
OBJ = ftdi_hw.o $(TARGET).o |
|
############################################################################### |
# Rules |
############################################################################### |
all: $(TARGET) |
|
clean: |
-rm *.o $(TARGET) |
|
%.o : %.c |
gcc -c $(CFLAGS) $< -o $@ |
|
%.o : %.cpp |
g++ -c $(CFLAGS) $< -o $@ |
|
$(TARGET): $(OBJ) |
g++ $(LDFLAGS) $(OBJ) $(LIBS) -o $@ |
/sw/peek.c
0,0 → 1,76
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define DEFAULT_FTDI_IFACE 1 |
|
//----------------------------------------------------------------- |
// main: |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int err = 0; |
int c; |
int help = 0; |
int ftdi_iface = DEFAULT_FTDI_IFACE; |
uint32_t addr = 0xFFFFFFFF; |
uint32_t value = 0; |
int quiet = 0; |
|
while ((c = getopt (argc, argv, "a:i:q")) != -1) |
{ |
switch(c) |
{ |
case 'a': |
addr = (uint32_t)strtoul(optarg, NULL, 0); |
break; |
case 'i': |
ftdi_iface = (int)strtol(optarg, NULL, 0); |
break; |
case 'q': |
quiet = 1; |
break; |
default: |
help = 1; |
break; |
} |
} |
|
if (help || addr == 0xFFFFFFFF) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-a 0xNNNNNNNN = Address to read\n"); |
fprintf (stderr,"-i id = FTDI interface ID (0 = A, 1 = B)\n"); |
fprintf (stderr,"-q = Quiet mode (data returned via return value)\n"); |
|
exit(-1); |
} |
|
// Try and communicate with FTDI interface |
if (ftdi_hw_init(ftdi_iface) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing / check connection\n"); |
exit(-2); |
} |
|
if (ftdi_hw_mem_read_word(addr, &value) != sizeof(value)) |
{ |
fprintf(stderr, "ERROR: Could not read from device\n"); |
err = 1; |
} |
|
if (!quiet) |
{ |
printf("Read 0x%x from 0x%x\n", value, addr); |
value = 0; |
} |
|
ftdi_hw_close(); |
|
return err ? -1 : value; |
} |
/sw/ftdi_hw.c
0,0 → 1,275
#include <stdio.h> |
#include <ftdi.h> |
|
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define CMD_NOP 0x0 |
#define CMD_WR 0x1 |
#define CMD_RD 0x2 |
#define CMD_GP_WR 0x3 |
#define CMD_GP_RD 0x4 |
|
#define MAX_TX_SIZE 2048 |
#define HDR_SIZE 6 |
|
#define FTDI_PID 0x0403 |
#define FTDI_VID 0x6010 |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static struct ftdi_context *_handle; |
|
//----------------------------------------------------------------- |
// ftdi_hw_init: |
//----------------------------------------------------------------- |
int ftdi_hw_init(int interface) |
{ |
int status; |
|
_handle = ftdi_new(); |
if (!_handle) |
return -1; |
|
// Open channel |
ftdi_set_interface(_handle, interface ? INTERFACE_B : INTERFACE_A); |
status = ftdi_usb_open(_handle, FTDI_PID, FTDI_VID); |
if (status != 0) |
{ |
ftdi_free(_handle); |
_handle = NULL; |
return -1; |
} |
|
// Reset FTDI |
status = ftdi_usb_reset(_handle); |
if (status != 0) |
{ |
ftdi_usb_close(_handle); |
ftdi_free(_handle); |
_handle = NULL; |
return -1; |
} |
|
// Flush buffers |
status = ftdi_usb_purge_buffers(_handle); |
if (status != 0) |
{ |
ftdi_usb_close(_handle); |
ftdi_free(_handle); |
_handle = NULL; |
return -1; |
} |
|
// Set transfer mode |
status = ftdi_set_bitmode(_handle, 0xFF, BITMODE_RESET); |
if (status != 0) |
{ |
ftdi_usb_close(_handle); |
ftdi_free(_handle); |
_handle = NULL; |
return -1; |
} |
|
return 0; |
} |
//----------------------------------------------------------------- |
// ftdi_hw_close: |
//----------------------------------------------------------------- |
int ftdi_hw_close(void) |
{ |
if (_handle) |
{ |
ftdi_usb_close(_handle); |
ftdi_free(_handle); |
_handle = NULL; |
} |
|
return 0; |
} |
//----------------------------------------------------------------- |
// ftdi_hw_mem_write: |
//----------------------------------------------------------------- |
int ftdi_hw_mem_write(uint32_t addr, uint8_t *data, int length) |
{ |
int i; |
int sent = 0; |
int size = length; |
int res; |
uint8_t buffer[MAX_TX_SIZE + HDR_SIZE]; |
uint8_t *p; |
|
while (sent < length) |
{ |
size = (length - sent); |
if (size > MAX_TX_SIZE) |
size = MAX_TX_SIZE; |
|
// Build packet header |
p = buffer; |
*p++ = (((size >> 8) & 0xF) << 4) | CMD_WR; |
*p++ = (size & 0xFF); |
|
*p++ = (addr >> 24); |
*p++ = (addr >> 16); |
*p++ = (addr >> 8); |
*p++ = (addr >> 0); |
|
// Fill packet payload |
for (i=0;i<size;i++) |
*p++ = *data++; |
|
// Write request + data to FTDI device |
res = ftdi_write_data(_handle, buffer, (size + HDR_SIZE)); |
if (res != (size + HDR_SIZE)) |
{ |
fprintf(stderr, "ftdi_hw_mem_write: Failed to send\n"); |
return -1; |
} |
|
sent += size; |
addr += size; |
} |
|
return sent; |
} |
//----------------------------------------------------------------- |
// ftdi_hw_mem_read: |
//----------------------------------------------------------------- |
int ftdi_hw_mem_read(uint32_t addr, uint8_t *data, int length) |
{ |
int i; |
int received = 0; |
int size = length; |
int remain; |
int res; |
uint8_t buffer[HDR_SIZE]; |
uint8_t *p; |
|
while (received < length) |
{ |
size = (length - received); |
if (size > MAX_TX_SIZE) |
size = MAX_TX_SIZE; |
|
// Round up to nearest 4 byte multiple |
size = (size + 3) & ~3; |
|
// Build packet header |
p = buffer; |
*p++ = (((size >> 8) & 0xF) << 4) | CMD_RD; |
*p++ = (size & 0xFF); |
|
*p++ = (addr >> 24); |
*p++ = (addr >> 16); |
*p++ = (addr >> 8); |
*p++ = (addr >> 0); |
|
// Write request to FTDI device |
res = ftdi_write_data(_handle, buffer, HDR_SIZE); |
if (res != HDR_SIZE) |
{ |
fprintf(stderr, "ftdi_hw_mem_read: Failed to send request\n"); |
return -1; |
} |
|
remain = size; |
do |
{ |
res = ftdi_read_data(_handle, data, remain); |
if (res < 0) |
{ |
fprintf(stderr, "ftdi_hw_mem_read: Failed to read data\n"); |
return -1; |
} |
|
remain -= res; |
data += res; |
} |
while (remain > 0); |
|
received += size; |
addr += size; |
} |
|
return received; |
} |
//----------------------------------------------------------------- |
// ftdi_hw_mem_write_word: |
//----------------------------------------------------------------- |
int ftdi_hw_mem_write_word(uint32_t addr, uint32_t data) |
{ |
uint8_t buffer[4]; |
|
buffer[3] = (data >> 24); |
buffer[2] = (data >> 16); |
buffer[1] = (data >> 8); |
buffer[0] = (data >> 0); |
|
return ftdi_hw_mem_write(addr, buffer, 4); |
} |
//----------------------------------------------------------------- |
// ftdi_hw_mem_read_word: |
//----------------------------------------------------------------- |
int ftdi_hw_mem_read_word(uint32_t addr, uint32_t *data) |
{ |
uint8_t buffer[4]; |
|
int res = ftdi_hw_mem_read(addr, buffer, 4); |
if (res > 0) |
{ |
(*data) = ((uint32_t)buffer[3]) << 24; |
(*data)|= ((uint32_t)buffer[2]) << 16; |
(*data)|= ((uint32_t)buffer[1]) << 8; |
(*data)|= ((uint32_t)buffer[0]) << 0; |
} |
return res; |
} |
//----------------------------------------------------------------- |
// ftdi_hw_gpio_write: |
//----------------------------------------------------------------- |
int ftdi_hw_gpio_write(uint8_t value) |
{ |
uint8_t buffer[2] = { CMD_GP_WR, value }; |
|
// Write request to FTDI device |
int res = ftdi_write_data(_handle, buffer, sizeof(buffer)); |
if (res != sizeof(buffer)) |
{ |
fprintf(stderr, "ftdi_hw_mem_write: Failed to send\n"); |
return -1; |
} |
|
return 0; |
} |
//----------------------------------------------------------------- |
// ftdi_hw_gpio_read: |
//----------------------------------------------------------------- |
int ftdi_hw_gpio_read(uint8_t *value) |
{ |
// Write request to FTDI device |
uint8_t request = CMD_GP_RD; |
int res = ftdi_write_data(_handle, &request, 1); |
if (res != 1) |
{ |
fprintf(stderr, "ftdi_hw_mem_write: Failed to send\n"); |
return -1; |
} |
|
// Poll for response |
do |
{ |
res = ftdi_read_data(_handle, value, 1); |
if (res < 0) |
{ |
fprintf(stderr, "ftdi_hw_mem_read: Failed to read data\n"); |
return -1; |
} |
} |
while (res != 1); |
|
return 0; |
} |
/sw/verify.c
0,0 → 1,184
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define CHUNK_SIZE 256 |
#define DEFAULT_FTDI_IFACE 1 |
|
//----------------------------------------------------------------- |
// load_file_to_mem |
//----------------------------------------------------------------- |
static uint8_t* load_file_to_mem(const char *filename, long size_override, int *pSize) |
{ |
uint8_t *buf = NULL; |
FILE *f = fopen(filename, "rb"); |
|
*pSize = 0; |
|
if (f) |
{ |
long size; |
|
// Get size of file |
fseek(f, 0, SEEK_END); |
size = ftell(f); |
rewind(f); |
|
// User overriden file size |
if (size_override >= 0) |
{ |
if (size > size_override) |
size = size_override; |
} |
|
buf = (uint8_t*)malloc(size); |
if (buf) |
{ |
// Read file data into allocated memory |
int len = fread(buf, 1, size, f); |
if (len != size) |
{ |
free(buf); |
buf = NULL; |
} |
else |
*pSize = size; |
} |
fclose(f); |
} |
|
return buf; |
} |
//----------------------------------------------------------------- |
// compare |
//----------------------------------------------------------------- |
static int compare(uint32_t addr, uint8_t *data, int length) |
{ |
uint8_t buf[CHUNK_SIZE]; |
int res = 1; |
int i; |
int size; |
|
for (i=0;i<length;i+=CHUNK_SIZE) |
{ |
size = (length - i); |
if (size > CHUNK_SIZE) |
size = CHUNK_SIZE; |
|
if (ftdi_hw_mem_read(addr, buf, size) != size) |
{ |
fprintf(stderr, "Compare: Error downloading file\n"); |
res = -1; |
break; |
} |
|
// Check for differences |
if (memcmp(data, buf, size) != 0) |
{ |
res = 0; |
break; |
} |
|
addr += CHUNK_SIZE; |
data += CHUNK_SIZE; |
|
printf("\r%d%%", (i * 100) / length); |
fflush(stdout); |
} |
|
return res; |
} |
//----------------------------------------------------------------- |
// main |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int c; |
long size_override = -1; |
char *filename = NULL; |
int help = 0; |
int err = 1; |
int res; |
int size; |
uint32_t address = 0x0; |
uint8_t *buf; |
int ftdi_iface = DEFAULT_FTDI_IFACE; |
|
while ((c = getopt (argc, argv, "f:s:a:i:")) != -1) |
{ |
switch(c) |
{ |
case 'f': |
filename = optarg; |
break; |
case 's': |
size_override = strtol(optarg, NULL, 0); |
break; |
case 'a': |
address = strtoul(optarg, NULL, 0); |
break; |
case 'i': |
ftdi_iface = (int)strtol(optarg, NULL, 0); |
break; |
default: |
help = 1; |
break; |
} |
} |
|
if (help || filename == NULL) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-f filename.bin = Executable to compare (binary)\n"); |
fprintf (stderr,"-a 0xnnnn = Address to compare to (default to 0x0)\n"); |
fprintf (stderr,"-i id = FTDI interface ID (0 = A, 1 = B)\n"); |
fprintf (stderr,"-s 0xnnnn = Size override\n"); |
|
exit(-1); |
} |
|
// Try and communicate with FTDI interface |
if (ftdi_hw_init(ftdi_iface) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing / check connection\n"); |
exit(-2); |
} |
|
// Read file into memory |
buf = load_file_to_mem(filename, size_override, &size); |
if (buf) |
{ |
printf("Comparing %s (%dKB) to 0x%x:\n", filename, (size + 1023) / 1024, address); |
|
// Upload file to target |
res = compare(address, buf, size); |
|
// Free file memory |
free(buf); |
buf = NULL; |
|
if (res == 1) |
printf("\nMatches!\n"); |
else if (res == 0) |
printf("\nDiffers!\n"); |
else |
{ |
printf("\n"); |
err = 1; |
} |
} |
else |
{ |
fprintf (stderr,"Error: Could not open image\n"); |
err = 1; |
} |
|
ftdi_hw_close(); |
|
return err; |
} |
/sw/sdram_test.c
0,0 → 1,147
#include <stdio.h> |
#include <sys/time.h> |
|
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define DEFAULT_FTDI_IFACE 1 |
#define BLOCK_SIZE 2048 |
|
#define MEM_SIZE ((32 * 1024) / 4) |
|
static uint32_t mem[MEM_SIZE]; |
|
//----------------------------------------------------------------- |
// main |
//----------------------------------------------------------------- |
int main(void) |
{ |
uint32_t buffer[BLOCK_SIZE/4]; |
uint32_t req; |
uint32_t resp; |
uint32_t addr; |
uint8_t gpio; |
struct timeval t1, t2; |
double elapsedTime; |
int res; |
int i; |
|
if (ftdi_hw_init(DEFAULT_FTDI_IFACE) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing\n"); |
return 0; |
} |
|
addr = 0x00000000; |
req = 0x12345678; |
ftdi_hw_mem_write_word(addr, req); |
ftdi_hw_mem_read_word(addr, &resp); |
|
if (req != resp) |
{ |
printf("ERR0: %x != %x\n", req, resp); |
} |
|
addr = 0x00000004; |
req = 0xcafebabe; |
ftdi_hw_mem_write_word(addr, req); |
ftdi_hw_mem_read_word(addr, &resp); |
|
if (req != resp) |
{ |
printf("ERR1: %x != %x\n", req, resp); |
} |
|
addr = 0x00000000; |
req = 0x12345678; |
ftdi_hw_mem_read_word(addr, &resp); |
|
if (req != resp) |
{ |
printf("ERR2: %x != %x\n", req, resp); |
} |
|
for (i=0;i<MEM_SIZE;i++) |
mem[i] = 0; |
|
printf("Erasing memory\n"); |
ftdi_hw_mem_write(0, (uint8_t*)mem, MEM_SIZE); |
printf("Erasing memory - done\n"); |
|
// Start timer |
gettimeofday(&t1, NULL); |
|
int sent = 0; |
while (1) |
{ |
// SINGLE |
if (rand() & 1) |
{ |
addr = rand() & ((MEM_SIZE * 4) - 1); |
addr &= ~3; |
|
req = rand(); |
|
ftdi_hw_mem_write(addr, (uint8_t*)&req, 4); |
ftdi_hw_mem_read(addr, (uint8_t*)&resp, 4); |
sent += 4; |
|
if (req != resp) |
{ |
printf("ERR (RB): %x - %x != %x\n", addr, req, resp); |
} |
|
mem[addr/4] = req; |
|
addr = rand() & (MEM_SIZE - 1); |
addr &= ~3; |
|
ftdi_hw_mem_read(addr, (uint8_t*)&resp, 4); |
sent += (4 * 3); |
|
if (mem[addr/4] != resp) |
{ |
printf("ERR (MEM): %x - %x != %x\n", addr, mem[addr/4], resp); |
} |
} |
// BLOCK |
else |
{ |
addr = rand() & ((MEM_SIZE * 4) - 1); |
addr &= ~3; |
|
// Stop block from overflowing RAM |
if (addr > ((MEM_SIZE * 4) - BLOCK_SIZE)) |
addr = ((MEM_SIZE * 4) - BLOCK_SIZE); |
|
for (i=0;i<BLOCK_SIZE / 4;i++) |
{ |
buffer[i] = rand(); |
mem[(addr/4)+i] = buffer[i]; |
} |
|
// Write block |
ftdi_hw_mem_write(addr, (uint8_t*)&buffer, BLOCK_SIZE); |
sent += BLOCK_SIZE; |
} |
|
// Stop timer |
gettimeofday(&t2, NULL); |
|
elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms |
elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms |
|
if (((int)elapsedTime) >= 1000) |
{ |
printf("%dKB/s\n", sent / 1024); |
|
gettimeofday(&t1, NULL); |
sent = 0; |
} |
} |
|
ftdi_hw_close(); |
return 0; |
} |
/sw/dump.c
0,0 → 1,130
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define CHUNK_SIZE 256 |
#define DEFAULT_FTDI_IFACE 1 |
|
//----------------------------------------------------------------- |
// download |
//----------------------------------------------------------------- |
static int download(FILE *f, uint32_t addr, int length) |
{ |
uint8_t buf[CHUNK_SIZE]; |
int err = 0; |
int i; |
int size; |
|
for (i=0;i<length;i+=CHUNK_SIZE) |
{ |
size = (length - i); |
if (size > CHUNK_SIZE) |
size = CHUNK_SIZE; |
|
if (ftdi_hw_mem_read(addr, buf, size) != size) |
{ |
fprintf(stderr, "Download: Error downloading file\n"); |
err = 1; |
break; |
} |
|
if (fwrite(buf, 1, size, f) != size) |
{ |
fprintf(stderr, "Download: Error writing file\n"); |
err = 1; |
break; |
} |
|
addr += CHUNK_SIZE; |
|
printf("\r%d%%", (i * 100) / length); |
fflush(stdout); |
} |
|
return err; |
} |
//----------------------------------------------------------------- |
// main |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int c; |
int size = -1; |
char *filename = NULL; |
int help = 0; |
int err = 1; |
uint32_t address = 0x0; |
int ftdi_iface = DEFAULT_FTDI_IFACE; |
FILE *f = NULL; |
|
while ((c = getopt (argc, argv, "o:s:a:i:")) != -1) |
{ |
switch(c) |
{ |
case 'o': |
filename = optarg; |
break; |
case 's': |
size = (int)strtol(optarg, NULL, 0); |
break; |
case 'a': |
address = strtoul(optarg, NULL, 0); |
break; |
case 'i': |
ftdi_iface = (int)strtol(optarg, NULL, 0); |
break; |
default: |
help = 1; |
break; |
} |
} |
|
if (help || filename == NULL || size < 0) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-o filename.bin = Output filename\n"); |
fprintf (stderr,"-s n = Size to dump\n"); |
fprintf (stderr,"-a 0xnnnn = Address to dump from (default to 0x0)\n"); |
fprintf (stderr,"-i id = FTDI interface ID (0 = A, 1 = B)\n"); |
|
exit(-1); |
} |
|
// Try and communicate with FTDI interface |
if (ftdi_hw_init(ftdi_iface) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing / check connection\n"); |
exit(-2); |
} |
|
// Try and create new file |
f = fopen(filename, "wb"); |
if (f) |
{ |
printf("Downloading %s (%dKB) from 0x%x:\n", filename, (size + 1023) / 1024, address); |
|
err = download(f, address, size); |
|
if (!err) |
printf("\rDone!\n"); |
else |
printf("\rFailed!\n"); |
|
fclose(f); |
f = NULL; |
} |
else |
{ |
fprintf (stderr,"Error: Could not create file\n"); |
err = 1; |
} |
|
ftdi_hw_close(); |
|
return err; |
} |
/sw/gpio_write.c
0,0 → 1,72
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define DEFAULT_FTDI_IFACE 1 |
|
//----------------------------------------------------------------- |
// main: |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int err = 0; |
int c; |
int help = 0; |
int ftdi_iface = DEFAULT_FTDI_IFACE; |
uint8_t value = 0; |
int quiet = 0; |
|
while ((c = getopt (argc, argv, "v:i:q")) != -1) |
{ |
switch(c) |
{ |
case 'v': |
value = (uint8_t)strtoul(optarg, NULL, 0); |
break; |
case 'i': |
ftdi_iface = (int)strtol(optarg, NULL, 0); |
break; |
case 'q': |
quiet = 1; |
break; |
default: |
help = 1; |
break; |
} |
} |
|
if (help) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-v 0xNN = Data to write\n"); |
fprintf (stderr,"-i id = FTDI interface ID (0 = A, 1 = B)\n"); |
fprintf (stderr,"-q = Quiet mode\n"); |
|
exit(-1); |
} |
|
// Try and communicate with FTDI interface |
if (ftdi_hw_init(ftdi_iface) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing / check connection\n"); |
exit(-2); |
} |
|
if (!quiet) |
printf("Write 0x%x to GPIO\n", value); |
|
if (ftdi_hw_gpio_write(value) != 0) |
{ |
fprintf(stderr, "ERROR: Could not write to device\n"); |
err = 1; |
} |
|
ftdi_hw_close(); |
|
return err; |
} |
/sw/gpio_read.c
0,0 → 1,72
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include "ftdi_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define DEFAULT_FTDI_IFACE 1 |
|
//----------------------------------------------------------------- |
// main: |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int err = 0; |
int c; |
int help = 0; |
int ftdi_iface = DEFAULT_FTDI_IFACE; |
uint8_t value = 0; |
int quiet = 0; |
|
while ((c = getopt (argc, argv, "i:q")) != -1) |
{ |
switch(c) |
{ |
case 'i': |
ftdi_iface = (int)strtol(optarg, NULL, 0); |
break; |
case 'q': |
quiet = 1; |
break; |
default: |
help = 1; |
break; |
} |
} |
|
if (help) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-v 0xNN = Data to write\n"); |
fprintf (stderr,"-i id = FTDI interface ID (0 = A, 1 = B)\n"); |
fprintf (stderr,"-q = Quiet mode (data returned via return value)\n"); |
|
exit(-1); |
} |
|
// Try and communicate with FTDI interface |
if (ftdi_hw_init(ftdi_iface) != 0) |
{ |
fprintf(stderr, "ERROR: Could not open FTDI interface, try SUDOing / check connection\n"); |
exit(-2); |
} |
|
if (ftdi_hw_gpio_read(&value) != 0) |
{ |
fprintf(stderr, "ERROR: Could not read from device\n"); |
err = 1; |
} |
|
if (!quiet) |
{ |
printf("Read 0x%x from GPIO\n", value); |
value = 0; |
} |
|
ftdi_hw_close(); |
|
return err ? -1 : value; |
} |
/sw/ftdi_hw.h
0,0 → 1,26
#ifndef _FTDI_HW_H_ |
#define _FTDI_HW_H_ |
|
#include <stdint.h> |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
int ftdi_hw_init(int interface); |
int ftdi_hw_close(void); |
|
// Memory Access |
int ftdi_hw_mem_write(uint32_t addr, uint8_t *data, int length); |
int ftdi_hw_mem_read(uint32_t addr, uint8_t *data, int length); |
int ftdi_hw_mem_write_word(uint32_t addr, uint32_t data); |
int ftdi_hw_mem_read_word(uint32_t addr, uint32_t *data); |
|
// GPIO |
int ftdi_hw_gpio_write(uint8_t value); |
int ftdi_hw_gpio_read(uint8_t *value); |
|
#endif |
/sw/makefile
0,0 → 1,23
############################################################################### |
# Rules |
############################################################################### |
all: |
make -f makefile.mk TARGET=load |
make -f makefile.mk TARGET=peek |
make -f makefile.mk TARGET=poke |
make -f makefile.mk TARGET=dump |
make -f makefile.mk TARGET=verify |
make -f makefile.mk TARGET=gpio_read |
make -f makefile.mk TARGET=gpio_write |
make -f makefile.mk TARGET=sdram_test |
|
clean: |
make -f makefile.mk TARGET=load clean |
make -f makefile.mk TARGET=peek clean |
make -f makefile.mk TARGET=poke clean |
make -f makefile.mk TARGET=dump clean |
make -f makefile.mk TARGET=verify clean |
make -f makefile.mk TARGET=gpio_read clean |
make -f makefile.mk TARGET=gpio_write clean |
make -f makefile.mk TARGET=sdram_test clean |
|