projects/nexys2_host_controller/host/epp_write
projects/nexys2_host_controller/host/digdude
projects/nexys2_host_controller/host/jtag
+projects/nexys2_host_controller/host/stm
.idea/
--- /dev/null
+--------------------------------------------------------------------------------
+-- dl_stb_o - a byte from the host is ready for the device
+-- dl_rdy_i - the device is ready to accept bytes (valid even when dl_stb_o unasserted - not an ack!)
+-- dl_dat_o - current byte to stream download from the host
+-- dl_end_o - byte transfered in previous clock cycle was the final byte
+--------------------------------------------------------------------------------
+-- ul_stb_i - a byte from the device is ready for the host
+-- ul_rdy_o - the host acknowledges the byte from the device
+-- ul_dat_i - byte to stream upload to the host
+-- ul_end_i - extra bit associated with ul_dat_i indicating that this is the last byte in a transfer
+--------------------------------------------------------------------------------
+
+-- There is a potential problem here that doesn't look like it can be solved.
+-- When ending a transfer, the controller will deassert FLAGA/B to signal that
+-- no more bytes are available for download or no more space is free for upload.
+-- The maximum potential delay between the IFCLK edge and the FLAGx changing is
+-- listed in the datasheet as T_XFLG = 9.6 ns. Since the IFCLK period is 20.83
+-- ns, that leaves 11.33 ns of slack before the next edge. However, the setup
+-- time for the SLRD and SLWR signals, T_SRD/T_SWR is 18.7 ns. So when the
+-- controller signals with the FLAGx signals that a transfer is complete, there
+-- isn't enough time left within that cycle to deassert SLRD/SLWR while still
+-- meeting timing. Leaving SLRD/SLWR asserted and releasing them in the next
+-- cycle feels like it would be a workable solution (since there's nothing left
+-- to transfer anyway), but some of the FIFO logic appears to still be active
+-- and future transfers get messed up when this is done. So here, we just
+-- release the SLRD/SLWR signals within the same clock cycle, potentially too
+-- late, and it seems to accidentally work well enough in practice.
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity stmex_wb is
+ port (
+ -- STM-bus signals
+ ifclk: in std_logic;
+ stmen: in std_logic;
+ db_i: in std_logic_vector(7 downto 0);
+ db_o: out std_logic_vector(7 downto 0);
+ flaga: in std_logic;
+ flagb: in std_logic;
+ fifoadr: out std_logic_vector(1 downto 0);
+ slrd: out std_logic;
+ slwr: out std_logic;
+ sloe: out std_logic;
+ pktend: out std_logic;
+
+ -- Download (host to device) Wishbone-like bus signals
+ dl_stb_o: out std_logic;
+ dl_rdy_i: in std_logic;
+ dl_dat_o: out std_logic_vector(7 downto 0);
+ dl_end_o: out std_logic;
+
+ -- Upload (device to host) Wishbone-like bus signals
+ ul_stb_i: in std_logic;
+ ul_ack_o: out std_logic;
+ ul_dat_i: in std_logic_vector(7 downto 0);
+ ul_end_i: in std_logic
+ );
+end stmex_wb;
+
+
+architecture behavioral of stmex_wb is
+
+ type state_t is (S_IDLE, S_DOWNLOAD, S_UPLOAD, S_PKTEND);
+ signal state_cur: state_t;
+ signal state_next: state_t;
+
+ signal fifoadr_int: std_logic_vector(1 downto 0);
+ signal slrd_int: std_logic;
+ signal slwr_int: std_logic;
+ signal sloe_int: std_logic;
+ signal pktend_int: std_logic;
+
+begin
+
+ dl_dat_o <= db_i;
+
+ -- Signals are externally pulled up, gate on stmen
+ fifoadr <= fifoadr_int;
+ slrd <= slrd_int;
+ slwr <= slwr_int;
+ sloe <= sloe_int;
+ pktend <= pktend_int;
+ db_o <= ul_dat_i;
+
+ process (ifclk, stmen, state_next)
+ begin
+ if rising_edge(ifclk) then
+ if stmen = '0' then
+ state_cur <= S_IDLE;
+ else
+ state_cur <= state_next;
+ end if;
+ end if;
+ end process;
+
+ process (state_cur, flaga, flagb, dl_rdy_i, ul_stb_i, ul_end_i)
+ begin
+ state_next <= state_cur;
+
+ slrd_int <= '1';
+ slwr_int <= '1';
+ sloe_int <= '1';
+ pktend_int <= '1';
+ fifoadr_int <= "00";
+
+ dl_stb_o <= '0';
+ dl_end_o <= '0';
+ ul_ack_o <= '0';
+
+ case state_cur is
+ when S_IDLE =>
+ -- Select fifoadr before entering upload/download state because the setup time is longer than one ifclk cycle
+ -- The max delay for the flagx signals should leave plenty of clock left to meet setup time for fifoadr
+ -- If setup time for FIFOADR still can't be met for some reason, entering an S_PRE_DOWNLOAD or S_PRE_UPLOAD
+ -- state before the S_DOWNLOAD or S_UPLOAD states would give a full cycle to assert the correct FIFOADR.
+ if flaga = '0' and dl_rdy_i = '1' then
+ fifoadr_int <= "00";
+ state_next <= S_DOWNLOAD;
+ elsif flagb = '0' and ul_stb_i = '1' then
+ fifoadr_int <= "10";
+ state_next <= S_UPLOAD;
+ end if;
+
+ when S_DOWNLOAD =>
+ fifoadr_int <= "00";
+ sloe_int <= '0';
+ slrd_int <= '0';
+ dl_stb_o <= '1';
+
+ if flaga = '1' or dl_rdy_i = '0' then
+ slrd_int <= '1';
+ dl_stb_o <= '0';
+ dl_end_o <= '1';
+ state_next <= S_IDLE;
+ end if;
+
+ when S_UPLOAD =>
+ fifoadr_int <= "10";
+ slwr_int <= '0';
+ ul_ack_o <= '1';
+
+ if flagb = '1' or ul_stb_i = '0' then
+ slwr_int <= '1';
+ ul_ack_o <= '0';
+ state_next <= S_IDLE;
+ elsif ul_end_i = '1' then
+ -- If the device signals an end-of-packet for this byte, leave SLWR asserted since
+ -- this byte still needs to be accepted.
+ state_next <= S_PKTEND;
+ end if;
+
+ when S_PKTEND =>
+ fifoadr_int <= "10";
+ pktend_int <= '0';
+ state_next <= S_IDLE;
+
+ when others =>
+ state_next <= S_IDLE;
+ end case;
+ end process;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library utility;
+
+library work;
+
+
+entity nexys2_stm is
+ port (
+ clk_50: in std_logic;
+
+ DB: inout std_logic_vector(7 downto 0);
+ DstmIFCLK: in std_logic;
+ DstmSLCS: in std_logic;
+ DstmFLAGA: in std_logic;
+ DstmFLAGB: in std_logic;
+ DstmADR: out std_logic_vector(1 downto 0);
+ DstmSLRD: out std_logic;
+ DstmSLWR: out std_logic;
+ DstmSLOE: out std_logic;
+ DstmPKTEND: out std_logic
+ );
+end nexys2_stm;
+
+
+architecture behavioral of nexys2_stm is
+
+ signal dl_stb: std_logic;
+ signal dl_rdy: std_logic;
+ signal dl_dat: std_logic_vector(7 downto 0);
+
+ signal ul_stb: std_logic;
+ signal ul_ack: std_logic;
+ signal ul_dat: std_logic_vector(7 downto 0);
+
+ signal int_stb: std_logic;
+ signal int_ack: std_logic;
+ signal int_dat: std_logic_vector(7 downto 0);
+
+begin
+
+ e_stm_wb: entity work.stmex_wb
+ port map (
+ ifclk => DstmIFCLK,
+ stmen => DstmSLCS,
+ db => DB,
+ flaga => DstmFLAGA,
+ flagb => DstmFLAGB,
+ fifoadr => DstmADR,
+ slrd => DstmSLRD,
+ slwr => DstmSLWR,
+ sloe => DstmSLOE,
+ pktend => DstmPKTEND,
+
+ dl_stb_o => dl_stb,
+ dl_rdy_i => dl_rdy,
+ dl_dat_o => dl_dat,
+ dl_end_o => open,
+
+ ul_stb_i => ul_stb,
+ ul_rdy_o => ul_ack,
+ ul_dat_i => ul_dat,
+ ul_end_i => '0'
+ );
+
+ e_dl_fifo: entity utility.fifo_xclk
+ port map (
+ head_clk_i => DstmIFCLK,
+ head_stb_i => dl_stb,
+ head_ack_o => dl_rdy,
+ head_dat_i => dl_dat,
+
+ tail_clk_i => clk_50,
+ tail_stb_o => int_stb,
+ tail_ack_i => int_ack,
+ tail_dat_o => int_dat
+ );
+
+ e_ul_fifo: entity utility.fifo_xclk
+ port map (
+ head_clk_i => clk_50,
+ head_stb_i => int_stb,
+ head_ack_o => int_ack,
+ head_dat_i => int_dat,
+
+ tail_clk_i => DstmIFCLK,
+ tail_stb_o => ul_stb,
+ tail_ack_i => ul_ack,
+ tail_dat_o => ul_dat
+ );
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library simulated;
+
+
+entity test_nexys2stm is
+end test_nexys2stm;
+
+
+architecture behavior of test_nexys2stm is
+
+ signal db: std_logic_vector(7 downto 0);
+ signal ifclk: std_logic;
+ signal slcs: std_logic;
+ signal flaga: std_logic;
+ signal flagb: std_logic;
+ signal fifoadr: std_logic_vector(1 downto 0);
+ signal slrd: std_logic;
+ signal slwr: std_logic;
+ signal sloe: std_logic;
+ signal pktend: std_logic;
+
+ signal dl_data: std_logic_vector(7 downto 0);
+ signal ul_count: integer;
+
+ signal clk_50: std_logic;
+
+begin
+
+ p_test: process
+ begin
+ DB <= (others => 'Z');
+ wait for 50 ns;
+ dl_data <= x"a0"; wait for 0 ns;
+ dl_data <= x"a1"; wait for 0 ns;
+ dl_data <= x"a2"; wait for 0 ns;
+ dl_data <= x"a3"; wait for 0 ns;
+ dl_data <= x"a4"; wait for 0 ns;
+ dl_data <= x"a5"; wait for 0 ns;
+ dl_data <= x"a6"; wait for 0 ns;
+ dl_data <= x"a7"; wait for 0 ns;
+ ul_count <= 8; wait for 0 ns;
+
+ wait for 600 ns;
+
+ dl_data <= x"b0"; wait for 0 ns;
+ dl_data <= x"b1"; wait for 0 ns;
+ dl_data <= x"b2"; wait for 0 ns;
+ dl_data <= x"b3"; wait for 0 ns;
+ dl_data <= x"b4"; wait for 0 ns;
+ dl_data <= x"b5"; wait for 0 ns;
+ dl_data <= x"b6"; wait for 0 ns;
+ dl_data <= x"b7"; wait for 0 ns;
+ ul_count <= 8; wait for 0 ns;
+
+ --dl_data <= x"c0"; wait for 0 ns;
+ --dl_data <= x"c1"; wait for 0 ns;
+ --dl_data <= x"c2"; wait for 0 ns;
+ --dl_data <= x"c3"; wait for 0 ns;
+ --dl_data <= x"c4"; wait for 0 ns;
+ --dl_data <= x"c5"; wait for 0 ns;
+ --dl_data <= x"c6"; wait for 0 ns;
+ --dl_data <= x"c7"; wait for 0 ns;
+ --dl_data <= x"d0"; wait for 0 ns;
+ --dl_data <= x"d1"; wait for 0 ns;
+ --dl_data <= x"d2"; wait for 0 ns;
+ --dl_data <= x"d3"; wait for 0 ns;
+ --dl_data <= x"d4"; wait for 0 ns;
+ --dl_data <= x"d5"; wait for 0 ns;
+ --dl_data <= x"d6"; wait for 0 ns;
+ --dl_data <= x"d7"; wait for 0 ns;
+
+ wait;
+ end process;
+
+
+ e_host: entity simulated.stmhost
+ port map (
+ ifclk => ifclk,
+ slcs => slcs,
+ flaga => flaga,
+ flagb => flagb,
+ slrd => slrd,
+ slwr => slwr,
+ sloe => sloe,
+ pktend => pktend,
+ fifoadr => fifoadr,
+ db => db,
+
+ host_dl_data => dl_data,
+ host_ul_count => ul_count
+ );
+
+
+ e_uut: entity work.nexys2_stm
+ port map (
+ clk_50 => clk_50,
+ DB => db,
+ DstmIFCLK => ifclk,
+ DstmSLCS => slcs,
+ DstmFLAGA => flaga,
+ DstmFLAGB => flagb,
+ DstmADR => fifoadr,
+ DstmSLRD => slrd,
+ DstmSLWR => slwr,
+ DstmSLOE => sloe,
+ DstmPKTEND => pktend
+ );
+
+ p_clk: process
+ begin
+ clk_50 <= '0';
+ wait for 10 ns;
+ clk_50 <= '1';
+ wait for 10 ns;
+ end process;
+
+end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library simulated;
+
+library utility;
+
+
+entity test_stmex is
+end test_stmex;
+
+
+architecture behavior of test_stmex is
+
+ -- Host
+ signal dl_data: std_logic_vector(7 downto 0);
+ signal ul_count: integer;
+
+ -- STM interface
+ signal ifclk: std_logic;
+ signal stmen: std_logic;
+ signal db: std_logic_vector(7 downto 0);
+ signal flaga: std_logic;
+ signal flagb: std_logic;
+ signal fifoadr: std_logic_vector(1 downto 0);
+ signal slrd: std_logic;
+ signal slwr: std_logic;
+ signal sloe: std_logic;
+ signal pktend: std_logic;
+
+ -- Device download interface
+ signal dl_stb: std_logic;
+ signal dl_rdy: std_logic;
+ signal dl_dat: std_logic_vector(7 downto 0);
+ signal dl_end: std_logic;
+
+ -- Device upload interface
+ signal ul_stb: std_logic;
+ signal ul_rdy: std_logic;
+ signal ul_dat: std_logic_vector(7 downto 0);
+ signal ul_end: std_logic;
+
+ -- Internal interface
+ signal int_stb: std_logic;
+ signal int_ack: std_logic;
+ signal int_dat: std_logic_vector(7 downto 0);
+
+begin
+
+ p_test: process
+ begin
+ --dl_rdy <= '1';
+ --ul_stb <= '0';
+
+ wait until falling_edge(ifclk);
+ wait until falling_edge(ifclk);
+ wait until falling_edge(ifclk);
+ wait until falling_edge(ifclk);
+ wait until falling_edge(ifclk);
+ wait until falling_edge(ifclk);
+ wait until falling_edge(ifclk);
+ wait until falling_edge(ifclk);
+
+ dl_data <= x"a0"; wait for 0 ns;
+ dl_data <= x"a1"; wait for 0 ns;
+ dl_data <= x"a2"; wait for 0 ns;
+ dl_data <= x"a3"; wait for 0 ns;
+ dl_data <= x"a4"; wait for 0 ns;
+ dl_data <= x"a5"; wait for 0 ns;
+ dl_data <= x"a6"; wait for 0 ns;
+ dl_data <= x"a7"; wait for 0 ns;
+ dl_data <= x"b0"; wait for 0 ns;
+ dl_data <= x"b1"; wait for 0 ns;
+ dl_data <= x"b2"; wait for 0 ns;
+ dl_data <= x"b3"; wait for 0 ns;
+ dl_data <= x"b4"; wait for 0 ns;
+ dl_data <= x"b5"; wait for 0 ns;
+ dl_data <= x"b6"; wait for 0 ns;
+ dl_data <= x"b7"; wait for 0 ns;
+ dl_data <= x"c0"; wait for 0 ns;
+ dl_data <= x"c1"; wait for 0 ns;
+ dl_data <= x"c2"; wait for 0 ns;
+ dl_data <= x"c3"; wait for 0 ns;
+ dl_data <= x"c4"; wait for 0 ns;
+ dl_data <= x"c5"; wait for 0 ns;
+ dl_data <= x"c6"; wait for 0 ns;
+ dl_data <= x"c7"; wait for 0 ns;
+ dl_data <= x"d0"; wait for 0 ns;
+ dl_data <= x"d1"; wait for 0 ns;
+ dl_data <= x"d2"; wait for 0 ns;
+ dl_data <= x"d3"; wait for 0 ns;
+ dl_data <= x"d4"; wait for 0 ns;
+ dl_data <= x"d5"; wait for 0 ns;
+ dl_data <= x"d6"; wait for 0 ns;
+ dl_data <= x"d7"; wait for 0 ns;
+ ul_count <= 32; wait for 0 ns;
+
+ --wait until dl_stb = '1';
+ --wait until falling_edge(ifclk);
+ --wait until falling_edge(ifclk);
+ --wait until falling_edge(ifclk);
+ --wait until rising_edge(ifclk);
+ --wait for 2 ns;
+ --dl_rdy <= '0';
+ --wait until falling_edge(ifclk);
+ --wait until falling_edge(ifclk);
+ --wait until falling_edge(ifclk);
+ --wait until rising_edge(ifclk);
+ --wait for 2 ns;
+ --dl_rdy <= '1';
+
+ wait;
+ end process;
+
+ e_dl_fifo: entity utility.fifo_xclk
+ port map (
+ head_clk_i => ifclk,
+ head_stb_i => dl_stb,
+ head_ack_o => dl_rdy,
+ head_dat_i => dl_dat,
+
+ tail_clk_i => ifclk,
+ tail_stb_o => int_stb,
+ tail_ack_i => int_ack,
+ tail_dat_o => int_dat
+ );
+
+ e_ul_fifo: entity utility.fifo_xclk
+ port map (
+ head_clk_i => ifclk,
+ head_stb_i => int_stb,
+ head_ack_o => int_ack,
+ head_dat_i => int_dat,
+
+ tail_clk_i => ifclk,
+ tail_stb_o => ul_stb,
+ tail_ack_i => ul_rdy,
+ tail_dat_o => ul_dat
+ );
+
+ e_uut: entity work.stmex_wb
+ port map (
+ ifclk => ifclk,
+ stmen => stmen,
+ db => db,
+ flaga => flaga,
+ flagb => flagb,
+ fifoadr => fifoadr,
+ slrd => slrd,
+ slwr => slwr,
+ sloe => sloe,
+ pktend => pktend,
+
+ dl_stb_o => dl_stb,
+ dl_rdy_i => dl_rdy,
+ dl_dat_o => dl_dat,
+ dl_end_o => open, -- dl_end,
+
+ ul_stb_i => ul_stb,
+ ul_rdy_o => ul_rdy,
+ ul_dat_i => ul_dat,
+ ul_end_i => '0' -- ul_end
+ );
+
+ e_host: entity simulated.stmhost
+ port map (
+ ifclk => ifclk,
+ slcs => stmen,
+ flaga => flaga,
+ flagb => flagb,
+ slrd => slrd,
+ slwr => slwr,
+ sloe => sloe,
+ pktend => pktend,
+ fifoadr => fifoadr,
+ db => db,
+
+ host_dl_data => dl_data,
+ host_ul_count => ul_count
+ );
+
+end;
gcc -o jtag jtag.c ec.c $CFLAGS -I $INC -L $LIBDIR -ldmgr -ldjtg
+gcc -o stm stm.c ec.c $CFLAGS -I $INC -L $LIBDIR -ldmgr -ldstm
--- /dev/null
+#include <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+
+// Digilent SDK
+#include "dpcdecl.h"
+#include "dstm.h"
+#include "dmgr.h"
+
+#include "ec.h"
+
+
+// -----------------------------------------------------------------------------
+
+
+#define SIZE (65536*32)
+#define COUNT 16
+
+
+// -----------------------------------------------------------------------------
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "STM test program for Digilent Nexys2\n"
+ "\n"
+ "Usage: stm [options]\n"
+ "\nConnection options:\n"
+ " -p, --part <name> Specify device (default: \"Nexys2\")\n"
+ " -P, --port <portnum> STM port number (default: 0)\n"
+ "\nOutput options:\n"
+ " -v, --verbose Verbose output; -v -v for more\n"
+ " -q, --quell Quell progress output; -q -q for less\n"
+ " -?, --help Display this message\n"
+ "\n"
+ );
+}
+
+
+int main(int argc, char **argv)
+{
+ // Arguments with defaults
+ char *part = "Nexys2";
+ int32_t port = 0;
+ int verbose = 0;
+ int quell = 0;
+
+ // Options
+ int opt;
+ int option_idx = 0;
+ struct option longopts[] = {
+ // Output options
+ {"help", no_argument, NULL, '?'},
+ {"quell", no_argument, NULL, 'q'},
+ {"verbose", no_argument, NULL, 'v'},
+
+ // Connection options
+ {"part", required_argument, NULL, 'p'},
+ {"port", required_argument, NULL, 'P'},
+ };
+
+ // Port handle and properties
+ HIF hif = hifInvalid;
+ int32_t port_count;
+ char version[cchVersionMax];
+
+ // -------------------------------------------------------------
+ // Parse arguments
+
+ while ((opt = getopt_long(argc, argv, "?qvp:P:", longopts, &option_idx)) != -1)
+ {
+ switch (opt)
+ {
+ case '?': usage(); exit(0); break;
+ case 'q': quell++; break;
+ case 'v': verbose++; break;
+
+ case 'p': part = optarg; break;
+ case 'P': port = strtol(optarg, NULL, 0); break;
+
+ default:
+ fprintf(stderr, "Invalid option -%c\n\n", opt);
+ usage();
+ exit(1);
+ break;
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Open session
+
+ EC_FALSE(DstmGetVersion(version));
+ printf("DSTM version: %s\n", version);
+
+ EC_FALSE(DmgrOpen(&hif, part));
+ printf("Opened device \"%s\"\n", part);
+
+ EC_FALSE(DstmGetPortCount(hif, &port_count));
+ printf("Port count: %" PRIi32 "\n", port_count);
+ for (int32_t i = 0; i < port_count; i++)
+ {
+ uint32_t port_properties = 0;
+
+ EC_FALSE(DstmGetPortProperties(hif, i, &port_properties));
+ printf("Port %" PRIi32 " properties: 0x%08" PRIx32 "\n", i, port_properties);
+ }
+
+ EC_FALSE(DstmEnableEx(hif, port));
+ printf("Opened STM port %" PRIi32 "\n", port);
+
+ // -------------------------------------------------------------
+ // Do something interesting
+
+ uint8_t dl_data[SIZE] = {0};
+ uint8_t ul_data[SIZE] = {0};
+ for (size_t i = 0; i < SIZE; i++)
+ {
+ dl_data[i] = (uint8_t)i;
+ }
+
+ for (int i = 0; i < COUNT; i++)
+ {
+ // Separate download/upload call transfer
+ //printf("Downloading\n");
+ //EC_FALSE(DstmIO(hif, dl_data, SIZE, NULL, 0, false));
+ //printf("Uploading\n");
+ //EC_FALSE(DstmIO(hif, NULL, 0, ul_data, SIZE, false));
+
+ // Single call transfer
+ //printf("Transfering\n");
+ EC_FALSE(DstmIOEx(hif, dl_data, SIZE, ul_data, SIZE, false));
+
+ //printf("Checking\n");
+ EC_NZ(memcmp(dl_data, ul_data, SIZE));
+ }
+
+ printf("Correct! Transferred %d bytes %d times.\n", SIZE, COUNT);
+
+ // -------------------------------------------------------------
+ // Close session
+
+ if (hif != hifInvalid)
+ {
+ DstmDisable(hif);
+ DmgrClose(hif);
+ printf("Closed session\n");
+ }
+
+ return 0;
+
+EC_CLEANUP_BEGIN
+ if (hif != hifInvalid)
+ {
+ DstmDisable(hif);
+ DmgrClose(hif);
+ }
+
+ ec_print();
+ return 1;
+EC_CLEANUP_END
+}
+