simple_ram_behavioural_tb.o: wishbone_types.o simple_ram_behavioural.o
simple_ram_behavioural.o: wishbone_types.o simple_ram_behavioural_helpers.o
sim_uart.o: wishbone_types.o sim_console.o
-soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o simple_ram_behavioural.o dmi_dtm_xilinx.o
+soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o simple_ram_behavioural.o dmi_dtm_xilinx.o wishbone_debug_master.o
wishbone_arbiter.o: wishbone_types.o
wishbone_types.o:
writeback.o: common.o
-dmi_dtm_tb.o: dmi_dtm_xilinx.o
+dmi_dtm_tb.o: dmi_dtm_xilinx.o wishbone_debug_master.o
dmi_dtm_xilinx.o: sim-unisim/unisim_vcomponents.o
+wishbone_debug_master.o: wishbone_types.o
UNISIM_BITS = sim-unisim/unisim_vcomponents.vhdl sim-unisim/BSCANE2.vhdl sim-unisim/BUFG.vhdl
sim-unisim/unisim_vcomponents.o: $(UNISIM_BITS)
simple_ram_behavioural_tb: simple_ram_behavioural_helpers_c.o simple_ram_behavioural_tb.o
$(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@
-dmi_dtm_tb: dmi_dtm_tb.o
- $(GHDL) -e $(GHDLFLAGS) $@
+dmi_dtm_tb: dmi_dtm_tb.o simple_ram_behavioural_helpers_c.o
+ $(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@
tests = $(sort $(patsubst tests/%.out,%,$(wildcard tests/*.out)))
dmi_ack => dmi_ack
);
- -- Dummy loopback until a debug module is present
- dmi_din <= dmi_dout;
- dmi_ack <= dmi_ack;
+ simple_ram_0: entity work.mw_soc_memory
+ generic map(RAM_INIT_FILE => "simple_ram_behavioural.bin",
+ MEMORY_SIZE => 524288)
+ port map(clk => clk, rst => rst,
+ wishbone_in => wishbone_ram_out,
+ wishbone_out => wishbone_ram_in);
+
+ wishbone_debug_0: entity work.wishbone_debug_master
+ port map(clk => clk, rst => rst,
+ dmi_addr => dmi_addr(1 downto 0),
+ dmi_dout => dmi_din,
+ dmi_din => dmi_dout,
+ dmi_wr => dmi_wr,
+ dmi_ack => dmi_ack,
+ dmi_req => dmi_req,
+ wb_in => wishbone_ram_in,
+ wb_out => wishbone_ram_out);
-- system clock
sys_clk: process
-- send command
dmi_read(x"00", data);
report "Read addr reg:" & to_hstring(data);
+ report "Writing addr reg to all 1's";
+ dmi_write(x"00", (others => '1'));
+ dmi_read(x"00", data);
+ report "Read addr reg:" & to_hstring(data);
+
+ report "Writing ctrl reg to all 1's";
+ dmi_write(x"02", (others => '1'));
+ dmi_read(x"02", data);
+ report "Read ctrl reg:" & to_hstring(data);
+
+ report "Read memory at 0...\n";
+ dmi_write(x"00", x"0000000000000000");
+ dmi_write(x"02", x"00000000000007ff");
+ dmi_read(x"01", data);
+ report "00:" & to_hstring(data);
+ dmi_read(x"01", data);
+ report "08:" & to_hstring(data);
+ dmi_read(x"01", data);
+ report "10:" & to_hstring(data);
+ dmi_read(x"01", data);
+ report "18:" & to_hstring(data);
+ clock(10);
std.env.finish;
end process;
end behave;
- multiply.vhdl
- writeback.vhdl
- insn_helpers.vhdl
+ - wishbone_debug_master.vhdl
- core.vhdl
- icache.vhdl
file_type : vhdlSource-2008
soc:
files:
- wishbone_arbiter.vhdl
+ - wishbone_debug_master.vhdl
- soc.vhdl
file_type : vhdlSource-2008
urc.set_instruction("USER2")
urc.shift_ir()
- print("Reading 0x00: %x" % do_read(urc, 0))
- print("Reading 0xaa: %x" % do_read(urc, 0xaa))
+ print("Reading memory at 0:")
+ do_write(urc, 0, 0)
+ do_write(urc, 2, 0x7ff)
+ print("00: %016x" % do_read(urc, 1))
+ print("08: %016x" % do_read(urc, 1))
+ print("10: %016x" % do_read(urc, 1))
+ print("18: %016x" % do_read(urc, 1))
+ do_write(urc, 0, 0x10)
+ do_write(urc, 1, 0xabcdef0123456789)
+ do_write(urc, 0, 0)
+ do_write(urc, 2, 0x7ff)
+ print("00: %016x" % do_read(urc, 1))
+ print("08: %016x" % do_read(urc, 1))
+ print("10: %016x" % do_read(urc, 1))
+ print("18: %016x" % do_read(urc, 1))
+
+# urc.set_dr_in(0,73,0);
+# print("Test DR_IN 1:", urc.get_dr_in_string())
+# urc.set_dr_in(0xa,3,0);
+# print("Test DR_IN 2:", urc.get_dr_in_string())
+# urc.set_dr_in(0x5,7,4);
+# print("Test DR_IN 3:", urc.get_dr_in_string())
+# urc.set_dr_in(1,73,73);
+# print("Test DR_IN 4:", urc.get_dr_in_string())
+
+# print("Reading ADDR reg: %x" % do_read(urc, 0))
+# print("Writing all 1's to it:")
+# do_write(urc, 0, 0xffffffffffffffff)
+# print("Reading ADDR reg: %x" % do_read(urc, 0))
+# print("Writing 0xabcdef0123456789 to it:")
+# do_write(urc, 0, 0xabcdef0123456789)
+# print("Reading ADDR reg: %x" % do_read(urc, 0))
+
+
+
+# urc.set_dr_in(0x1,41,0)
+# print("Sending:", urc.get_dr_in_string())
+# urc.shift_dr()
+# urc.set_dr_in(0x0,41,0)
+# urc.shift_dr()
+# print("Got1:", urc.get_dr_out_string())
+# urc.shift_dr()
+# print("Got2:", hex(urc.get_dr_out()))
if __name__ == "__main__":
wb_out => wb_master_out, wb_in => wb_master_in
);
- -- Dummy wishbone debug module
- wishbone_debug_out.cyc <= '0';
- wishbone_debug_out.stb <= '0';
-
-- Wishbone slaves address decoder & mux
slave_intercon: process(wb_master_out, wb_bram_out, wb_uart0_out)
-- Selected slave
dmi_ack => dmi_ack
);
- -- Dummy loopback until a debug module is present
- dmi_din <= dmi_dout;
- dmi_ack <= dmi_ack;
+ -- Wishbone debug master (TODO: Add a DMI address decoder)
+ wishbone_debug: entity work.wishbone_debug_master
+ port map(clk => system_clk, rst => rst,
+ dmi_addr => dmi_addr(1 downto 0),
+ dmi_dout => dmi_din,
+ dmi_din => dmi_dout,
+ dmi_wr => dmi_wr,
+ dmi_ack => dmi_ack,
+ dmi_req => dmi_req,
+ wb_in => wishbone_debug_in,
+ wb_out => wishbone_debug_out);
+
end architecture behaviour;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.wishbone_types.all;
+
+entity wishbone_debug_master is
+ port(clk : in std_ulogic;
+ rst : in std_ulogic;
+
+ -- Debug bus interface
+ dmi_addr : in std_ulogic_vector(1 downto 0);
+ dmi_din : in std_ulogic_vector(63 downto 0);
+ dmi_dout : out std_ulogic_vector(63 downto 0);
+ dmi_req : in std_ulogic;
+ dmi_wr : in std_ulogic;
+ dmi_ack : out std_ulogic;
+
+ -- Wishbone master interface
+ wb_out : out wishbone_master_out;
+ wb_in : in wishbone_slave_out
+ );
+end entity wishbone_debug_master;
+
+architecture behaviour of wishbone_debug_master is
+
+ -- ** Register offsets definitions. All registers are 64-bit
+ constant DBG_WB_ADDR : std_ulogic_vector(1 downto 0) := "00";
+ constant DBG_WB_DATA : std_ulogic_vector(1 downto 0) := "01";
+ constant DBG_WB_CTRL : std_ulogic_vector(1 downto 0) := "10";
+ constant DBG_WB_RSVD : std_ulogic_vector(1 downto 0) := "11";
+
+ -- CTRL register:
+ --
+ -- bit 0..7 : SEL bits (byte enables)
+ -- bit 8 : address auto-increment
+ -- bit 10..9 : auto-increment value:
+ -- 00 - +1
+ -- 01 - +2
+ -- 10 - +4
+ -- 11 - +8
+
+ -- ** Address and control registers and read data
+ signal reg_addr : std_ulogic_vector(63 downto 0);
+ signal reg_ctrl_out : std_ulogic_vector(63 downto 0);
+ signal reg_ctrl : std_ulogic_vector(10 downto 0);
+ signal data_latch : std_ulogic_vector(63 downto 0);
+
+ type state_t is (IDLE, WB_CYCLE, DMI_WAIT);
+ signal state : state_t;
+
+begin
+
+ -- Hard wire unused bits to 0
+ reg_ctrl_out <= (63 downto 11 => '0',
+ 10 downto 0 => reg_ctrl);
+
+ -- DMI read data mux
+ with dmi_addr select dmi_dout <=
+ reg_addr when DBG_WB_ADDR,
+ data_latch when DBG_WB_DATA,
+ reg_ctrl_out when DBG_WB_CTRL,
+ (others => '0') when others;
+
+ -- ADDR and CTRL register writes
+ reg_write : process(clk)
+ subtype autoinc_inc_t is integer range 1 to 8;
+ function decode_autoinc(c : std_ulogic_vector(1 downto 0))
+ return autoinc_inc_t is
+ begin
+ case c is
+ when "00" => return 1;
+ when "01" => return 2;
+ when "10" => return 4;
+ when "11" => return 8;
+ -- Below shouldn't be necessary but GHDL complains
+ when others => return 8;
+ end case;
+ end function decode_autoinc;
+ begin
+ if rising_edge(clk) then
+ if (rst) then
+ reg_addr <= (others => '0');
+ reg_ctrl <= (others => '0');
+ else -- Standard register writes
+ if dmi_req and dmi_wr then
+ if dmi_addr = DBG_WB_ADDR then
+ reg_addr <= dmi_din;
+ elsif dmi_addr = DBG_WB_CTRL then
+ reg_ctrl <= dmi_din(10 downto 0);
+ end if;
+ end if;
+ -- Address register auto-increment
+ if state = WB_CYCLE and (wb_in.ack and reg_ctrl(8))= '1' then
+ reg_addr <= std_ulogic_vector(unsigned(reg_addr) +
+ decode_autoinc(reg_ctrl(10 downto 9)));
+ end if;
+ end if;
+ end if;
+ end process;
+
+ -- ACK is hard wired to req for register writes. For data read/writes
+ -- (aka commands), it's sent when the state machine got the WB ack.
+ --
+ -- Note: We never set it to 1, we just pass dmi_req back when acking.
+ -- This fullfills two purposes:
+ --
+ -- * Avoids polluting the ack signal when another DMI slave is
+ -- selected. This allows the decoder to just OR all the acks
+ -- together rather than mux them.
+ --
+ -- * Makes ack go down on the same cycle as req goes down, thus
+ -- saving a clock cycle. This is safe because we know that
+ -- the state machine will no longer be in DMI_WAIT state on
+ -- the next cycle, so we won't be bouncing the signal back up.
+ --
+ dmi_ack <= dmi_req when (dmi_addr /= DBG_WB_DATA or state = DMI_WAIT) else '0';
+
+ -- Some WB signals are direct wires from registers or DMI
+ wb_out.adr <= reg_addr;
+ wb_out.dat <= dmi_din;
+ wb_out.sel <= reg_ctrl(7 downto 0);
+ wb_out.we <= dmi_wr;
+
+ -- We always move WB cyc and stb simultaneously (no pipelining yet...)
+ wb_out.cyc <= '1' when state = WB_CYCLE else '0';
+ wb_out.stb <= '1' when state = WB_CYCLE else '0';
+
+ -- Data latch. WB will take the read data away as soon as the cycle
+ -- terminates but we must maintain it on DMI until req goes down, so
+ -- we latch it. (Q: Should we move that latch to dmi_dtm itself ?)
+ --
+ latch_reads : process(clk)
+ begin
+ if rising_edge(clk) then
+ if state = WB_CYCLE and wb_in.ack = '1' and dmi_wr = '0' then
+ data_latch <= wb_in.dat;
+ end if;
+ end if;
+ end process;
+
+ -- Command state machine (generate wb_cyc)
+ wb_trigger : process(clk)
+ begin
+ if rising_edge(clk) then
+ if (rst) then
+ state <= IDLE;
+ else
+ case state is
+ when IDLE =>
+ if dmi_req = '1' and dmi_addr = DBG_WB_DATA then
+ state <= WB_CYCLE;
+ end if;
+ when WB_CYCLE =>
+ if wb_in.ack then
+ state <= DMI_WAIT;
+ end if;
+ when DMI_WAIT =>
+ if dmi_req = '0' then
+ state <= IDLE;
+ end if;
+ end case;
+ end if;
+ end if;
+ end process;
+end architecture behaviour;