@ -0,0 +1,126 @@ | |||
-- This design implements a register file which can | |||
-- be accessed by an UART with 9600 baud | |||
-- | |||
-- See into uart_ctrl.vhd for documentation of the protocol | |||
-- used to read / write the register file. | |||
library ieee ; | |||
use ieee.std_logic_1164.all; | |||
use ieee.numeric_std.all; | |||
library gatemate; | |||
use gatemate.components.all; | |||
entity uart_loop is | |||
port ( | |||
clk_i : in std_logic; -- 10 MHz clock | |||
rst_n_i : in std_logic; -- SW3 button | |||
uart_rx_i : in std_logic; -- PMODA IO3 | |||
uart_tx_o : out std_logic -- PMODA IO5 | |||
); | |||
end entity uart_loop; | |||
architecture rtl of uart_loop is | |||
signal s_pll_clk : std_logic; | |||
signal s_pll_lock : std_logic; | |||
signal s_rst_n : std_logic; | |||
signal s_cfg_end : std_logic; | |||
signal s_uart_rx_tdata : std_logic_vector(7 downto 0); | |||
signal s_uart_rx_tvalid : std_logic; | |||
signal s_uart_rx_tready : std_logic; | |||
signal s_uart_tx_tdata : std_logic_vector(7 downto 0); | |||
signal s_uart_tx_tvalid : std_logic; | |||
signal s_uart_tx_tready : std_logic; | |||
begin | |||
pll : CC_PLL | |||
generic map ( | |||
REF_CLK => "10", | |||
OUT_CLK => "1", | |||
PERF_MD => "ECONOMY" | |||
) | |||
port map ( | |||
CLK_REF => clk_i, | |||
CLK_FEEDBACK => '0', | |||
USR_CLK_REF => '0', | |||
USR_LOCKED_STDY_RST => '0', | |||
USR_PLL_LOCKED_STDY => open, | |||
USR_PLL_LOCKED => s_pll_lock, | |||
CLK270 => open, | |||
CLK180 => open, | |||
CLK0 => s_pll_clk, | |||
CLK90 => open, | |||
CLK_REF_OUT => open | |||
); | |||
cfg_end_inst : CC_CFG_END | |||
port map ( | |||
CFG_END => s_cfg_end | |||
); | |||
uart_rx : entity work.uart_rx | |||
generic map ( | |||
CLK_DIV => 104 | |||
) | |||
port map ( | |||
-- globals | |||
rst_n_i => s_rst_n, | |||
clk_i => s_pll_clk, | |||
-- axis user interface | |||
tdata_o => s_uart_rx_tdata, | |||
tvalid_o => s_uart_rx_tvalid, | |||
tready_i => s_uart_rx_tready, | |||
-- uart interface | |||
rx_i => uart_rx_i | |||
); | |||
axis_fifo : entity work.axis_fifo | |||
generic map ( | |||
DEPTH => 64, | |||
WIDTH => 8 | |||
) | |||
port map ( | |||
-- globals | |||
rst_n_i => s_rst_n, | |||
clk_i => s_pll_clk, | |||
-- uart rx interface | |||
tdata_i => s_uart_rx_tdata, | |||
tvalid_i => s_uart_rx_tvalid, | |||
tready_o => s_uart_rx_tready, | |||
-- uart tx interface | |||
tdata_o => s_uart_tx_tdata, | |||
tvalid_o => s_uart_tx_tvalid, | |||
tready_i => s_uart_tx_tready | |||
); | |||
-- s_uart_tx_tdata <= s_uart_rx_tdata; | |||
-- s_uart_tx_tvalid <= s_uart_rx_tvalid; | |||
-- s_uart_rx_tready <= s_uart_tx_tready; | |||
uart_tx : entity work.uart_tx | |||
generic map ( | |||
CLK_DIV => 104 | |||
) | |||
port map ( | |||
-- globals | |||
rst_n_i => s_rst_n, | |||
clk_i => s_pll_clk, | |||
-- axis user interface | |||
tdata_i => s_uart_tx_tdata, | |||
tvalid_i => s_uart_tx_tvalid, | |||
tready_o => s_uart_tx_tready, | |||
-- uart interface | |||
tx_o => uart_tx_o | |||
); | |||
s_rst_n <= rst_n_i and s_pll_lock and s_cfg_end; | |||
end architecture; |
@ -0,0 +1,105 @@ | |||
-- Copyright (c) 2022 by Torsten Meissner | |||
-- | |||
-- Licensed under the Apache License, Version 2.0 (the "License"); | |||
-- you may not use this file except in compliance with the License. | |||
-- You may obtain a copy of the License at | |||
-- | |||
-- https://www.apache.org/licenses/LICENSE-2.0 | |||
-- | |||
-- Unless required by applicable law or agreed to in writing, software | |||
-- distributed under the License is distributed on an "AS IS" BASIS, | |||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
-- See the License for the specific language governing permissions and | |||
-- limitations under the License. | |||
library ieee; | |||
use ieee.std_logic_1164.all; | |||
use ieee.numeric_std.all; | |||
entity uart_rx is | |||
generic ( | |||
CLK_DIV : natural := 10 | |||
); | |||
port ( | |||
-- globals | |||
rst_n_i : in std_logic; | |||
clk_i : in std_logic; | |||
-- axis user interface | |||
tdata_o : out std_logic_vector(7 downto 0); | |||
tvalid_o : out std_logic; | |||
tready_i : in std_logic; | |||
-- uart interface | |||
rx_i : in std_logic | |||
); | |||
end entity uart_rx; | |||
architecture rtl of uart_rx is | |||
type t_uart_state is (IDLE, RECEIVE, VALID); | |||
signal s_uart_state : t_uart_state; | |||
signal s_clk_en : std_logic; | |||
signal s_clk_cnt : natural range 0 to CLK_DIV-1; | |||
signal s_bit_cnt : natural range 0 to tdata_o'length+1; | |||
signal s_rx_d : std_logic_vector(3 downto 0); | |||
begin | |||
ClkDivP : process (clk_i, rst_n_i) is | |||
begin | |||
if (not rst_n_i) then | |||
s_clk_cnt <= CLK_DIV-1; | |||
elsif (rising_edge(clk_i)) then | |||
if (s_uart_state = IDLE) then | |||
s_clk_cnt <= CLK_DIV-2; | |||
elsif (s_uart_state = RECEIVE) then | |||
if (s_clk_cnt = 0) then | |||
s_clk_cnt <= CLK_DIV-1; | |||
else | |||
s_clk_cnt <= s_clk_cnt - 1; | |||
end if; | |||
end if; | |||
end if; | |||
end process ClkDivP; | |||
s_clk_en <= '1' when s_uart_state = RECEIVE and s_clk_cnt = CLK_DIV/2-1 else '0'; | |||
RxP : process (clk_i, rst_n_i) is | |||
begin | |||
if (not rst_n_i) then | |||
s_uart_state <= IDLE; | |||
tdata_o <= (others => '0'); | |||
s_rx_d <= x"1"; | |||
s_bit_cnt <= 0; | |||
elsif (rising_edge(clk_i)) then | |||
s_rx_d <= s_rx_d(2 downto 0) & rx_i; | |||
FsmL : case s_uart_state is | |||
when IDLE => | |||
s_bit_cnt <= tdata_o'length+1; | |||
if (s_rx_d = "1000") then | |||
s_uart_state <= RECEIVE; | |||
end if; | |||
when RECEIVE => | |||
if (s_clk_en) then | |||
if (s_bit_cnt = 0) then | |||
s_uart_state <= VALID; | |||
else | |||
tdata_o <= s_rx_d(3) & tdata_o(tdata_o'length-1 downto 1); | |||
s_bit_cnt <= s_bit_cnt - 1; | |||
end if; | |||
end if; | |||
when VALID => | |||
if (tready_i) then | |||
s_uart_state <= IDLE; | |||
end if; | |||
end case; | |||
end if; | |||
end process RxP; | |||
tvalid_o <= '1' when s_uart_state = VALID else '0'; | |||
end architecture rtl; |
@ -0,0 +1,102 @@ | |||
-- Copyright (c) 2022 by Torsten Meissner | |||
-- | |||
-- Licensed under the Apache License, Version 2.0 (the "License"); | |||
-- you may not use this file except in compliance with the License. | |||
-- You may obtain a copy of the License at | |||
-- | |||
-- https://www.apache.org/licenses/LICENSE-2.0 | |||
-- | |||
-- Unless required by applicable law or agreed to in writing, software | |||
-- distributed under the License is distributed on an "AS IS" BASIS, | |||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
-- See the License for the specific language governing permissions and | |||
-- limitations under the License. | |||
library ieee; | |||
use ieee.std_logic_1164.all; | |||
use ieee.numeric_std.all; | |||
entity uart_tx is | |||
generic ( | |||
CLK_DIV : natural := 10 | |||
); | |||
port ( | |||
-- globals | |||
rst_n_i : in std_logic; | |||
clk_i : in std_logic; | |||
-- axis user interface | |||
tdata_i : in std_logic_vector(7 downto 0); | |||
tvalid_i : in std_logic; | |||
tready_o : out std_logic; | |||
-- uart interface | |||
tx_o : out std_logic | |||
); | |||
end entity uart_tx; | |||
architecture rtl of uart_tx is | |||
type t_uart_state is (IDLE, SEND); | |||
signal s_uart_state : t_uart_state; | |||
signal s_data : std_logic_vector(tdata_i'length+1 downto 0); | |||
signal s_clk_cnt : natural range 0 to CLK_DIV-1; | |||
signal s_clk_en : std_logic; | |||
signal s_bit_cnt : natural range 0 to s_data'length-1; | |||
begin | |||
ClkDivP : process (clk_i, rst_n_i) is | |||
begin | |||
if (not rst_n_i) then | |||
s_clk_cnt <= CLK_DIV-1; | |||
elsif (rising_edge(clk_i)) then | |||
if (s_uart_state = IDLE) then | |||
s_clk_cnt <= CLK_DIV-2; | |||
elsif (s_uart_state = SEND) then | |||
if (s_clk_cnt = 0) then | |||
s_clk_cnt <= CLK_DIV-1; | |||
else | |||
s_clk_cnt <= s_clk_cnt - 1; | |||
end if; | |||
end if; | |||
end if; | |||
end process ClkDivP; | |||
s_clk_en <= '1' when s_uart_state = SEND and s_clk_cnt = 0 else '0'; | |||
TxP : process (clk_i, rst_n_i) is | |||
begin | |||
if (not rst_n_i) then | |||
s_uart_state <= IDLE; | |||
s_data <= (0 => '1', others => '0'); | |||
s_bit_cnt <= 0; | |||
elsif (rising_edge(clk_i)) then | |||
FsmL : case s_uart_state is | |||
when IDLE => | |||
s_bit_cnt <= s_data'length-1; | |||
if (tvalid_i) then | |||
s_data <= '1' & tdata_i & '0'; | |||
s_uart_state <= SEND; | |||
end if; | |||
when SEND => | |||
if (s_clk_en) then | |||
s_data <= '1' & s_data(s_data'length-1 downto 1); | |||
if (s_bit_cnt = 0) then | |||
s_uart_state <= IDLE; | |||
else | |||
s_bit_cnt <= s_bit_cnt - 1; | |||
end if; | |||
end if; | |||
end case; | |||
end if; | |||
end process TxP; | |||
tready_o <= '1' when s_uart_state = IDLE else '0'; | |||
tx_o <= s_data(0); | |||
end architecture rtl; |
@ -0,0 +1,30 @@ | |||
DESIGN_NAME := uart_loop | |||
LIB_SRC := ../../lib/rtl_components.vhd ../../lib/sim_components.vhd | |||
RTL_SRC := ../../lib/user_components.vhd ../rtl/uart_tx.vhd ../rtl/uart_rx.vhd ../rtl/${DESIGN_NAME}.vhd | |||
SIM_SRC := tb_${DESIGN_NAME}.vhd | |||
SIM_FLAGS := --std=08 -fpsl --workdir=work | |||
.PHONY: all compile sim clean | |||
all: sim | |||
compile: tb_${DESIGN_NAME} | |||
tb_${DESIGN_NAME}: ${LIB_SRC} ${RTL_SRC} ${SIM_SRC} | |||
mkdir -p work | |||
@echo "Analyze gatemate library ..." | |||
ghdl -a ${SIM_FLAGS} --work=gatemate ${LIB_SRC} | |||
@echo "Analyze testbench & design ..." | |||
ghdl -a ${SIM_FLAGS} -Pwork ${RTL_SRC} ${SIM_SRC} | |||
@echo "Elaborate testbench & design ..." | |||
ghdl -e ${SIM_FLAGS} -Pwork $@ | |||
sim: tb_${DESIGN_NAME} | |||
@echo "Run testbench ..." | |||
ghdl -r ${SIM_FLAGS} -Pwork tb_${DESIGN_NAME} --assert-level=error | |||
work: | |||
mkdir $@ | |||
clean: | |||
@echo "Cleaning simulation files ..." | |||
rm -rf tb_${DESIGN_NAME} *.o work/ |
@ -0,0 +1,96 @@ | |||
library ieee ; | |||
use ieee.std_logic_1164.all; | |||
use ieee.numeric_std.all; | |||
use std.env.all; | |||
entity tb_uart_loop is | |||
end entity tb_uart_loop; | |||
architecture sim of tb_uart_loop is | |||
signal s_clk : std_logic := '1'; | |||
signal s_rst_n : std_logic := '0'; | |||
signal s_uart_rx : std_logic := '1'; | |||
signal s_uart_tx : std_logic; | |||
constant c_baudrate : natural := 9600; | |||
constant c_period_ns : time := 1000000000 / c_baudrate * ns; | |||
procedure uart_send ( data : in std_logic_vector(7 downto 0); | |||
signal tx : out std_logic) is | |||
begin | |||
report "UART send: 0x" & to_hstring(data); | |||
tx <= '0'; | |||
wait for c_period_ns; | |||
for i in 0 to 7 loop | |||
tx <= data(i); | |||
wait for c_period_ns; | |||
end loop; | |||
tx <= '1'; | |||
wait for c_period_ns; | |||
end procedure; | |||
procedure uart_recv ( data : out std_logic_vector(7 downto 0); | |||
signal rx : in std_logic) is | |||
begin | |||
wait until not rx; | |||
wait for c_period_ns; -- Skip start bit | |||
wait for c_period_ns/2; | |||
for i in 0 to 7 loop | |||
data(i) := rx; | |||
wait for c_period_ns; | |||
end loop; | |||
report "UART recv: 0x" & to_hstring(data); | |||
end procedure; | |||
begin | |||
dut : entity work.uart_loop | |||
port map ( | |||
clk_i => s_clk, | |||
rst_n_i => s_rst_n, | |||
uart_rx_i => s_uart_rx, | |||
uart_tx_o => s_uart_tx | |||
); | |||
s_rst_n <= '1' after 120 ns; | |||
s_clk <= not s_clk after 50 ns; | |||
SendP : process is | |||
variable v_data : std_logic_vector(7 downto 0); | |||
begin | |||
wait until s_rst_n; | |||
wait until rising_edge(s_clk); | |||
wait for 200 us; | |||
-- First read all registers | |||
for i in 0 to 255 loop | |||
v_data := std_logic_vector(to_unsigned(i, 8)); | |||
uart_send(v_data, s_uart_rx); | |||
end loop; | |||
wait; | |||
end process; | |||
ReceiveP : process is | |||
variable v_exp : std_logic_vector(7 downto 0); | |||
variable v_data : std_logic_vector(7 downto 0); | |||
begin | |||
wait until s_rst_n; | |||
wait until rising_edge(s_clk); | |||
-- First read all registers | |||
for i in 0 to 255 loop | |||
v_exp := std_logic_vector(to_unsigned(i, 8)); | |||
uart_recv(v_data, s_uart_tx); | |||
assert v_data = v_exp | |||
report "UART receive error, got 0x" & to_hstring(v_data) & ", expected 0x" & to_hstring(v_exp) | |||
severity failure; | |||
end loop; | |||
wait for 200 us; | |||
report "Simulation finished :-)"; | |||
stop(0); | |||
end process; | |||
end architecture; |
@ -0,0 +1,51 @@ | |||
DESIGN_NAME := uart_loop | |||
WORK_FILES := ../../lib/user_components.vhd ../rtl/uart_tx.vhd ../rtl/uart_rx.vhd ../rtl/${DESIGN_NAME}.vhd | |||
GM_FILES := ../../lib/rtl_components.vhd | |||
GHDL_FLAGS := --std=08 --workdir=build -Pbuild | |||
YOSYSPIPE := -nomx8 -retime -nobram | |||
# ATTENTION: -luttree option seems to mis-synthesize the design, broken with synth_gatemate? | |||
PNRFLAGS := -om 2 | |||
PNRTOOL := $(shell which p_r) | |||
.PHONY: all syn imp prog syn_sim imp_sim | |||
all: imp | |||
syn: ${DESIGN_NAME}.v | |||
imp: ${DESIGN_NAME}.bit | |||
build/work-obj08.cf: ${WORK_FILES} build/gatemate-obj08.cf | |||
ghdl -a ${GHDL_FLAGS} --work=work ${WORK_FILES} | |||
build/gatemate-obj08.cf: ${GM_FILES} | |||
mkdir -p build | |||
ghdl -a ${GHDL_FLAGS} --work=gatemate ${GM_FILES} | |||
# Synthesis target for implementation | |||
${DESIGN_NAME}.v: build/work-obj08.cf | |||
yosys -m ghdl -p 'ghdl ${GHDL_FLAGS} --warn-no-binding --no-formal ${DESIGN_NAME}; synth_gatemate -top $(DESIGN_NAME) ${YOSYSPIPE} -vlog $@' \ | |||
2>&1 | tee build/yosys-report.txt | |||
# Implementation target for FPGA | |||
${DESIGN_NAME}.bit: ${DESIGN_NAME}.v ${DESIGN_NAME}.ccf | |||
cd build && \ | |||
${PNRTOOL} -i ../${DESIGN_NAME}.v -o $@ --ccf ../${DESIGN_NAME}.ccf $(PNRFLAGS) \ | |||
2>&1 | tee p_r-report.txt && \ | |||
mv ${DESIGN_NAME}*.bit ../$@ | |||
# Post-synthesis simulation target | |||
syn_sim: ${DESIGN_NAME}.v | |||
iverilog -g2012 -o tb_${DESIGN_NAME}_syn.vvp ${DESIGN_NAME}.v tb_${DESIGN_NAME}.v /usr/local/share/yosys/gatemate/cells_sim.v | |||
vvp -N tb_${DESIGN_NAME}_syn.vvp -fst | |||
# Post-implementation simulation target | |||
imp_sim: ${DESIGN_NAME}.bit | |||
iverilog -g2012 -o tb_${DESIGN_NAME}_imp.vvp build/${DESIGN_NAME}_00.v tb_${DESIGN_NAME}.v /opt/cc-toolchain-linux/bin/p_r/cpelib.v | |||
vvp -N tb_${DESIGN_NAME}_imp.vvp -fst | |||
# FPGA FW load per JTAG | |||
prog: ${DESIGN_NAME}.bit | |||
openFPGALoader -b gatemate_evb_jtag $< | |||
clean : | |||
echo "# Cleaning files" | |||
rm -rf build ${DESIGN_NAME}.v ${DESIGN_NAME}_sim.v ${DESIGN_NAME}.vhd ${DESIGN_NAME}.bit *.vvp *.fst |
@ -0,0 +1,125 @@ | |||
`timescale 1 ns/10 ps // time-unit = 1 ns, precision = 10 ps | |||
// simplified CC_PLL model | |||
module CC_PLL #( | |||
parameter REF_CLK = "", // e.g. "10.0" | |||
parameter OUT_CLK = "", // e.g. "50.0" | |||
parameter PERF_MD = "", // LOWPOWER, ECONOMY, SPEED | |||
parameter LOW_JITTER = 1, | |||
parameter CI_FILTER_CONST = 2, | |||
parameter CP_FILTER_CONST = 4 | |||
)( | |||
input CLK_REF, CLK_FEEDBACK, USR_CLK_REF, | |||
input USR_LOCKED_STDY_RST, USR_SET_SEL, | |||
output USR_PLL_LOCKED_STDY, USR_PLL_LOCKED, | |||
output CLK270, CLK180, CLK90, CLK0, CLK_REF_OUT | |||
); | |||
reg r_pll_clk; | |||
reg r_user_pll_locked; | |||
// OUT_FREQ = 1 MHz | |||
integer clk_half_period = 500; | |||
initial begin | |||
r_pll_clk = 1'b0; | |||
r_user_pll_locked = 1'b1; | |||
end | |||
always #clk_half_period r_pll_clk = ~r_pll_clk; | |||
assign CLK0 = r_pll_clk; | |||
assign USR_PLL_LOCKED = r_user_pll_locked; | |||
endmodule | |||
// simplified CC_CFG_END model | |||
module CC_CFG_END ( | |||
output CFG_END | |||
); | |||
assign CFG_END = 1'b1; | |||
endmodule | |||
module tb_uart_loop; | |||
// DUT in/out | |||
reg clk = 1'b0; | |||
reg rst_n = 1'b1; | |||
reg uart_rx; | |||
wire uart_tx; | |||
// Testbench variables | |||
reg [7:0] tx_data = 8'h0; | |||
reg [7:0] rx_data = 8'h0; | |||
// Testbench 1/2 clock period | |||
localparam clk_half_period = 50; | |||
// UART period calculation (9600 baud) | |||
localparam uart_bit_period = 1000000000 / 9600; | |||
localparam uart_bit_half_period = uart_bit_period/2; | |||
uart_loop UUT (.clk_i(clk), .rst_n_i(rst_n), .uart_rx_i(uart_rx), .uart_tx_o(uart_tx)); | |||
// set dumpfile | |||
initial begin | |||
$dumpfile ("tb_uart_loop.fst"); | |||
$dumpvars (0, tb_uart_loop); | |||
end | |||
// Setup simulation | |||
initial begin | |||
uart_rx = 1'b1; | |||
#1 rst_n = 1'b0; | |||
#120 rst_n = 1'b1; | |||
end | |||
// Generate 10 mhz clock | |||
always #clk_half_period clk = !clk; | |||
// Stimuli generator | |||
initial | |||
forever @(posedge rst_n) begin | |||
uart_rx = 1'b1; | |||
#uart_bit_period; | |||
for (integer tx = 0; tx < 32; tx = tx + 1) begin | |||
tx_data = tx; | |||
$display ("UART send: 0x%h", tx_data); | |||
uart_rx = 1'b0; | |||
#uart_bit_period; | |||
for (integer i = 0; i < 7; i = i + 1) begin | |||
uart_rx = tx_data[i]; | |||
#uart_bit_period; | |||
end | |||
uart_rx = 1'b1; | |||
#uart_bit_period; | |||
#uart_bit_period | |||
#uart_bit_period; | |||
end | |||
end | |||
// Checker | |||
initial begin | |||
@(posedge rst_n) | |||
for (reg [7:0] rx = 0; rx < 32; rx = rx + 1) begin | |||
@(negedge uart_tx) | |||
#uart_bit_period; | |||
#uart_bit_half_period; | |||
for (integer i = 0; i < 7; i = i + 1) begin | |||
rx_data[i] = uart_tx; | |||
#uart_bit_period; | |||
end | |||
assert (rx_data == rx) | |||
$display("UART recv: 0x%h", rx_data); | |||
else | |||
$warning("UART receive error, got 0x%h, expected 0x%h", rx_data, rx); | |||
end | |||
$display ("UART tests finished"); | |||
$finish; | |||
end | |||
endmodule |
@ -0,0 +1,16 @@ | |||
# Configuration for the Gatemate eval board | |||
Pin_in "clk_i" Loc = "IO_SB_A8" | SCHMITT_TRIGGER=true; | |||
Pin_in "rst_n_i" Loc = "IO_EB_B0"; # SW3 | |||
Pin_in "uart_rx_i" Loc = "IO_NB_A1"; # PMODA IO3 | |||
Pin_out "uart_tx_o" Loc = "IO_NB_A0"; # PMODA IO1 | |||
Pin_out "debug_o[0]" Loc = "IO_NB_A4"; | |||
Pin_out "debug_o[1]" Loc = "IO_NB_A5"; | |||
Pin_out "debug_o[2]" Loc = "IO_NB_A6"; | |||
Pin_out "debug_o[3]" Loc = "IO_NB_A7"; | |||
Pin_out "debug_o[4]" Loc = "IO_NB_B4"; | |||
Pin_out "debug_o[5]" Loc = "IO_NB_B5"; | |||
Pin_out "debug_o[6]" Loc = "IO_NB_B6"; | |||
Pin_out "debug_o[7]" Loc = "IO_NB_B7"; |