From f0c22bf2e159b8c7c7a2c15ea546d5d08790f706 Mon Sep 17 00:00:00 2001 From: Martin Meloun Date: Wed, 18 Sep 2013 16:18:44 +0200 Subject: [PATCH] Multiple changes in FPGA, include Tumbl coprocessor - remove deprecated control bram - remove testing bcd counter - fix IRC indexing reacting on index level - update ucf file - Tumbl: add sumbodule - Tumbl: add lx-rocon implementation for Spartan6 - Tumbl: add primitive firmware (requires MicroBlaze binutils and gcc to compile) - do not use coregen, infer the bram or use primitives - Master CPU bus: now on 100 MHz instead of 72 MHz - Master CPU bus: rd / bls is async and filtered --- .gitmodules | 3 + hw/Makefile | 49 ++- hw/bcd.vhd | 50 --- hw/bus_bcd.vhd | 83 ----- hw/bus_calibration.vhd | 37 +-- hw/bus_control_bram.vhd | 96 ------ hw/bus_irc.vhd | 22 +- hw/bus_tumbl.vhd | 268 +++++++++++++++++ hw/calibration_read_register.vhd | 15 +- hw/calibration_write_register.vhd | 22 +- hw/dff2.vhd | 41 +++ hw/ipcore_dir/control_bram.ngc | 3 - hw/ipcore_dir/control_bram.vhd | 164 ---------- hw/irc_reader.vhd | 70 ++--- hw/irc_register.vhd | 75 ++--- hw/lx-rocon.ucf | 8 +- hw/lx-rocon_firmware/firmware.c | 83 +++++ hw/lx-rocon_firmware/start.S | 66 ++++ hw/lx-rocon_firmware/utils | 1 + hw/lx-rocon_tumbl/lx_rocon_dmem.vhd | 72 +++++ hw/lx-rocon_tumbl/lx_rocon_gprf_abd.vhd | 161 ++++++++++ hw/lx-rocon_tumbl/lx_rocon_imem.vhd | 64 ++++ hw/lx-rocon_tumbl/lx_rocon_tumbl.vhd | 298 ++++++++++++++++++ hw/lx-rocon_tumbl/tb/lx_rocon_tumbl_tb.vhd | 143 +++++++++ hw/lx_rocon_pkg.vhd | 334 +++++++++++++++++++++ hw/lx_rocon_top.prj | 19 +- hw/lx_rocon_top.vhd | 270 ++++++++--------- hw/qcounter.vhd | 66 +++- hw/tb/lx_rocon_top_tb.vhd | 210 ++----------- hw/tumbl | 1 + hw/xilinx_dualport_bram.vhd | 96 ++++++ submodule/tumbl | 1 + 32 files changed, 1950 insertions(+), 941 deletions(-) delete mode 100644 hw/bcd.vhd delete mode 100644 hw/bus_bcd.vhd delete mode 100644 hw/bus_control_bram.vhd create mode 100644 hw/bus_tumbl.vhd create mode 100644 hw/dff2.vhd delete mode 100644 hw/ipcore_dir/control_bram.ngc delete mode 100644 hw/ipcore_dir/control_bram.vhd create mode 100644 hw/lx-rocon_firmware/firmware.c create mode 100644 hw/lx-rocon_firmware/start.S create mode 120000 hw/lx-rocon_firmware/utils create mode 100644 hw/lx-rocon_tumbl/lx_rocon_dmem.vhd create mode 100644 hw/lx-rocon_tumbl/lx_rocon_gprf_abd.vhd create mode 100644 hw/lx-rocon_tumbl/lx_rocon_imem.vhd create mode 100644 hw/lx-rocon_tumbl/lx_rocon_tumbl.vhd create mode 100644 hw/lx-rocon_tumbl/tb/lx_rocon_tumbl_tb.vhd create mode 100644 hw/lx_rocon_pkg.vhd create mode 120000 hw/tumbl create mode 100644 hw/xilinx_dualport_bram.vhd create mode 160000 submodule/tumbl diff --git a/.gitmodules b/.gitmodules index 6b3e724..58a36f4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "submodule/ulan-drv"] path = submodule/ulan-drv url = git://git.code.sf.net/p/ulan/ulan-drv +[submodule "submodule/tumbl"] + path = submodule/tumbl + url = ssh://git@rtime.felk.cvut.cz/fpga/lx-cpu1/tumbl.git diff --git a/hw/Makefile b/hw/Makefile index 10aa237..6d18021 100644 --- a/hw/Makefile +++ b/hw/Makefile @@ -21,6 +21,7 @@ # - gen : Transfer placed and routed NCD file into the bin file, which can # be then used to configure particular FPGA (this is further packaged # for SelectMap interface via the ARM CPU) +# - firmware : Builds the firmware for Tumbl core # Dependicies are handled, so in most cases only 'download' target is called. @@ -56,6 +57,26 @@ REQ_BIN := $(REQB).bin REQ_PKG := $(REQB).pkg REQ_SRC := . +REQ_FIRMWARE := $(OUT)/imem.bin $(OUT)/imem.asm $(OUT)/dmem.bin $(OUT)/firmware.lst + +#=============================================================================== + +MB_CROSS_COMPILE ?= mb- +TARGET_CC := $(MB_CROSS_COMPILE)gcc +TARGET_LD := $(MB_CROSS_COMPILE)ld +TARGET_OBJCOPY := $(MB_CROSS_COMPILE)objcopy +TARGET_OBJDUMP := $(MB_CROSS_COMPILE)objdump + +C_OBJS := $(OUT)/firmware.o +A_OBJS := +CFLAGS := -mxl-soft-div -msoft-float -mno-xl-soft-mul -mxl-barrel-shift -Wno-main -Wl,-no-check-sections -fno-zero-initialized-in-bss -g -O2 -Wall +AFLAGS := -D__ASSEMBLY__ $(CFLAGS) +LDFLAGS := -static -nostdlib -defsym _STACK_SIZE=0x0200 + +OBJS := $(OUT)/start.o $(C_OBJS) $(A_OBJS) + +FIRMWARE_DIR := ./lx-rocon_firmware + #=============================================================================== # Attempt to create a output directory. @@ -68,7 +89,7 @@ $(if $(OUTPUT_DIR),,$(error output directory "$(OUT)" does not exist)) #=============================================================================== .PHONY: all -all: pkg +all: pkg firmware .PHONY: re-synthesize re-synthesize $(REQ_NGC): $(addprefix $(REQ_SRC)/,$(PRJ)) @@ -117,6 +138,29 @@ re-pkg $(REQ_PKG): $(OUT)/packager $(REQ_BIN) cd $(OUT); \ ./packager le $(BIN) $(PKG) +$(OUT)/%.o: $(FIRMWARE_DIR)/%.c + $(TARGET_CC) $(CFLAGS) -c $< -o $@ + +$(OUT)/%.o: $(FIRMWARE_DIR)/%.S + $(TARGET_CC) $(AFLAGS) -c $< -o $@ + +$(OUT)/firmware.elf: $(OBJS) + $(TARGET_LD) $(LDFLAGS) -T $(FIRMWARE_DIR)/utils/tumbl.ld-script -o $@ $(OBJS) + +$(OUT)/mb-dasm: $(FIRMWARE_DIR)/utils/mb-dasm.cpp + g++ $< -o $@ + +$(OUT)/bin2mem: $(FIRMWARE_DIR)/utils/bin2mem.c + gcc $< -o $@ + +.PHONY: re-firmware +re-firmware $(REQ_FIRMWARE): $(REQ_PKG) $(OUT)/mb-dasm $(OUT)/bin2mem $(OUT)/firmware.elf + $(TARGET_OBJCOPY) -O binary $(OUT)/firmware.elf -j .text -S $(OUT)/imem.bin + $(TARGET_OBJCOPY) -O binary $(OUT)/firmware.elf -j .data -S $(OUT)/dmem.bin + $(TARGET_OBJDUMP) -DSCz $(OUT)/firmware.elf > $@ + cd $(OUT); \ + ./mb-dasm imem.bin > imem.asm + #=============================================================================== .PHONY: clean @@ -140,3 +184,6 @@ gen: $(REQ_BIN) .PHONY: pkg pkg: $(OUT)/packager $(REQ_PKG) + +.PHONY: firmware +firmware: $(OUT)/mb-dasm $(OUT)/bin2mem $(REQ_FIRMWARE) diff --git a/hw/bcd.vhd b/hw/bcd.vhd deleted file mode 100644 index 611d897..0000000 --- a/hw/bcd.vhd +++ /dev/null @@ -1,50 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.std_logic_arith.all; -use ieee.std_logic_unsigned.all; -use ieee.numeric_std.all; - --- Bcd for clock debugging purposes - -entity bcd is - generic - ( - width : integer := 32 - ); - port - ( - -- Reset - reset : in std_logic; - - -- Enabled - en : in std_logic; - - -- Clock - clk : in std_logic; - - -- Value - value : out std_logic_vector((width-1) downto 0) - ); -end bcd; - -architecture Behavioral of bcd is - signal counter : std_logic_vector((width-1) downto 0); -begin - - value <= counter; - - update: process (clk, reset) - begin - - if reset = '1' then - counter <= (others => '0'); - elsif clk = '1' and clk'event then - if en = '1' then - counter <= counter + 1; - end if; - end if; - - end process; - -end Behavioral; - diff --git a/hw/bus_bcd.vhd b/hw/bus_bcd.vhd deleted file mode 100644 index 76a847e..0000000 --- a/hw/bus_bcd.vhd +++ /dev/null @@ -1,83 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.std_logic_arith.all; -use ieee.std_logic_unsigned.all; -use ieee.numeric_std.all; - --- BCD interconnection - -entity bus_bcd is - port - ( - -- Reset - reset : in std_logic; - - -- Enable - en : in std_logic; - - -- Clock - clk : in std_logic; - - -- Chip enable - ce : in std_logic; - - -- Data bus (read only) - data_out : out std_logic_vector(31 downto 0); - - -- Bus signals - rd : in std_logic; - ta : out std_logic - ); -end bus_bcd; - -architecture Behavioral of bus_bcd is - - signal value : std_logic_vector(31 downto 0); - - component bcd - generic - ( - width : integer - ); - port - ( - reset : in std_logic; - en : in std_logic; - clk : in std_logic; - value : out std_logic_vector((width-1) downto 0) - ); - end component; - -begin - - my_bcd: bcd - generic map - ( - width => 32 - ) - port map - ( - reset => reset, - en => en, - clk => clk, - value => value - ); - - memory_bus: process(ce, rd, value) - begin - - -- Init defaults - ta <= '1'; - data_out <= (others => 'X'); - - if ce = '0' and rd = '0' then - ta <= '0'; - -- ID in big endian - data_out <= value; - end if; - - end process; - - -end Behavioral; - diff --git a/hw/bus_calibration.vhd b/hw/bus_calibration.vhd index 0d3c168..a7bddf5 100644 --- a/hw/bus_calibration.vhd +++ b/hw/bus_calibration.vhd @@ -3,6 +3,7 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; +use work.lx_rocon_pkg.all; -- Memory bus calibration -- Holds the signal for one clock to simulate longest route @@ -38,11 +39,9 @@ architecture Behavioral of bus_calibration is -- Wiring signal read1_out : std_logic_vector(31 downto 0); signal read1_ta : std_logic; - signal read1_ce : std_logic; signal read2_out : std_logic_vector(31 downto 0); signal read2_ta : std_logic; - signal read2_ce : std_logic; signal write1_out : std_logic_vector(31 downto 0); signal write1_ta : std_logic; @@ -52,34 +51,6 @@ architecture Behavioral of bus_calibration is signal write2_ta : std_logic; signal write2_ce : std_logic; - component calibration_read_register - generic - ( - id : std_logic_vector(31 downto 0) - ); - port - ( - ce : in std_logic; - data_out : out std_logic_vector(31 downto 0); - rd : in std_logic; - ta : out std_logic - ); - end component; - - component calibration_write_register - port - ( - clk : in std_logic; - reset : in std_logic; - ce : in std_logic; - data_in : in std_logic_vector(31 downto 0); - data_out : out std_logic_vector(31 downto 0); - rd : in std_logic; - bls : in std_logic_vector(3 downto 0); - ta : out std_logic - ); - end component; - begin -- First read calibration register (0xAAAAAAAA) @@ -90,7 +61,6 @@ begin ) port map ( - ce => read1_ce, rd => rd, ta => read1_ta, data_out => read1_out @@ -104,7 +74,6 @@ begin ) port map ( - ce => read2_ce, rd => rd, ta => read2_ta, data_out => read2_out @@ -145,8 +114,6 @@ begin if clk = '1' and clk'event then -- Defaults - read1_ce <= '1'; - read2_ce <= '1'; write1_ce <= '1'; write2_ce <= '1'; @@ -158,11 +125,9 @@ begin if ce = '0' then case address is when "00" => -- Read1 - read1_ce <= '0'; ta <= read1_ta; data_out <= read1_out; when "01" => -- Read2 - read2_ce <= '0'; ta <= read2_ta; data_out <= read2_out; when "10" => -- Write1 diff --git a/hw/bus_control_bram.vhd b/hw/bus_control_bram.vhd deleted file mode 100644 index 44e9aee..0000000 --- a/hw/bus_control_bram.vhd +++ /dev/null @@ -1,96 +0,0 @@ - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; - --- Wrapper for the memory bus for CPU and the BRAM - -entity bus_control_bram is - port - ( - -- Clock - clk : in std_logic; - - -- This is wired to CPU memory bus - ena : in std_logic; - wea : in std_logic_vector(3 downto 0); - addra : in std_logic_vector(8 downto 0); - dina : in std_logic_vector(31 downto 0); - douta : out std_logic_vector(31 downto 0); - taa : out std_logic; - - -- This is wired to control unit bus - enb : in std_logic; - web : in std_logic_vector(3 downto 0); - addrb : in std_logic_vector(8 downto 0); - dinb : in std_logic_vector(31 downto 0); - doutb : out std_logic_vector(31 downto 0) - ); -end bus_control_bram; - -architecture Behavioral of bus_control_bram is - - signal neg_ena : std_logic; - signal neg_wea : std_logic_vector(3 downto 0); - - component control_bram - port - ( - clka : in std_logic; - ena : in std_logic; - wea : in std_logic_vector(3 downto 0); - addra : in std_logic_vector(8 downto 0); - dina : in std_logic_vector(31 downto 0); - douta : out std_logic_vector(31 downto 0); - - clkb : in std_logic; - enb : in std_logic; - web : in std_logic_vector(3 downto 0); - addrb : in std_logic_vector(8 downto 0); - dinb : in std_logic_vector(31 downto 0); - doutb : out std_logic_vector(31 downto 0) - ); - end component; - -begin - - -- Wire it to the actual BRAM - my_bram: control_bram - port map - ( - clka => clk, - ena => neg_ena, - wea => neg_wea, - addra => addra, - dina => dina, - douta => douta, - - clkb => clk, - enb => enb, - web => web, - addrb => addrb, - dinb => dinb, - doutb => doutb - ); - - -- Transaction acknowledge - my_bram_ta: process(clk) - begin - - -- It puts there data synchronously with clock, so make the same for ack - if clk = '1' and clk'event then - taa <= ena; - end if; - - end process; - - -- Wire negated inputs - my_bream_neg: process(ena, wea) - begin - - neg_ena <= not ena; - neg_wea <= not wea; - - end process; - -end Behavioral; - diff --git a/hw/bus_irc.vhd b/hw/bus_irc.vhd index 722f6fa..8e93b3f 100644 --- a/hw/bus_irc.vhd +++ b/hw/bus_irc.vhd @@ -3,6 +3,7 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; +use work.lx_rocon_pkg.all; -- IRC bus interconnect: memory region for IRC @@ -68,24 +69,6 @@ architecture Behavioral of bus_irc is signal irc4_ta : std_logic; signal irc4_ce : std_logic_vector(1 downto 0); - -- IRC register - component irc_register - port - ( - clk : in std_logic; - reset : in std_logic; - a0, b0 : in std_logic; - index0 : in std_logic; - mark0 : in std_logic; - data_in : in std_logic; - data_out : out std_logic_vector(31 downto 0); - ce : in std_logic_vector(1 downto 0); - rd : in std_logic; - ta : out std_logic; - wr : in std_logic - ); - end component; - begin -- IRC for first axis @@ -199,8 +182,7 @@ begin data_out <= irc4_out; ta <= irc4_ta; - when others => - data_out <= (others => 'X'); + when others => NULL; end case; diff --git a/hw/bus_tumbl.vhd b/hw/bus_tumbl.vhd new file mode 100644 index 0000000..0661347 --- /dev/null +++ b/hw/bus_tumbl.vhd @@ -0,0 +1,268 @@ +library ieee; + +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.mbl_Pkg.all; +use work.lx_rocon_pkg.all; + +-- Connects tumbl to the Master CPU + +entity bus_tumbl is + port + ( + -- Clock + clk_100m : in std_logic; + clk_50m : in std_logic; + + -- Chip enable + ce : in std_logic; + + -- Global Reset + reset : in std_logic; + + -- Master CPU bus for the memory + rd : in std_logic; + bls : in std_logic_vector(3 downto 0); + address : in std_logic_vector(11 downto 0); + data_in : in std_logic_vector(31 downto 0); + data_out : out std_logic_vector(31 downto 0); + ta : out std_logic; + + -- Tumbl extrenal memory bus + XMEMB_sel_o : out std_logic; + XMEMB_i : in DMEMB2CORE_Type; + XMEMB_o : out CORE2DMEMB_Type + ); +end bus_tumbl; + +architecture Behavioral of bus_tumbl is + + -- Internal state + signal tumbl_reset : std_logic; + signal tumbl_halt : std_logic; + signal tumbl_int : std_logic; + signal tumbl_trace : std_logic; + signal tumbl_trace_kick : std_logic; -- driven by 50M clock + signal tumbl_trace_kick_ack : std_logic; -- driven by 50M clock + signal tumbl_trace_kick_req : std_logic; -- driven by 100M clock + signal tumbl_done : std_logic; -- driven by 50M clock + signal tumbl_bad_op : std_logic; -- driven by 50M clock + + -- Tumbl PC (copy it with cpu clock and then wire further) + signal tumbl_pc : std_logic_vector(31 downto 0); -- driven by 50M clock + + -- Internal memory signals + signal imem_en : std_logic; + signal dmem_en : std_logic; + + signal imem_we : std_logic_vector(3 downto 0); + signal dmem_we : std_logic_vector(3 downto 0); + + signal imem_dout : std_logic_vector(31 downto 0); + signal dmem_dout : std_logic_vector(31 downto 0); + + -- Internal bus structure + -- 12 address bits: 2 bits for selection, 10 bits for address + -- + -- Selection: + -- 00 - imem + -- 01 - dmem + -- 10 - reserved + -- 11 - registers + + -- Registers + -- 0x000 + -- + -- Bit 0: R/W - Reset + -- Bit 1: R/W - Interrupt + -- Bit 2: R/W - Halt + -- Bit 3: R/W - Trace + -- Bit 3: R - Done + -- Bit 4: R - Bad Op (halts the core until reset) + + -- 0x001 + -- Bit 0: W - Write 1 for trace kick, R - Read internal signals + + -- 0x002 + -- Tumbl program counter (R) + +begin + + -- Wire it to the tumbl + I_TUMBL: lx_rocon_tumbl + generic map + ( + IMEM_ABITS_g => 11, + DMEM_ABITS_g => 12, + -- + USE_HW_MUL_g => true, + USE_BARREL_g => true + ) + port map + ( + clk_i => clk_50m, + rst_i => tumbl_reset, + halt_i => tumbl_halt, + int_i => tumbl_int, + trace_i => tumbl_trace, + trace_kick_i => tumbl_trace_kick, + + pc_o => tumbl_pc, + + -- Internal memory (instruction) + imem_clk => clk_100m, + imem_en => imem_en, + imem_we => imem_we, + imem_addr => address(8 downto 0), + imem_din => data_in, + imem_dout => imem_dout, + + -- Internal memory (data) + dmem_clk => clk_100m, + dmem_en => dmem_en, + dmem_we => dmem_we, + dmem_addr => address(9 downto 0), + dmem_din => data_in, + dmem_dout => dmem_dout, + + -- External memory bus + XMEMB_sel_o => XMEMB_sel_o, + XMEMB_i => XMEMB_i, + XMEMB_o => XMEMB_o, + -- + done_o => tumbl_done, + bad_op_o => tumbl_bad_op + ); + + -- Wiring + wiring: process(ce, rd, bls, address, imem_en, imem_dout, dmem_en, dmem_dout, + tumbl_reset, tumbl_int, tumbl_halt, tumbl_trace, tumbl_done, tumbl_bad_op, tumbl_pc) + begin + + if ce = '0' and address(11 downto 10) = "00" then + imem_en <= '1'; + else + imem_en <= '0'; + end if; + + if ce = '0' and address(11 downto 10) = "01" then + dmem_en <= '1'; + else + dmem_en <= '0'; + end if; + + if imem_en = '1' and tumbl_reset = '1' then + imem_we <= not bls; + else + imem_we <= "0000"; + end if; + + if dmem_en = '1' and tumbl_reset = '1' then + dmem_we <= not bls; + else + dmem_we <= "0000"; + end if; + + if imem_en = '1' then + data_out <= imem_dout; + elsif dmem_en = '1' then + data_out <= dmem_dout; + elsif ce = '0' and rd = '0' and address(11 downto 10) = "11" then + if address(9 downto 0) = "0000000000" then + data_out(0) <= tumbl_reset; + data_out(1) <= tumbl_int; + data_out(2) <= tumbl_halt; + data_out(3) <= tumbl_trace; + data_out(4) <= tumbl_done; + data_out(5) <= tumbl_bad_op; + data_out(31 downto 5) <= (others => '0'); + elsif address(9 downto 0) = "0000000010" then + data_out <= tumbl_pc; + else + data_out <= (others => 'X'); + end if; + else + data_out <= (others => 'X'); + end if; + + end process; + + -- Transaction acknowledge and writing to registers + -- The clock are synchronous! + update: process(clk_100m) + begin + + -- Update on the 100 MHz clock + if clk_100m = '1' and clk_100m'event then + ta <= '1'; + + if imem_en = '1' or dmem_en = '1' then + ta <= '0'; + end if; + + if reset = '1' then + tumbl_reset <= '1'; + tumbl_int <= '0'; + tumbl_halt <= '0'; + tumbl_trace <= '0'; + tumbl_trace_kick_req <= '0'; + else + + if tumbl_trace_kick_ack = '1' then + tumbl_trace_kick_req <= '0'; + end if; + + if ce = '0' and address(11 downto 10) = "11" then + if bls(0) = '0' then + if address(9 downto 0) = "0000000000" then + tumbl_reset <= data_in(0); + tumbl_int <= data_in(1); + tumbl_halt <= data_in(2); + tumbl_trace <= data_in(3); + elsif address(9 downto 0) = "0000000001" then + if data_in(0) = '1' and tumbl_trace_kick = '0' then + tumbl_trace_kick_req <= '1'; + end if; + end if; + end if; + + if rd = '0' then + ta <= '0'; + end if; + end if; + end if; + + end if; + end process; + + -- Update tracing + tumbl: process(clk_50m) + begin + + -- Update on the 50 MHz clock + if clk_50m = '1' and clk_50m'event then + + if reset = '1' then + tumbl_trace_kick <= '0'; + tumbl_trace_kick_ack <= '0'; + else + if tumbl_trace_kick = '0' and tumbl_trace_kick_req = '1' then + tumbl_trace_kick <= '1'; + tumbl_trace_kick_ack <= '1'; + else + tumbl_trace_kick <= '0'; + end if; + end if; + + if tumbl_trace_kick_req <= '0' then + tumbl_trace_kick_ack <= '0'; + end if; + + end if; + + end process; + +end Behavioral; + diff --git a/hw/calibration_read_register.vhd b/hw/calibration_read_register.vhd index ebefc39..86af594 100644 --- a/hw/calibration_read_register.vhd +++ b/hw/calibration_read_register.vhd @@ -14,9 +14,6 @@ entity calibration_read_register is ); port ( - -- Chip enable - ce : in std_logic; - -- Data bus (read only) data_out : out std_logic_vector(31 downto 0); @@ -29,17 +26,11 @@ end calibration_read_register; architecture Behavioral of calibration_read_register is begin - memory_bus: process(ce, rd) + memory_bus: process(rd) begin - -- Init defaults - ta <= '1'; - data_out <= (others => 'X'); - - if ce = '0' and rd = '0' then - ta <= '0'; - data_out <= id; - end if; + ta <= rd; + data_out <= id; end process; diff --git a/hw/calibration_write_register.vhd b/hw/calibration_write_register.vhd index 546a331..4dd7330 100644 --- a/hw/calibration_write_register.vhd +++ b/hw/calibration_write_register.vhd @@ -35,30 +35,24 @@ architecture Behavioral of calibration_write_register is begin -- Read is immideate - memory_bus_read: process(ce, rd, value) + memory_bus_read: process(rd, value) begin - -- Init defaults - ta <= '1'; - data_out <= (others => 'X'); - - if ce = '0' and rd = '0' then - ta <= '0'; - data_out <= value; - end if; + ta <= rd; + data_out <= value; end process; -- Write waits for clock - memory_bus_write: process(clk, reset) + memory_bus_write: process(clk) begin - if reset = '1' then - value <= (others => '0'); - end if; - if clk = '1' and clk'event then + if reset = '1' then + value <= (others => '0'); + end if; + if ce = '0' then if reset = '0' and bls /= "1111" then diff --git a/hw/dff2.vhd b/hw/dff2.vhd new file mode 100644 index 0000000..28d92b4 --- /dev/null +++ b/hw/dff2.vhd @@ -0,0 +1,41 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +-- D circuit (filtered) + +entity dff2 is + port + ( + clk : in std_logic; + reset : in std_logic; + d : in std_logic; + q : out std_logic + ); +end dff2; + +architecture behavioral of dff2 is + signal last_d : std_logic; + signal data: std_logic; +begin + q <= data; + + seq: process(clk) + begin + if clk = '1' and clk'event then + if reset = '1' then + last_d <= '0'; + data <= '0'; + else + if d = last_d then + data <= d; + end if; + end if; + + last_d <= d; + end if; + end process; + +end behavioral; diff --git a/hw/ipcore_dir/control_bram.ngc b/hw/ipcore_dir/control_bram.ngc deleted file mode 100644 index 2dbab84..0000000 --- a/hw/ipcore_dir/control_bram.ngc +++ /dev/null @@ -1,3 +0,0 @@ -XILINX-XDB 0.1 STUB 0.1 ASCII -XILINX-XDM V1.6e -$0a644<,[o}e~g`n;"2*73>(-80!<;40123416<89:;<=>?0123456789:;<=>?0123456789:;<=>?0123456789:;<=>?012345679h1:?7GAPTV9EABUI^XJHI\31383:4g<9:0BB][[:@FGVGTCIMNY0<<50?37?40=AGZ^X7JFAEK?50<768>0=;4FNQWW>AOEL@6:97>114922?IR\Y__6IANDN>21?699<1::7AZTQWW>AIELF6:97>11591>LHW]]0OE]OKIQ>2>586<281EC^ZT;FJTGBNX5;1<3?<;38JJUSS2^OJ[HB31;2=56=52@D[YY4XECUFQ97=87;>7?4@UURVP?BHXHND\1?50?36?7<5IORVP?bnfh68=7>112906?OIX\^1hd`m<2394;723:81CXZ_UU8gkprf4:;1<3?:;209KPRW]]0ocxzm<2394;773=0BB][[:vgb86<768:087GAPTV9s`d;;3:5h68|ly;wub73<$8:>675IORVP?gcl{k747>1139:>LHW]]0jhi|m<983:`=FLMXJ[_OKDS>3:c=FLMXJ[_OKDS>24;`5i6OKDSCTVDBCZ5?5i6OKDSCTVDBCZ5<5i6OKDSCTVDBCZ5=5i6OKDSCTVDBCZ525i6OKDSCTVDBCZ535i6OKDS@Q@DBCZ5:5j6OKDS@Q@DBCZ5;;2k5NDEPAVAGCL[6:=3?>;@FGVGTCIMNY0<<50?d8EABUJ[NJHI\3138178GIM>8<1H@FO>7:AOOD7C:>1H@FO>D558GIMF9M227NBDAVP@HN37NBDFY:8GIMAP82;56M@MLKWP@B6<2ID^HQHEOGQEQOHFVCEJB94CSGBP@Bd3MK_MRYFDUJ\Ef=CI]KT[DJ[H^@;?AOFL@6;245KI@FJ846912NBMIG310<:?AOFL@6:>374DHCGM974601OELJF<06=f>BNIMC7=84?>89GMDBN48?546JFAEK?5;>BNIMC79364DHCGM90902NBMIG37?:8@LGCA52546JFAEK?=;>19:FJFAO;99427IGMDH>25;?89GMGBN489556JFBEK?518e3MCIHD2>5;2==>BNJMC7=807;EKA@L:6611OEOJF<3<;?AOEL@68255KICFJ818?3MCIHD2:>99GMGBN4?437IGMDH>4:==CAKNB0507;EKA@L:>6h1OE]OKIQ>3:f=CAYKOE]2>:12:==CGHND0=06;EMB@J:68730HBOKO=32:<=CGHND0<<19:FLEAI;9:427IANDN>20;d720HBOKO=5=<>BHIME74364DNCGK9?9?2NDMR\JG99GKGBH49427IAMDN>24;?>89GKGBH488556J@BEM?568>3MEIHB2>4?`8@JDCG5;>6=06;EMA@J:6=720HBLKO=3=<>BHJME7>364DN@GK95902NDNIA34?:8@JDCG5?546J@BEM?2;>BHJVXNKl5KOQCGKU:76j1OC]OKOQ>2>58f3ME[MIA_<01NBLY]EO58AKDULLDi7H@PRRVQEHYFj2OES_][R@O\F0=AIEYN=6I<;FLG<>OIA]ZT<=64IOKWTZ6602CEEY^P03:8MKOSXV:8;6GAIU]342=NF@^T<<94IOKW[5403@DBXR><7:KMMQY7<>1BBDZP0458MKOSW9<<7D@FT^243>OIA]U;4:5FNHV\4<11BBDZP1458MKOSW8<<7D@FT^343>OIA]U:4:5FNHV\5<1C69JJLRX9M=0ECG[_0G4?LHN\V;M:6GAIU]B2>OIA]UI56GAIU]EMIC13EEJHHJ9;MM@O@B03EELENOCc:ObnjtQm{ybccm4MhllvScu{`ee>6@>7:LFPRIUC=1ECCK>7:MSPLKNRLU[^DCFTHTFWZH@K>1[";6k_M68TDTSi2ZBBRLZSHF[f>VNFVH^_COBE79SWAIIM01YM@L7BVGQ<>TFEVGDHH84RDE@ADd1Y_YL]SU58VVRSQYOn7_][_QPJKWOSQVKn7_][_QPJKWOSQVH:=6]GRDE\A]RUIJ^TBJMj;RJQABYJAGUXEWK>3:QJIZEHDECXEB@PCIG@O3=TG\XHI:5\RWCO[D1<[[\J@RL9;RVBPPU33ZSEO>5[DQ68P\VB?91^<"v|t^`ooZkbeVmnbh|ntnp,ckgsaoiaj aaukuaZdkcVgnaRijn.tbhlb)kz~y#oblnms_5[)zhg%~"}9_hljp+tfe&^YYHQKP/RQMH?)zhg<<6[?/yqw[gjlWdofSjkaescwkw)`fh~bzhlbg/lbplpbWkf`S`kb_fgm+sgkam$hy| r`ookjv\9T$ym` }/r4\mkos&{kf#Y\ZE^FS*UTNE0$ym`9?;T2,|vrXjeaTahcPgdlfvdrhz&memygyecod*kgsaoTnaePmdo\c`h(~hfbh#m|ts-qehjhgyQ9Q#|nm/p,w3Ynf`~%~lc TSWF[AV)X[CF5#|nm628Q5){}Ui`fQbel]dakcui}ey#j`nthtffha)fh~bzhQmlj]nahY`mg%}magk.bqwv*tfeeed|V=R.scn*w)t>Vceey }al-WVPCXLY$[^DC6.scng>STM[U]E^GMLD;8RLCPW]S[I45XE@UFH969j2]NMZKC<083:<=PMH]N@1?19:UFFRCR494i7ZKMWDW?5?6912]NNZKZ<0^T\VMEHo5W_BMQAZOINF<0TilPIed8\anXX{cfZh||inl24>^ceVGjfb|Yesqjkk773QnfS@gaosTfvvohf:1Sy=4Ydq;?dbczh6;255ndepb848?3hno~l2=>99b`atf4:437ljkr`>7:==flmxj0807;`fgvd:1611jhi|n<699b`ate4=437ljkrc>6:==flmxi0;07;`fgvg:06h1jhi|m<983:==flmxi050>8:`ooZkbeVmnbRijndpjgZet|{;37obd_lgn[bciWyxbaRyfduj\54>6lck^ofiZabfVzye`Qxr`rsawYt>VceeyQ=239ahnYjmdUlicQrho\swgwxlxT;Qfnhv\774%:<:4bmi\i`kXoldTz:Q<_yqw56=edbUfi`Qfnqww[gjhkb;?7obd_lgn[jssx|~Tnaalk59`hng33jf`nn5loovqkiYezhg?j85loovqkiYezhg'naePmdo\c`hX~>U8 vmPaefqeZqnl}b65!mPaefqfZqnl}b65!mPamelvlroe4:'oRowi^kg[roc|a7? nQnxh]phdpbW}s{i0>#c^c{mZr~xl7: nQmyug\wl|b51&hSnabmnl\gim:8%iThhhnumv\`drf59&hSig|acnf[rgufVhczRm`lm?3(fYcazki`hQxasl\fmpXzhdli0>#c^goegiui}cdbRjfr<-kkhc({bxb`lv dqr,v`vh'er&~bm`n.jt)iidie%b|na}e^fjv*rjx&Uhk""l_dlbficX;;hbxRokdsgpw86+kVljadbv=rrbvqgi>%iTdl}Payk\ma;7$jUcm~Qjn`?2(fYoizUnbo3>,b]kevYnfcohxh|}=1.`[mgtWdofSb{{ptv\v`atWh7; nQgar]nahYh}}z~xR|jgr]a95*dWakxS`{w_nwwtprXzlmxSl3?,b]kevYj}qUdyy~zt^pfcvYe59&hSeo|_sgdg`g:8%iTdl}Prde`ag;7$jUcm~Q}suc>4)eX`hyT~~zm=1.`[mgtWzemxhml_hlsqqYumnyTm0>#c^jbwZuhn}ohoRaztqww[wc`{Vh64)eXag~n~kole^vzt`;7$jUgcljPiokw[cokm4:'oRcjm^vzt`;5$jUfyuQiqgomkcX{}kli~3?,b]svlkX|pzn1>"l_sgb`Zbbx}bTm0<78-a\v`gcWmo{xeQm=3:;(fYumhnT{dj{h^c>77*dW{ojhRyfduj\f855$jUyyQrhmqmqXi4IN nQ}su]svliua}sTn0MJ,b]qwqYsqyo6_T@L,b]qwqtfeVk618:fjjd:68720hd`n<03=<>bnfh6:>364dhlb845902nbbl2>4?:8`lhf48?546jfn`>22;>bnfh6:255kioc?658?3mcem1<>>99gmkg;:;437igaa=00:==cagk7>907;ekme942611oeco327<;?aoii58<255kioc?6=8?3mcem1<6>69gmkg;:720hd`n<22=e>bnfh68=7>18:fjjd:497=0hd`n<2<4?aoii5>5;6jfn`>6:2=cagk7:394dhlb82803mcem1617:fjjd:>6>1oecl30?:8`lhe48:546jfnc>25;>bnfk6:9364dhla840902nbbo2>7?:8`lhe482546jfnc>2=;199gmkd;:<437igab=05:==cagh7>:07;ekmf94?611oecl328<4?aoij58546jfnc>04;g?50?:8`lhe4:;5;6jfnc>0:2=cagh78394dhla80803mcen1817:fjjg:06>1oecl38?58`lhe40437iazt`>3:<=cg|~j0<>19:flqqg;98427iazt`>26;?89gkprf48>556j`uuc?508>3me~xl2>6?;8`jssi5;<245kotvb84>912ndyyo318<;?air|h6:245kotvb876912ndyyo320<:?air|h69>374dnwwe944601ocxzn<36==>bh}}k7>806;emvpd:5>730hb{{a=04:<=cg|~j0?619:flqqg;:0437iazt`>1:<=cg|~j0>>1b:flqqg;;80;245kotvb867902ndyyo33?:8`jssi5>546j`uuc?1;>bh}}k75364dnwwf96912ndyyl311<:?air|k6:=374dnwwf975601ocxzm<01==>bh}}h7=906;emvpg:6=730hb{{b=35:<=cg|~i0<919:flqqd;91427iaztc>2=;>15;?89gkpre4;9556j`uu`?618>3me~xo2=5?;8`jssj58=245kotva871912ndyyl329<:?air|k695364dnwwf94912ndyyl33119:flqqd;;8437iaztc>0:==cg|~i0907;emvpg:2611ocxzm<7<;?air|k6<255kotva8=8?3me~xo26>29fjd579tad:66?1|il2=>99tad:4294=7zkn<2<5?rce494=7zkm<0<5?rce4;437zkm<283:3=pmk682pNOp2c6?EF9::1J7:51zQ7a?7713nj6<=<2b2;>45>k=qe==951:l24=<13-;;97??1:P0f<6800om7?<33a30h<=?:182>4}T5<62802jv];e;33=?bf2898>n>7:01:g==#n>0o?6X>0781pb3281~h84?;|&gf?713k;8<7>59d86><`|@o<0(k?51228^60=0r;?6<9511821?7?28;1=?4>3;'552=9;k0(>651208 1b=9:;0(h751:&f4db3gnh6=54i0`g>5<#lm0:nh5adb82?>o6jj0;6)jk:0`f?kbd2;10e5=1083>!bc28;87cjl:398m477290/hi4>129m`f<432c:4743gnh6954i02f>5<#lm0:=>5adb86?>o68m0;6)jk:030?kbd2?10e<>l:18'`a<69:1ehn48;:k24g<72-no6==h6=4+de820g=ilj0;76g>4`83>!bc28>i7cjl:098m42?290/hi4>4c9m`f<532c:8:4?:%fg>42e3gnh6>54i065>5<#lm0:8o5adb87?>o6<<0;6)jk:06a?kbd2<10e<:;:18'`a<62=96=4+de820g=ilj0376g>4083>!bc28>i7cjl:898m427290/hi4>4c9m`f42e3gnh6o54i01g>5<#lm0:8o5adb8`?>o6;j0;6)jk:06a?kbd2m10e<=m:18'`a<6c=o6;>0;6)jk:06a?kbd28807d?<6;29 ab=9=h0bim51298m452290/hi4>4c9m`f<6<21b=>:50;&g`?73j2doo7?:;:k216<72-no6<:m;of`>40<3`;>>7>5$ef951d5<#lm0:8o5adb82<>=n9<:1<7*kd;37f>hck3;276g>4g83>!bc28>i7cjl:0c8?l73m3:1(ij515`8jae=9k10e<:k:18'`a<6c:9j51?=83.oh7?;b:lgg?7c32c:?h4?:%fg>42e3gnh6c383>!bc28i87cjl:098m4e6290/hi4>c29m`f<532c:o=4?:%fg>4e43gnh6>54i03f>5<#lm0:=i5adb83?>o69j0;6)jk:03g?kbd2810e6=1983>!bc28;o7cjl:498m470290/hi4>1e9m`f<132c:=;4?:%fg>47c3gnh6:54i036>5<#lm0:=i5adb8;?>o6>m0;6)jk:04`?kbd2910e<8m:18'`a<6>j1ehn4>;:k22<<72-no6<8l;of`>7=6683>!bc286b9m`f<232c::84?:%fg>40d3gnh6;54i047>5<#lm0::n5adb84?>o6>:0;6)jk:04`?kbd2110e<8=:18'`a<6>j1ehn46;:k224<72-no6<8l;of`>d=5d83>!bc286b9m`f40d3gnh6h54i07a>5<#lm0::n5adb8e?>o6=h0;6)jk:04`?kbd28:07d?:9;29 ab=9?i0bim51098m43?290/hi4>6b9m`f<6:21b=8950;&g`?71k2doo7?<;:k213<72-no6<8l;of`>42<3`;>97>5$ef953e5<#lm0::n5adb822>=n9>91<7*kd;35g>hck3;<76g>7383>!bc28j1ehn4>a:9j53`=83.oh7?9c:lgg?7e32c::h4?:%fg>40d3gnh6o6:l0;66g>b683>>o6:o0;66g>b983>>i60l0;6)jk:0:g?kbd2910c<6l:18'`a<60m1ehn4>;:m27=8983>!bc282o7cjl:598k4>0290/hi4>8e9m`f<232e:4;4?:%fg>4>c3gnh6;54o0:6>5<#lm0:4i5adb84?>i60=0;6)jk:0:g?kbd2110c<6<:18'`a<60m1ehn46;:m2<7<72-no6<6k;of`>d=7g83>!bc282o7cjl:b98k41b290/hi4>8e9m`f4>c3gnh6h54o05`>5<#lm0:4i5adb8e?>i6?k0;6)jk:0:g?kbd28:07b?8a;29 ab=91n0bim51098k41>290/hi4>8e9m`f<6:21d=:650;&g`?7?l2doo7?<;:m232<72-no6<6k;of`>42<3f;<:7>5$ef95=b5<#lm0:4i5adb822>=h90>1<7*kd;3;`>hck3;<76a>9283>!bc282o7cjl:0:8?j7>:3:1(ij519f8jae=9010c<7>:18'`a<60m1ehn4>a:9l5<6=83.oh7?7d:lgg?7e32e:4k4?:%fg>4>c3gnh6i6io0;6)jk:0cf?kbd2910c;:m2eg<72-no67=a883>!bc28kn7cjl:598k4g?290/hi4>ad9m`f<232e:m:4?:%fg>4gb3gnh6;54o0c5>5<#lm0:mh5adb84?>i6i<0;6)jk:0cf?kbd2110cd=a183>!bc28kn7cjl:b98k4?a290/hi4>ad9m`f4gb3gnh6h54o0;g>5<#lm0:mh5adb8e?>i61j0;6)jk:0cf?kbd28:07b?6b;29 ab=9ho0bim51098k4?f290/hi4>ad9m`f<6:21d=4750;&g`?7fm2doo7?<;:m2==<72-no642<3f;2;7>5$ef95dc5<#lm0:mh5adb822>=h9k?1<7*kd;3ba>hck3;<76a>b583>!bc28kn7cjl:0:8?j7e;3:1(ij51`g8jae=9010ca:9l5g7=83.oh7?ne:lgg?7e32e:n=4?:%fg>4gb3gnh6d68:0;6<4?:1y'b45=#i<0j;6*n6;c4?!gf2:1/mo4<;%c`>6=#im087)oj:29'ec<43-h;6>5+b080?!d52:1/n>4<;%`7>6=#j<087)l9:29'f2<43-h36>5+b880?!df2:1/no4<;%``>6=#jm087)lj:29'fc<43-i;6>5+c080?!e52:1/o>4<;%a7>6=#k<087)m9:29'g2<43-i36>5+c880?!ef2:1/oo4<;%a`>6=#km087)mj:39'gc<53-n;6i64$d29b5=#m<0nj6*j6;14?!c02:=0(ho5349'af<53-oo6?5+fg8ea>"6890mi6gj4;29?lg32900eh?50;9je6<722c??7>5;h66>5<>oai3:1(ij5f89m`f<732cm47>5$ef9b<=ilj0:76a70;29 ab=?o1ehn4?;:m4a?6=,mn1;k5adb82?>i0l3:1(ij57g9m`f<532e5$ef93c=ilj0876a8b;29 ab=?o1ehn4;;:m4e?6=,mn1;k5adb86?>i?13:1(ij57g9m`f<132e347>5$ef93c=ilj0<76a77;29 ab=?o1ehn47;:m;2?6=,mn1;k5adb8:?>i?=3:1(ij57g9m`f5$ef93c=ilj0i76a73;29 ab=?o1ehn4l;:m;6?6=,mn1;k5adb8g?>i?93:1(ij57g9m`f5$ef93c=ilj0m76a6f;29 ab=1l1ehn4?;:m:`?6=,mn15h5adb82?>if:3:1(ij5a09m`f<732ej<7>5$ef9e4=ilj0:76gid;29 ab=nj1ehn4?;:kef?6=,mn1jn5adb82?>o6l3:1(ij51b9m`f<732c:n7>5$ef95f=ilj0:76g>a;29 ab=9j1ehn4=;:k12?6=,mn1=n5adb80?>o5=3:1(ij51b9m`f<332c987>5$ef95f=ilj0>76g=3;29 ab=9j1ehn49;:k16?6=,mn1=n5adb84?>o593:1(ij51b9m`f5$ef95f=ilj0276g>f;29 ab=9j1ehn4n;:k2a?6=,mn1=n5adb8a?>o613:1(ij51b9m`f5$ef932=ilj0;76g86;29 ab=?>1ehn4>;:k5=?6=,mn1:55adb83?>o1?3:1(ij5699m`f<632c=:7>5$ef92==ilj0976g95;29 ab=>11ehn4<;:k50?6=,mn1:55adb87?>o1;3:1(ij5699m`f<232c<>7>5$ef92==ilj0=76g81;29 ab=>11ehn48;:k44?6=,mn1:55adb8;?>o1n3:1(ij5699m`f<>32c=i7>5$ef92==ilj0j76g9d;29 ab=>11ehn4m;:k5g?6=,mn1:55adb8`?>o1j3:1(ij5699m`f5$ef92==ilj0n76g92;29 ab=>11ehn4i;:k6o2>3:1(ij5569m`f<632c>97>5$ef912=ilj0976g:4;29 ab==>1ehn4<;:k67?6=,mn19:5adb87?>o2:3:1(ij5569m`f<232c==7>5$ef912=ilj0=76g90;29 ab==>1ehn48;:k6b?6=,mn19:5adb8;?>o2m3:1(ij5569m`f<>32c>h7>5$ef912=ilj0j76g:c;29 ab==>1ehn4m;:k6f?6=,mn19:5adb8`?>o2i3:1(ij5569m`f57>5$ef912=ilj0n76g:1;29 ab==>1ehn4i;:k1f?6=,mn1>l5adb83?>o513:1(ij52`9m`f<632c947>5$ef96d=ilj0976g<4;29 ab=:h1ehn4<;:k07?6=,mn1>l5adb87?>o4:3:1(ij52`9m`f<232c8=7>5$ef96d=ilj0=76g<0;29 ab=:h1ehn48;:k1b?6=,mn1>l5adb8;?>o5m3:1(ij52`9m`f<>32c9h7>5$ef96d=ilj0j76g=c;29 ab=:h1ehn4m;:k13?6=,mn1>l5adb8`?>i>:3:1(ij5909m`f<732e2<7>5$ef9=4=ilj0:76a7f;29 ab=181ehn4=;:m;a?6=,mn15<5adb80?>i?l3:1(ij5909m`f<332e3o7>5$ef9=4=ilj0>76a6b;29 ab=181ehn49;:m:e?6=,mn15<5adb84?>i>13:1(ij5909m`f5$ef9=4=ilj0276a67;29 ab=181ehn4n;:m:2?6=,mn15<5adb8a?>i>=3:1(ij5909m`f5$ef9=4=ilj0o76a63;29 ab=181ehn4j;:m;f?6=,mn15<5adb8e?>o0=3:1(ij5759m`f<732c5$ef931=ilj0:76smf283>3c=83:p(k?5dg9K554<@o<0V>85cz691?c=n3h1m7m5d;:93?0=13w/h44>b`9m0c<>3g?;645a8`83?k?d291/m84n7:&b2?g03-kj6>5+ac80?!gd2:1/mi4<;%cf>6=#io087)l?:29'f4<43-h96>5+b280?!d32:1/n84<;%`5>6=#j>087)l7:29'f<<43-hj6>5+bc80?!dd2:1/ni4<;%`f>6=#jo087)m?:29'g4<43-i96>5+c280?!e32:1/o84<;%a5>6=#k>087)m7:29'g<<43-ij6>5+cc80?!ed2:1/oi4<;%af>7=#ko097)j?:e:8 `6=n91/i84jf:&f2?503-o<6>94$dc970=#mj097)kk:39'bc5$ef9b<=ilj0;76gi8;29 ab=n01ehn4>;:m;4?6=,mn1;k5adb83?>i0m3:1(ij57g9m`f<632e5$ef93c=ilj0976a8c;29 ab=?o1ehn4<;:m4f?6=,mn1;k5adb87?>i0i3:1(ij57g9m`f<232e357>5$ef93c=ilj0=76a78;29 ab=?o1ehn48;:m;3?6=,mn1;k5adb8;?>i?>3:1(ij57g9m`f<>32e397>5$ef93c=ilj0j76a74;29 ab=?o1ehn4m;:m;7?6=,mn1;k5adb8`?>i?:3:1(ij57g9m`f5$ef93c=ilj0n76a89;29 ab=?o1ehn4i;:m:b?6=,mn15h5adb83?>i>l3:1(ij59d9m`f<632ej>7>5$ef9e4=ilj0;76an0;29 ab=i81ehn4>;:ke`?6=,mn1jn5adb83?>oaj3:1(ij5fb9m`f<632c:h7>5$ef95f=ilj0;76g>b;29 ab=9j1ehn4>;:k2e?6=,mn1=n5adb81?>o5>3:1(ij51b9m`f<432c997>5$ef95f=ilj0?76g=4;29 ab=9j1ehn4:;:k17?6=,mn1=n5adb85?>o5:3:1(ij51b9m`f<032c9=7>5$ef95f=ilj0376g=0;29 ab=9j1ehn46;:k2b?6=,mn1=n5adb8b?>o6m3:1(ij51b9m`f5$ef95f=ilj0h76g88;29 ab=?>1ehn4?;:k42?6=,mn1;:5adb82?>o113:1(ij5699m`f<732c=;7>5$ef92==ilj0:76g96;29 ab=>11ehn4=;:k51?6=,mn1:55adb80?>o1<3:1(ij5699m`f<332c=?7>5$ef92==ilj0>76g82;29 ab=>11ehn49;:k45?6=,mn1:55adb84?>o083:1(ij5699m`f5$ef92==ilj0276g9e;29 ab=>11ehn4n;:k5`?6=,mn1:55adb8a?>o1k3:1(ij5699m`f5$ef92==ilj0o76g9a;29 ab=>11ehn4j;:k56?6=,mn1:55adb8e?>o203:1(ij5569m`f<732c>:7>5$ef912=ilj0:76g:5;29 ab==>1ehn4=;:k60?6=,mn19:5adb80?>o2;3:1(ij5569m`f<332c>>7>5$ef912=ilj0>76g91;29 ab==>1ehn49;:k54?6=,mn19:5adb84?>o2n3:1(ij5569m`fi7>5$ef912=ilj0276g:d;29 ab==>1ehn4n;:k6g?6=,mn19:5adb8a?>o2j3:1(ij5569m`fm7>5$ef912=ilj0o76g:9;29 ab==>1ehn4j;:k65?6=,mn19:5adb8e?>o5j3:1(ij52`9m`f<732c957>5$ef96d=ilj0:76g=8;29 ab=:h1ehn4=;:k00?6=,mn1>l5adb80?>o4;3:1(ij52`9m`f<332c8>7>5$ef96d=ilj0>76g<1;29 ab=:h1ehn49;:k04?6=,mn1>l5adb84?>o5n3:1(ij52`9m`f5$ef96d=ilj0276g=d;29 ab=:h1ehn4n;:k1g?6=,mn1>l5adb8a?>o5?3:1(ij52`9m`f7>5$ef9=4=ilj0;76a60;29 ab=181ehn4>;:m;b?6=,mn15<5adb81?>i?m3:1(ij5909m`f<432e3h7>5$ef9=4=ilj0?76a7c;29 ab=181ehn4:;:m:f?6=,mn15<5adb85?>i>i3:1(ij5909m`f<032e257>5$ef9=4=ilj0376a68;29 ab=181ehn46;:m:3?6=,mn15<5adb8b?>i>>3:1(ij5909m`f5$ef9=4=ilj0h76a64;29 ab=181ehn4k;:m:7?6=,mn15<5adb8f?>i?j3:1(ij5909m`f5$ef931=ilj0;76g83;29 ab=?=1ehn4>;:ab1<72?o1<7>t$g39`c=O9980Dk84Z249g~2==3o1j7l5a;a9`?>=?3<157s+d882fd=i"f>3k<7)on:29'eg<43-kh6>5+ae80?!gb2:1/mk4<;%`3>6=#j8087)l=:29'f6<43-h?6>5+b480?!d12:1/n:4<;%`;>6=#j0087)ln:29'fg<43-hh6>5+be80?!db2:1/nk4<;%a3>6=#k8087)m=:29'g6<43-i?6>5+c480?!e12:1/o:4<;%a;>6=#k0087)mn:29'gg<43-ih6>5+ce80?!eb2;1/ok4=;%f3>a><,l:1j=5+e48fb>"b>39<7)k8:258 `g=;<1/in4=;%gg>7=#no0mi6*>018ea>ob<3:17do;:188m`7=831bm>4?::k77?6=3`>>6=44id094?=nm:0;66gia;29 ab=n01ehn4?;:kei?83:1(ij57g9m`f<732e5$ef93c=ilj0:76a8d;29 ab=?o1ehn4=;:m4g?6=,mn1;k5adb80?>i0j3:1(ij57g9m`f<332e5$ef93c=ilj0>76a79;29 ab=?o1ehn49;:m;i??3:1(ij57g9m`f5$ef93c=ilj0276a75;29 ab=?o1ehn4n;:m;0?6=,mn1;k5adb8a?>i?;3:1(ij57g9m`f7>5$ef93c=ilj0o76a71;29 ab=?o1ehn4j;:m4=?6=,mn1;k5adb8e?>i>n3:1(ij59d9m`f<732e2h7>5$ef9=`=ilj0:76an2;29 ab=i81ehn4?;:mb4?6=,mn1m<5adb82?>oal3:1(ij5fb9m`f<732cmn7>5$ef9bf=ilj0:76g>d;29 ab=9j1ehn4?;:k2f?6=,mn1=n5adb82?>o6i3:1(ij51b9m`f<532c9:7>5$ef95f=ilj0876g=5;29 ab=9j1ehn4;;:k10?6=,mn1=n5adb86?>o5;3:1(ij51b9m`f<132c9>7>5$ef95f=ilj0<76g=1;29 ab=9j1ehn47;:k14?6=,mn1=n5adb8:?>o6n3:1(ij51b9m`f5$ef95f=ilj0i76g>9;29 ab=9j1ehn4l;:k4o0>3:1(ij5769m`f<632c=57>5$ef92==ilj0;76g97;29 ab=>11ehn4>;:k52?6=,mn1:55adb81?>o1=3:1(ij5699m`f<432c=87>5$ef92==ilj0?76g93;29 ab=>11ehn4:;:k46?6=,mn1:55adb85?>o093:1(ij5699m`f<032c<<7>5$ef92==ilj0376g9f;29 ab=>11ehn46;:k5a?6=,mn1:55adb8b?>o1l3:1(ij5699m`f5$ef92==ilj0h76g9b;29 ab=>11ehn4k;:k5e?6=,mn1:55adb8f?>o1:3:1(ij5699m`f47>5$ef912=ilj0;76g:6;29 ab==>1ehn4>;:k61?6=,mn19:5adb81?>o2<3:1(ij5569m`f<432c>?7>5$ef912=ilj0?76g:2;29 ab==>1ehn4:;:k55?6=,mn19:5adb85?>o183:1(ij5569m`f<032c>j7>5$ef912=ilj0376g:e;29 ab==>1ehn46;:k6`?6=,mn19:5adb8b?>o2k3:1(ij5569m`fn7>5$ef912=ilj0h76g:a;29 ab==>1ehn4k;:k6=?6=,mn19:5adb8f?>o293:1(ij5569m`f5$ef96d=ilj0;76g=9;29 ab=:h1ehn4>;:k1l5adb81?>o4<3:1(ij52`9m`f<432c8?7>5$ef96d=ilj0?76g<2;29 ab=:h1ehn4:;:k05?6=,mn1>l5adb85?>o483:1(ij52`9m`f<032c9j7>5$ef96d=ilj0376g=e;29 ab=:h1ehn46;:k1`?6=,mn1>l5adb8b?>o5k3:1(ij52`9m`f5$ef96d=ilj0h76a62;29 ab=181ehn4?;:m:4?6=,mn15<5adb82?>i?n3:1(ij5909m`f<532e3i7>5$ef9=4=ilj0876a7d;29 ab=181ehn4;;:m;g?6=,mn15<5adb86?>i>j3:1(ij5909m`f<132e2m7>5$ef9=4=ilj0<76a69;29 ab=181ehn47;:m:i>?3:1(ij5909m`f5$ef9=4=ilj0i76a65;29 ab=181ehn4l;:m:0?6=,mn15<5adb8g?>i>;3:1(ij5909m`f5$ef9=4=ilj0m76g85;29 ab=?=1ehn4?;:k47?6=,mn1;95adb82?>{en<0;6;k50;2x c7=lo1C==<4Hg48^60=kr>197k5f;`9e?e=l321;7859;'`<<6jh1e8k46;o73><=i0h0;7c7l:19'e06=#ik087)ol:29'ea<43-kn6>5+ag80?!d72:1/n<4<;%`1>6=#j:087)l;:29'f0<43-h=6>5+b680?!d?2:1/n44<;%`b>6=#jk087)ll:29'fa<43-hn6>5+bg80?!e72:1/o<4<;%a1>6=#k:087)m;:29'g0<43-i=6>5+c680?!e?2:1/o44<;%ab>6=#kk087)ml:29'ga<43-in6?5+cg81?!b72m20(h>5f19'a061<,lk1?85+eb81?!cc2;1/jk4ie:&2455;hc7>5<>o3;3:17d:::188m`4=831bi>4?::kee?6=,mn1j45adb83?>oa03:1(ij5f89m`f<632e3<7>5$ef93c=ilj0;76a8e;29 ab=?o1ehn4>;:m4`?6=,mn1;k5adb81?>i0k3:1(ij57g9m`f<432e5$ef93c=ilj0?76a8a;29 ab=?o1ehn4:;:m;=?6=,mn1;k5adb85?>i?03:1(ij57g9m`f<032e3;7>5$ef93c=ilj0376a76;29 ab=?o1ehn46;:m;1?6=,mn1;k5adb8b?>i?<3:1(ij57g9m`f5$ef93c=ilj0h76a72;29 ab=?o1ehn4k;:m;5?6=,mn1;k5adb8f?>i013:1(ij57g9m`f5$ef9=`=ilj0;76a6d;29 ab=1l1ehn4>;:mb6?6=,mn1m<5adb83?>if83:1(ij5a09m`f<632cmh7>5$ef9bf=ilj0;76gib;29 ab=nj1ehn4>;:k2`?6=,mn1=n5adb83?>o6j3:1(ij51b9m`f<632c:m7>5$ef95f=ilj0976g=6;29 ab=9j1ehn4<;:k11?6=,mn1=n5adb87?>o5<3:1(ij51b9m`f<232c9?7>5$ef95f=ilj0=76g=2;29 ab=9j1ehn48;:k15?6=,mn1=n5adb8;?>o583:1(ij51b9m`f<>32c:j7>5$ef95f=ilj0j76g>e;29 ab=9j1ehn4m;:k2=?6=,mn1=n5adb8`?>o003:1(ij5769m`f<732c<:7>5$ef932=ilj0:76g99;29 ab=>11ehn4?;:k53?6=,mn1:55adb82?>o1>3:1(ij5699m`f<532c=97>5$ef92==ilj0876g94;29 ab=>11ehn4;;:k57?6=,mn1:55adb86?>o0:3:1(ij5699m`f<132c<=7>5$ef92==ilj0<76g80;29 ab=>11ehn47;:k5b?6=,mn1:55adb8:?>o1m3:1(ij5699m`f5$ef92==ilj0i76g9c;29 ab=>11ehn4l;:k5f?6=,mn1:55adb8g?>o1i3:1(ij5699m`f7>5$ef92==ilj0m76g:8;29 ab==>1ehn4?;:k62?6=,mn19:5adb82?>o2=3:1(ij5569m`f<532c>87>5$ef912=ilj0876g:3;29 ab==>1ehn4;;:k66?6=,mn19:5adb86?>o193:1(ij5569m`f<132c=<7>5$ef912=ilj0<76g:f;29 ab==>1ehn47;:k6a?6=,mn19:5adb8:?>o2l3:1(ij5569m`fo7>5$ef912=ilj0i76g:b;29 ab==>1ehn4l;:k6e?6=,mn19:5adb8g?>o213:1(ij5569m`f=7>5$ef912=ilj0m76g=b;29 ab=:h1ehn4?;:k1=?6=,mn1>l5adb82?>o503:1(ij52`9m`f<532c887>5$ef96d=ilj0876g<3;29 ab=:h1ehn4;;:k06?6=,mn1>l5adb86?>o493:1(ij52`9m`f<132c8<7>5$ef96d=ilj0<76g=f;29 ab=:h1ehn47;:k1a?6=,mn1>l5adb8:?>o5l3:1(ij52`9m`f5$ef96d=ilj0i76g=7;29 ab=:h1ehn4l;:m:6?6=,mn15<5adb83?>i>83:1(ij5909m`f<632e3j7>5$ef9=4=ilj0976a7e;29 ab=181ehn4<;:m;`?6=,mn15<5adb87?>i?k3:1(ij5909m`f<232e2n7>5$ef9=4=ilj0=76a6a;29 ab=181ehn48;:m:=?6=,mn15<5adb8;?>i>03:1(ij5909m`f<>32e2;7>5$ef9=4=ilj0j76a66;29 ab=181ehn4m;:m:1?6=,mn15<5adb8`?>i><3:1(ij5909m`f5$ef9=4=ilj0n76a7b;29 ab=181ehn4i;:k41?6=,mn1;95adb83?>o0;3:1(ij5759m`f<632wxh;4?:93x94642h201k<51e9>b7<6n27m>7?j;4?<5o81>o52f381`>;a:38h70h=:3589c4==116j?4:6:?e6?3234l968:4=g0916=:n;0>>63i2;42?8`52?:01k<5689>b7<1?27m>789;33<5o81:952f3857>;a:3=970h=:6389c4=?<16j?483:?e6?1?34l96:84=g09a4=:n;0n>63i2;g0?8`52l>01k=51e9>b6<6n27m?7?j;4?<5o91>o52f281`>;a;38h70h<:3589c5==116j>4:6:?e7?3234l868:4=g1916=:n:0>>63i3;42?8`42?:01k=5689>b6<1?27m?789;33<5o91:952f2857>;a;3=970h<:6389c5=?<16j>483:?e7?1?34l86:84=g19a4=:n:0n>63i3;g0?8`42l>01k:51e9>b1<6n27m87?j;4?<5o>1>o52f581`>;a<38h70h;:3589c2==116j94:6:?e0?3234l?68:4=g6916=:n=0>>63i4;42?8`32?:01k:5689>b1<1?27m8789;33<5o>1:952f5857>;a<3=970h;:6389c2=?<16j9483:?e0?1?34l?6:84=g69a4=:n=0n>63i4;g0?8`32l>01k;51e9>b0<6n27m97?j;4?<5o?1>o52f481`>;a=38h70h::3589c3==116j84:6:?e1?3234l>68:4=g7916=:n<0>>63i5;42?8`22?:01k;5689>b0<1?27m9789;33<5o?1:952f4857>;a=3=970h::6389c3=?<16j8483:?e1?1?34l>6:84=g79a4=:n<0n>63i5;g0?8`22l>0q~?66;296~X61?16j?47b:p5d7=838pR;<552z\2ef=:n;0286s|1c294?4|V8h;70h=:878yv7e93:1>vP>b09>b7<>>2wx=o<50;0xZ4d534l96494}r3a7?6=:rT:n>52f38:<>{t9k>1<747b:p5g0=838pR<552z\2=2=:n:0286s|18:94?4|V83370h<:878yv7>13:1>vP>989>b6<>>2wx=4o50;0xZ4?f34l86494}r3:f?6=:rT:5o52f28:<>{t90i1<7<552z\2=c=:n=0286s|1`294?4|V8k;70h;:878yv7f:3:1>vP>a39>b1<>>2wx=l=50;0xZ4g434l?6494}r3b0?6=:rT:m952f58:<>{t9h?1<7<552z\2e==:n<0286s|1`;94?4|V8k270h::878yv7fi3:1>vP>a`9>b0<>>2wx=ll50;0xZ4ge34l>6494}r3b`?6=:rT:mi52f48:<>{t9hl1<7=752z\26s|19d94?4|V82m70h=:918yv7>83:1>vP>919>b7{t9091<7489:p5<3=838pR<7:;=752z\233=:n:03>6s|16594?4|V8=<70h<:918yv7003:1>vP>799>b634l865;4}r34e?6=:rT:;l52f28;2>{t9>h1<7=752z\23`=:n=03>6s|16d94?4|V8=m70h;:918yv7?93:1>vP>809>b1534l?65;4}r3;7?6=:rT:4>52f58;2>{t91>1<7=752z\2<2=:n<03>6s|19:94?4|V82370h::918yv7?13:1>vP>889>b0f34l>65;4}r3;g?6=:rT:4n52f48;2>{t91o1<7;a:3>>70h<:5789c2=<<16j84;5:p5g1=83?pRd5<5o91m>52f58b7>;a=3k87p}>2d83>0}Y9;o01k<5429>b6<3;27m87:<;1587>52z\211=:n;0=>6s|14d94?4|V8?m70h=:7c8yv71i3:1>vP>6`9>b7<1j2wx=;k50;0xZ40b34l96;m4}r35b?6=:rT::k52f385`>{t9>:1<72652z\236=:n:0=>6s|16694?4|V8=?70h<:7c8yv72=3:1>vP>549>b6<1j2wx=8850;0xZ43134l86;m4}r363?6=:rT:9:52f285`>{t9<21<749f:p50g=838pR<;n;26n7>52z\21g=:n=0=>6s|14a94?4|V8?h70h;:7c8yv72l3:1>vP>5e9>b1<1j2wx=8k50;0xZ43b34l?6;m4}r354?6=:rT::=52f585`>{t9?;1<7;16j949f:p535=838pR<8<;2652z\221=:n<0=>6s|17794?4|V8<>70h::7c8yv71>3:1>vP>679>b0<1j2wx=;950;0xZ40034l>6;m4}r35{t9?31<7k16j849f:p53b=838pR<8k;2655z\250=:n;09i63i3;0f?8`32;o01k;52d9~w471290>wS?>6:?e6?4a34l86?h4=g696c=:n<09j6s|10594?3|V8;<70h=:2289c5=;916j94<0:?e1?573ty:=54?:4y]54><5o81?<52f2805>;a<39:70h::238yv7613:19vP>189>b7<4:27m?7==;64<5o?1??5rs03b>5<2sW;:m63i2;10?8`42:901k:5329>b0<4;2wx=:4=g1971=:n=08863i5;17?xu69j0;68uQ10a89c4=:116j>4=8:?e0?4?34l>6?64}r32a?6==rT:=h52f381=>;a;38270h;:3;89c3=:01v7hk;cd53z\2g4=:n:0mh63i3;da?xu6k;0;6>uQ1b089c2=nm16j94ib:p5f2=839pRcb<5o?1jo5rs010>5<5sW;8?63i2;72?xu6;l0;6?uQ12g89c4==01v<:6:181[73127m>7;n;|q20a<72;qU=9j4=g091g=z{8>n6=4={_37a>;a:3?h7p}>4g83>7}Y9=l01k<55e9~w4372909wS?:0:?e6?3b3ty:9<4?:3y]507<5o819k5rs071>5<5sW;>>63i3;72?xu6=:0;6?uQ14189c5==01v<=;:181[74<27m?7;n;|q270<72;qU=>;4=g191g=z{89=6=4={_302>;a;3?h7p}>3683>7}Y9:=01k=55e9~w45?2909wS?<8:?e7?3b3ty:?44?:3y]56?<5o919k5rs01b>5<5sW;8m63i4;72?xu6;k0;6?uQ12`89c2==01v<=l:181[74k27m87;n;|q27a<72;qU=>j4=g691g=z{89m6=4={_30b>;a<3?h7p}>4183>7}Y9=:01k:55e9~w4262909wS?;1:?e0?3b3ty:8?4?:3y]514<5o>19k5rs060>5<5sW;??63i5;72?xu6<=0;6?uQ15689c3==01v<:::181[73=27m97;n;|q203<72;qU=984=g791g=z{8><6=4={_373>;a=3?h7p}>4983>7}Y9=201k;55e9~w42f2909wS?;a:?e1?3b3ty:8n4?:3y]51e<5o?19k5rs02a>5<2sW;;n63i2;03?8`42;:01k:5219>b0<582wx==m50;7xZ46d34l96??4=g1964=:n=09=63i5;02?xu68m0;68uQ11f89c4=:;16j>4=2:?e0?4534l>6?<4}r33a?6==rT:;a;38870h;:3189c3=::1v<>i:186[77n27m>7<;;72<5o>1>952f4810>{t98:1<7;t^033?8`52;?01k=5249>b1<5=27m97<:;|q254<722;291~X69;16j?4>a:?e7?7f34l?6;a:3;i70h<:0`89c2=9k16j84>b:p5gd=839pRcg<5o81j55rs0``>5<4sW;io63i3;db?8`42o20q~?md;297~X6jm16j94ia:?e0?`?3ty:nk4?:2y]5g`<5o?1jl52f48e<>{zf;<<6=4>{Id5?xh5>10;6290:wEh9;|l12d<728qCj;5rn34a>5<6sAl=7p`=6b83>4}On?1vb?8k:182M`13td9:h4?:0yKb3=zf;{Id5?xh5?90;65<6sAl=7p`=7583>4}On?1vb?9::182M`13td9;;4?:0yKb3=zf;=<6=4>{Id5?xh5?10;6290:wEh9;|l13d<728qCj;5rn35a>5<6sAl=7p`=7b83>4}On?1vb?9k:182M`13td9;h4?:0yKb3=zf;=m6=4>{Id5?xh5090;66290:wEh9;|l1<7<728qCj;5rn3:0>5<6sAl=7p`=8583>4}On?1vb?6::182M`13td94;4?:0yKb3=zf;2<6=4>{Id5?xh5010;6>290:wEh9;|l15<6sAl=7p`=8b83>4}On?1vb?6k:182M`13td94h4?:0yKb3=zf;2m6=4>{Id5?xh5190;65<6sAl=7p`=9583>4}On?1vb?7::182M`13td95;4?:0yKb3=zf;3<6=4>{Id5?xh5110;6290:wEh9;|l1=d<728qCj;5rn3;a>5<6sAl=7p`=9b83>4}On?1vb?7k:182M`13td95h4?:0yKb3=zf;3m6=4>{Id5?xh5i90;65<6sAl=7p`=a583>4}On?1vb?o::182M`13td9m;4?:0yKb3=zf;k<6=4>{Id5?xh5i10;6290:wEh9;|l1ed<728qCj;5rn3ca>5<6sAl=7p`=ab83>4}On?1vb?ok:182M`13td9mh4?:0yKb3=zf;km6=4>{Id5?xh5j90;65<6sAl=7p`=b583>4}On?1vb?l::182M`13td9n;4?:0yKb3=zf;h<6=4>{Id5?xh5j10;6290:wEh9;|l1fd<728qCj;5rn3`a>5<6sAl=7p`=bb83>4}On?1vb?lk:182M`13td9nh4?:0yKb3=zf;hm6=4>{Id5?xh5k90;65<6sAl=7p`=c583>4}On?1vb?m::182M`13td9o;4?:0yKb3=zf;i<6=4>{Id5?xh5k10;6290:wEh9;|l1gd<728qCj;5rn3aa>5<6sAl=7p`=cb83>4}On?1vb?mk:182M`13td9oh4?:0yKb3=zf;im6=4>{Id5?xh5l90;65<6sAl=7p`=d583>4}On?1vb?j::182M`13td9h;4?:0yKb3=zf;n<6=4>{Id5?xh5l10;6290:wEh9;|l1`d<728qCj;5rn3fa>5<6sAl=7p`=db83>4}On?1vb?jk:182M`13td9hh4?:0yKb3=zf;nm6=4>{Id5?xh5m90;65<6sAl=7p`=e583>4}On?1vb?k::182M`13td9i;4?:0yKb3=zf;o<6=4>{Id5?xh5m10;6290:wEh9;|l1ad<728qCj;5rn3ga>5<6sAl=7p`=eb83>4}On?1vb?kk:182M`13td9ih4?:0yKb3=zf;om6=4>{Id5?xh5n90;65<6sAl=7p`=f583>4}On?1vb?h::182M`13td9j;4?:0yKb3=zf;l<6=4>{Id5?xh5n10;6290:wEh9;|l1bd<728qCj;5rn3da>5<6sAl=7p`=fb83>4}On?1vb?hk:182M`13td9jh4?:0yKb3=zf;lm6=4>{Id5?xh4890;65<6sAl=7p`<0583>4}On?1vb>>::182M`13twvqMNL{2c6>a7al:;9 9, - c_addrb_width => 9, - c_algorithm => 0, - c_axi_id_width => 4, - c_axi_slave_type => 0, - c_axi_type => 1, - c_byte_size => 8, - c_common_clk => 0, - c_default_data => "0", - c_disable_warn_bhv_coll => 0, - c_disable_warn_bhv_range => 0, - c_enable_32bit_address => 0, - c_family => "spartan6", - c_has_axi_id => 0, - c_has_ena => 1, - c_has_enb => 1, - c_has_injecterr => 0, - c_has_mem_output_regs_a => 0, - c_has_mem_output_regs_b => 0, - c_has_mux_output_regs_a => 0, - c_has_mux_output_regs_b => 0, - c_has_regcea => 0, - c_has_regceb => 0, - c_has_rsta => 0, - c_has_rstb => 0, - c_has_softecc_input_regs_a => 0, - c_has_softecc_output_regs_b => 0, - c_init_file => "BlankString", - c_init_file_name => "no_coe_file_loaded", - c_inita_val => "0", - c_initb_val => "0", - c_interface_type => 0, - c_load_init_file => 0, - c_mem_type => 2, - c_mux_pipeline_stages => 0, - c_prim_type => 3, - c_read_depth_a => 288, - c_read_depth_b => 288, - c_read_width_a => 32, - c_read_width_b => 32, - c_rst_priority_a => "CE", - c_rst_priority_b => "CE", - c_rst_type => "SYNC", - c_rstram_a => 0, - c_rstram_b => 0, - c_sim_collision_check => "ALL", - c_use_bram_block => 0, - c_use_byte_wea => 1, - c_use_byte_web => 1, - c_use_default_data => 1, - c_use_ecc => 0, - c_use_softecc => 0, - c_wea_width => 4, - c_web_width => 4, - c_write_depth_a => 288, - c_write_depth_b => 288, - c_write_mode_a => "WRITE_FIRST", - c_write_mode_b => "WRITE_FIRST", - c_write_width_a => 32, - c_write_width_b => 32, - c_xdevicefamily => "spartan6" - ); --- synthesis translate_on -BEGIN --- synthesis translate_off -U0 : wrapped_control_bram - PORT MAP ( - clka => clka, - ena => ena, - wea => wea, - addra => addra, - dina => dina, - douta => douta, - clkb => clkb, - enb => enb, - web => web, - addrb => addrb, - dinb => dinb, - doutb => doutb - ); --- synthesis translate_on - -END control_bram_a; diff --git a/hw/irc_reader.vhd b/hw/irc_reader.vhd index 8172f8a..b4cd177 100644 --- a/hw/irc_reader.vhd +++ b/hw/irc_reader.vhd @@ -3,71 +3,36 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; +use work.lx_rocon_pkg.all; -- IRC reader module entity irc_reader is port ( - clk : in std_logic; - reset : in std_logic; - a0, b0 : in std_logic; - index0 : in std_logic; - mark0 : in std_logic; - - qcount : out std_logic_vector (31 downto 0); - ab_event : out std_logic; - ab_error : out std_logic; - out_index : out std_logic; - out_mark : out std_logic + clk : in std_logic; + reset : in std_logic; + a0, b0 : in std_logic; + index0 : in std_logic; + mark0 : in std_logic; + + qcount : out std_logic_vector (31 downto 0); + qcount_index : out std_logic_vector (31 downto 0); + ab_event : out std_logic; + ab_error : out std_logic; + out_mark : out std_logic ); end irc_reader; -architecture Behavioral of irc_reader is - component qcounter - port - ( - clk : in std_logic; - reset : in std_logic; - a0, b0 : in std_logic; - - a_rise : out std_logic; - a_fall : out std_logic; - b_rise : out std_logic; - b_fall : out std_logic; - - qcount : out std_logic_vector (31 downto 0); - ab_event : out std_logic; - ab_error : out std_logic - ); - end component; - - component dff - port - ( - clk : in std_logic; - reset : in std_logic; - d : in std_logic; - q : out std_logic - ); - end component; +architecture rtl of irc_reader is begin - dff_index: dff + dff_mark: dff2 port map ( clk => clk, - reset => reset, - d => index0, - q => out_index - ); - - dff_mark: dff - port map - ( - clk => clk, - reset => reset, + reset => '0', d => mark0, q => out_mark ); @@ -79,7 +44,9 @@ architecture Behavioral of irc_reader is reset => reset, a0 => a0, b0 => b0, + index0 => index0, qcount => qcount, + qcount_index => qcount_index, ab_event => ab_event, ab_error => ab_error, a_rise => open, @@ -88,5 +55,4 @@ architecture Behavioral of irc_reader is b_fall => open ); -end Behavioral; - +end rtl; diff --git a/hw/irc_register.vhd b/hw/irc_register.vhd index 21029ca..50a215c 100644 --- a/hw/irc_register.vhd +++ b/hw/irc_register.vhd @@ -3,6 +3,7 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; +use work.lx_rocon_pkg.all; -- IRC register: connects IRC output to memory bus @@ -15,7 +16,7 @@ entity irc_register is index0 : in std_logic; mark0 : in std_logic; - -- Data bus + -- Data bus for Master CPU data_in : in std_logic; -- 1 bit input data_out : out std_logic_vector(31 downto 0); @@ -33,27 +34,24 @@ architecture Behavioral of irc_register is signal qcount_error : std_logic; signal qcount : std_logic_vector (31 downto 0); signal qcount_index : std_logic_vector (31 downto 0); - signal qcount_index_prev : std_logic_vector (31 downto 0); signal ab_event : std_logic; signal ab_error : std_logic; - signal old_index : std_logic; - signal out_index : std_logic; signal out_mark : std_logic; component irc_reader port ( - clk : in std_logic; - reset : in std_logic; - a0, b0 : in std_logic; - index0 : in std_logic; - mark0 : in std_logic; - - qcount : out std_logic_vector (31 downto 0); - ab_event : out std_logic; - ab_error : out std_logic; - out_index : out std_logic; - out_mark : out std_logic + clk : in std_logic; + reset : in std_logic; + a0, b0 : in std_logic; + index0 : in std_logic; + mark0 : in std_logic; + + qcount : out std_logic_vector (31 downto 0); + qcount_index : out std_logic_vector (31 downto 0); + ab_event : out std_logic; + ab_error : out std_logic; + out_mark : out std_logic ); end component; @@ -69,9 +67,9 @@ begin index0 => index0, mark0 => mark0, qcount => qcount, + qcount_index => qcount_index, ab_event => ab_event, ab_error => ab_error, - out_index => out_index, out_mark => out_mark ); @@ -84,59 +82,34 @@ begin else qcount_error <= qcount_error or ab_error; end if; - - old_index <= out_index; - qcount_index_prev <= qcount_index; end if; end process; - signals: process(reset, old_index, out_index, qcount, qcount_index_prev) - begin - - if reset = '0' and old_index = '0' and out_index = '1' then - qcount_index <= qcount; - elsif reset = '1' then - qcount_index <= (others => '0'); - else - qcount_index <= qcount_index_prev; - end if; - - end process; memory_bus: process(ce, rd, qcount, qcount_index, qcount_error, ab_event, ab_error, out_mark) begin -- Reset signals - ta <= '1'; + ta <= rd; data_out <= (others => 'X'); -- Check chip enable case ce is when "00" => - if rd = '0' then - data_out <= qcount; - ta <= '0'; - end if; + data_out <= qcount; when "01" => - if rd = '0' then - data_out <= qcount_index; - ta <= '0'; - end if; + data_out <= qcount_index; when "10" => - if rd = '0' then - data_out(0) <= ab_event; - data_out(1) <= ab_error; - data_out(2) <= qcount_error; - data_out(3) <= out_mark; - data_out(31 downto 4) <= (others => '0'); - ta <= '0'; - end if; - - when others => - data_out <= (others => 'X'); + data_out(0) <= ab_event; + data_out(1) <= ab_error; + data_out(2) <= qcount_error; + data_out(3) <= out_mark; + data_out(31 downto 4) <= (others => '0'); + + when others => NULL; end case; diff --git a/hw/lx-rocon.ucf b/hw/lx-rocon.ucf index 1700764..73ed939 100644 --- a/hw/lx-rocon.ucf +++ b/hw/lx-rocon.ucf @@ -6,10 +6,10 @@ CONFIG VCCAUX = 3.3; # ==================================================================== # Clock -NET CLK_CPU PERIOD = 13.8ns HIGH 50%; -NET CLK_CPU LOC = P15 | IOSTANDARD = LVCMOS33; -#NET CLK_50M PERIOD = 20.0ns HIGH 50%; -#NET CLK_50M LOC = P14 | IOSTANDARD = LVCMOS33; +#NET CLK_CPU PERIOD = 13.8ns HIGH 50%; +#NET CLK_CPU LOC = P15 | IOSTANDARD = LVCMOS33; +NET CLK_50M PERIOD = 20.0ns HIGH 50%; +NET CLK_50M LOC = P14 | IOSTANDARD = LVCMOS33; # Reset (active LOW) NET INIT LOC = P39 | IOSTANDARD = LVCMOS33; diff --git a/hw/lx-rocon_firmware/firmware.c b/hw/lx-rocon_firmware/firmware.c new file mode 100644 index 0000000..e12a76a --- /dev/null +++ b/hw/lx-rocon_firmware/firmware.c @@ -0,0 +1,83 @@ +/* Firmware file for lx-rocon tumbl coprocessor */ + +#include + +typedef struct +{ + int16_t p; + int16_t i; + int32_t irc_period; + int16_t req_current; + int16_t acc_dev; + int16_t max_acc; +} axis_settings; + +typedef struct +{ + /* Input */ + int16_t current; + int32_t irc; + int32_t irc_last; + int32_t irc_norm; + + /* Output */ + uint16_t pwm[3]; +} axis_io; + +axis_settings a_settings; + +axis_io a_io; +int32_t irc_a_reg; +int16_t current_a_reg; +uint32_t count; +int16_t phase_table[1][1]; + +void init_defvals() +{ + a_settings.p = 20; + a_settings.i = 2; + a_settings.irc_period = 7000; + a_settings.req_current = 500; + a_settings.acc_dev = 0; +} + +void update_axis(axis_settings *settings, axis_io* io) +{ + int i; + int16_t dev; + int32_t mag, irc_diff; + + dev = settings->req_current - io->current; + settings->acc_dev += dev; + + if (settings->acc_dev > settings->max_acc) + settings->acc_dev = settings->max_acc; + else if (-(settings->acc_dev) <= -(settings->max_acc)) + settings->acc_dev = -(settings->max_acc); + + mag = settings->acc_dev * settings->i + dev * settings->p; + + irc_diff = io->irc - io->irc_last; + io->irc_last = io->irc; + io->irc_norm += irc_diff; + + if (io->irc_norm > settings->irc_period) + io->irc_norm -= settings->irc_period; + else if (io->irc_norm < 0) + io->irc_norm += settings->irc_period; + + for (i = 0; i < 3; i++) + io->pwm[i] = (uint16_t)((mag * phase_table[/*i*/ 0][/*irc_norm*/ 0]) >> 16); +} + +void main() +{ + while (1) + { + update_axis(&a_settings, &a_io); + a_io.irc = irc_a_reg; + a_io.current = current_a_reg; + count++; + } +} + diff --git a/hw/lx-rocon_firmware/start.S b/hw/lx-rocon_firmware/start.S new file mode 100644 index 0000000..b3b34c6 --- /dev/null +++ b/hw/lx-rocon_firmware/start.S @@ -0,0 +1,66 @@ +/* LX ROCON firmware startup file */ + +.globl _main +.align 2 + +_main: + + /* Stack pointer */ + addi r1, r0, 0xFFC + + /* Other register values are not initialized to 0 */ + addi r2, r0, 0 + addi r3, r0, 0 + addi r4, r0, 0 + addi r5, r0, 0 + addi r6, r0, 0 + addi r7, r0, 0 + addi r8, r0, 0 + addi r9, r0, 0 + addi r10, r0, 0 + addi r11, r0, 0 + addi r12, r0, 0 + addi r13, r0, 0 + addi r14, r0, 0 + addi r15, r0, 0 + addi r16, r0, 0 + addi r17, r0, 0 + addi r18, r0, 0 + addi r19, r0, 0 + addi r20, r0, 0 + addi r21, r0, 0 + addi r22, r0, 0 + addi r23, r0, 0 + addi r24, r0, 0 + addi r25, r0, 0 + addi r26, r0, 0 + addi r27, r0, 0 + addi r28, r0, 0 + addi r29, r0, 0 + addi r30, r0, 0 + addi r31, r0, 0 + + /* reset data */ + addi r6, r0, _sdata + addi r7, r0, _edata + rsub r18, r6, r7 + blei r18, .Lenddata +.Lloopdata: + swi r0, r6, 0 + addi r6, r6, 4 + rsub r18, r6, r7 + bgti r18, .Lloopdata + or r0, r0, r0 +.Lenddata: + /* Init default values */ + brlid r15, init_defvals + addi r31, r0, 20 + or r0, r0, r0 + + /* Run program */ + brlid r15, main + or r0, r0, r0 + + /* End of program */ + bri 0x00 + or r0, r0, r0 diff --git a/hw/lx-rocon_firmware/utils b/hw/lx-rocon_firmware/utils new file mode 120000 index 0000000..a755350 --- /dev/null +++ b/hw/lx-rocon_firmware/utils @@ -0,0 +1 @@ +../../submodule/tumbl/utils \ No newline at end of file diff --git a/hw/lx-rocon_tumbl/lx_rocon_dmem.vhd b/hw/lx-rocon_tumbl/lx_rocon_dmem.vhd new file mode 100644 index 0000000..b9e3f58 --- /dev/null +++ b/hw/lx-rocon_tumbl/lx_rocon_dmem.vhd @@ -0,0 +1,72 @@ +library ieee; + +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.mbl_Pkg.all; +use work.lx_rocon_pkg.all; + +-- 4 kB data memory for Thumbl core +-- To be flashed from the Master CPU + +entity lx_rocon_dmem is + port + ( + -- Memory wiring for Tumbl + clk_i : in std_logic; + ce_i : in std_logic; + adr_i : in std_logic_vector(11 downto 2); + wre_i : in std_logic; + bsel_i : in std_logic_vector(3 downto 0); + dat_i : in std_logic_vector(31 downto 0); + dat_o : out std_logic_vector(31 downto 0); + + -- Memory wiring for Master CPU + clk_m : in std_logic; + en_m : in std_logic; + we_m : in std_logic_vector(3 downto 0); + addr_m : in std_logic_vector(9 downto 0); + din_m : in std_logic_vector(31 downto 0); + dout_m : out std_logic_vector(31 downto 0) + + ); +end lx_rocon_dmem; + +architecture rtl of lx_rocon_dmem is + + signal wre_i_s : std_logic_vector(3 downto 0); + +begin + + wre_i_s <= bsel_i when (wre_i = '1') else "0000"; + + I_RAMB: xilinx_dualport_bram + generic map + ( + we_width => 4, + byte_width => 8, + address_width => 10 + ) + port map + ( + -- Tumblr port + clka => clk_i, + rsta => '0', + ena => ce_i, + wea => wre_i_s, + addra => adr_i(11 downto 2), + dina => dat_i, + douta => dat_o, + + -- Master CPU port + clkb => clk_m, + rstb => '0', + enb => en_m, + web => we_m, + addrb => addr_m, + dinb => din_m, + doutb => dout_m + ); + +end rtl; diff --git a/hw/lx-rocon_tumbl/lx_rocon_gprf_abd.vhd b/hw/lx-rocon_tumbl/lx_rocon_gprf_abd.vhd new file mode 100644 index 0000000..3e825a6 --- /dev/null +++ b/hw/lx-rocon_tumbl/lx_rocon_gprf_abd.vhd @@ -0,0 +1,161 @@ +library ieee; + +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.mbl_Pkg.all; +use work.lx_rocon_pkg.all; + +-- 32x32b General Puprose Registers for Tumbl Core +-- Uses 3 BRAMs + +entity lx_rocon_gprf_abd is + port + ( + clk_i : in std_logic; + rst_i : in std_logic; + clken_i : in std_logic; + + ID2GPRF_i : in ID2GPRF_Type; + MEM_WRB_i : in WRB_Type; + GPRF2EX_o : out GPRF2EX_Type + ); +end entity lx_rocon_gprf_abd; + +architecture rtl of lx_rocon_gprf_abd is + + signal rdix_rA_s : std_logic_vector(4 downto 0); + signal rdix_rB_s : std_logic_vector(4 downto 0); + signal rdix_rD_s : std_logic_vector(4 downto 0); + + signal wre_rD_s : std_logic; + signal ena_rA_s : std_logic; + signal ena_rB_s : std_logic; + signal ena_rD_s : std_logic; + + signal clken_s : std_logic; + + signal wthru_rA_r : std_logic; + signal rA_DOA_s : std_logic_vector(31 downto 0); + signal rA_DOB_s : std_logic_vector(31 downto 0); + signal wthru_rB_r : std_logic; + signal rB_DOA_s : std_logic_vector(31 downto 0); + signal rB_DOB_s : std_logic_vector(31 downto 0); + signal wthru_rD_r : std_logic; + signal rD_DOA_s : std_logic_vector(31 downto 0); + signal rD_DOB_s : std_logic_vector(31 downto 0); + +begin + + -- writeback if WRB_EX or WRB_MEM, but not when r0 involved + wre_rD_s <= '1' when ((MEM_WRB_i.wrb_Action /= NO_WRB) and + (MEM_WRB_i.wrix_rD /= "00000")) else '0'; + + -- ports A should remain unchanged when clken_i is low, while also + -- reading from the same address as will be written to should be disabled + -- (setup for writeThru of data_rD) + ena_rA_s <= '1' when rst_i = '1' else clken_i when ((ID2GPRF_i.rdix_rA /= MEM_WRB_i.wrix_rD)) else '0'; + ena_rB_s <= '1' when rst_i = '1' else clken_i when ((ID2GPRF_i.rdix_rB /= MEM_WRB_i.wrix_rD)) else '0'; + ena_rD_s <= '1' when rst_i = '1' else clken_i when ((ID2GPRF_i.rdix_rD /= MEM_WRB_i.wrix_rD)) else '0'; + + -- make sure reset does it's job (writes 0 to R0 and resets the ports) + clken_s <= rst_i or clken_i; + rdix_rA_s <= (others => '0') when rst_i = '1' else ID2GPRF_i.rdix_rA; + rdix_rB_s <= (others => '0') when rst_i = '1' else ID2GPRF_i.rdix_rB; + rdix_rD_s <= (others => '0') when rst_i = '1' else ID2GPRF_i.rdix_rD; + + GPRF2EX_o.data_rA <= rA_DOA_s when (wthru_rA_r = '0') else rA_DOB_s; + GPRF2EX_o.data_rB <= rB_DOA_s when (wthru_rB_r = '0') else rB_DOB_s; + GPRF2EX_o.data_rD <= rD_DOA_s when (wthru_rD_r = '0') else rD_DOB_s; -- also for rD ??? + + I_rA: xilinx_dualport_bram + generic map + ( + byte_width => 32, + we_width => 1, + address_width => 5 + ) + port map + ( + clka => clk_i, + rsta => rst_i, + ena => ena_rA_s, + wea(0) => rst_i, + addra => rdix_rA_s, + dina => C_32_ZEROS, + douta => rA_DOA_s, + -- Write-back + clkb => clk_i, + rstb => rst_i, + enb => clken_s, + web(0) => wre_rD_s, + addrb => MEM_WRB_i.wrix_rD, + dinb => MEM_WRB_i.data_rD, + doutb => rA_DOB_s + ); + + I_rB: xilinx_dualport_bram + generic map + ( + byte_width => 32, + we_width => 1, + address_width => 5 + ) + port map + ( + clka => clk_i, + rsta => rst_i, + ena => ena_rB_s, + wea(0) => rst_i, + addra => rdix_rB_s, + dina => C_32_ZEROS, + douta => rB_DOA_s, + -- Write-back + clkb => clk_i, + rstb => rst_i, + enb => clken_s, + web(0) => wre_rD_s, + addrb => MEM_WRB_i.wrix_rD, + dinb => MEM_WRB_i.data_rD, + doutb => rB_DOB_s + ); + + I_rD: xilinx_dualport_bram + generic map + ( + byte_width => 32, + we_width => 1, + address_width => 5 + ) + port map + ( + clka => clk_i, + rsta => rst_i, + ena => ena_rD_s, + wea(0) => rst_i, + addra => rdix_rD_s, + dina => C_32_ZEROS, + douta => rD_DOA_s, + -- Write-back + clkb => clk_i, + rstb => rst_i, + enb => clken_s, + web(0) => wre_rD_s, + addrb => MEM_WRB_i.wrix_rD, + dinb => MEM_WRB_i.data_rD, + doutb => rD_DOB_s + ); + + p_regd: process(clk_i) + begin + if clk_i = '1' and clk_i'event then + if (clken_i = '1') then + wthru_rA_r <= not ena_rA_s; + wthru_rB_r <= not ena_rB_s; + wthru_rD_r <= not ena_rD_s; + end if; + end if; + end process; + +end architecture rtl; diff --git a/hw/lx-rocon_tumbl/lx_rocon_imem.vhd b/hw/lx-rocon_tumbl/lx_rocon_imem.vhd new file mode 100644 index 0000000..fc61dc6 --- /dev/null +++ b/hw/lx-rocon_tumbl/lx_rocon_imem.vhd @@ -0,0 +1,64 @@ +library ieee; + +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.mbl_Pkg.all; +use work.lx_rocon_pkg.all; + +-- 2 kB instruction memory for Thumbl core +-- To be flashed from the Master CPU + +entity lx_rocon_imem is + port + ( + -- Memory wiring for Tumbl + clk_i : in std_logic; + cs_i : in std_logic; + adr_i : in std_logic_vector(10 downto 2); + dat_o : out std_logic_vector(31 downto 0); + + -- Memory wiring for Master CPU + clk_m : in std_logic; + en_m : in std_logic; + we_m : in std_logic_vector(3 downto 0); + addr_m : in std_logic_vector(8 downto 0); + din_m : in std_logic_vector(31 downto 0); + dout_m : out std_logic_vector(31 downto 0) + + ); +end lx_rocon_imem; + +architecture rtl of lx_rocon_imem is +begin + + I_RAMB: xilinx_dualport_bram + generic map + ( + we_width => 4, + byte_width => 8, + address_width => 9 + ) + port map + ( + -- Tumblr port + clka => clk_i, + rsta => '0', + ena => cs_i, + wea => "0000", + addra => adr_i(10 downto 2), + dina => C_32_ZEROS, + douta => dat_o, + + -- Master CPU port + clkb => clk_m, + rstb => '0', + enb => en_m, + web => we_m, + addrb => addr_m, + dinb => din_m, + doutb => dout_m + ); + +end rtl; diff --git a/hw/lx-rocon_tumbl/lx_rocon_tumbl.vhd b/hw/lx-rocon_tumbl/lx_rocon_tumbl.vhd new file mode 100644 index 0000000..0063c10 --- /dev/null +++ b/hw/lx-rocon_tumbl/lx_rocon_tumbl.vhd @@ -0,0 +1,298 @@ +library ieee; + +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.mbl_Pkg.all; +use work.lx_rocon_pkg.all; + +-- Tumbl configured as a coprocessor for lx_rocon +-- Uses 10 bits width address bus with HW barrel and multiplier + +entity lx_rocon_tumbl is + generic + ( + IMEM_ABITS_g : positive := 11; + DMEM_ABITS_g : positive := 12; + -- + USE_HW_MUL_g : boolean := true; + USE_BARREL_g : boolean := true + ); + port + ( + clk_i : in std_logic; + rst_i : in std_logic; + halt_i : in std_logic; + int_i : in std_logic; + trace_i : in std_logic; + trace_kick_i : in std_logic; + + -- Program counter + pc_o : out std_logic_vector(31 downto 0); + + -- Internal memory (instruction) + imem_clk : in std_logic; + imem_en : in std_logic; + imem_we : in std_logic_vector(3 downto 0); + imem_addr : in std_logic_vector(8 downto 0); + imem_din : in std_logic_vector(31 downto 0); + imem_dout : out std_logic_vector(31 downto 0); + + -- Internal memory (data) + dmem_clk : in std_logic; + dmem_en : in std_logic; + dmem_we : in std_logic_vector(3 downto 0); + dmem_addr : in std_logic_vector(9 downto 0); + dmem_din : in std_logic_vector(31 downto 0); + dmem_dout : out std_logic_vector(31 downto 0); + + -- External memory bus + XMEMB_sel_o : out std_logic; + XMEMB_i : in DMEMB2CORE_Type; + XMEMB_o : out CORE2DMEMB_Type; + -- + bad_op_o : out std_logic; + done_o : out std_logic + ); +end entity lx_rocon_tumbl; + +architecture rtl of lx_rocon_tumbl is + + constant DMEM_TEST_c : std_logic_vector((31-DMEM_ABITS_g) downto 0) := (others => '0'); + + signal imem_clken_s : std_logic; + signal imem_addr_s : std_logic_vector(31 downto 0); + signal imem_data_s : std_logic_vector(31 downto 0); + signal gprf_clken_s : std_logic; + signal core_clk_en_s : std_logic; + signal pc_ctrl_s : std_logic; + signal c2dmemb_s : CORE2DMEMB_Type; + signal dmem_data_s : std_logic_vector(31 downto 0); + signal DMEMB_i_s : DMEMB2CORE_Type; + + signal MEM2CTRL_s : MEM2CTRL_Type; + signal INT_CTRL_s : INT_CTRL_Type; + signal ID2CTRL_s : ID2CTRL_Type; + + signal IF2ID_s, IF2ID_r : IF2ID_Type; + signal ID2EX_s, ID2EX_r : ID2EX_Type; + signal ID2GPRF_s : ID2GPRF_Type; + signal GPRF2EX_s : GPRF2EX_Type; + signal EX2IF_s, EX2IF_r : EX2IF_Type; + signal EX2MEM_s, EX2MEM_r : EX2MEM_Type; + signal EX_WRB_s, EX_WRB_r : WRB_Type; + signal MEM_WRB_s : WRB_Type; + signal IMM_LOCK_s, IMM_LOCK_r : IMM_LOCK_Type; + signal HAZARD_WRB_s, HAZARD_WRB_r : HAZARD_WRB_Type; + signal EX2MSR_s : MSR_Type; + signal MSR2EX_s : MSR_Type; + signal MEM_REG_s, MEM_REG_r : MEM_REG_Type; + signal dmem_sel_s, dmem_sel_r : std_logic; + signal BAD_OP_s : std_logic; + signal BAD_OP_up_s : std_logic; + signal halt_s : std_logic; + + signal imem_really_clken_s : std_logic; + signal dmem_really_sel_s : std_logic; + signal gprf_really_clken_s : std_logic; + +begin + + -- select internal data memory when all address bits above DMEM_ABITS_g are zero + dmem_sel_s <= '1' when (c2dmemb_s.addr(31 downto DMEM_ABITS_g) = DMEM_TEST_c) + else '0'; + XMEMB_sel_o <= not dmem_sel_s; + XMEMB_o <= c2dmemb_s; + pc_o <= ID2EX_r.program_counter; -- Program counter for EXEQ + bad_op_o <= BAD_OP_s; + halt_s <= halt_i or BAD_OP_up_s; + + imem_really_clken_s <= imem_clken_s and core_clk_en_s; + dmem_really_sel_s <= dmem_sel_s and core_clk_en_s; + gprf_really_clken_s <= gprf_clken_s and core_clk_en_s; + + I_IMEM: lx_rocon_imem + port map + ( + clk_i => clk_i, + cs_i => imem_really_clken_s, + adr_i => imem_addr_s((IMEM_ABITS_g-1) downto 2), + dat_o => imem_data_s, + + clk_m => imem_clk, + en_m => imem_en, + we_m => imem_we, + addr_m => imem_addr, + din_m => imem_din, + dout_m => imem_dout + ); + + I_DMEM: lx_rocon_dmem + port map + ( + clk_i => clk_i, + ce_i => dmem_really_sel_s, + adr_i => c2dmemb_s.addr((DMEM_ABITS_g-1) downto 2), + wre_i => c2dmemb_s.wre, + bsel_i => c2dmemb_s.bSel, + dat_i => c2dmemb_s.data, + dat_o => dmem_data_s, + + clk_m => dmem_clk, + en_m => dmem_en, + we_m => dmem_we, + addr_m => dmem_addr, + din_m => dmem_din, + dout_m => dmem_dout + ); + + I_FETCH: fetch + port map + ( + prog_cntr_i => IF2ID_r.program_counter, + inc_pc_i => pc_ctrl_s, + EX2IF_i => EX2IF_r, + IF2ID_o => IF2ID_s + ); + + I_DECODE: decode + generic map(USE_HW_MUL_g, USE_BARREL_g) + port map + ( + IF2ID_i => IF2ID_r, + imem_data_i => imem_data_s, + -- + ID2GPRF_o => ID2GPRF_s, + ID2EX_o => ID2EX_s, + -- + INT_CTRL_i => INT_CTRL_s, + ID2CTRL_o => ID2CTRL_s, + -- + noLiteOpc_o => BAD_OP_s + ); + + I_GPRF: lx_rocon_gprf_abd + port map + ( + clk_i => clk_i, + rst_i => rst_i, + clken_i => gprf_really_clken_s, + -- + ID2GPRF_i => ID2GPRF_s, + MEM_WRB_i => MEM_WRB_s, + GPRF2EX_o => GPRF2EX_s + ); + + I_EXEQ: exeq + generic map(USE_HW_MUL_g, USE_BARREL_g) + port map + ( + ID2EX_i => ID2EX_r, + GPRF2EX_i => GPRF2EX_s, + EX2IF_o => EX2IF_s, + -- + EX_WRB_i => EX_WRB_r, + EX_WRB_o => EX_WRB_s, + MEM_WRB_i => MEM_WRB_s, + -- + HAZARD_WRB_i => HAZARD_WRB_r, + HAZARD_WRB_o => HAZARD_WRB_s, + -- + IMM_LOCK_i => IMM_LOCK_r, + IMM_LOCK_o => IMM_LOCK_s, + -- + MSR_i => MSR2EX_s, + MSR_o => EX2MSR_s, + -- + EX2MEM_o => EX2MEM_s + ); + + -- this is a very simple address block decoder, just "internal" dmem or "external" + -- clken and int hardwired for fast internal data-memory + DMEMB_i_s.clken <= '1' when (dmem_sel_s = '1') else XMEMB_i.clken; + DMEMB_i_s.data <= dmem_data_s when (dmem_sel_r = '1') else XMEMB_i.data; + DMEMB_i_s.int <= XMEMB_i.int; + + I_MEM: mem + port map + ( + EX2MEM_i => EX2MEM_r, + MEM_WRB_o => MEM_WRB_s, + -- + DMEMB_i => DMEMB_i_s, + DMEMB_o => c2dmemb_s, + -- + MEM_REG_i => MEM_REG_r, + MEM_REG_o => MEM_REG_s, + -- + MEM2CTRL_o => MEM2CTRL_s + ); + + I_CTRL: core_ctrl + port map + ( + clk_i => clk_i, + rst_i => rst_i, + halt_i => halt_s, + int_i => int_i, + trace_i => trace_i, + trace_kick_i => trace_kick_i, + core_clk_en_o => core_clk_en_s, + -- specific fetch i/o + imem_addr_o => imem_addr_s, + imem_clken_o => imem_clken_s, + pc_ctrl_o => pc_ctrl_s, + -- fetch to decode pipeline registers + IF2ID_REG_i => IF2ID_s, + IF2ID_REG_o => IF2ID_r, + -- decode to exeq pipeline registers + ID2EX_REG_i => ID2EX_s, + ID2EX_REG_o => ID2EX_r, + -- GPRF control + gprf_clken_o => gprf_clken_s, + -- exeq to fetch feedback registers + EX2IF_REG_i => EX2IF_s, + EX2IF_REG_o => EX2IF_r, + -- exeq to mem pipeline registers + EX2MEM_REG_i => EX2MEM_s, + EX2MEM_REG_o => EX2MEM_r, + -- mem pipeline register + MEM_REG_i => MEM_REG_s, + MEM_REG_o => MEM_REG_r, + -- decode control i/o + ID2CTRL_i => ID2CTRL_s, + INT_CTRL_o => INT_CTRL_s, + -- exeq control i/o + EX_WRB_i => EX_WRB_s, + EX_WRB_o => EX_WRB_r, + -- data hazard i/o + HAZARD_WRB_i => HAZARD_WRB_s, + HAZARD_WRB_o => HAZARD_WRB_r, + -- for handling the 'IMM' instruction + IMM_LOCK_i => IMM_LOCK_s, + IMM_LOCK_o => IMM_LOCK_r, + -- for handling the Machine Status Register + MSR_i => EX2MSR_s, + MSR_o => MSR2EX_s, + -- miscellaneous + MEM2CTRL_i => MEM2CTRL_s, + done_o => done_o + ); + + regd_proc: process(clk_i, rst_i) + begin + if clk_i = '1' and clk_i'event then + if (rst_i = '1') then -- synchronous reset ... + dmem_sel_r <= '1'; + BAD_OP_up_s <= '0'; + else -- delay select_external_mem (needed for reading ...) + if (DMEMB_i_s.clken = '1') then + dmem_sel_r <= dmem_sel_s; -- OR c2dmemb_s.wre; ?? + end if; + BAD_OP_up_s <= BAD_OP_up_s or BAD_OP_s; + end if; + end if; + end process regd_proc; + +end architecture rtl; diff --git a/hw/lx-rocon_tumbl/tb/lx_rocon_tumbl_tb.vhd b/hw/lx-rocon_tumbl/tb/lx_rocon_tumbl_tb.vhd new file mode 100644 index 0000000..b25f986 --- /dev/null +++ b/hw/lx-rocon_tumbl/tb/lx_rocon_tumbl_tb.vhd @@ -0,0 +1,143 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; +USE work.mbl_Pkg.ALL; +USE work.lx_rocon_pkg.ALL; + +-- Tumbl core testbench + +ENTITY lx_rocon_tumbl_tb IS +END lx_rocon_tumbl_tb; + +ARCHITECTURE behavior OF lx_rocon_tumbl_tb IS + + -- Component Declaration for the Unit Under Test (UUT) + + COMPONENT lx_rocon_tumbl + PORT( + clk_i : IN std_logic; + rst_i : IN std_logic; + halt_i : IN std_logic; + int_i : IN std_logic; + trace_i : IN std_logic; + trace_kick_i : IN std_logic; + pc_o : OUT std_logic_vector(31 downto 0); + imem_clk : IN std_logic; + imem_en : IN std_logic; + imem_we : IN std_logic_vector(3 downto 0); + imem_addr : IN std_logic_vector(8 downto 0); + imem_din : IN std_logic_vector(31 downto 0); + imem_dout : OUT std_logic_vector(31 downto 0); + dmem_clk : IN std_logic; + dmem_en : IN std_logic; + dmem_we : IN std_logic_vector(3 downto 0); + dmem_addr : IN std_logic_vector(9 downto 0); + dmem_din : IN std_logic_vector(31 downto 0); + dmem_dout : OUT std_logic_vector(31 downto 0); + XMEMB_sel_o : OUT std_logic; + XMEMB_i : IN DMEMB2CORE_Type; + XMEMB_o : OUT CORE2DMEMB_Type; + bad_op_o : OUT std_logic; + done_o : OUT std_logic + ); + END COMPONENT; + + + --Inputs + signal clk_i : std_logic := '0'; + signal rst_i : std_logic := '0'; + signal halt_i : std_logic := '0'; + signal int_i : std_logic := '0'; + signal trace_i : std_logic := '0'; + signal trace_kick_i : std_logic := '0'; + signal imem_clk : std_logic := '0'; + signal imem_en : std_logic := '0'; + signal imem_we : std_logic_vector(3 downto 0) := (others => '0'); + signal imem_addr : std_logic_vector(8 downto 0) := (others => '0'); + signal imem_din : std_logic_vector(31 downto 0) := (others => '0'); + signal dmem_clk : std_logic := '0'; + signal dmem_en : std_logic := '0'; + signal dmem_we : std_logic_vector(3 downto 0) := (others => '0'); + signal dmem_addr : std_logic_vector(9 downto 0) := (others => '0'); + signal dmem_din : std_logic_vector(31 downto 0) := (others => '0'); + signal XMEMB_i : DMEMB2CORE_Type := (clken => '0', data => (others => '0'), int => '0'); + + --Outputs + signal pc_o : std_logic_vector(31 downto 0); + signal imem_dout : std_logic_vector(31 downto 0); + signal dmem_dout : std_logic_vector(31 downto 0); + signal XMEMB_sel_o : std_logic; + signal XMEMB_o : CORE2DMEMB_Type; + signal bad_op_o : std_logic; + signal done_o : std_logic; + + -- Clock period definitions + constant clk_i_period : time := 20 ns; -- 50 MHz + constant imem_clk_period : time := 13.8 ns; -- 72 MHz + constant dmem_clk_period : time := 13.8 ns; -- 72 MHz + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: lx_rocon_tumbl PORT MAP ( + clk_i => clk_i, + rst_i => rst_i, + halt_i => halt_i, + int_i => int_i, + trace_i => trace_i, + trace_kick_i => trace_kick_i, + pc_o => pc_o, + imem_clk => imem_clk, + imem_en => imem_en, + imem_we => imem_we, + imem_addr => imem_addr, + imem_din => imem_din, + imem_dout => imem_dout, + dmem_clk => dmem_clk, + dmem_en => dmem_en, + dmem_we => dmem_we, + dmem_addr => dmem_addr, + dmem_din => dmem_din, + dmem_dout => dmem_dout, + XMEMB_sel_o => XMEMB_sel_o, + XMEMB_i => XMEMB_i, + XMEMB_o => XMEMB_o, + bad_op_o => bad_op_o, + done_o => done_o + ); + + -- Clock process definitions + clk_i_process :process + begin + clk_i <= '0'; + wait for clk_i_period/2; + clk_i <= '1'; + wait for clk_i_period/2; + end process; + + imem_clk_process :process + begin + imem_clk <= '0'; + wait for imem_clk_period/2; + imem_clk <= '1'; + wait for imem_clk_period/2; + end process; + + dmem_clk_process :process + begin + dmem_clk <= '0'; + wait for dmem_clk_period/2; + dmem_clk <= '1'; + wait for dmem_clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + -- External ModelSim script + + wait; + end process; + +END; diff --git a/hw/lx_rocon_pkg.vhd b/hw/lx_rocon_pkg.vhd new file mode 100644 index 0000000..410bef2 --- /dev/null +++ b/hw/lx_rocon_pkg.vhd @@ -0,0 +1,334 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.mbl_Pkg.all; + +-- Entities within lx_rocon + +package lx_rocon_pkg is + + -- IRC register + component irc_register + port + ( + clk : in std_logic; + reset : in std_logic; + a0, b0 : in std_logic; + index0 : in std_logic; + mark0 : in std_logic; + data_in : in std_logic; + data_out : out std_logic_vector(31 downto 0); + ce : in std_logic_vector(1 downto 0); + rd : in std_logic; + ta : out std_logic; + wr : in std_logic + ); + end component; + + -- BCD counter + component bcd + generic + ( + width : integer + ); + port + ( + reset : in std_logic; + en : in std_logic; + clk : in std_logic; + value : out std_logic_vector((width-1) downto 0) + ); + end component; + + -- Quadcount + component qcounter + port + ( + clk : in std_logic; + reset : in std_logic; + a0, b0 : in std_logic; + index0 : in std_logic; + + a_rise : out std_logic; + a_fall : out std_logic; + b_rise : out std_logic; + b_fall : out std_logic; + + qcount : out std_logic_vector (31 downto 0); + qcount_index : out std_logic_vector (31 downto 0); + ab_event : out std_logic; + ab_error : out std_logic + ); + end component; + + -- D sampler + component dff + port + ( + clk : in std_logic; + reset : in std_logic; + d : in std_logic; + q : out std_logic + ); + end component; + + -- D sampler (filtered) + component dff2 + port + ( + clk : in std_logic; + reset : in std_logic; + d : in std_logic; + q : out std_logic + ); + end component; + + -------------------------------------------------------------------------------- + -- TUMBL + -------------------------------------------------------------------------------- + + component lx_rocon_tumbl + generic + ( + IMEM_ABITS_g : positive := 12; + DMEM_ABITS_g : positive := 12; + -- + USE_HW_MUL_g : boolean := true; + USE_BARREL_g : boolean := true + ); + port + ( + clk_i : in std_logic; + rst_i : in std_logic; + halt_i : in std_logic; + int_i : in std_logic; + trace_i : in std_logic; + trace_kick_i : in std_logic; + pc_o : out std_logic_vector(31 downto 0); + imem_clk : in std_logic; + imem_en : in std_logic; + imem_we : in std_logic_vector(3 downto 0); + imem_addr : in std_logic_vector(8 downto 0); + imem_din : in std_logic_vector(31 downto 0); + imem_dout : out std_logic_vector(31 downto 0); + dmem_clk : in std_logic; + dmem_en : in std_logic; + dmem_we : in std_logic_vector(3 downto 0); + dmem_addr : in std_logic_vector(9 downto 0); + dmem_din : in std_logic_vector(31 downto 0); + dmem_dout : out std_logic_vector(31 downto 0); + XMEMB_sel_o : out std_logic; + XMEMB_i : in DMEMB2CORE_Type; + XMEMB_o : out CORE2DMEMB_Type; + bad_op_o : out std_logic; + done_o : out std_logic + ); + end component; + + component lx_rocon_imem + port + ( + clk_i : in std_logic; + cs_i : in std_logic; + adr_i : in std_logic_vector(10 downto 2); + dat_o : out std_logic_vector(31 downto 0); + clk_m : in std_logic; + en_m : in std_logic; + we_m : in std_logic_vector(3 downto 0); + addr_m : in std_logic_vector(8 downto 0); + din_m : in std_logic_vector(31 downto 0); + dout_m : out std_logic_vector(31 downto 0) + + ); + end component; + + component lx_rocon_dmem + port + ( + clk_i : in std_logic; + ce_i : in std_logic; + adr_i : in std_logic_vector(11 downto 2); + wre_i : in std_logic; + bsel_i : in std_logic_vector(3 downto 0); + dat_i : in std_logic_vector(31 downto 0); + dat_o : out std_logic_vector(31 downto 0); + clk_m : in std_logic; + en_m : in std_logic; + we_m : in std_logic_vector(3 downto 0); + addr_m : in std_logic_vector(9 downto 0); + din_m : in std_logic_vector(31 downto 0); + dout_m : out std_logic_vector(31 downto 0) + ); + end component; + + component lx_rocon_gprf_abd + port + ( + clk_i : in std_logic; + rst_i : in std_logic; + clken_i : in std_logic; + ID2GPRF_i : in ID2GPRF_Type; + MEM_WRB_i : in WRB_Type; + GPRF2EX_o : out GPRF2EX_Type + ); + end component; + + -------------------------------------------------------------------------------- + -- MEMORY BUS + -------------------------------------------------------------------------------- + + -- Calibration read register + component calibration_read_register + generic + ( + id : std_logic_vector(31 downto 0) + ); + port + ( + data_out : out std_logic_vector(31 downto 0); + rd : in std_logic; + ta : out std_logic + ); + end component; + + -- Calibration write register + component calibration_write_register + port + ( + clk : in std_logic; + reset : in std_logic; + ce : in std_logic; + data_in : in std_logic_vector(31 downto 0); + data_out : out std_logic_vector(31 downto 0); + rd : in std_logic; + bls : in std_logic_vector(3 downto 0); + ta : out std_logic + ); + end component; + + -- Calibration interconnect + component bus_calibration + port + ( + clk : in std_logic; + reset : in std_logic; + ce : in std_logic; + address : in std_logic_vector(1 downto 0); + data_in : in std_logic_vector(31 downto 0); + data_out : out std_logic_vector(31 downto 0); + rd : in std_logic; + bls : in std_logic_vector(3 downto 0); + ta : out std_logic + ); + end component; + + -- IRC interconnect + component bus_irc + port + ( + clk : in std_logic; + reset : in std_logic; + + address : in std_logic_vector(3 downto 0); + ce : in std_logic; + + data_in : in std_logic; + data_out : out std_logic_vector(31 downto 0); + + rd : in std_logic; + wr : in std_logic; + ta : out std_logic; + + irc1_a : in std_logic; + irc1_b : in std_logic; + irc1_index : in std_logic; + irc1_mark : in std_logic; + + irc2_a : in std_logic; + irc2_b : in std_logic; + irc2_index : in std_logic; + irc2_mark : in std_logic; + + irc3_a : in std_logic; + irc3_b : in std_logic; + irc3_index : in std_logic; + irc3_mark : in std_logic; + + irc4_a : in std_logic; + irc4_b : in std_logic; + irc4_index : in std_logic; + irc4_mark : in std_logic + ); + end component; + + -- BCD interconnect + component bus_bcd + port + ( + reset : in std_logic; + en : in std_logic; + clk : in std_logic; + data_out : out std_logic_vector(31 downto 0); + rd : in std_logic; + ta : out std_logic + ); + end component; + + -- Tumbl interconnect + component bus_tumbl + port + ( + clk_100m : in std_logic; + clk_50m : in std_logic; + ce : in std_logic; + reset : in std_logic; + rd : in std_logic; + bls : in std_logic_vector(3 downto 0); + address : in std_logic_vector(11 downto 0); + data_in : in std_logic_vector(31 downto 0); + data_out : out std_logic_vector(31 downto 0); + ta : out std_logic; + XMEMB_sel_o : out std_logic; + XMEMB_i : in DMEMB2CORE_Type; + XMEMB_o : out CORE2DMEMB_Type + ); + end component; + + -------------------------------------------------------------------------------- + -- BRAM + -------------------------------------------------------------------------------- + + component xilinx_dualport_bram + generic + ( + byte_width : positive := 8; + address_width : positive := 8; + we_width : positive := 4 + ); + port + ( + clka : in std_logic; + rsta : in std_logic; + ena : in std_logic; + wea : in std_logic_vector((we_width-1) downto 0); + addra : in std_logic_vector((address_width-1) downto 0); + dina : in std_logic_vector(((byte_width*we_width)-1) downto 0); + douta : out std_logic_vector(((byte_width*we_width)-1) downto 0); + clkb : in std_logic; + rstb : in std_logic; + enb : in std_logic; + web : in std_logic_vector((we_width-1) downto 0); + addrb : in std_logic_vector((address_width-1) downto 0); + dinb : in std_logic_vector(((byte_width*we_width)-1) downto 0); + doutb : out std_logic_vector(((byte_width*we_width)-1) downto 0) + ); + end component; + +end lx_rocon_pkg; + +package body lx_rocon_pkg is + + +end lx_rocon_pkg; diff --git a/hw/lx_rocon_top.prj b/hw/lx_rocon_top.prj index 36d4830..cdfca3d 100644 --- a/hw/lx_rocon_top.prj +++ b/hw/lx_rocon_top.prj @@ -1,13 +1,22 @@ -vhdl work "dff.vhd" +vhdl work "tumbl/mbl_Pkg.vhd" +vhdl work "lx_rocon_pkg.vhd" +vhdl work "dff2.vhd" +vhdl work "xilinx_dualport_bram.vhd" vhdl work "qcounter.vhd" +vhdl work "tumbl/mem.vhd" +vhdl work "tumbl/fetch.vhd" +vhdl work "tumbl/exeq.vhd" +vhdl work "tumbl/decode.vhd" +vhdl work "tumbl/core_ctrl.vhd" +vhdl work "lx-rocon_tumbl/lx_rocon_imem.vhd" +vhdl work "lx-rocon_tumbl/lx_rocon_gprf_abd.vhd" +vhdl work "lx-rocon_tumbl/lx_rocon_dmem.vhd" vhdl work "irc_reader.vhd" +vhdl work "lx-rocon_tumbl/lx_rocon_tumbl.vhd" vhdl work "irc_register.vhd" -vhdl work "ipcore_dir/control_bram.vhd" vhdl work "calibration_write_register.vhd" vhdl work "calibration_read_register.vhd" -vhdl work "bcd.vhd" +vhdl work "bus_tumbl.vhd" vhdl work "bus_irc.vhd" -vhdl work "bus_control_bram.vhd" vhdl work "bus_calibration.vhd" -vhdl work "bus_bcd.vhd" vhdl work "lx_rocon_top.vhd" diff --git a/hw/lx_rocon_top.vhd b/hw/lx_rocon_top.vhd index a98a0b8..44a8d96 100644 --- a/hw/lx_rocon_top.vhd +++ b/hw/lx_rocon_top.vhd @@ -4,13 +4,19 @@ use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; --- lx_rocon_top - wires the modules with outside world +library unisim; +use unisim.vcomponents.all; + +use work.mbl_Pkg.all; +use work.lx_rocon_pkg.all; + +-- lx_rocon_top - wires the modules with the outside world -- ====================================================== --- INTERNAL MEMORY BUS +-- MASTER CPU EXTERNAL MEMORY BUS -- ====================================================== -- --- Internal memory bus has the following wires: +-- Master cpu memory bus has the following wires: -- -- - address[15..0] The address -- - data_in[31..0] The data coming to bus @@ -19,12 +25,17 @@ use ieee.numeric_std.all; -- - bls[3..0] Write enable for respective bytes, active LOW -- In some cases, only WR is used -- - ta Transaction acknowledge (latches data out), active LOW, multiplexed +-- +-- ====================================================== +-- TUMBL EXTERNAL MEMORY BUS +-- ====================================================== entity lx_rocon_top is port ( -- External - clk_cpu : in std_logic; + --clk_cpu : in std_logic; + clk_50m : in std_logic; cs0_xc : in std_logic; @@ -61,20 +72,22 @@ architecture Behavioral of lx_rocon_top is -- Reset signal signal reset : std_logic; + signal neg_init : std_logic; + + -- 100 MHz clock + signal clk_100m : std_logic; + signal clk_100m_fb : std_logic; + signal clk_100m_locked : std_logic; -- Peripherals on the memory bus - signal bram_out : std_logic_vector(31 downto 0); - signal bram_ta : std_logic; - signal bram_ce : std_logic; + signal tumbl_out : std_logic_vector(31 downto 0); + signal tumbl_ta : std_logic; + signal tumbl_ce : std_logic; signal irc_reg_out : std_logic_vector(31 downto 0); signal irc_reg_ta : std_logic; signal irc_reg_ce : std_logic; - signal bcd_out : std_logic_vector(31 downto 0); - signal bcd_ta : std_logic; - signal bcd_ce : std_logic; - signal calib_out : std_logic_vector(31 downto 0); signal calib_ta : std_logic; signal calib_ce : std_logic; @@ -96,115 +109,80 @@ architecture Behavioral of lx_rocon_top is -- Data latching is synchronous - it's purpose is to -- provide stable data for CPU on the bus on high rise -- of trans. ack signal + signal rd_f : std_logic; + signal rd_d : std_logic; + + signal data_read : std_logic_vector(31 downto 0); + signal i_ta : std_logic; signal i_rd : std_logic; - signal data_read : std_logic_vector(31 downto 0); signal acked : std_logic; -- Writing logic: - signal i_bls : std_logic_vector(3 downto 0); + signal bls_f : std_logic_vector(3 downto 0); + signal bls_d : std_logic_vector(3 downto 0); + signal data_write : std_logic_vector(31 downto 0); - component bus_irc - port - ( - clk : in std_logic; - reset : in std_logic; - - address : in std_logic_vector(3 downto 0); - ce : in std_logic; - - data_in : in std_logic; - data_out : out std_logic_vector(31 downto 0); - - rd : in std_logic; - wr : in std_logic; - ta : out std_logic; - - irc1_a : in std_logic; - irc1_b : in std_logic; - irc1_index : in std_logic; - irc1_mark : in std_logic; - - irc2_a : in std_logic; - irc2_b : in std_logic; - irc2_index : in std_logic; - irc2_mark : in std_logic; - - irc3_a : in std_logic; - irc3_b : in std_logic; - irc3_index : in std_logic; - irc3_mark : in std_logic; - - irc4_a : in std_logic; - irc4_b : in std_logic; - irc4_index : in std_logic; - irc4_mark : in std_logic - ); - end component; + signal i_bls : std_logic_vector(3 downto 0); - component bus_control_bram - port - ( - clk : in std_logic; - - ena : in std_logic; - wea : in std_logic_vector(3 downto 0); - addra : in std_logic_vector(8 downto 0); - dina : in std_logic_vector(31 downto 0); - douta : out std_logic_vector(31 downto 0); - taa : out std_logic; - - enb : in std_logic; - web : in std_logic_vector(3 downto 0); - addrb : in std_logic_vector(8 downto 0); - dinb : in std_logic_vector(31 downto 0); - doutb : out std_logic_vector(31 downto 0) - ); - end component; - - component bus_bcd - port - ( - reset : in std_logic; - en : in std_logic; - clk : in std_logic; - ce : in std_logic; - data_out : out std_logic_vector(31 downto 0); - rd : in std_logic; - ta : out std_logic - ); - end component; +begin - component bus_calibration - port + -- Clocking + clk_100m_dcm_sp : DCM_SP + generic map ( - clk : in std_logic; - reset : in std_logic; - ce : in std_logic; - address : in std_logic_vector(1 downto 0); - data_in : in std_logic_vector(31 downto 0); - data_out : out std_logic_vector(31 downto 0); - rd : in std_logic; - bls : in std_logic_vector(3 downto 0); - ta : out std_logic + clkdv_divide => 2.0, + clkfx_divide => 1, + clkfx_multiply => 2, + clkin_divide_by_2 => false, + clkin_period => 20.0, -- 50 MHz + clkout_phase_shift => "NONE", + clk_feedback => "1X", + deskew_adjust => "SYSTEM_SYNCHRONOUS", + dfs_frequency_mode => "LOW", + dll_frequency_mode => "LOW", + dss_mode => "NONE", + duty_cycle_correction => true, + factory_jf => X"c080", + phase_shift => 0, + startup_wait => false + ) + port map + ( + clk0 => clk_100m_fb, + clk180 => open, + clk270 => open, + clk2x => clk_100m, + clk2x180 => open, + clk90 => open, + clkdv => open, + clkfx => open, + clkfx180 => open, + locked => clk_100m_locked, + psdone => open, + status => open, + clkfb => clk_100m_fb, + clkin => clk_50m, + dssen => '0', + psclk => '0', + psen => '0', + psincdec => '0', + rst => neg_init ); - end component; - -begin -- IRC interconnect memory_bus_irc: bus_irc port map ( - clk => clk_cpu, + clk => clk_100m, reset => reset, address => address(3 downto 0), ce => irc_reg_ce, data_in => data_in_bus(0), data_out => irc_reg_out, rd => i_rd, - wr => bls(0), + wr => i_bls(0), ta => irc_reg_ta, irc1_a => irc1_a, @@ -228,43 +206,33 @@ begin irc4_mark => irc4_mark ); - -- Control BRAM interconnect (9 kib) - memory_bus_control_bram: bus_control_bram + -- Tumbl coprocessor + memory_bus_tumbl: bus_tumbl port map ( - clk => clk_cpu, - ena => bram_ce, - taa => bram_ta, - wea => i_bls, - addra => address(8 downto 0), - dina => data_in_bus, - douta => bram_out, - - enb => '0', - web => (others => '0'), - addrb => (others => '0'), - dinb => (others => '0'), - doutb => open - ); - - -- BCD - memory_bus_bcd: bus_bcd - port map - ( - clk => clk_cpu, + clk_100m => clk_100m, + clk_50m => clk_50m, reset => reset, - en => '1', - ce => bcd_ce, + ce => tumbl_ce, + ta => tumbl_ta, rd => i_rd, - ta => bcd_ta, - data_out => bcd_out + bls => i_bls, + address => address(11 downto 0), + data_in => data_in_bus, + data_out => tumbl_out, + + XMEMB_o => open, + XMEMB_i.clken => '1', + XMEMB_i.data => (others => '1'), + XMEMB_i.int => '0', + XMEMB_sel_o => open ); -- Calibration memory_bus_calibration: bus_calibration port map ( - clk => clk_cpu, + clk => clk_100m, reset => reset, ce => calib_ce, address => address(1 downto 0), @@ -275,16 +243,19 @@ begin data_out => calib_out ); + -- Filters + bls_f <= bls when bls = bls_d else "1111"; + rd_f <= rd when rd = rd_d else '1'; + -- Bus update - memory_bus_update: process(clk_cpu) + memory_bus_update: process(clk_100m) begin - if clk_cpu = '1' and clk_cpu'event then + if clk_100m = '1' and clk_100m'event then -- Set every signal to inactive state here irc_reg_ce <= '1'; - bram_ce <= '1'; - bcd_ce <= '1'; + tumbl_ce <= '1'; calib_ce <= '1'; i_rd <= '1'; i_bls <= (others => '1'); @@ -296,23 +267,18 @@ begin -- Memory Map (16-bit address @ 32-bit each) -- Each address is seen as 32-bit entry now - -- 0x0000 - 0x011F: Control dual-port BRAM + -- 0x0000 - 0x0FFF: Tumbl -- 0x8000 - 0x800F: IRC registers - -- 0xFFFB: 32-bit BCD -- 0xFFFC - 0xFFFF: Calibration - if address < "0000000100100000" then -- Control BRAM - bram_ce <= '0'; - i_ta <= bram_ta; - data_out_bus <= bram_out; + if address < "0001000000000000" then -- Tumbl + tumbl_ce <= '0'; + i_ta <= tumbl_ta; + data_out_bus <= tumbl_out; elsif address(15 downto 4) = "100000000000" then -- IRC irc_reg_ce <= '0'; i_ta <= irc_reg_ta; data_out_bus <= irc_reg_out; - elsif address = "1111111111111011" then -- BCD - bcd_ce <= '0'; - i_ta <= bcd_ta; - data_out_bus <= bcd_out; elsif address(15 downto 2) = "11111111111111" then -- Calibration calib_ce <= '0'; i_ta <= calib_ta; @@ -320,7 +286,7 @@ begin end if; -- Reading - if rd = '0' then + if rd_f = '0' then if last_rd = '1' or last_address /= address then -- Getting something new -- Set internal RD to active and reset ack and latched data @@ -344,20 +310,21 @@ begin data_read <= (others => 'X'); end if; - last_rd <= rd; + last_rd <= rd_f; - -- Writing - if bls /= "1111" then - if last_bls /= bls or last_address /= address then - -- Data are valid when BLS is active, broadcast it for one cycle - i_bls <= bls; + -- Writing (BLS is filtered due to bus error otherwise) + if bls_f /= "1111" then + + if last_bls /= bls_f or last_address /= address then + -- Broadcast BLS for once cycle to write the data + i_bls <= bls_f; data_in_bus <= data_write; end if; last_address <= address; end if; - last_bls <= bls; + last_bls <= bls_f; else @@ -367,6 +334,10 @@ begin end if; + -- Filters + bls_d <= bls; + rd_d <= rd; + end if; end process; @@ -389,10 +360,11 @@ begin end process; -- Reset - initialization: process(init) + initialization: process(init, clk_100m_locked) begin - reset <= not init; + neg_init <= not init; + reset <= (not init) or (not clk_100m_locked); end process; diff --git a/hw/qcounter.vhd b/hw/qcounter.vhd index e77c815..408d54e 100644 --- a/hw/qcounter.vhd +++ b/hw/qcounter.vhd @@ -3,6 +3,7 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; +use work.lx_rocon_pkg.all; -- Quadcounter (for IRC) @@ -12,31 +13,27 @@ entity qcounter is clk : in std_logic; reset : in std_logic; a0, b0 : in std_logic; + index0 : in std_logic; qcount : out std_logic_vector (31 downto 0); + qcount_index : out std_logic_vector (31 downto 0); a_rise, a_fall, b_rise, b_fall, ab_event: out std_logic; ab_error : out std_logic ); end qcounter; architecture behavioral of qcounter is - component dff - port - ( - clk : in std_logic; - reset : in std_logic; - d : in std_logic; - q : out std_logic - ); - end component; -subtype std_logic4 is std_logic_vector (3 downto 0); signal last_reset: std_logic; signal a, b, a_prev, b_prev: std_logic; + signal index: std_logic; signal count_prev: std_logic_vector (29 downto 0); signal count: std_logic_vector (29 downto 0); + signal count_index_prev: std_logic_vector (31 downto 0); + signal count_index: std_logic_vector (31 downto 0); + begin - dff_a: dff + dff_a: dff2 port map ( clk => clk, @@ -45,7 +42,7 @@ begin q => a ); - dff_b: dff + dff_b: dff2 port map ( clk => clk, @@ -54,10 +51,21 @@ begin q => b ); + dff_index: dff2 + port map + ( + clk => clk, + reset => '0', + d => index0, + q => index + ); + qcount(0) <= a xor b; qcount(1) <= b; qcount(31 downto 2) <= count; + qcount_index <= count_index; + comb_event: process (reset, last_reset, a_prev, b_prev, a, b) begin a_rise <= '0'; @@ -81,17 +89,47 @@ begin end if; end process; - comb_count: process (reset, last_reset, a_prev, b_prev, a, b, count_prev) + comb_count: process (reset, last_reset, a_prev, b_prev, a, b, index, count_prev, count_index_prev) begin if reset = '1' or last_reset = '1' then count <= count_prev; + count_index <= count_index_prev; + elsif (a_prev = '0') and (b_prev = '1') and (a = '0') and (b = '0') then count <= count_prev + 1; + + if index = '1' then + count_index(0) <= a xor b; + count_index(1) <= b; + count_index(31 downto 2) <= count_prev + 1; + else + count_index <= count_index_prev; + end if; + elsif (a_prev = '0') and (b_prev = '0') and (a = '0') and (b = '1') then count <= count_prev - 1; + + if index = '1' then + count_index(0) <= a xor b; + count_index(1) <= b; + count_index(31 downto 2) <= count_prev - 1; + else + count_index <= count_index_prev; + end if; + else count <= count_prev; + + if index = '1' then + count_index(0) <= a xor b; + count_index(1) <= b; + count_index(31 downto 2) <= count_prev; + else + count_index <= count_index_prev; + end if; + end if; + end process; seq: process (clk) @@ -101,8 +139,10 @@ begin if clk = '1' and clk'event then if reset = '0' then count_prev <= count; + count_index_prev <= count_index; else count_prev <= (others => '0'); + count_index_prev <= (others => '0'); end if; a_prev <= a; b_prev <= b; diff --git a/hw/tb/lx_rocon_top_tb.vhd b/hw/tb/lx_rocon_top_tb.vhd index 3d8f813..60244ff 100644 --- a/hw/tb/lx_rocon_top_tb.vhd +++ b/hw/tb/lx_rocon_top_tb.vhd @@ -10,7 +10,8 @@ ARCHITECTURE behavior OF lx_rocon_top_tb IS COMPONENT lx_rocon_top PORT( - clk_cpu : IN std_logic; + --clk_cpu : IN std_logic; + clk_50m : IN std_logic; cs0_xc : IN std_logic; rd : IN std_logic; bls : IN std_logic_vector(3 downto 0); @@ -38,7 +39,8 @@ ARCHITECTURE behavior OF lx_rocon_top_tb IS --Inputs - signal clk_cpu : std_logic := '0'; + --signal clk_cpu : std_logic := '0'; + signal clk_50m : std_logic := '0'; signal cs0_xc : std_logic := '1'; signal rd : std_logic := '1'; signal bls : std_logic_vector(3 downto 0) := (others => '1'); @@ -65,13 +67,15 @@ ARCHITECTURE behavior OF lx_rocon_top_tb IS signal data : std_logic_vector(31 downto 0); -- Clock period definitions - constant clk_period : time := 20 ns; + constant clk_period_cpu : time := 13.8 ns; + constant clk_period_50m : time := 20 ns; BEGIN -- Instantiate the Unit Under Test (UUT) uut: lx_rocon_top PORT MAP ( - clk_cpu => clk_cpu, + --clk_cpu => clk_cpu, + clk_50m => clk_50m, cs0_xc => cs0_xc, rd => rd, bls => bls, @@ -97,197 +101,27 @@ BEGIN ); -- Clock process definitions - clk_process :process +-- clk_cpu_process :process +-- begin +-- clk_cpu <= '0'; +-- wait for clk_period_cpu/2; +-- clk_cpu <= '1'; +-- wait for clk_period_cpu/2; +-- end process; + + clk_50m_process :process begin - clk_cpu <= '0'; - wait for clk_period/2; - clk_cpu <= '1'; - wait for clk_period/2; + clk_50m <= '0'; + wait for clk_period_50m/2; + clk_50m <= '1'; + wait for clk_period_50m/2; end process; -- Stimulus process stim_proc: process begin - -- hold reset state for 100 ns. - init <= '0'; - data <= (others => 'Z'); - wait for 100 ns; - init <= '1'; - - wait for clk_period*10; - - -- insert stimulus here - - -- Increment IRC1 - irc1_a <= '1'; - wait for clk_period*2; - - irc1_b <= '1'; - wait for clk_period*2; - - irc1_a <= '0'; - wait for clk_period*2; - - irc1_b <= '0'; - wait for clk_period*2; - - irc1_a <= '1'; - wait for clk_period*2; - - irc1_b <= '1'; - wait for clk_period*2; - - irc1_a <= '0'; - wait for clk_period*2; - - -- Read IRC1 value (bus has 72 MHz, but signals are set to stay longer) - cs0_xc <= '0'; - wait for clk_period; - - address <= "1000000000000000"; - wait for clk_period; - - rd <= '0'; - wait for 5*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period*3; - - -- Test BRAM: Write something and then read it back - cs0_xc <= '0'; - wait for clk_period; - - address <= "0000000000011000"; - data <= "10101010101010101010101010101010"; - wait for clk_period; - - bls <= "0000"; - wait for 5*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - bls <= "1111"; - wait for clk_period; - - -- Now read it back - cs0_xc <= '0'; - wait for clk_period; - - rd <= '0'; - wait for 5*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period*3; - - -- Now try writing to above address but with only some bytes active - cs0_xc <= '0'; - wait for clk_period; - - address <= "0000000000011100"; - data <= "10101010101010101010101010101010"; - wait for clk_period; - - bls <= "0011"; - wait for 5*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - bls <= "1111"; - wait for clk_period; - - data <= (others => 'Z'); - wait for clk_period; - - -- Now read it back - cs0_xc <= '0'; - wait for clk_period; - - rd <= '0'; - wait for 5*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period; - - -- Poke the bcd a few times - cs0_xc <= '0'; - address <= "1111111111111011"; - wait for clk_period; - - rd <= '0'; - wait for 5*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period*5; - - cs0_xc <= '0'; - wait for clk_period; - - rd <= '0'; - wait for 5*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period; - - -- Read calibration register - cs0_xc <= '0'; - address <= "1111111111111100"; - wait for clk_period; - - rd <= '0'; - wait for 8*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period*5; - - -- Write & Read calibration register - cs0_xc <= '0'; - address <= "1111111111111110"; - data <= "10101010101010101010101010101010"; - wait for clk_period; - - bls <= "0000"; - wait for 8*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period*5; - - cs0_xc <= '0'; - address <= "1111111111111110"; - data <= (others => 'Z'); - wait for clk_period; - - rd <= '0'; - wait for 8*clk_period; - - cs0_xc <= '1'; - wait for clk_period; - - rd <= '1'; - wait for clk_period*5; + -- External ModelSim script wait; end process; diff --git a/hw/tumbl b/hw/tumbl new file mode 120000 index 0000000..1a543c2 --- /dev/null +++ b/hw/tumbl @@ -0,0 +1 @@ +../submodule/tumbl/hw \ No newline at end of file diff --git a/hw/xilinx_dualport_bram.vhd b/hw/xilinx_dualport_bram.vhd new file mode 100644 index 0000000..45dc86a --- /dev/null +++ b/hw/xilinx_dualport_bram.vhd @@ -0,0 +1,96 @@ +-- Xilinx dualport BRAM template, write-first mode, no delay +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lx_rocon_pkg.all; + +entity xilinx_dualport_bram is + generic + ( + -- Not all combinations are plausible for BRAMs + -- byte width: 8, 9, 32, 36 + -- we_width: 1, 2, 3, 4 + byte_width : positive := 8; + address_width : positive := 8; + we_width : positive := 4 + ); + port + ( + clka : in std_logic; + rsta : in std_logic; + ena : in std_logic; + wea : in std_logic_vector((we_width-1) downto 0); + addra : in std_logic_vector((address_width-1) downto 0); + dina : in std_logic_vector(((byte_width*we_width)-1) downto 0); + douta : out std_logic_vector(((byte_width*we_width)-1) downto 0); + clkb : in std_logic; + rstb : in std_logic; + enb : in std_logic; + web : in std_logic_vector((we_width-1) downto 0); + addrb : in std_logic_vector((address_width-1) downto 0); + dinb : in std_logic_vector(((byte_width*we_width)-1) downto 0); + doutb : out std_logic_vector(((byte_width*we_width)-1) downto 0) + ); +end xilinx_dualport_bram; + +architecture Behavioral of xilinx_dualport_bram is + type ram is array (0 to ((2**address_width) - 1)) of std_logic_vector(((byte_width*we_width)-1) downto 0); + shared variable ram_block : ram := (others => (others => '0')); + +begin + + -- CLKA process + ram_process_a : process(clka) + begin + + if clka = '1' and clka'event then + + if ena = '1' then + + for i in 0 to (we_width-1) loop + if wea(i) = '1' then + ram_block(to_integer(unsigned(addra)))(((i+1)*byte_width-1) downto (i*byte_width)) + := dina(((i+1)*byte_width-1) downto (i*byte_width)); + end if; + end loop; + + if rsta = '1' then + douta <= (others => '0'); + else + douta <= ram_block(to_integer(unsigned(addra))); + end if; + + end if; + + end if; + + end process; + + -- CLKB process + ram_process_b : process(clkb) + begin + + if clkb = '1' and clkb'event then + + if enb = '1' then + + for i in 0 to (we_width-1) loop + if web(i) = '1' then + ram_block(to_integer(unsigned(addrb)))(((i+1)*byte_width-1) downto (i*byte_width)) + := dinb(((i+1)*byte_width-1) downto (i*byte_width)); + end if; + end loop; + + if rstb = '1' then + doutb <= (others => '0'); + else + doutb <= ram_block(to_integer(unsigned(addrb))); + end if; + + end if; + + end if; + + end process; + +end Behavioral; diff --git a/submodule/tumbl b/submodule/tumbl new file mode 160000 index 0000000..342b65f --- /dev/null +++ b/submodule/tumbl @@ -0,0 +1 @@ +Subproject commit 342b65f43eca19d8169829aa8d342d1424c6d323 -- 2.39.2