]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-dad.git/commitdiff
Include hardware design of FPGA peripherals to external LPC bus connection.
authorPavel Pisa <pisa@cmp.felk.cvut.cz>
Sun, 15 Feb 2015 00:36:19 +0000 (01:36 +0100)
committerPavel Pisa <pisa@cmp.felk.cvut.cz>
Sun, 15 Feb 2015 00:36:19 +0000 (01:36 +0100)
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
15 files changed:
hw/Makefile [new file with mode: 0644]
hw/bus_example.vhd [new file with mode: 0644]
hw/bus_measurement.vhd [new file with mode: 0644]
hw/cnt_div.vhd [new file with mode: 0644]
hw/dff2.vhd [new file with mode: 0644]
hw/dff3.vhd [new file with mode: 0644]
hw/lx-dad.ucf [new file with mode: 0644]
hw/lx_crosdom_ser_fifo.vhd [new file with mode: 0644]
hw/lx_dad_pkg.vhd [new file with mode: 0644]
hw/lx_dad_top.prj [new file with mode: 0644]
hw/lx_dad_top.vhd [new file with mode: 0644]
hw/measurement_register.vhd [new file with mode: 0644]
hw/packager.c [new file with mode: 0644]
hw/util_pkg.vhd [new file with mode: 0644]
hw/xilinx_dualport_bram.vhd [new file with mode: 0644]

diff --git a/hw/Makefile b/hw/Makefile
new file mode 100644 (file)
index 0000000..57d99f8
--- /dev/null
@@ -0,0 +1,263 @@
+# TOP           - Name of the top-level module
+# DEVICE        - Name of the FPGA device (device-package-speed)
+# PRJ           - Name of .prj file with names of all source files. See XST manual.
+# UCF           - Name of the user constraints file
+# SEARCH_DIRS   - Directories to search when searching for netlists (.ngc, ...).
+#                 See NGDBUILD manual.
+# INTSTYLE      - Style of screen output. (ise | xflow | silent)
+
+# Targets desctiption:
+#  - synthesize : Synthesize all VHDL and Verilog source files, libraries, etc.
+#                 defined in PRJ files and produces NGC file.
+#  - translate  : Translate all netlist files (.ngc, ...) into the NGD file,
+#                 where the design is described in terms of deneral logic elements
+#                 such as (RAM, flip-flop, XOR, ...).
+#  - map        : Map the general logic from NGD file to the components in the
+#                 target FPGA and produces NCD_MAP file.
+#  - par        : PAR stands for Plase & Route. This procedure takes NCD_MAP file,
+#                 places all components and makes routes between them (depending
+#                 on the chosen optimization mode) and produces NCD file.
+#  - clean      : Clean build directory, dependency (*.d) files and call
+#  - 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.
+
+DEVICE := xc6slx9-2tqg144
+
+TOP    := lx_dad_top
+OUT    := _build
+OUTB   := lx-dad
+REQB   := $(OUT)/$(OUTB)
+PRJ    := lx_dad_top.prj
+UCF    := lx-dad.ucf
+SEARCH_DIRS := ipcore_dir
+INTSTYLE    := xflow
+SRC         := ..
+
+#===============================================================================
+# Abbreviations of frequently used file names.
+
+NGC            := $(OUTB).ngc
+NGD            := $(OUTB).ngd
+PCF            := $(OUTB).pcf
+NCD_MAP        := $(OUTB)_map.ncd
+NCD            := $(OUTB).ncd
+BIN            := $(OUTB).bin
+PKG            := $(OUTB).pkg
+TWR            := $(OUTB).twr
+TSI            := $(OUTB).tsi
+
+REQ_NGC            := $(REQB).ngc
+REQ_NGD            := $(REQB).ngd
+REQ_PCF            := $(REQB).pcf
+REQ_NCD_MAP        := $(REQB)_map.ncd
+REQ_NCD            := $(REQB).ncd
+REQ_BIN            := $(REQB).bin
+REQ_PKG            := $(REQB).pkg
+REQ_SRC            := .
+
+#REQ_FIRMWARE       := $(OUT)/imem.bin $(OUT)/imem.asm $(OUT)/dmem.bin $(OUT)/firmware.lst
+
+#===============================================================================
+# Sythesis settings (SmartXplorer)
+
+XST_GLOB_OPT := AllClockNets
+XST_OPT_LEVEL := 2
+XST_OPT_MODE := Speed
+XST_IOB_PACKING := False
+XST_POWER := NO
+XST_KEEP_HIEARCHY := No
+XST_NETLIST_HIEARCHY := As_Optimized
+XST_READ_CORES := YES
+XST_WRITE_TIMING_CONSTRAINTS := NO
+XST_CROSS_CLOCK_ANALYSIS := NO
+XST_CASE := Maintain
+XST_REDUCE_CONTROL_SETS := Auto
+XST_REGISTER_DUPLICATION := YES
+XST_REGISTER_BALANCING := Yes
+XST_MOVE_FIRST_STAGE := YES
+XST_MOVE_LAST_STAGE := YES
+XST_OPTIMIZE_PRIMITIVES := NO
+XST_USE_CLOCK_ENABLE := AUTO
+XST_EQUIVALENT_REGISTER_REMOVAL := YES
+XST_IOBUF := YES
+XST_MAX_FANOUT := 100000
+XST_RESOURCE_SHARING := YES
+XST_SLICE_UTILIZATION_RATIO_MARGIN := 5
+XST_SLICE_UTILIZATION_RATIO := 100
+XST_BRAM_UTILIZATION_RATIO := 100
+XST_DSP_UTILIZATION_RATIO := 100
+XST_USE_DSP48 := Auto
+XST_USE_SYNC_SET := Auto
+XST_USE_SYNC_RESET := Auto
+XST_SAFE_IMPLEMENTATION := No
+
+MAP_PLACER_COST_TABLE := 2
+MAP_LOGIC_OPT := on
+MAP_GLOBAL_OPT := off
+MAP_EQUIVALENT_REGISTER_REMOVAL := off
+MAP_LUT_COMBINING := off
+
+#===============================================================================
+# Firmware
+
+MB_CROSS_COMPILE ?= mbtumbl-elf-
+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 -Wno-main -Wl,-no-check-sections -ffunction-sections -fno-zero-initialized-in-bss -g -O2 -Wall
+AFLAGS := -D__ASSEMBLY__ $(CFLAGS)
+LDFLAGS := -static -nostdlib -relax -defsym _STACK_SIZE=0x0200 --gc-sections
+
+OBJS := $(OUT)/start.o $(C_OBJS) $(A_OBJS)
+
+FIRMWARE_DIR := ./lx-dad_firmware
+
+#===============================================================================
+
+# Attempt to create a output directory.
+$(shell [ -d ${OUT} ] || mkdir -p ${OUT})
+
+# Verify if it was successful.
+OUTPUT_DIR := $(shell cd $(OUT) && /bin/pwd)
+$(if $(OUTPUT_DIR),,$(error output directory "$(OUT)" does not exist))
+
+#===============================================================================
+
+.PHONY: all
+all: pkg firmware
+
+.PHONY: re-synthesize
+re-synthesize $(REQ_NGC): $(addprefix $(REQ_SRC)/,$(PRJ))
+       cd $(OUT); \
+       echo " \
+         run \
+         $(addprefix -ifn $(SRC)/,$(PRJ)) \
+         -ifmt mixed \
+         -ofn $(NGC) \
+         -ofmt NGC \
+         -top $(TOP) \
+         -p $(DEVICE) \
+         -keep_hierarchy $(XST_KEEP_HIEARCHY) \
+         -glob_opt $(XST_GLOB_OPT) \
+         -opt_mode $(XST_OPT_MODE) \
+         -opt_level $(XST_OPT_LEVEL) \
+         -power $(XST_POWER) \
+         -iob $(XST_IOB_PACKING) \
+         -read_cores $(XST_READ_CORES) \
+         -write_timing_constraints $(XST_WRITE_TIMING_CONSTRAINTS) \
+         -cross_clock_analysis $(XST_CROSS_CLOCK_ANALYSIS) \
+         -case $(XST_CASE) \
+         -reduce_control_sets $(XST_REDUCE_CONTROL_SETS) \
+         -resource_sharing $(XST_RESOURCE_SHARING) \
+         -iobuf $(XST_IOBUF) \
+         -max_fanout $(XST_MAX_FANOUT) \
+         -register_duplication $(XST_REGISTER_DUPLICATION) \
+         -register_balancing $(XST_REGISTER_BALANCING) \
+         -move_first_stage $(XST_MOVE_FIRST_STAGE) \
+         -move_last_stage $(XST_MOVE_LAST_STAGE) \
+         -optimize_primitives $(XST_OPTIMIZE_PRIMITIVES) \
+         -use_clock_enable $(XST_USE_CLOCK_ENABLE) \
+         -equivalent_register_removal $(XST_EQUIVALENT_REGISTER_REMOVAL) \
+         -slice_utilization_ratio_maxmargin $(XST_SLICE_UTILIZATION_RATIO_MARGIN) \
+         -slice_utilization_ratio $(XST_SLICE_UTILIZATION_RATIO) \
+         -bram_utilization_ratio $(XST_BRAM_UTILIZATION_RATIO) \
+         -dsp_utilization_ratio $(XST_DSP_UTILIZATION_RATIO)" | xst | tee xst.log
+
+.PHONY: re-translate
+re-translate $(REQ_NGD): $(REQ_NGC) $(REQ_UCF)
+       cd $(OUT); \
+       ngdbuild -intstyle $(INTSTYLE) -p $(DEVICE) -nt timestamp -uc $(SRC)/$(UCF) \
+         $(addprefix -sd $(SRC)/,$(SEARCH_DIRS)) \
+         $(NGC) \
+         $(NGD)
+
+.PHONY: re-map
+re-map $(REQ_NCD_MAP) $(REQ_PCF): $(REQ_NGD)
+       cd $(OUT); \
+       map -w -intstyle $(INTSTYLE) -p $(DEVICE) -logic_opt $(MAP_LOGIC_OPT) -ol high -t $(MAP_PLACER_COST_TABLE) -xt 0 \
+         -r 4 -global_opt $(MAP_GLOBAL_OPT) -mt off -ir off -pr off -lc $(MAP_LUT_COMBINING) \
+         -power off -equivalent_register_removal $(MAP_EQUIVALENT_REGISTER_REMOVAL) \
+         -o $(NCD_MAP) $(NGD) $(PCF) | tee map.log
+
+.PHONY: re-par
+re-par $(REQ_NCD): $(REQ_NCD_MAP) $(REQ_PCF)
+       cd $(OUT); \
+       par -w -intstyle $(INTSTYLE) -ol high -xe n -mt off $(NCD_MAP) $(NCD) $(PCF) | tee par.log
+       cd $(OUT); \
+       trce -e 20 -tsi $(TSI) -o $(TWR) $(NCD) $(PCF)
+
+.PHONY: re-gen
+re-gen $(REQ_BIN): $(REQ_NCD)
+       cd $(OUT); \
+       bitgen -w -g Binary:yes -g INIT_9K:Yes -g StartUpClk:Cclk $(NCD) $(OUTB) $(PCF) | tee bitgen.log
+
+.PHONY: packager
+packager $(OUT)/packager:
+       gcc packager.c -o $(OUT)/packager
+
+.PHONY: re-pkg
+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)/bin2mem: $(FIRMWARE_DIR)/utils/bin2mem.c
+       gcc $< -o $@
+
+.PHONY: re-firmware
+re-firmware $(REQ_FIRMWARE): $(REQ_PKG) $(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 >$(OUT)/firmware.lst
+       cd $(OUT); \
+       $(TARGET_OBJDUMP) -b binary -mmbtumbl -EB -D imem.bin | sed -e 's/.data/.text/' > imem.asm
+
+# imem
+# watch -d ./usb_sendhex -d 0x1669:0x1023 -t 4 -s 0x80000000 -l 0x200 -f dump -u -
+# dmem
+# watch -d ./usb_sendhex -d 0x1669:0x1023 -t 4 -s 0x80001000 -l 0x200 -f dump -u -
+# PC
+# watch -d ./usb_sendhex -d 0x1669:0x1023 -t 4 -s 0x80003008 -l 0x4 -f dump -u -
+
+#===============================================================================
+
+.PHONY: clean
+clean:
+       rm -rf $(OUT)
+
+.PHONY: synthesize
+synthesize: $(REQ_NGC)
+
+.PHONY: translate
+translate: $(REQ_NGD)
+
+.PHONY: map
+map: $(REQ_NCD_MAP) $(REQ_PCF)
+
+.PHONY: par
+par: $(REQ_NCD)
+
+.PHONY: gen
+gen: $(REQ_BIN)
+
+.PHONY: pkg
+pkg: $(OUT)/packager $(REQ_PKG)
+
+.PHONY: firmware
+firmware: $(REQ_FIRMWARE)
diff --git a/hw/bus_example.vhd b/hw/bus_example.vhd
new file mode 100644 (file)
index 0000000..333c487
--- /dev/null
@@ -0,0 +1,38 @@
+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.lx_dad_pkg.all;
+
+-- Connects example memory
+
+entity bus_example is
+       port
+       (
+               -- Clock
+               clk_i        : in std_logic;
+               -- Chip enable
+               ce_i         : in std_logic;
+               -- Global Reset
+               reset_i      : in std_logic;
+               -- Master CPU peripheral bus
+               bls_i        : in std_logic_vector(3 downto 0);
+               address_i    : in std_logic_vector(11 downto 0);
+               data_i       : in std_logic_vector(31 downto 0);
+               data_o       : out std_logic_vector(31 downto 0)
+
+               -- Non bus signals
+               --
+               -- Add there external component signals
+  );
+end bus_example;
+
+architecture Behavioral of bus_example is
+
+begin
+
+       data_o <= (others => '0');
+
+end Behavioral;
diff --git a/hw/bus_measurement.vhd b/hw/bus_measurement.vhd
new file mode 100644 (file)
index 0000000..b10f1ac
--- /dev/null
@@ -0,0 +1,99 @@
+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.lx_dad_pkg.all;
+
+-- Memory bus measurement
+-- Holds the signal for one clock to simulate longest route
+
+entity bus_measurement is
+       port
+       (
+               -- Clock
+               clk_i     : in std_logic;
+               -- Reset
+               reset_i   : in std_logic;
+               -- Chip enable
+               ce_i      : in std_logic;
+               -- Address
+               address_i : in std_logic_vector(1 downto 0);
+               -- Data bus
+               data_i    : in std_logic_vector(31 downto 0);
+               data_o    : out std_logic_vector(31 downto 0);
+               -- Bus signals
+               bls_i     : in std_logic_vector(3 downto 0)
+       );
+end bus_measurement;
+
+architecture Behavioral of bus_measurement is
+
+       -- Wiring
+       signal meas1_out_s    : std_logic_vector(31 downto 0);
+       signal meas1_ce_s     : std_logic;
+       --
+       signal meas2_out_s    : std_logic_vector(31 downto 0);
+       signal meas2_ce_s     : std_logic;
+
+begin
+
+       -- First measurement register (0xAAAAAAAA)
+measurement1: measurement_register
+       generic map
+       (
+               id_g   => "10101010101010101010101010101010"
+       )
+       port map
+       (
+               clk_i    => clk_i,
+               ce_i     => meas1_ce_s,
+               switch_i => address_i(0),
+               reset_i  => reset_i,
+               bls_i    => bls_i,
+               data_i   => data_i,
+               data_o   => meas1_out_s
+       );
+
+       -- Second measurement register (=0x55555555)
+measurement2: measurement_register
+       generic map
+       (
+               id_g   => "01010101010101010101010101010101"
+       )
+       port map
+       (
+               clk_i    => clk_i,
+               ce_i     => meas2_ce_s,
+               switch_i => address_i(0),
+               reset_i  => reset_i,
+               bls_i    => bls_i,
+               data_i   => data_i,
+               data_o   => meas2_out_s
+       );
+
+-- Bus process
+update:
+       process (ce_i, address_i, meas1_out_s, meas2_out_s)
+       begin
+
+               -- Defaults
+               meas1_ce_s <= '0';
+               meas2_ce_s <= '0';
+               data_o     <= (others => 'X');
+
+               -- Chip Enable
+               if ce_i = '1' then
+                       if address_i(1) = '0' then
+                               meas1_ce_s  <= '1';
+                               data_o      <= meas1_out_s;
+                       else
+                               meas2_ce_s  <= '1';
+                               data_o      <= meas2_out_s;
+                       end if;
+               end if;
+
+       end process;
+
+end Behavioral;
+
diff --git a/hw/cnt_div.vhd b/hw/cnt_div.vhd
new file mode 100644 (file)
index 0000000..79c4cce
--- /dev/null
@@ -0,0 +1,60 @@
+--
+-- * Counter - divider *
+--
+-- part of LXPWR motion control board (c) PiKRON Ltd
+-- idea by Pavel Pisa PiKRON Ltd <ppisa@pikron.com>
+--
+-- license: BSD
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity cnt_div is
+       generic (
+               cnt_width_g : natural := 8
+       );
+       port
+       (
+               clk_i     : in std_logic;
+               en_i      : in std_logic;
+               reset_i   : in std_logic;
+               ratio_i   : in std_logic_vector(cnt_width_g-1 downto 0);
+               q_out_o   : out std_logic
+       );
+end cnt_div;
+
+architecture behavioral of cnt_div is
+       signal cnt_val_s : natural range 0 to (2**cnt_width_g - 1);
+       signal cnt_val_r : natural range 0 to (2**cnt_width_g - 1);
+begin
+
+comb: process (reset_i, en_i, ratio_i, cnt_val_r)
+       begin
+               if reset_i = '1' then
+                       cnt_val_s <= to_integer(unsigned(ratio_i));
+                       q_out_o   <= '0';
+               else
+                       if en_i = '0' then
+                               cnt_val_s <= cnt_val_r;
+                               q_out_o   <= '0';
+                       else
+                               if cnt_val_r <= 1 then
+                                       cnt_val_s <= to_integer(unsigned(ratio_i));
+                                       q_out_o   <= '1';
+                               else
+                                       cnt_val_s <= cnt_val_r - 1;
+                                       q_out_o   <= '0';
+                               end if;
+                       end if;
+               end if;
+       end process;
+
+seq: process
+       begin
+               wait until clk_i'event and clk_i = '1';
+               cnt_val_r <= cnt_val_s;
+       end process;
+
+end behavioral;
diff --git a/hw/dff2.vhd b/hw/dff2.vhd
new file mode 100644 (file)
index 0000000..5560dd1
--- /dev/null
@@ -0,0 +1,44 @@
+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.lx_dad_pkg.all;
+
+-- D circuit (filtered)
+
+entity dff2 is
+  port
+       (
+    clk_i   : in std_logic;
+    d_i     : in std_logic;
+    q_o     : out std_logic
+  );
+end dff2;
+
+architecture behavioral of dff2 is
+       signal d_2r   : std_logic;
+       signal d_r    : std_logic;
+  signal data_s : std_logic;
+
+       -- XST attributes
+  attribute REGISTER_DUPLICATION : string;
+       attribute REGISTER_DUPLICATION of d_2r : signal is "NO";
+       attribute REGISTER_DUPLICATION of d_r  : signal is "NO";
+
+begin
+  q_o <= data_s;
+
+seq:
+       process
+       begin
+    wait until clk_i'event and clk_i = '1';
+               if d_2r = d_r then
+                       data_s <= d_r;
+               end if;
+
+               d_2r    <= d_r;
+               d_r     <= d_i;
+  end process;
+
+end behavioral;
diff --git a/hw/dff3.vhd b/hw/dff3.vhd
new file mode 100644 (file)
index 0000000..7e31e59
--- /dev/null
@@ -0,0 +1,47 @@
+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.lx_dad_pkg.all;
+
+-- D circuit (filtered)
+
+entity dff3 is
+  port
+       (
+    clk_i   : in std_logic;
+    d_i     : in std_logic;
+    q_o     : out std_logic
+  );
+end dff3;
+
+architecture behavioral of dff3 is
+       signal d_3r   : std_logic;
+  signal d_2r   : std_logic;
+       signal d_r    : std_logic;
+  signal data_s : std_logic;
+
+       -- XST attributes
+  attribute REGISTER_DUPLICATION : string;
+       attribute REGISTER_DUPLICATION of d_3r : signal is "NO";
+       attribute REGISTER_DUPLICATION of d_2r : signal is "NO";
+       attribute REGISTER_DUPLICATION of d_r  : signal is "NO";
+
+begin
+  q_o <= data_s;
+
+seq:
+       process
+       begin
+    wait until clk_i'event and clk_i = '1';
+               if d_3r = d_2r and d_2r = d_r then
+                       data_s <= d_3r;
+               end if;
+
+               d_3r <= d_2r;
+               d_2r <= d_r;
+               d_r  <= d_i;
+  end process;
+
+end behavioral;
diff --git a/hw/lx-dad.ucf b/hw/lx-dad.ucf
new file mode 100644 (file)
index 0000000..a7baf9a
--- /dev/null
@@ -0,0 +1,132 @@
+# lx-dad with LPC4088 and Spartan6 XC6SLX9-2TQG144
+CONFIG VCCAUX  = 3.3;
+
+# ====================================================================
+# INPUTS
+# ====================================================================
+
+# Clock
+#NET CLK_CPU             PERIOD = 13.88ns HIGH 50%;
+#NET CLK_CPU             LOC = P15  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+NET CLK_50M             PERIOD = 20.00ns HIGH 50%;
+NET CLK_50M             LOC = P14  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+
+# Reset (active LOW)
+NET INIT                LOC = P39  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+
+# Memory peripheral
+NET CS0_XC              LOC = P64  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+#NET CS1_XC              LOC = P1   | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+
+NET RD                  LOC = P60  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+NET BLS<0>              LOC = P70  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+NET BLS<1>              LOC = P67  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+NET BLS<2>              LOC = P66  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+NET BLS<3>              LOC = P55  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+
+NET ADDRESS<0>          LOC = P134 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<1>          LOC = P133 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<2>          LOC = P132 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<3>          LOC = P131 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<4>          LOC = P127 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<5>          LOC = P126 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<6>          LOC = P124 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<7>          LOC = P123 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<8>          LOC = P121 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<9>          LOC = P120 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<10>         LOC = P119 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<11>         LOC = P118 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<12>         LOC = P117 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<13>         LOC = P116 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<14>         LOC = P115 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET ADDRESS<15>         LOC = P114 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+
+NET DATA<0>             LOC = P65  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<1>             LOC = P62  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<2>             LOC = P61  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<3>             LOC = P46  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<4>             LOC = P45  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<5>             LOC = P44  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<6>             LOC = P43  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<7>             LOC = P48  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<8>             LOC = P41  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<9>             LOC = P40  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<10>            LOC = P59  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<11>            LOC = P58  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<12>            LOC = P57  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<13>            LOC = P56  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<14>            LOC = P51  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<15>            LOC = P50  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<16>            LOC = P38  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<17>            LOC = P35  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<18>            LOC = P34  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<19>            LOC = P33  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<20>            LOC = P32  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<21>            LOC = P30  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<22>            LOC = P29  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<23>            LOC = P27  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<24>            LOC = P144 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<25>            LOC = P143 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<26>            LOC = P142 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<27>            LOC = P141 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<28>            LOC = P140 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<29>            LOC = P139 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<30>            LOC = P138 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET DATA<31>            LOC = P137 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+
+# Interrupt to master MCU
+NET EVENT_JK_J          LOC = P111 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+
+# IRC
+#NET IRC0_A              LOC = P2   | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC0_B              LOC = P6   | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC0_INDEX          LOC = P7   | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC0_MARK           LOC = P5   | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+#NET IRC1_A              LOC = P8   | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC1_B              LOC = P10  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC1_INDEX          LOC = P11  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC1_MARK           LOC = P9   | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+#NET IRC2_A              LOC = P12  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC2_B              LOC = P17  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC2_INDEX          LOC = P21  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC2_MARK           LOC = P16  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+#NET IRC3_A              LOC = P22  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC3_B              LOC = P24  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC3_INDEX          LOC = P26  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC3_MARK           LOC = P23  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+#NET IRC4_A              LOC = P93  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC4_B              LOC = P104 | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC4_INDEX          LOC = P105 | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC4_MARK           LOC = P92  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+#NET IRC5_A              LOC = P85  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC5_B              LOC = P87  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC5_INDEX          LOC = P88  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC5_MARK           LOC = P84  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+#NET IRC6_A              LOC = P81  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC6_B              LOC = P82  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC6_INDEX          LOC = P83  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC6_MARK           LOC = P80  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+#NET IRC7_A              LOC = P75  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC7_B              LOC = P78  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC7_INDEX          LOC = P79  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET IRC7_MARK           LOC = P74  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+
+# ====================================================================
+# S1 Interface
+# ====================================================================
+
+#NET S1_CLK_IN            PERIOD = 20.00ns HIGH 50%;
+#NET S1_CLK_IN            LOC = P95  | IOSTANDARD = LVCMOS33 | SLEW = FAST | PULLUP;
+#NET S1_MISO              LOC = P98  | IOSTANDARD = LVCMOS33 | SLEW = SLOW | PULLUP;
+#NET S1_SYNC_IN           LOC = P100 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | PULLUP;
+
+#NET S1_CLK_OUT           LOC = P94  | IOSTANDARD = LVCMOS33 | SLEW = FAST;
+#NET S1_MOSI              LOC = P97  | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+#NET S1_SYNC_OUT          LOC = P101 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
diff --git a/hw/lx_crosdom_ser_fifo.vhd b/hw/lx_crosdom_ser_fifo.vhd
new file mode 100644 (file)
index 0000000..49846c5
--- /dev/null
@@ -0,0 +1,147 @@
+-- Clock Cross Domain Synchronization Elastic Buffer/FIFO
+--
+-- Copyright (c) 2014, Pavel Pisa <pisa@cmp.felk.cvut.cz>
+-- Designed for PiKRON company robotic controller
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are met:
+--
+-- 1. Redistributions of source code must retain the above copyright notice, this
+--    list of conditions and the following disclaimer.
+-- 2. Redistributions in binary form must reproduce the above copyright notice,
+--    this list of conditions and the following disclaimer in the documentation
+--    and/or other materials provided with the distribution.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+-- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+-- Can be used and distributed under GPLv3 license as well
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_unsigned.all;
+use ieee.numeric_std.all;
+use work.util_pkg.all;
+use work.lx_dad_pkg.all;
+
+entity lx_crosdom_ser_fifo is
+generic
+(
+       fifo_len_g   : positive := 8;
+       sync_adj_g   : integer := 0
+);
+port
+(
+       -- Asynchronous clock domain interface
+       acd_clock_i  : in std_logic;
+       acd_miso_i   : in std_logic;
+       acd_sync_i   : in std_logic;
+       -- Clock
+       clk_i        : in std_logic;
+       reset_i      : in std_logic;
+       -- Output synchronous with clk_i
+       miso_o       : out std_logic;
+       sync_o       : out std_logic;
+       data_ready_o : out std_logic
+);
+end lx_crosdom_ser_fifo;
+
+architecture Behavioral of lx_crosdom_ser_fifo is
+       signal fifo_bits_s     : std_logic_vector(0 to fifo_len_g - 1);
+       signal fifo_bits_r     : std_logic_vector(0 to fifo_len_g - 1);
+
+       signal acd_miso_r      : std_logic;
+       signal acd_sync_r      : std_logic;
+       signal acd_sync_prev_s : std_logic;
+       signal acd_sync_prev_r : std_logic;
+
+       signal acd_in_loc_s    : natural range 0 to fifo_len_g - 1;
+       signal acd_in_loc_r    : natural range 0 to fifo_len_g - 1;
+
+       signal out_loc_s       : natural range 0 to fifo_len_g - 1;
+       signal out_loc_r       : natural range 0 to fifo_len_g - 1;
+
+       signal out_sync_s      : std_logic_vector(0 to fifo_len_g / 2 - 1);
+       signal out_sync_r      : std_logic_vector(0 to fifo_len_g / 2 - 1);
+
+       signal out_miso_s      : std_logic;
+
+  attribute REGISTER_DUPLICATION : string;
+       attribute REGISTER_DUPLICATION of fifo_bits_s : signal is "NO";
+       attribute REGISTER_DUPLICATION of fifo_bits_r : signal is "NO";
+       attribute REGISTER_DUPLICATION of acd_sync_r : signal is "NO";
+       attribute REGISTER_DUPLICATION of out_sync_s : signal is "NO";
+       attribute REGISTER_DUPLICATION of out_sync_r : signal is "NO";
+
+begin
+       sync_o <= out_sync_r(max(-sync_adj_g, 0));
+
+       data_ready_o <= '0';
+
+acd_logic:
+       process (acd_miso_r, acd_sync_r, acd_sync_prev_r, acd_in_loc_r, fifo_bits_r)
+       begin
+               acd_sync_prev_s <= acd_sync_r;
+               fifo_bits_s <= fifo_bits_r;
+               if (acd_sync_r = '1') and (acd_sync_prev_r = '0') then
+                       acd_in_loc_s <= 0;
+                       fifo_bits_s(0) <= acd_miso_r;
+               else
+                       fifo_bits_s(acd_in_loc_r) <= acd_miso_r;
+                       if acd_in_loc_r /= fifo_len_g - 1 then
+                               acd_in_loc_s <= acd_in_loc_r + 1;
+                       else
+                               acd_in_loc_s <= 0;
+                       end if;
+               end if;
+       end process;
+
+acd_update:
+       process
+       begin
+               wait until acd_clock_i'event and acd_clock_i = '1';
+
+               acd_miso_r <= acd_miso_i;
+               acd_sync_r <= acd_sync_i;
+               acd_sync_prev_r <= acd_sync_prev_s;
+               acd_in_loc_r <= acd_in_loc_s;
+               fifo_bits_r <= fifo_bits_s;
+       end process;
+
+sync_logic:
+       process (fifo_bits_r, out_loc_r, out_sync_r, acd_sync_r)
+       begin
+               out_sync_s <= out_sync_r(1 to out_sync_r'length - 1 ) & acd_sync_r;
+               if out_sync_r(max(sync_adj_g, 0)) = '0' then
+                       out_loc_s <= 0;
+                       out_miso_s <= '0';
+               else
+                       out_miso_s <= fifo_bits_r(out_loc_r);
+                       if out_loc_r /= fifo_len_g - 1 then
+                               out_loc_s <= out_loc_r + 1;
+                       else
+                               out_loc_s <= 0;
+                       end if;
+               end if;
+       end process;
+
+sync_update:
+       process
+       begin
+               wait until clk_i'event and clk_i = '1';
+
+               out_loc_r <= out_loc_s;
+               miso_o <= out_miso_s;
+               out_sync_r <= out_sync_s;
+       end process;
+
+end Behavioral;
diff --git a/hw/lx_dad_pkg.vhd b/hw/lx_dad_pkg.vhd
new file mode 100644 (file)
index 0000000..de69d2c
--- /dev/null
@@ -0,0 +1,204 @@
+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.util_pkg.all;
+
+-- Entities within lx_dad
+
+package lx_dad_pkg is
+
+       -- D sampler (filtered, 2 cycles)
+       component dff2
+       port
+       (
+               clk_i   : in std_logic;
+               d_i     : in std_logic;
+               q_o     : out std_logic
+       );
+       end component;
+
+       -- D sampler (filtered, 3 cycles)
+       component dff3
+       port
+       (
+               clk_i   : in std_logic;
+               d_i     : in std_logic;
+               q_o     : out std_logic
+       );
+       end component;
+
+       -- Counter - divider
+       component cnt_div
+       generic (
+               cnt_width_g : natural := 8
+       );
+       port
+       (
+               clk_i     : in std_logic;
+               en_i      : in std_logic;
+               reset_i   : in std_logic;
+               ratio_i   : in std_logic_vector(cnt_width_g-1 downto 0);
+               q_out_o   : out std_logic
+       );
+       end component;
+
+       -- Clock Cross Domain Synchronization Elastic Buffer/FIFO
+       component lx_crosdom_ser_fifo
+       generic
+       (
+               fifo_len_g   : positive := 8;
+               sync_adj_g   : integer := 0
+       );
+       port
+       (
+               -- Asynchronous clock domain interface
+               acd_clock_i  : in std_logic;
+               acd_miso_i   : in std_logic;
+               acd_sync_i   : in std_logic;
+               -- Clock
+               clk_i        : in std_logic;
+               reset_i      : in std_logic;
+               -- Output synchronous with clk_i
+               miso_o       : out std_logic;
+               sync_o       : out std_logic;
+               data_ready_o : out std_logic
+       );
+       end component;
+
+       --------------------------------------------------------------------------------
+       -- MEMORY BUS
+       --------------------------------------------------------------------------------
+
+       -- Measurement register
+       component measurement_register
+       generic
+       (
+               id_g   : std_logic_vector(31 downto 0) := (others => '0')
+       );
+       port
+       (
+               -- Clock
+               clk_i    : in std_logic;
+               -- Reset
+               reset_i  : in std_logic;
+               -- Chip enable
+               ce_i     : in std_logic;
+               -- Switch
+               switch_i : in std_logic;
+               -- Data bus
+               data_i   : in std_logic_vector(31 downto 0);
+               data_o   : out std_logic_vector(31 downto 0);
+               -- Bus signals
+               bls_i    : in std_logic_vector(3 downto 0)
+       );
+       end component;
+
+       -- Example component interconnect
+       component bus_example
+       port
+       (
+               clk_i        : in std_logic;
+               reset_i      : in std_logic;
+               -- Master CPU peripheral bus
+               address_i    : in std_logic_vector(11 downto 0);
+               ce_i         : in std_logic;
+               data_i       : in std_logic_vector(31 downto 0);
+               data_o       : out std_logic_vector(31 downto 0);
+               --
+               bls_i        : in std_logic_vector(3 downto 0)
+
+               -- Non bus signals
+               --
+               -- Add there externaly visible signals
+       );
+       end component;
+
+       -- Measurement interconnect
+       component bus_measurement
+       port
+       (
+               -- Clock
+               clk_i     : in std_logic;
+               -- Reset
+               reset_i   : in std_logic;
+               -- Chip enable
+               ce_i      : in std_logic;
+               -- Address
+               address_i : in std_logic_vector(1 downto 0);
+               -- Data bus
+               data_i    : in std_logic_vector(31 downto 0);
+               data_o    : out std_logic_vector(31 downto 0);
+               -- Bus signals
+               bls_i     : in std_logic_vector(3 downto 0)
+       );
+       end component;
+
+       -- Register on the bus
+       component bus_register is
+       generic
+       (
+               -- Reset value
+               reset_value_g : std_logic_vector(31 downto 0) := (others => '0');
+               -- Width
+               b0_g          : natural := 8;
+               b1_g          : natural := 8;
+               b2_g          : natural := 8;
+               b3_g          : natural := 8
+       );
+       port
+       (
+               -- Clock
+               clk_i         : in std_logic;
+               -- Reset
+               reset_i       : in std_logic;
+               -- Chip enable
+               ce_i          : in std_logic;
+               -- Data bus
+               data_i        : in std_logic_vector((b0_g+b1_g+b2_g+b3_g-1) downto 0);
+               data_o        : out std_logic_vector((b0_g+b1_g+b2_g+b3_g-1) downto 0);
+               -- Bus signals
+               bls_i         : in std_logic_vector(3 downto 0)
+       );
+       end component;
+
+
+       --------------------------------------------------------------------------------
+       -- BRAM
+       --------------------------------------------------------------------------------
+       type BRAM_type is (READ_FIRST, WRITE_FIRST, NO_CHANGE);
+
+       component xilinx_dualport_bram
+       generic
+       (
+               byte_width    : positive := 8;
+               address_width : positive := 8;
+               we_width      : positive := 4;
+               port_a_type   : BRAM_type := READ_FIRST;
+               port_b_type   : BRAM_type := READ_FIRST
+       );
+       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_dad_pkg;
+
+package body lx_dad_pkg is
+
+end lx_dad_pkg;
diff --git a/hw/lx_dad_top.prj b/hw/lx_dad_top.prj
new file mode 100644 (file)
index 0000000..5693fcb
--- /dev/null
@@ -0,0 +1,11 @@
+vhdl work "util_pkg.vhd"
+vhdl work "lx_dad_pkg.vhd"
+vhdl work "xilinx_dualport_bram.vhd"
+vhdl work "dff3.vhd"
+vhdl work "dff2.vhd"
+vhdl work "cnt_div.vhd"
+vhdl work "measurement_register.vhd"
+vhdl work "lx_crosdom_ser_fifo.vhd"
+vhdl work "bus_measurement.vhd"
+vhdl work "bus_example.vhd"
+vhdl work "lx_dad_top.vhd"
diff --git a/hw/lx_dad_top.vhd b/hw/lx_dad_top.vhd
new file mode 100644 (file)
index 0000000..0905804
--- /dev/null
@@ -0,0 +1,338 @@
+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;
+
+library unisim;
+use unisim.vcomponents.all;
+
+use work.lx_dad_pkg.all;
+
+-- lx_dad_top - wires the modules with the outside world
+
+-- ======================================================
+--  MASTER CPU EXTERNAL MEMORY BUS
+-- ======================================================
+--
+-- Master cpu memory bus has the following wires:
+--
+-- - address[15..0]          The address, used to mark chip enable
+-- - data_in[31..0]          The data coming to bus
+-- - data_out[31..0]         The data coming from bus, multiplexed
+-- - bls[3..0]               Write enable for respective bytes
+
+entity lx_dad_top is
+       port
+       (
+               -- External
+               --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);
+               address     : in std_logic_vector(15 downto 0);
+               data        : inout std_logic_vector(31 downto 0);
+               --
+               init        : in std_logic;
+               -- signal connected to external JK FF
+               event_jk_j  : out std_logic
+       );
+end lx_dad_top;
+
+architecture Behavioral of lx_dad_top is
+
+       -- Reset signal
+       signal reset_s                  : std_logic;
+       signal init_s                   : std_logic;
+       -- Peripherals on the memory buses
+       -- Example memory
+       signal example_out_s            : std_logic_vector(31 downto 0);
+       signal example_ce_s             : std_logic;
+       -- Measurement (Master)
+       signal meas_out_s               : std_logic_vector(31 downto 0);
+       signal meas_ce_s                : std_logic;
+       -- Signals for external bus transmission
+       signal data_i_s                 : std_logic_vector(31 downto 0);
+       signal data_o_s                 : std_logic_vector(31 downto 0);
+       -- Signals for internal transaction
+       signal last_address_s           : std_logic_vector(15 downto 0);
+       signal next_last_address_s      : std_logic_vector(15 downto 0);
+       signal next_address_hold_s      : std_logic;
+       signal address_hold_s           : std_logic;
+       signal last_rd_s                : std_logic;
+       signal next_last_rd_s           : std_logic;
+       signal last_bls_s               : std_logic_vector(3 downto 0); -- prev bls_f_s (active 1)
+       signal next_last_bls_s          : std_logic_vector(3 downto 0);
+
+       -- Reading logic for Master CPU:
+       -- Broadcast rd only till ta (transaction acknowledge)
+       -- is received, then latch the data till the state of
+       -- rd or address changes
+       --
+       -- Data latching is synchronous - it's purpose is to
+       -- provide stable data for CPU on the bus
+       signal cs0_xc_f_s          : std_logic;
+       signal rd_f_s              : std_logic; -- Filtered RD
+       signal i_rd_s              : std_logic; -- Internal bus RD (active 1)
+       -- signal next_i_rd_s         : std_logic;
+       signal last_i_rd_s         : std_logic; -- Delayed RD bus, used for latching
+       signal next_last_i_rd_s    : std_logic;
+       signal i_rd_cycle2_s       : std_logic; -- Some internal subsystems provide
+       signal next_i_rd_cycle2_s  : std_logic; -- data only after 2 cycles
+       --
+       signal address_f_s         : std_logic_vector(15 downto 0); -- Filtered address
+       --
+       signal data_f_s            : std_logic_vector(31 downto 0); -- Filterred input data
+       --
+       signal data_read_s         : std_logic_vector(31 downto 0); -- Latched read data
+       signal next_data_read_s    : std_logic_vector(31 downto 0);
+
+       -- Writing logic:
+       signal bls_f_s             : std_logic_vector(3 downto 0); -- Filtered BLS (active 1)
+       signal i_bls_s             : std_logic_vector(3 downto 0); -- Internal BLS (active 1)
+       signal next_i_bls_s        : std_logic_vector(3 downto 0);
+       --
+       signal data_write_s        : std_logic_vector(31 downto 0); -- Data broadcasted to write
+       signal next_data_write_s   : std_logic_vector(31 downto 0);
+
+       -- signal s0   : std_logic;
+       -- signal s1   : std_logic;
+       -- signal s2   : std_logic;
+
+       -- XST attributes
+       attribute REGISTER_DUPLICATION : string;
+       attribute REGISTER_DUPLICATION of rd : signal is "NO";
+       attribute REGISTER_DUPLICATION of rd_f_s : signal is "NO";
+       attribute REGISTER_DUPLICATION of bls : signal is "NO";
+       attribute REGISTER_DUPLICATION of bls_f_s : signal is "NO";
+       attribute REGISTER_DUPLICATION of address : signal is "NO";
+       attribute REGISTER_DUPLICATION of address_f_s : signal is "NO";
+       attribute REGISTER_DUPLICATION of cs0_xc : signal is "NO";
+       attribute REGISTER_DUPLICATION of cs0_xc_f_s : signal is "NO";
+
+begin
+
+-- Example connection
+memory_bus_example: bus_example
+       port map
+       (
+               clk_i          => clk_50m,
+               reset_i        => reset_s,
+               ce_i           => example_ce_s,
+               bls_i          => i_bls_s,
+               address_i      => address_f_s(11 downto 0),
+               data_i         => data_i_s,
+               data_o         => example_out_s
+               --
+               --
+               -- additional externally connected signals goes there
+       );
+
+-- Measurement
+memory_bus_measurement: bus_measurement
+       port map
+       (
+               clk_i     => clk_50m,
+               reset_i   => reset_s,
+               ce_i      => meas_ce_s,
+               address_i => address_f_s(1 downto 0),
+               bls_i     => i_bls_s,
+               data_i    => data_i_s,
+               data_o    => meas_out_s
+       );
+
+-- Reset
+dff_reset: dff2
+       port map
+       (
+               clk_i   => clk_50m,
+               d_i     => init_s,
+               q_o     => reset_s
+       );
+
+       -- Reset
+       init_s          <= not init;
+
+       -- Signalling
+       data_i_s        <= data_write_s;
+
+
+       event_jk_j <= '0';
+
+-- Bus update
+memory_bus_logic:
+       process(cs0_xc_f_s, rd_f_s, last_rd_s, i_rd_cycle2_s, last_i_rd_s,
+               bls_f_s, last_bls_s, data_f_s, data_write_s,
+               data_o_s, data_read_s, last_address_s, address_f_s)
+       begin
+               -- Defaults
+               next_i_rd_cycle2_s <= '0';
+               next_address_hold_s <= '0';
+
+               -- Check if we have chip select
+               if cs0_xc_f_s = '1' then
+
+                       -- Reading
+                       if rd_f_s = '1' then
+                               -- Internal read
+                               if last_rd_s = '0' or (last_address_s /= address_f_s) then
+                                       i_rd_s <= '1';
+                                       next_i_rd_cycle2_s <= '1';
+                                       next_last_i_rd_s  <= '1';
+                               elsif i_rd_cycle2_s = '1' then    -- FIXME it seems that some internal
+                                       i_rd_s <= '1';            -- peripherals demands 2 cycles to read
+                                       next_last_i_rd_s  <= '1';
+                               else
+                                       i_rd_s            <= '0';
+                                       next_last_i_rd_s  <= '0';
+                               end if;
+
+                               if last_i_rd_s = '1' then
+                                       -- Latch data we just read - they are valid in this cycle
+                                       next_data_read_s <= data_o_s;
+                               else
+                                       next_data_read_s <= data_read_s;
+                               end if;
+                       else
+                       --      -- Not reading, anything goes
+                       --      data_read_s       <= (others => 'X');
+                               next_data_read_s  <= data_read_s;
+                               i_rd_s            <= '0';
+                               next_last_i_rd_s  <= '0';
+                       end if;
+
+                       next_last_rd_s            <= rd_f_s;
+
+                       -- Data for write are captured only when BLS signals are stable
+                       if bls_f_s /= "0000" then
+                               next_data_write_s <= data_f_s;
+                               next_address_hold_s <= '1';
+                       else
+                               next_data_write_s <= data_write_s;
+                       end if;
+
+                       if (bls_f_s /= "0000") or (rd_f_s = '1') then
+                               next_last_address_s <= address_f_s;
+                       else
+                               next_last_address_s <= last_address_s;
+                       end if;
+               else
+                       next_last_rd_s <= '0';
+                       i_rd_s <= '0';
+                       next_last_i_rd_s <= '0';
+
+                       next_i_bls_s <= "0000";
+                       next_data_write_s <= data_write_s;
+                       next_data_read_s  <= data_read_s;
+                       next_last_address_s <= last_address_s;
+               end if;
+
+               -- Data for write are captured at/before BLS signals are negated
+               -- and actual write cycle takes place exacly after BLS negation
+               if ((last_bls_s and not bls_f_s) /= "0000") or
+                   ((last_bls_s /= "0000") and (cs0_xc_f_s = '0')) then
+                       next_i_bls_s <= last_bls_s;
+                       next_last_bls_s   <= "0000";
+                       next_address_hold_s <= '1';
+               else
+                       next_i_bls_s <= "0000";
+                       if cs0_xc_f_s = '1' then
+                               next_last_bls_s <= bls_f_s;
+                       else
+                               next_last_bls_s <= "0000" ;
+                       end if;
+               end if;
+
+       end process;
+
+-- Bus update
+memory_bus_update:
+       process
+       begin
+
+               wait until clk_50m = '1' and clk_50m'event;
+
+               address_hold_s <= next_address_hold_s;
+
+               -- Synchronized external signals with main clock domain
+               cs0_xc_f_s     <= not cs0_xc;
+               bls_f_s        <= not bls;
+               rd_f_s         <= not rd;
+               data_f_s       <= data;
+               if address_hold_s = '0' then
+                       address_f_s <= address;
+               else
+                       address_f_s <= next_last_address_s;
+               end if;
+
+               -- Synchronoust state andvance to next period
+               last_bls_s     <= next_last_bls_s;
+               last_rd_s      <= next_last_rd_s;
+               i_bls_s        <= next_i_bls_s;
+               -- i_rd_s         <= next_i_rd_s;
+               i_rd_cycle2_s  <= next_i_rd_cycle2_s;
+               last_i_rd_s    <= next_last_i_rd_s;
+               data_write_s   <= next_data_write_s;
+               last_address_s <= next_last_address_s;
+               data_read_s    <= next_data_read_s;
+
+       end process;
+
+-- Do the actual wiring here
+memory_bus_wiring:
+       process(cs0_xc_f_s, i_bls_s, address_f_s, example_out_s, meas_out_s)
+       begin
+
+               -- Inactive by default
+               example_ce_s           <= '0';
+               meas_ce_s              <= '0';
+               data_o_s               <= (others => '0');
+
+               if cs0_xc_f_s = '1' or i_bls_s /= "0000" then
+
+                       -- Memory Map (16-bit address @ 32-bit each)
+
+                       -- Each address is seen as 32-bit entry now
+                       -- 0x0000 - 0x0FFF: Example memory
+                       -- 0x1FFC - 0x1FFF: Measurement
+                       -- 0x2000 - 0x8FFF: Free space
+
+                       if address_f_s < "0001000000000000" then                  -- Tumbl
+                               example_ce_s           <= '1';
+                               data_o_s               <= example_out_s;
+                       elsif address_f_s(15 downto 2) = "00011111111111" then    -- Measurement
+                               meas_ce_s              <= '1';
+                               data_o_s               <= meas_out_s;
+                       end if;
+
+               end if;
+
+       end process;
+
+-- If RD and BLS is not high, we must keep DATA at high impedance
+-- or the FPGA collides with SDRAM (damaging each other)
+memory_bus_out:
+       process(cs0_xc, rd, data_read_s)
+       begin
+
+               -- CS0 / RD / BLS are active LOW
+               if cs0_xc = '0' and rd = '0' then
+                       -- Don't risk flipping (between data_o_s and latched data_read_s, it's better to wait)
+                       -- Maybe check this later.
+                       -- if last_i_rd_s = '1' then
+                       --   data <= data_o_s;
+                       -- else
+                       data <= data_read_s;
+                       -- end if;
+               else
+                       -- IMPORTANT!!!
+                       data <= (others => 'Z');
+               end if;
+
+       end process;
+
+end Behavioral;
+
diff --git a/hw/measurement_register.vhd b/hw/measurement_register.vhd
new file mode 100644 (file)
index 0000000..8cfd103
--- /dev/null
@@ -0,0 +1,71 @@
+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.lx_dad_pkg.all;
+
+-- Transaction measurement register
+
+entity measurement_register is
+       generic
+       (
+               id_g   : std_logic_vector(31 downto 0) := (others => '0')
+       );
+       port
+       (
+               -- Clock
+               clk_i    : in std_logic;
+               -- Reset
+               reset_i  : in std_logic;
+               -- Chip enable
+               ce_i     : in std_logic;
+               -- Switch
+               switch_i : in std_logic;
+               -- Data bus
+               data_i   : in std_logic_vector(31 downto 0);
+               data_o   : out std_logic_vector(31 downto 0);
+               -- Bus signals
+               bls_i    : in std_logic_vector(3 downto 0)
+       );
+end measurement_register;
+
+architecture Behavioral of measurement_register is
+       signal value_s : std_logic_vector(31 downto 0);
+begin
+
+       data_o <= value_s when switch_i = '1' else id_g;
+
+-- Write waits for clock
+memory_bus_write:
+       process
+       begin
+
+               wait until clk_i'event and clk_i = '1';
+
+               if reset_i = '1' then
+                       value_s <= (others => '0');
+               else
+
+                       if ce_i = '1' and bls_i /= "0000" then
+
+                               if bls_i(0) = '1' then
+                                       value_s(7 downto 0)   <= data_i(7 downto 0);
+                               end if;
+                               if bls_i(1) = '1' then
+                                       value_s(15 downto 8)  <= data_i(15 downto 8);
+                               end if;
+                               if bls_i(2) = '1' then
+                                       value_s(23 downto 16) <= data_i(23 downto 16);
+                               end if;
+                               if bls_i(3) = '1' then
+                                       value_s(31 downto 24) <= data_i(31 downto 24);
+                               end if;
+
+                       end if;
+               end if;
+
+       end process;
+
+end Behavioral;
+
diff --git a/hw/packager.c b/hw/packager.c
new file mode 100644 (file)
index 0000000..65f14ac
--- /dev/null
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <endian.h>
+
+/* This util converts bitstream to more friendly format
+ * for select map interface with x16 line.
+ */
+
+/* Endianness */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+int source_be = 0;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+int source_be = 1;
+#else
+#error Invalid endianness.
+#endif
+
+uint32_t swab32(uint32_t x)
+{
+       return x<<24 | x>>24 |
+               (x & (uint32_t)0x0000ff00UL)<<8 |
+               (x & (uint32_t)0x00ff0000UL)>>8;
+}
+
+uint8_t fpga_swap(uint8_t x)
+{
+       return ((x & (uint8_t)0x01) << 7) | ((x & (uint8_t)0x02) << 5) |
+               ((x & (uint8_t)0x04) << 3) | ((x & (uint8_t)0x08) << 1) |
+               ((x & (uint8_t)0x10) >> 1) | ((x & (uint8_t)0x20) >> 3) |
+               ((x & (uint8_t)0x40) >> 5) | ((x & (uint8_t)0x80) >> 7);
+}
+
+void __attribute__((noreturn)) error_usage(const char* argv0)
+{
+       printf("Usage: %s le|be <bin> <pkg>\n", argv0);
+       exit(1);
+}
+
+void __attribute__((noreturn)) error_reason(const char* argv0, const char* reason)
+{
+       printf("ERROR: %s\n", reason);
+       printf("Usage: %s le|be <bin> <pkg>\n", argv0);
+       exit(1);
+}
+
+int main(int argc, char** argv)
+{
+       int target_be, i;
+       uint32_t sz, szs;
+       uint8_t hb, lb;
+       char magic[4];
+       FILE *fin, *fout;
+
+       if (argc != 4)
+               error_usage(argv[0]);
+
+       if (!strcmp(argv[1], "le"))
+               target_be = 0;
+       else if (!strcmp(argv[1], "be"))
+               target_be = 1;
+       else
+               error_usage(argv[0]);
+
+       fin = fopen(argv[2], "r");
+       if (!fin)
+               error_reason(argv[0], "Failed to open input file.");
+
+       fseek(fin, 0L, SEEK_END);
+       sz = ftell(fin);
+       fseek(fin, 0L, SEEK_SET);
+
+       if (sz & 0x01)
+               error_reason(argv[0], "Invalid size (not aligned).");
+
+       fout = fopen(argv[3], "w+");
+       if (!fout)
+               error_reason(argv[0], "Failed to open output file.");
+
+       /* If we're switching endianness, we need to swap the bytes */
+       if (target_be != source_be)
+               szs = swab32(sz);
+       else
+               szs = sz;
+
+       /* Write magic */
+       magic[0] = 'F';
+       magic[1] = 'P';
+       magic[2] = 'G';
+       magic[3] = 'A';
+       fwrite(&magic, 1, 4, fout);
+
+       /* Write size */
+       fwrite(&szs, 1, sizeof(uint32_t), fout);
+
+       /* Binary must be aligned */
+       for (i = 0; i < sz / 2; i++)
+       {
+               /* Bitstream is big endian */
+               fread(&hb, 1, 1, fin);
+               fread(&lb, 1, 1, fin);
+
+               /* Swap the bites */
+               hb = fpga_swap(hb);
+               lb = fpga_swap(lb);
+
+               /* Write it */
+               if (target_be)
+               {
+                       fwrite(&hb, 1, 1, fout);
+                       fwrite(&lb, 1, 1, fout);
+               }
+               else
+               {
+                       fwrite(&lb, 1, 1, fout);
+                       fwrite(&hb, 1, 1, fout);
+               }
+       }
+
+       fclose(fout);
+       return 0;
+}
diff --git a/hw/util_pkg.vhd b/hw/util_pkg.vhd
new file mode 100644 (file)
index 0000000..a9b7048
--- /dev/null
@@ -0,0 +1,51 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+package util_pkg is
+  -- ceil(log2(n))
+  function ceil_log2(n: natural) return natural;
+  -- ceil(a/b)
+  function ceil_div(a: integer; b: integer) return integer;
+  --
+  function max(left, right: integer) return integer;
+  function min(left, right: integer) return integer;
+end;
+
+---
+
+package body util_pkg is
+
+  function ceil_log2(n: natural) return natural is
+  begin
+    if n <= 1 then
+      return 0;
+    else
+      if n mod 2 = 0 then
+        return 1 + ceil_log2(n/2);
+      else
+        return 1 + ceil_log2((n+1)/2);
+      end if;
+    end if;
+  end function ceil_log2;
+
+  function ceil_div(a: integer; b: integer) return integer is
+  begin
+    return (a+b-1)/b;
+  end function ceil_div;
+
+  function max(left, right: integer) return integer is
+  begin
+    if left > right then return left;
+    else return right;
+    end if;
+  end;
+
+  function min(left, right: integer) return integer is
+  begin
+    if left < right then return left;
+    else return right;
+    end if;
+  end;
+
+end util_pkg;
diff --git a/hw/xilinx_dualport_bram.vhd b/hw/xilinx_dualport_bram.vhd
new file mode 100644 (file)
index 0000000..75d928a
--- /dev/null
@@ -0,0 +1,170 @@
+-- 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_dad_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_a_type   : BRAM_type := READ_FIRST;
+               port_b_type   : BRAM_type := READ_FIRST
+       );
+       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
+       begin
+
+               wait until clka'event and clka = '1';
+
+               if ena = '1' then
+
+                       -- Depends on the port type
+                       case port_a_type is
+                               when READ_FIRST =>
+                                       -- Read
+                                       if rsta = '1' then
+                                               douta <= (others => '0');
+                                       else
+                                               douta <= ram_block(to_integer(unsigned(addra)));
+                                       end if;
+                                       -- Write
+                                       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;
+
+                               when WRITE_FIRST =>
+                                       -- Write
+                                       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;
+                                       -- Read
+                                       if rsta = '1' then
+                                               douta <= (others => '0');
+                                       else
+                                               douta <= ram_block(to_integer(unsigned(addra)));
+                                       end if;
+
+                               when NO_CHANGE =>
+                                       -- Write
+                                       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;
+                                       -- Read (if not writing)
+                                       if to_integer(unsigned(wea)) = 0 then
+                                               if rsta = '1' then
+                                                       douta <= (others => '0');
+                                               else
+                                                       douta <= ram_block(to_integer(unsigned(addra)));
+                                               end if;
+                                       end if;
+                               end case;
+
+               end if;
+
+       end process;
+
+-- CLKB process
+ram_process_b:
+       process
+       begin
+
+               wait until clkb'event and clkb = '1';
+
+               if enb = '1' then
+
+                       -- Depends on the port type
+                       case port_b_type is
+                               when READ_FIRST =>
+                                       -- Read
+                                       if rstb = '1' then
+                                               doutb <= (others => '0');
+                                       else
+                                               doutb <= ram_block(to_integer(unsigned(addrb)));
+                                       end if;
+                                       -- Write
+                                       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;
+
+                               when WRITE_FIRST =>
+                                       -- Write
+                                       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;
+                                       -- Read
+                                       if rstb = '1' then
+                                               doutb <= (others => '0');
+                                       else
+                                               doutb <= ram_block(to_integer(unsigned(addrb)));
+                                       end if;
+
+                               when NO_CHANGE =>
+                                       -- Write
+                                       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;
+                                       -- Read (if not writing)
+                                       if to_integer(unsigned(web)) = 0 then
+                                               if rstb = '1' then
+                                                       doutb <= (others => '0');
+                                               else
+                                                       doutb <= ram_block(to_integer(unsigned(addrb)));
+                                               end if;
+                                       end if;
+                               end case;
+
+               end if;
+
+       end process;
+
+end Behavioral;