You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
546 lines
17 KiB
VHDL
546 lines
17 KiB
VHDL
3 years ago
|
-- © IBM Corp. 2020
|
||
|
-- Licensed under the Apache License, Version 2.0 (the "License"), as modified by
|
||
|
-- the terms below; you may not use the files in this repository except in
|
||
|
-- compliance with the License as modified.
|
||
|
-- You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||
|
--
|
||
|
-- Modified Terms:
|
||
|
--
|
||
|
-- 1) For the purpose of the patent license granted to you in Section 3 of the
|
||
|
-- License, the "Work" hereby includes implementations of the work of authorship
|
||
|
-- in physical form.
|
||
|
--
|
||
|
-- 2) Notwithstanding any terms to the contrary in the License, any licenses
|
||
|
-- necessary for implementation of the Work that are available from OpenPOWER
|
||
|
-- via the Power ISA End User License Agreement (EULA) are explicitly excluded
|
||
|
-- hereunder, and may be obtained from OpenPOWER under the terms and conditions
|
||
|
-- of the EULA.
|
||
|
--
|
||
|
-- Unless required by applicable law or agreed to in writing, the reference design
|
||
|
-- 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.
|
||
|
--
|
||
|
-- Additional rights, including the ability to physically implement a softcore that
|
||
|
-- is compliant with the required sections of the Power ISA Specification, are
|
||
|
-- available at no cost under the terms of the OpenPOWER Power ISA EULA, which can be
|
||
|
-- obtained (along with the Power ISA) here: https://openpowerfoundation.org.
|
||
|
|
||
|
library ieee;
|
||
|
use ieee.std_logic_1164.all;
|
||
|
use ieee.numeric_std.all;
|
||
|
|
||
|
package a2x_pkg is
|
||
|
|
||
|
attribute dont_touch : string;
|
||
|
|
||
|
constant c_ld_queue_size : integer := 8;
|
||
|
constant c_ld_queue_bits : integer := 3;
|
||
|
constant c_st_queue_size : integer := 32;
|
||
|
constant c_st_queue_bits : integer := 5;
|
||
|
constant c_max_pointer : integer := 2;
|
||
|
|
||
|
-- A2L2 ttypes
|
||
|
constant IFETCH : std_logic_vector(0 to 5) := "000000";
|
||
|
constant IFETCHPRE : std_logic_vector(0 to 5) := "000001";
|
||
|
constant LOAD : std_logic_vector(0 to 5) := "001000";
|
||
|
constant STORE : std_logic_vector(0 to 5) := "100000";
|
||
|
|
||
|
constant LARX : std_logic_vector(0 to 5) := "001001";
|
||
|
constant LARXHINT : std_logic_vector(0 to 5) := "001011";
|
||
|
constant STCX : std_logic_vector(0 to 5) := "101011";
|
||
|
|
||
|
constant LWSYNC : std_logic_vector(0 to 5) := "101010";
|
||
|
constant HWSYNC : std_logic_vector(0 to 5) := "101011";
|
||
|
constant MBAR : std_logic_vector(0 to 5) := "110010";
|
||
|
constant TLBSYNC : std_logic_vector(0 to 5) := "111010";
|
||
|
|
||
|
constant DCBI : std_logic_vector(0 to 5) := "111111";
|
||
|
|
||
|
function or_reduce(slv: in std_logic_vector) return std_logic;
|
||
|
function and_reduce(slv: in std_logic_vector) return std_logic;
|
||
|
function inc(a: in std_logic_vector) return std_logic_vector;
|
||
|
function inc(a: in std_logic_vector; b: in integer) return std_logic_vector;
|
||
|
function dec(a: in std_logic_vector) return std_logic_vector;
|
||
|
function eq(a: in std_logic_vector; b: in integer) return boolean;
|
||
|
function eq(a: in std_logic_vector; b: in integer) return std_logic;
|
||
|
function eq(a: in std_logic_vector; b: in std_logic_vector) return boolean;
|
||
|
function eq(a: in std_logic_vector; b: in std_logic_vector) return std_logic;
|
||
|
function ne(a: in std_logic_vector; b: in integer) return boolean;
|
||
|
function ne(a: in std_logic_vector; b: in integer) return std_logic;
|
||
|
function ne(a: in std_logic_vector; b: in std_logic_vector) return boolean;
|
||
|
function ne(a: in std_logic_vector; b: in std_logic_vector) return std_logic;
|
||
|
function gt(a: in std_logic_vector; b: in integer) return boolean;
|
||
|
function gt(a: in std_logic_vector; b: in std_logic_vector) return boolean;
|
||
|
function gt(a: in std_logic_vector; b: in std_logic_vector) return std_logic;
|
||
|
function nz(a: in std_logic_vector) return boolean;
|
||
|
function nz(a: in std_logic_vector) return std_logic;
|
||
|
function b(a: in boolean) return std_logic;
|
||
|
function b(a: in std_logic) return boolean;
|
||
|
|
||
|
function clog2(n : in integer) return integer;
|
||
|
function conv_integer(a: in std_logic_vector) return integer;
|
||
|
function max(a: in integer; b: in integer) return integer;
|
||
|
|
||
|
function right_one(a: in std_logic_vector) return std_logic_vector;
|
||
|
function gate_and(a: in std_logic; b: in std_logic_vector) return std_logic_vector;
|
||
|
function rotl(a: in std_logic_vector; b: in integer) return std_logic_vector;
|
||
|
function rotl(a: in std_logic_vector; b: in std_logic_vector) return std_logic_vector;
|
||
|
function rotr(a: in std_logic_vector; b: in integer) return std_logic_vector;
|
||
|
function rotr(a: in std_logic_vector; b: in std_logic_vector) return std_logic_vector;
|
||
|
function enc(a: in std_logic_vector) return std_logic_vector;
|
||
|
function enc(a: in std_logic_vector; b: in integer) return std_logic_vector;
|
||
|
|
||
|
subtype RADDR is std_logic_vector(64-42 to 63);
|
||
|
subtype LINEADDR is std_logic_vector(64-42 to 59);
|
||
|
|
||
|
type A2L2REQUEST is record
|
||
|
valid : std_logic;
|
||
|
sent : std_logic;
|
||
|
data : std_logic;
|
||
|
dseq : std_logic_vector(0 to 2);
|
||
|
endian : std_logic;
|
||
|
tag : std_logic_vector(0 to 4);
|
||
|
len : std_logic_vector(0 to 2);
|
||
|
ra : RADDR;
|
||
|
thread : std_logic_vector(0 to 1);
|
||
|
spec : std_logic;
|
||
|
ditc : std_logic;
|
||
|
ttype : std_logic_vector(0 to 5);
|
||
|
user : std_logic_vector(0 to 3);
|
||
|
wimg : std_logic_vector(0 to 3);
|
||
|
hwsync : std_logic;
|
||
|
end record;
|
||
|
|
||
|
type A2L2STOREDATA is record
|
||
|
data : std_logic_vector(0 to 127);
|
||
|
be : std_logic_vector(0 to 15);
|
||
|
end record;
|
||
|
|
||
|
type A2L2RELOAD is record
|
||
|
coming : std_logic;
|
||
|
valid : std_logic;
|
||
|
tag : std_logic_vector(0 to 4);
|
||
|
data : std_logic_vector(0 to 127);
|
||
|
ee : std_logic;
|
||
|
ue : std_logic;
|
||
|
qw : std_logic_vector(57 to 59);
|
||
|
crit : std_logic;
|
||
|
dump : std_logic;
|
||
|
end record;
|
||
|
|
||
|
type A2L2STATUS is record
|
||
|
ld_pop : std_logic;
|
||
|
st_pop : std_logic;
|
||
|
st_pop_thrd : std_logic_vector(0 to 2);
|
||
|
gather : std_logic;
|
||
|
res_valid : std_logic_vector(0 to 3);
|
||
|
stcx_complete : std_logic_vector(0 to 3);
|
||
|
stcx_pass : std_logic_vector(0 to 3);
|
||
|
sync_ack : std_logic_vector(0 to 3);
|
||
|
--back_inv, back_inv_target, back_inv_addr, back_inv_ind, back_inv_gs, back_inv_lbit, back_inv_lpar_id, back_inv_local, back_inv_reject
|
||
|
--icbi_ack, icbi_ack_thread
|
||
|
--ext_interrupt, crit_interrupt, perf_interrupt
|
||
|
--power_managed, rvwinkle_mode, sleep_en
|
||
|
--FLH2L2_GATE
|
||
|
end record;
|
||
|
|
||
|
type A2L2RESV is record
|
||
|
valid : std_logic;
|
||
|
ra : LINEADDR;
|
||
|
end record;
|
||
|
|
||
|
type LOADQUEUE is array(0 to c_ld_queue_size-1) of A2L2REQUEST;
|
||
|
type LOADDATAQUEUE is array(0 to c_ld_queue_size*16-1) of std_logic_vector(0 to 31);
|
||
|
type LOADQUEUEDEP is array(0 to c_ld_queue_size-1) of std_logic_vector(0 to c_st_queue_bits); -- 0: valid
|
||
|
type STOREQUEUE is array(0 to c_st_queue_size-1) of A2L2REQUEST;
|
||
|
type STOREDATAQUEUE is array(0 to c_st_queue_size-1) of A2L2STOREDATA;
|
||
|
type STOREQUEUEDEP is array(0 to c_st_queue_size-1) of std_logic_vector(0 to c_ld_queue_bits); -- 0: valid
|
||
|
type RESVARRAY is array(0 to 3) of A2L2RESV;
|
||
|
|
||
|
function address_check(a: in A2L2REQUEST; b: in A2L2REQUEST) return std_logic;
|
||
|
|
||
|
function mux_queue(a: in LOADQUEUE; b: in std_logic_vector) return A2L2REQUEST;
|
||
|
function mux_queue(a: in LOADDATAQUEUE; b: in integer) return std_logic_vector;
|
||
|
function mux_queue(a: in LOADDATAQUEUE; b: in std_logic_vector) return std_logic_vector;
|
||
|
function mux_queue(a: in LOADQUEUEDEP; b: in std_logic_vector) return std_logic_vector;
|
||
|
function mux_queue(a: in STOREQUEUE; b: in std_logic_vector) return A2L2REQUEST;
|
||
|
function mux_queue(a: in STOREDATAQUEUE; b: in std_logic_vector) return A2L2STOREDATA;
|
||
|
function mux_queue(a: in STOREQUEUEDEP; b: in std_logic_vector) return std_logic_vector;
|
||
|
|
||
|
end a2x_pkg;
|
||
|
|
||
|
package body a2x_pkg is
|
||
|
|
||
|
|
||
|
function or_reduce(slv: in std_logic_vector) return std_logic is
|
||
|
variable res: std_logic := '0';
|
||
|
begin
|
||
|
for i in slv'range loop
|
||
|
res := res or slv(i);
|
||
|
end loop;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function and_reduce(slv: in std_logic_vector) return std_logic is
|
||
|
variable res: std_logic := '1';
|
||
|
begin
|
||
|
for i in slv'range loop
|
||
|
res := res and slv(i);
|
||
|
end loop;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function inc(a: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a'length-1);
|
||
|
begin
|
||
|
res := std_logic_vector(unsigned(a) + 1);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function inc(a: in std_logic_vector; b: in integer) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a'length-1);
|
||
|
begin
|
||
|
res := std_logic_vector(unsigned(a) + b);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function dec(a: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a'length-1);
|
||
|
begin
|
||
|
res := std_logic_vector(unsigned(a) - 1);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function eq(a: in std_logic_vector; b: in integer) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
res := unsigned(a) = b;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function eq(a: in std_logic_vector; b: in integer) return std_logic is
|
||
|
variable res: std_logic;
|
||
|
begin
|
||
|
if unsigned(a) = b then
|
||
|
res := '1';
|
||
|
else
|
||
|
res := '0';
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function eq(a: in std_logic_vector; b: in std_logic_vector) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
res := unsigned(a) = unsigned(b);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function eq(a: in std_logic_vector; b: in std_logic_vector) return std_logic is
|
||
|
variable res: std_logic;
|
||
|
begin
|
||
|
if unsigned(a) = unsigned(b) then
|
||
|
res := '1';
|
||
|
else
|
||
|
res := '0';
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function ne(a: in std_logic_vector; b: in integer) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
res := unsigned(a) /= b;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function ne(a: in std_logic_vector; b: in integer) return std_logic is
|
||
|
variable res: std_logic;
|
||
|
begin
|
||
|
if unsigned(a) /= b then
|
||
|
res := '1';
|
||
|
else
|
||
|
res := '0';
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function ne(a: in std_logic_vector; b: in std_logic_vector) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
res := unsigned(a) /= unsigned(b);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function ne(a: in std_logic_vector; b: in std_logic_vector) return std_logic is
|
||
|
variable res: std_logic;
|
||
|
begin
|
||
|
if unsigned(a) /= unsigned(b) then
|
||
|
res := '1';
|
||
|
else
|
||
|
res := '0';
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function gt(a: in std_logic_vector; b: in integer) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
res := unsigned(a) > b;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function gt(a: in std_logic_vector; b: in std_logic_vector) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
res := unsigned(a) > unsigned(b);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function gt(a: in std_logic_vector; b: in std_logic_vector) return std_logic is
|
||
|
variable res: std_logic;
|
||
|
begin
|
||
|
if unsigned(a) > unsigned(b) then
|
||
|
res := '1';
|
||
|
else
|
||
|
res := '0';
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function nz(a: in std_logic_vector) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
res := unsigned(a) /= 0;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function nz(a: in std_logic_vector) return std_logic is
|
||
|
variable res: std_logic;
|
||
|
begin
|
||
|
if unsigned(a) /= 0 then
|
||
|
res := '1';
|
||
|
else
|
||
|
res := '0';
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function b(a: in boolean) return std_logic is
|
||
|
variable res: std_logic;
|
||
|
begin
|
||
|
if a then
|
||
|
res := '1';
|
||
|
else
|
||
|
res := '0';
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function b(a: in std_logic) return boolean is
|
||
|
variable res: boolean;
|
||
|
begin
|
||
|
if a = '1' then
|
||
|
res := true;
|
||
|
else
|
||
|
res := false;
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function right_one(a: in std_logic_vector) return std_logic_vector is
|
||
|
variable res : std_logic_vector(0 to a'length - 1);
|
||
|
begin
|
||
|
for i in a'length - 1 downto 0 loop
|
||
|
if a(i) = '1' then
|
||
|
res(i) := '1';
|
||
|
exit;
|
||
|
end if;
|
||
|
end loop;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function rotl(a: in std_logic_vector; b: in integer) return std_logic_vector is
|
||
|
variable res : std_logic_vector(0 to a'length - 1);
|
||
|
begin
|
||
|
res := a(b to a'length - 1) & a(0 to b - 1);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function rotl(a: in std_logic_vector; b: in std_logic_vector) return std_logic_vector is
|
||
|
variable res : std_logic_vector(0 to a'length - 1) := a;
|
||
|
variable c : integer := conv_integer(b);
|
||
|
variable i : integer;
|
||
|
begin
|
||
|
for i in 0 to a'length - 1 loop
|
||
|
if (i + c < a'length) then
|
||
|
res(i) := a(i + c);
|
||
|
else
|
||
|
res(i) := a(i + c - a'length);
|
||
|
end if;
|
||
|
end loop;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function rotr(a: in std_logic_vector; b: in integer) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a'length - 1);
|
||
|
begin
|
||
|
res := a(a'length - b to a'length - 1) & a(0 to a'length - b - 1);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function rotr(a: in std_logic_vector; b: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a'length - 1);
|
||
|
variable c : integer := conv_integer(b);
|
||
|
begin
|
||
|
for i in 0 to a'length - 1 loop
|
||
|
if (a'length - c + i < a'length) then
|
||
|
res(i) := a(a'length - c + i);
|
||
|
else
|
||
|
res(i) := a(-c + i);
|
||
|
end if;
|
||
|
end loop;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function gate_and(a: in std_logic; b: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to b'length-1);
|
||
|
begin
|
||
|
if a = '1' then
|
||
|
res := b;
|
||
|
else
|
||
|
res := (others => '0');
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function enc(a: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to clog2(a'length)-1) := (others => '0');
|
||
|
begin
|
||
|
for i in 0 to a'length - 1 loop
|
||
|
if (a(i) = '1') then
|
||
|
res := std_logic_vector(to_unsigned(i, res'length));
|
||
|
exit;
|
||
|
end if;
|
||
|
end loop;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function enc(a: in std_logic_vector; b: in integer) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to b-1) := (others => '0');
|
||
|
begin
|
||
|
for i in 0 to a'length - 1 loop
|
||
|
if (a(i) = '1') then
|
||
|
res := std_logic_vector(to_unsigned(i, res'length));
|
||
|
exit;
|
||
|
end if;
|
||
|
end loop;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function conv_integer(a: in std_logic_vector) return integer is
|
||
|
variable res: integer;
|
||
|
begin
|
||
|
res := to_integer(unsigned(a));
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function max(a: in integer; b: in integer) return integer is
|
||
|
variable res : integer;
|
||
|
begin
|
||
|
if (a > b) then
|
||
|
res := a;
|
||
|
else
|
||
|
res := b;
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function mux_queue(a: in LOADQUEUE; b: in std_logic_vector) return A2L2REQUEST is
|
||
|
variable res: A2L2REQUEST;
|
||
|
begin
|
||
|
res := a(conv_integer(b));
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function mux_queue(a: in LOADDATAQUEUE; b: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a(0)'length-1);
|
||
|
begin
|
||
|
res := a(conv_integer(b));
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function mux_queue(a: in LOADDATAQUEUE; b: in integer) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a(0)'length-1);
|
||
|
begin
|
||
|
res := a(b);
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function mux_queue(a: in LOADQUEUEDEP; b: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a(0)'length-1);
|
||
|
begin
|
||
|
res := a(conv_integer(b));
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
|
||
|
function mux_queue(a: in STOREQUEUE; b: in std_logic_vector) return A2L2REQUEST is
|
||
|
variable res: A2L2REQUEST;
|
||
|
begin
|
||
|
res := a(conv_integer(b));
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function mux_queue(a: in STOREDATAQUEUE; b: in std_logic_vector) return A2L2STOREDATA is
|
||
|
variable res: A2L2STOREDATA;
|
||
|
begin
|
||
|
res := a(conv_integer(b));
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function mux_queue(a: in STOREQUEUEDEP; b: in std_logic_vector) return std_logic_vector is
|
||
|
variable res: std_logic_vector(0 to a(0)'length-1);
|
||
|
begin
|
||
|
res := a(conv_integer(b));
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function address_check(a: in A2L2REQUEST; b: in A2L2REQUEST) return std_logic is
|
||
|
variable res: std_logic := '0';
|
||
|
variable a_start, a_end, b_start, b_end : unsigned(0 to a.ra'length-1);
|
||
|
begin
|
||
|
a_start := unsigned(a.ra);
|
||
|
a_end := unsigned(a.ra) + 64;
|
||
|
b_start := unsigned(b.ra);
|
||
|
b_end := unsigned(b.ra) + 64;
|
||
|
if ((a.valid = '1') and (a.spec = '0') and (b.valid = '1') and (b.spec = '0')) then
|
||
|
if ((a_start >= b_start) and (a_start <= b_end)) then
|
||
|
res := '1';
|
||
|
elsif ((a_end >= b_start) and (a_end <= b_end)) then
|
||
|
res := '1';
|
||
|
end if;
|
||
|
end if;
|
||
|
return res;
|
||
|
end function;
|
||
|
|
||
|
function clog2(n : in integer) return integer is
|
||
|
variable i : integer;
|
||
|
variable j : integer := n - 1;
|
||
|
variable res : integer := 1;
|
||
|
begin
|
||
|
for i in 0 to 31 loop
|
||
|
if (j > 1) then
|
||
|
j := j / 2;
|
||
|
res := res + 1;
|
||
|
else
|
||
|
exit;
|
||
|
end if;
|
||
|
end loop;
|
||
|
return res;
|
||
|
end;
|
||
|
|
||
|
end a2x_pkg;
|
||
|
|